X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fobject%2Fplayer.cpp;h=2005f512d179c36d937e650fe1da40a2fac01c12;hb=5f1c84ed5ce0ab5450f92082a9aaaa9ca0effc39;hp=a7643b79d12bef5bf2b54d86f5e3e980332222eb;hpb=4378796209c0979eb096ece16425d29464d8669a;p=supertux.git diff --git a/src/object/player.cpp b/src/object/player.cpp index a7643b79d..2005f512d 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -64,6 +64,8 @@ static const float WALK_SPEED = 100; static const float KICK_TIME = .3; +static const float UNDUCK_HURT_TIME = 0.25; /**< if Tux cannot unduck for this long, he will get hurt */ + // growing animation Surface* growingtux_left[GROWING_FRAMES]; Surface* growingtux_right[GROWING_FRAMES]; @@ -102,7 +104,7 @@ TuxBodyParts::draw(DrawingContext& context, const Vector& pos, int layer) } Player::Player(PlayerStatus* _player_status) - : player_status(_player_status), grabbed_object(0) + : player_status(_player_status), grabbed_object(NULL), ghost_mode(false) { controller = main_controller; smalltux_gameover = sprite_manager->create("images/creatures/tux_small/smalltux-gameover.sprite"); @@ -128,10 +130,9 @@ void Player::init() { if(is_big()) - bbox.set_size(31.8, 62.8); + set_size(31.8, 62.8); else - bbox.set_size(31.8, 30.8); - adjust_height = 0; + set_size(31.8, 30.8); dir = RIGHT; old_dir = dir; @@ -150,7 +151,7 @@ Player::init() visible = true; on_ground_flag = false; - grabbed_object = 0; + grabbed_object = NULL; floor_normal = Vector(0,-1); @@ -176,6 +177,20 @@ Player::set_controller(Controller* controller) this->controller = controller; } +bool +Player::adjust_height(float new_height) +{ + Rect bbox2 = bbox; + bbox2.move(Vector(0, bbox.get_height() - new_height)); + bbox2.set_height(new_height); + if (!Sector::current()->is_free_space(bbox2)) return false; + // adjust bbox accordingly + // note that we use members of moving_object for this, so we can run this during CD, too + set_pos(bbox2.p1); + set_size(bbox2.get_width(), bbox2.get_height()); + return true; +} + void Player::update(float elapsed_time) { @@ -184,26 +199,20 @@ Player::update(float elapsed_time) return; } - if(adjust_height != 0) { - bbox.move(Vector(0, bbox.get_height() - adjust_height)); - bbox.set_height(adjust_height); - adjust_height = 0; - } - if(!dying && !deactivated) handle_input(); movement = physic.get_movement(elapsed_time); - if(grabbed_object != 0 && !dying ) { + if(grabbed_object != NULL && !dying) { Vector pos = get_pos() + - Vector(dir == LEFT ? -16 : 16, - bbox.get_height()*0.66666 - 32); + Vector(dir == LEFT ? -16 : 16, get_bbox().get_height()*0.66666 - 32); grabbed_object->grab(*this, pos, dir); } - if(grabbed_object != 0 && dying){ + if(grabbed_object != NULL && dying){ grabbed_object->ungrab(*this, dir); + grabbed_object = NULL; } on_ground_flag = false; @@ -282,7 +291,7 @@ Player::handle_horizontal_input() // dust some particles Sector::current()->add_object( new Particles( - Vector(dir == RIGHT ? bbox.p2.x : bbox.p1.x, bbox.p2.y), + Vector(dir == RIGHT ? get_bbox().p2.x : get_bbox().p1.x, get_bbox().p2.y), dir == RIGHT ? 270+20 : 90-40, dir == RIGHT ? 270+40 : 90-20, Vector(280, -260), Vector(0, 300), 3, Color(.4, .4, .4), 3, .8, LAYER_OBJECTS+1)); @@ -295,7 +304,7 @@ Player::handle_horizontal_input() // we get slower when not pressing any keys if(dirsign == 0) { - if(fabs(vx) < WALK_SPEED) { + if ((on_ground()) && (fabs(vx) < WALK_SPEED)) { vx = 0; ax = 0; } else if(vx < 0) { @@ -323,9 +332,9 @@ Player::handle_horizontal_input() // extend/shrink tux collision rectangle so that we fall through/walk over 1 // tile holes if(fabsf(vx) > MAX_WALK_XM) { - bbox.set_width(34); + set_width(34); } else { - bbox.set_width(31.8); + set_width(31.8); } // on downward slopes, adjust vertical velocity to match slope angle @@ -466,6 +475,11 @@ Player::handle_vertical_input() void Player::handle_input() { + if (ghost_mode) { + handle_input_ghost(); + return; + } + if(!controller->hold(Controller::ACTION) && grabbed_object) { // move the grabbed object a bit away from tux Vector pos = get_pos() + @@ -480,7 +494,7 @@ Player::handle_input() log_debug << "Non MovingObjetc grabbed?!?" << std::endl; } grabbed_object->ungrab(*this, dir); - grabbed_object = 0; + grabbed_object = NULL; } } @@ -512,28 +526,45 @@ Player::handle_input() /* Duck! */ if (controller->hold(Controller::DOWN) && is_big() && !duck && physic.get_velocity_y() == 0 && on_ground()) { - duck = true; - bbox.move(Vector(0, 32)); - bbox.set_height(31.8); - } else if(!controller->hold(Controller::DOWN) && is_big() && duck) { - // if we have some velocity left then check if there is space for - // unducking - bbox.move(Vector(0, -32)); - bbox.set_height(63.8); - if(Sector::current()->is_free_space(bbox) || ( - physic.get_velocity_x() > -.01 && physic.get_velocity_x() < .01 - && physic.get_velocity_y() > -.01 && physic.get_velocity_y() < .01)) - { + if (adjust_height(31.8)) { + duck = true; + unduck_hurt_timer.stop(); + } else { + // FIXME: what now? + } + } + /* Unduck! */ + else if(!controller->hold(Controller::DOWN) && is_big() && duck) { + if (adjust_height(63.8)) { duck = false; + unduck_hurt_timer.stop(); } else { - // undo the ducking changes - bbox.move(Vector(0, 32)); - bbox.set_height(31.8); + // if timer is not already running, start it. + if (unduck_hurt_timer.get_period() == 0) { + unduck_hurt_timer.start(UNDUCK_HURT_TIME); + } + else if (unduck_hurt_timer.check()) { + kill(false); + } } } } void +Player::handle_input_ghost() +{ + float vx = 0; + float vy = 0; + if (controller->hold(Controller::LEFT)) vx -= MAX_RUN_XM; + if (controller->hold(Controller::RIGHT)) vx += MAX_RUN_XM; + if ((controller->hold(Controller::UP)) || (controller->hold(Controller::JUMP))) vy += MAX_RUN_XM; + if (controller->hold(Controller::DOWN)) vy -= MAX_RUN_XM; + if (controller->hold(Controller::ACTION)) set_ghost_mode(false); + physic.set_velocity(vx, vy); + physic.set_acceleration(0, 0); +} + +void Player::add_coins(int count) { player_status->add_coins(count); @@ -579,7 +610,7 @@ void Player::set_bonus(BonusType type, bool animate) { if(player_status->bonus == NO_BONUS) { - adjust_height = 62.8; + if (!adjust_height(62.8)) return; if(animate) growing_timer.start(GROWING_TIME); } @@ -720,13 +751,14 @@ Player::draw(DrawingContext& context) /* Draw Tux */ if(dying) { smalltux_gameover->draw(context, get_pos(), LAYER_FLOATINGOBJECTS + 1); - } else if(growing_timer.get_timeleft() > 0) { + } + else if ((growing_timer.get_timeleft() > 0) && (!duck)) { if (dir == RIGHT) { context.draw_surface(growingtux_right[int((growing_timer.get_timegone() * - GROWING_FRAMES) / GROWING_TIME)], get_pos() - Vector(0, 32), layer); + GROWING_FRAMES) / GROWING_TIME)], get_pos(), layer); } else { context.draw_surface(growingtux_left[int((growing_timer.get_timegone() * - GROWING_FRAMES) / GROWING_TIME)], get_pos() - Vector(0, 32), layer); + GROWING_FRAMES) / GROWING_TIME)], get_pos(), layer); } } else if (safe_timer.started() && size_t(game_time*40)%2) @@ -764,9 +796,12 @@ Player::collision(GameObject& other, const CollisionHit& hit) if(other.get_flags() & FLAG_PORTABLE) { Portable* portable = dynamic_cast (&other); - if(portable && grabbed_object == 0 && controller->hold(Controller::ACTION) + assert(portable != NULL); + if(portable && grabbed_object == NULL + && controller->hold(Controller::ACTION) && fabsf(hit.normal.x) > .9) { grabbed_object = portable; + grabbed_object->grab(*this, get_pos(), dir); return CONTINUE; } } @@ -851,7 +886,7 @@ Player::collision(GameObject& other, const CollisionHit& hit) BadGuy* badguy = dynamic_cast (&other); if(badguy != NULL) { - if(safe_timer.started()) + if(safe_timer.started() || invincible_timer.started()) return FORCE_MOVE; return CONTINUE; @@ -875,8 +910,7 @@ Player::kill(bool completely) if(dying || deactivated) return; - if(!completely && - (safe_timer.get_timeleft() > 0 || invincible_timer.get_timeleft() > 0)) + if(!completely && safe_timer.started() || invincible_timer.started()) return; sound_manager->play("sounds/hurt.wav"); @@ -891,7 +925,7 @@ Player::kill(bool completely) } else { //growing_timer.start(GROWING_TIME); safe_timer.start(TUX_SAFE_TIME /* + GROWING_TIME */); - adjust_height = 30.8; + adjust_height(30.8); duck = false; set_bonus(NO_BONUS); } @@ -922,11 +956,13 @@ Player::kill(bool completely) void Player::move(const Vector& vector) { - bbox.set_pos(vector); + set_pos(vector); + + // TODO: do we need the following? Seems irrelevant to moving the player if(is_big()) - bbox.set_size(31.8, 63.8); + set_size(31.8, 63.8); else - bbox.set_size(31.8, 31.8); + set_size(31.8, 31.8); duck = false; last_ground_y = vector.y; @@ -940,7 +976,7 @@ Player::check_bounds(Camera* camera) if (get_pos().x < 0) { // Lock Tux to the size of the level, so that he doesn't fall of // on the left side - bbox.set_pos(Vector(0, get_pos().y)); + set_pos(Vector(0, get_pos().y)); } /* Keep in-bounds, vertically: */ @@ -952,12 +988,12 @@ Player::check_bounds(Camera* camera) bool adjust = false; // can happen if back scrolling is disabled if(get_pos().x < camera->get_translation().x) { - bbox.set_pos(Vector(camera->get_translation().x, get_pos().y)); + set_pos(Vector(camera->get_translation().x, get_pos().y)); adjust = true; } if(get_pos().x >= camera->get_translation().x + SCREEN_WIDTH - bbox.get_width()) { - bbox.set_pos(Vector( + set_pos(Vector( camera->get_translation().x + SCREEN_WIDTH - bbox.get_width(), get_pos().y)); adjust = true; @@ -982,6 +1018,15 @@ Player::add_velocity(const Vector& velocity) } void +Player::add_velocity(const Vector& velocity, const Vector& end_speed) +{ + if (end_speed.x > 0) physic.set_velocity_x(std::min(physic.get_velocity_x() + velocity.x, end_speed.x)); + if (end_speed.x < 0) physic.set_velocity_x(std::max(physic.get_velocity_x() + velocity.x, end_speed.x)); + if (end_speed.y > 0) physic.set_velocity_y(std::min(physic.get_velocity_y() + velocity.y, end_speed.y)); + if (end_speed.y < 0) physic.set_velocity_y(std::max(physic.get_velocity_y() + velocity.y, end_speed.y)); +} + +void Player::bounce(BadGuy& ) { if(controller->hold(Controller::JUMP)) @@ -1013,3 +1058,20 @@ void Player::walk(float speed) physic.set_velocity_x(speed); } +void +Player::set_ghost_mode(bool enable) +{ + if (ghost_mode == enable) return; + if (enable) { + ghost_mode = true; + set_group(COLGROUP_DISABLED); + physic.enable_gravity(false); + log_debug << "You feel lightheaded. Use movement controls to float around, press ACTION to scare badguys." << std::endl; + } else { + ghost_mode = false; + set_group(COLGROUP_MOVING); + physic.enable_gravity(true); + log_debug << "You feel solid again." << std::endl; + } +} +