void Slider::update () { sprite[pingu->direction].update(); for (int i = 0; i < speed && rel_getpixel(1, 0) == Groundtype::GP_NOTHING; ++i) { pingu->set_x(pingu->get_x() + static_cast<float>(pingu->direction)); if (rel_getpixel(0, -1) == Groundtype::GP_NOTHING) { speed = (speed > 5) ? 5 : speed; if (pingu->direction.is_right()) { pingu->set_velocity(pingu->get_velocity() + Vector3f(speed, 0.0)); } else { pingu->set_velocity(pingu->get_velocity() + Vector3f(-speed, 0.0)); } pingu->set_action(ActionName::WALKER); return; } } speed -= 7 * 0.025f; if (speed < 1) { pingu->set_action(ActionName::WALKER); return; } }
Blocker::Blocker(Pingu* p) : PinguAction(p) { sprite.load(Direction::LEFT, "pingus/player" + pingu->get_owner_str() + "/blocker/left"); sprite.load(Direction::RIGHT, "pingus/player" + pingu->get_owner_str() + "/blocker/right"); if ( rel_getpixel(0,-1) == Groundtype::GP_NOTHING && rel_getpixel(0, -2) == Groundtype::GP_GROUND) { pingu->set_y(pingu->get_y() + 1); } else if ( rel_getpixel(0,-1) == Groundtype::GP_NOTHING && rel_getpixel(0,-2) == Groundtype::GP_NOTHING && rel_getpixel(0,-3) == Groundtype::GP_GROUND) { pingu->set_y(pingu->get_y() + 2); } }
bool Digger::have_something_to_dig () { if (rel_getpixel(0, -1) != Groundtype::GP_NOTHING) { if (rel_getpixel(0, -1) == Groundtype::GP_SOLID) { Sound::PingusSound::play_sound("chink"); return false; } else return true; } else { return false; } }
bool PinguAction::head_collision_on_walk (int x, int y) { int pixel = rel_getpixel(x, y + pingu_height); if (pixel != Groundtype::GP_NOTHING && !(pixel & Groundtype::GP_BRIDGE)) return true; return false; }
void Digger::update () { sprite.update (); if (rel_getpixel(0, -1) == Groundtype::GP_WATER || rel_getpixel(0, -1) == Groundtype::GP_LAVA) { pingu->set_action(Actions::Drown); return; } if (++digger_c >= 5) { digger_c = 0; dig(); } if (!have_something_to_dig()) { dig (); pingu->set_action(Actions::Walker); } }
bool PinguAction::collision_on_walk (int x, int y) { bool collision = false; int pixel = Groundtype::GP_NOTHING; for (int pingu_y = 0; pingu_y <= pingu_height; ++pingu_y) { pixel = rel_getpixel(x, y + pingu_y); if (pixel != Groundtype::GP_NOTHING && pixel != Groundtype::GP_BRIDGE) { collision = true; break; } } return collision; }
void Floater::update() { sprite.update (); pingu->set_velocity(Vector3f(0.0f, 1.0f)); if (rel_getpixel(0, -1) == Groundtype::GP_NOTHING) { ++step; if (step > 0) { pingu->set_y(pingu->get_y() + 1); step = 0; } } else { pingu->set_action (ActionName::WALKER); } }
void Walker::update () { // update the sprite walker[pingu->direction].update(0.033f); floaterlayer[pingu->direction].update(0.033f); Vector3f last_pos = pingu->get_pos(); /* How should this code work? 1) Check that the Pingu stands still on ground, if not turn it into a faller or drown. The reason we do so, is that we catch situations where a digger or a similar action removed the ground under the walker. 2) If pingu is still on ground, we can preprare the next step 3) Check if up-hill or down-hill is required 4) */ if (rel_getpixel(1, 0) == Groundtype::GP_OUTOFSCREEN) { pingu->set_x(pingu->get_x() + static_cast<float>(pingu->direction)); return; } if (rel_getpixel(0, -1) == Groundtype::GP_WATER) { pingu->set_action(ActionName::DROWN); return; } // The Pingu stands no longer on ground, the cause for this could be // a digger, miner or a bomber if (rel_getpixel(0, -1) == Groundtype::GP_NOTHING) { // We search for the nearest ground below the pingu, if we can't // find anything within a few pixels, we will turn into a faller bool found_ground = false; int i; for (i = -2; i > -5; --i) { if (!(rel_getpixel(0, i) == Groundtype::GP_NOTHING)) { found_ground = true; break; } } if (found_ground) { pingu->set_y(pingu->get_y() - static_cast<float>(i)); } else { pingu->set_action(ActionName::FALLER); return; } } // FIXME: here we could/should scan more pixels if (rel_getpixel(1, 0) == Groundtype::GP_BRIDGE && !head_collision_on_walk(1, 1)) // bridge { // simple, stupid, but working bridge code // FIXME: We don't check if we 'drift' into a solid ground block pingu->set_pos(pingu->get_x() + static_cast<float>(pingu->direction), pingu->get_y() - 1.0f); // pingus 'float' through bridges } else { // Non of the trivial moves worked, so we do up-hill or down-hill walking // FIXME: currently the pingu takes multiple steps at once when // FIXME: working uphill, this looks kind of ugly // FIXME: rel_getpixel works on the current pos, so modifing pos // FIXME: is evil, a backup copy might help // if infront is a pixel // Pingu is walking up the mountain // we can continue walking up. search for the correct y_pos int y_inc = 0; int possible_y_step = 0; bool found_next_step = false; for (y_inc = -max_steps; y_inc <= max_steps; ++y_inc) {// up/down-hill scan if (( rel_getpixel(1, y_inc) == Groundtype::GP_NOTHING || rel_getpixel(1, y_inc) == Groundtype::GP_BRIDGE) // FIXME: This causes a rather huge step && rel_getpixel(1, y_inc - 1) != Groundtype::GP_NOTHING) { // FIXME: found_next_step = true; possible_y_step = y_inc; // No break here, since we always want to use the highest possible position //break; } } if (found_next_step) { // pos.y has a reversed co-system to rel_getpixel()? pingu->set_pos(pingu->get_x() + static_cast<float>(pingu->direction), pingu->get_y() - static_cast<float>(possible_y_step)); } else { if (rel_getpixel(1, 0) != Groundtype::GP_NOTHING) { // We reached a wall if (pingu->request_wall_action()) { pout(PINGUS_DEBUG_ACTIONS) << "Pingu: We are in front of a wall, setting persistant action" << std::endl; return; } // No persitent action found, so change the direction pingu->direction.change(); } else { // We take the step, so that we are in the air pingu->set_x(pingu->get_x() + static_cast<float>(pingu->direction)); // We reached a cliff pingu->set_action(ActionName::FALLER); return; } } } // This is moved here to fix the bug where pingu stuck turning both // sides indefinetely when a head collision occured. the fix needs the // above downhill walk being done before head collision check. if (head_collision_on_walk(0, 0)) { pout(PINGUS_DEBUG_ACTIONS) << "Pingu: Head collision" << std::endl; //if the new position causes a head collision, we are already //stuck in a wall, so lets go back to the old position pingu->direction.change(); pingu->set_pos(last_pos); return; } /* for(int y_inc=1; y_inc <= max_steps; ++y_inc) { if (rel_getpixel(1, -y_inc) == ColMap::WATER) { pingu->set_paction ("drown"); return; } else if(rel_getpixel(1, -y_inc) != ColMap::NOTHING) { // there is land pingu->pos.y += y_inc - 1; break; } } */ }
bool Blocker::standing_on_ground() { return (rel_getpixel(0,-1) != Groundtype::GP_NOTHING); }
void PinguAction::move_with_forces () { // Apply gravity pingu->set_velocity(pingu->get_velocity() + Vector3f(0.0f, 1.0f)); #if 0 // New Code Vector3f pos = pingu->get_pos(); Vector3f target_pos = pos + pingu->get_velocity(); Vector3f dir = target_pos - pingu->get_pos(); Vector3f velocity = pingu->get_velocity(); float length = dir.length(); dir.normalize(); for(float i = 0; i < length; ++i) { pingu->set_pos(pos + (dir * i)); // If there is something below the Pingu if (rel_getpixel(0, -1) != Groundtype::GP_NOTHING) { // FIXME: this shouldn't be really here, but its a // FIXME: quick&dirty way to kill falling pingus if (velocity.y > Actions::Faller::deadly_velocity+1) { // log_debug("Velocity: " << velocity); pingu->set_action(Actions::Splashed); return; } else { // Make it so that the Pingu won't go down any further. pingu->set_velocity(Vector3f(0, 0)); return; } } else if (head_collision_on_walk(0, 1)) { return; } else if (collision_on_walk(1, 0)) { // Make the Pingu bounce off the wall velocity.x = -velocity.x / 3.0f; pingu->set_velocity(velocity); pingu->direction.change(); return; } } #else // Old Code // FIXME: What does this variable do? Vector3f resultant_force = pingu->get_velocity(); // FIXME: and what is this all about?! Can't we just use floats? // Strictly speaking x_numerator should be initialised with // (resultant_force.y / 2) and y_numerator with (resultant_force.x / 2). // This would make the algorithm essentially match the Mid-Point Line // Algorithm. However, zero should do and is more comprehendable. int x_numerator = 0; int y_numerator = 0; int denominator = 0; int x_inc = 0; int y_inc = 0; if (Math::abs(resultant_force.x) > Math::abs(resultant_force.y)) { // Initialise so that we move in whole pixels in x direction and // 'fractions' of a pixel in y direction. denominator = static_cast<int>(Math::abs(resultant_force.x)); x_inc = denominator; y_inc = static_cast<int>(Math::abs(resultant_force.y)); } else { // Initialise so that we move in whole pixels in y direction and // 'fractions' of a pixel in x direction. denominator = static_cast<int>(Math::abs(resultant_force.y)); x_inc = static_cast<int>(Math::abs(resultant_force.x)); y_inc = denominator; } Vector3f force_counter = resultant_force; // Keep moving the Pingu until there is only a fraction left while ( force_counter.x <= -1 || force_counter.x >= 1 || force_counter.y <= -1 || force_counter.y >= 1) { x_numerator += x_inc; // Is it now not a fraction? if (x_numerator >= denominator) { // Revert back to being a fraction x_numerator -= denominator; // If there is something to the left of the Pingu if (collision_on_walk(1, 0)) { // Make the Pingu reflect off the wall force_counter.x = -(force_counter.x); resultant_force.x = -(resultant_force.x/3); pingu->set_velocity(resultant_force); pingu->direction.change(); } else { // Move the Pingu left pingu->set_x(pingu->get_x() + static_cast<float>(pingu->direction)); force_counter.x -= static_cast<float>(pingu->direction); } } y_numerator += y_inc; // Is it now not a fraction? if (y_numerator >= denominator) { // Revert back to being a fraction y_numerator -= denominator; // Move the Pingu depending on what the direction of the force is if (force_counter.y >= 1) { // If there is something below the Pingu if (rel_getpixel(0, -1) != Groundtype::GP_NOTHING) { // FIXME: this shouldn't be really here, but its a // FIXME: quick&dirty way to kill falling pingus if (resultant_force.y >= deadly_velocity) { pingu->set_action(ActionName::SPLASHED); return; } // Make it so that the Pingu won't go down any further. pingu->set_velocity(Vector3f(0, 0)); return; } else { // Move the Pingu down pingu->set_y(pingu->get_y() + 1); force_counter.y--; } } else if (force_counter.y <= -1) { // If there is something in the way above the Pingu if (head_collision_on_walk(0, 1)) { // Make it so that the Pingu won't go up any further. force_counter.y = 0; resultant_force.y = 0; pingu->set_velocity(resultant_force); } else { // Move the Pingu up pingu->set_y(pingu->get_y() - 1); force_counter.y++; } } } } #endif }