X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fobject%2Fplayer.cpp;h=033f569b257867093b025bf6e686cde71e8789e8;hb=555d1b7bebb45326d82d934e07463209837309b0;hp=5e68d1d58d3702cbec8efc25b6ec790b6ff995f5;hpb=bf50931d8b9cdf1b9c0215832c9b2bd3ce452d49;p=supertux.git diff --git a/src/object/player.cpp b/src/object/player.cpp index 5e68d1d58..033f569b2 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -53,41 +53,60 @@ //#define SWIMMING -static const int TILES_FOR_BUTTJUMP = 3; -static const float BUTTJUMP_MIN_VELOCITY_Y = 700.0f; -static const float SHOOTING_TIME = .150f; -/// time before idle animation starts -static const float IDLE_TIME = 2.5f; - -/** acceleration in horizontal direction when walking - * (all acceleratiosn are in pixel/s^2) */ -static const float WALK_ACCELERATION_X = 300; -/** acceleration in horizontal direction when running */ -static const float RUN_ACCELERATION_X = 400; -/** acceleration when skidding */ -static const float SKID_XM = 200; -/** time of skidding in seconds */ -static const float SKID_TIME = .3f; -/** maximum walk velocity (pixel/s) */ -static const float MAX_WALK_XM = 230; -/** maximum run velcoity (pixel/s) */ -static const float MAX_RUN_XM = 320; -/** maximum horizontal climb velocity */ -static const float MAX_CLIMB_XM = 48; -/** maximum vertical climb velocity */ -static const float MAX_CLIMB_YM = 128; -/** instant velocity when tux starts to walk */ -static const float WALK_SPEED = 100; - -/** time of the kick (kicking mriceblock) animation */ -static const float KICK_TIME = .3f; -/** time of tux cheering (currently unused) */ -static const float CHEER_TIME = 1.0f; - -/** if Tux cannot unduck for this long, he will get hurt */ -static const float UNDUCK_HURT_TIME = 0.25f; - -namespace{ +namespace { + static const int TILES_FOR_BUTTJUMP = 3; + static const float BUTTJUMP_MIN_VELOCITY_Y = 400.0f; + static const float SHOOTING_TIME = .150f; + + /** number of idle stages, including standing */ + static const unsigned int IDLE_STAGE_COUNT = 5; + /** + * how long to play each idle animation in milliseconds + * '0' means the sprite action is played once before moving onto the next + * animation + */ + static const int IDLE_TIME[] = { 5000, 0, 2500, 0, 2500 }; + /** idle stages */ + static const std::string IDLE_STAGES[] = + { "stand", + "idle", + "stand", + "idle", + "stand" }; + + /** acceleration in horizontal direction when walking + * (all accelerations are in pixel/s^2) */ + static const float WALK_ACCELERATION_X = 300; + /** acceleration in horizontal direction when running */ + static const float RUN_ACCELERATION_X = 400; + /** acceleration when skidding */ + static const float SKID_XM = 200; + /** time of skidding in seconds */ + static const float SKID_TIME = .3f; + /** maximum walk velocity (pixel/s) */ + static const float MAX_WALK_XM = 230; + /** maximum run velocity (pixel/s) */ + static const float MAX_RUN_XM = 320; + /** maximum horizontal climb velocity */ + static const float MAX_CLIMB_XM = 48; + /** maximum vertical climb velocity */ + static const float MAX_CLIMB_YM = 128; + /** instant velocity when tux starts to walk */ + static const float WALK_SPEED = 100; + + /** time of the kick (kicking mriceblock) animation */ + static const float KICK_TIME = .3f; + /** time of tux cheering (currently unused) */ + static const float CHEER_TIME = 1.0f; + + /** if Tux cannot unduck for this long, he will get hurt */ + static const float UNDUCK_HURT_TIME = 0.25f; + /** gravity is higher after the jump key is released before + the apex of the jump is reached */ + static const float JUMP_EARLY_APEX_FACTOR = 3.0; + + static const float JUMP_GRACE_TIME = 0.25f; /**< time before hitting the ground that the jump button may be pressed (and still trigger a jump) */ + bool no_water = true; } @@ -95,22 +114,23 @@ Player::Player(PlayerStatus* _player_status, const std::string& name) : scripting_controller(0), player_status(_player_status), scripting_controller_old(0), - grabbed_object(NULL), ghost_mode(false), edit_mode(false), climbing(0) + grabbed_object(NULL), ghost_mode(false), edit_mode(false), idle_stage(0), + climbing(0) { this->name = name; controller = main_controller; scripting_controller = new CodeController(); sprite = sprite_manager->create("images/creatures/tux/tux.sprite"); airarrow.reset(new Surface("images/engine/hud/airarrow.png")); + idle_timer.start(IDLE_TIME[0]/1000.0f); sound_manager->preload("sounds/bigjump.wav"); sound_manager->preload("sounds/jump.wav"); sound_manager->preload("sounds/hurt.wav"); sound_manager->preload("sounds/skid.wav"); sound_manager->preload("sounds/flip.wav"); - sound_manager->preload("sounds/invincible.wav"); + sound_manager->preload("sounds/invincible_start.ogg"); sound_manager->preload("sounds/splash.ogg"); - sound_manager->preload("sounds/shoot.wav"); init(); } @@ -136,12 +156,15 @@ Player::init() dead = false; dying = false; - peeking = AUTO; + peekingX = AUTO; + peekingY = AUTO; last_ground_y = 0; fall_mode = ON_GROUND; jumping = false; + jump_early_apex = false; can_jump = true; - butt_jump = false; + wants_buttjump = false; + does_buttjump = false; growing = false; deactivated = false; backflipping = false; @@ -340,12 +363,12 @@ Player::update(float elapsed_time) Vector paccel = Vector(0, 0); // draw bright sparkle when there is lots of time left, dark sparkle when invincibility is about to end if (invincible_timer.get_timeleft() > TUX_INVINCIBLE_TIME_WARNING) { - // make every other a longer sparkle to make trail a bit fuzzy - if (size_t(game_time*20)%2) { - Sector::current()->add_object(new SpriteParticle("images/objects/particles/sparkle.sprite", "small", ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS+1+5)); - } else { - Sector::current()->add_object(new SpriteParticle("images/objects/particles/sparkle.sprite", "medium", ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS+1+5)); - } + // make every other a longer sparkle to make trail a bit fuzzy + if (size_t(game_time*20)%2) { + Sector::current()->add_object(new SpriteParticle("images/objects/particles/sparkle.sprite", "small", ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS+1+5)); + } else { + Sector::current()->add_object(new SpriteParticle("images/objects/particles/sparkle.sprite", "medium", ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS+1+5)); + } } else { Sector::current()->add_object(new SpriteParticle("images/objects/particles/sparkle.sprite", "dark", ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS+1+5)); } @@ -496,7 +519,7 @@ Player::do_duck() { return; if (!on_ground()) return; - if (butt_jump) + if (does_buttjump) return; if (adjust_height(31.8f)) { @@ -566,10 +589,30 @@ Player::do_jump(float yspeed) { } void +Player::early_jump_apex() { + if(jump_early_apex) { + return; + } + jump_early_apex = true; + physic.set_gravity(physic.get_gravity() * JUMP_EARLY_APEX_FACTOR); +}; + +void +Player::do_jump_apex() { + if(!jump_early_apex) { + return; + } + jump_early_apex = false; + physic.set_gravity(physic.get_gravity() / JUMP_EARLY_APEX_FACTOR); +} + +void Player::handle_vertical_input() { // Press jump key - if(controller->pressed(Controller::JUMP) && (can_jump)) { + if(controller->pressed(Controller::JUMP)) jump_button_timer.start(JUMP_GRACE_TIME); + if(controller->hold(Controller::JUMP) && jump_button_timer.started() && can_jump) { + jump_button_timer.stop(); if (duck) { // when running, only jump a little bit; else do a backflip if ((physic.get_velocity_x() != 0) || (controller->hold(Controller::LEFT)) || (controller->hold(Controller::RIGHT))) do_jump(-300); else do_backflip(); @@ -582,19 +625,26 @@ Player::handle_vertical_input() else if(!controller->hold(Controller::JUMP)) { if (!backflipping && jumping && physic.get_velocity_y() < 0) { jumping = false; - physic.set_velocity_y(0); + early_jump_apex(); } } + if(jump_early_apex && physic.get_velocity_y() >= 0) { + do_jump_apex(); + } + /* In case the player has pressed Down while in a certain range of air, enable butt jump action */ - if (controller->hold(Controller::DOWN) && !butt_jump && !duck && is_big() && !on_ground() && (physic.get_velocity_y() >= BUTTJUMP_MIN_VELOCITY_Y)) { - butt_jump = true; + if (controller->hold(Controller::DOWN) && !duck && is_big() && !on_ground()) { + wants_buttjump = true; + if (physic.get_velocity_y() >= BUTTJUMP_MIN_VELOCITY_Y) does_buttjump = true; } /* When Down is not held anymore, disable butt jump */ - if(butt_jump && !controller->hold(Controller::DOWN)) - butt_jump = false; + if(!controller->hold(Controller::DOWN)) { + wants_buttjump = false; + does_buttjump = false; + } // swimming physic.set_acceleration_y(0); @@ -621,35 +671,36 @@ Player::handle_input() /* Peeking */ if( controller->released( Controller::PEEK_LEFT ) ) { - peeking = AUTO; + peekingX = AUTO; } if( controller->released( Controller::PEEK_RIGHT ) ) { - peeking = AUTO; + peekingX = AUTO; } - if( controller->released( Controller::UP ) ) { - peeking = AUTO; + if( controller->released( Controller::PEEK_UP ) ) { + peekingY = AUTO; } - if( controller->released( Controller::DOWN ) ) { - peeking = AUTO; + if( controller->released( Controller::PEEK_DOWN ) ) { + peekingY = AUTO; } if( controller->pressed( Controller::PEEK_LEFT ) ) { - peeking = LEFT; + peekingX = LEFT; } if( controller->pressed( Controller::PEEK_RIGHT ) ) { - peeking = RIGHT; - } - if( controller->pressed( Controller::UP ) ) { - peeking = UP; + peekingX = RIGHT; } - if( controller->pressed( Controller::DOWN ) ) { - peeking = DOWN; + if(!backflipping && !jumping && on_ground()) { + if( controller->pressed( Controller::PEEK_UP ) ) { + peekingY = UP; + } else if( controller->pressed( Controller::PEEK_DOWN ) ) { + peekingY = DOWN; + } } /* Handle horizontal movement: */ if (!backflipping) handle_horizontal_input(); /* Jump/jumping? */ - if (on_ground() && !controller->hold(Controller::JUMP)) + if (on_ground()) can_jump = true; /* Handle vertical movement: */ @@ -833,7 +884,7 @@ Player::set_bonus(BonusType type, bool animate) } if (type == NO_BONUS) { - if (butt_jump) butt_jump = false; + if (does_buttjump) does_buttjump = false; } if ((type == NO_BONUS) || (type == GROWUP_BONUS)) { @@ -902,6 +953,8 @@ Player::draw(DrawingContext& context) } std::string sa_prefix = ""; + std::string sa_postfix = ""; + if (player_status->bonus == GROWUP_BONUS) sa_prefix = "big"; else if (player_status->bonus == FIRE_BONUS) @@ -911,43 +964,69 @@ Player::draw(DrawingContext& context) else sa_prefix = "small"; + if(dir == LEFT) + sa_postfix = "-left"; + else + sa_postfix = "-right"; + /* Set Tux sprite action */ - if (growing) { + if(dying) { + sprite->set_action("gameover"); + } + else if (growing) { + sprite->set_action_continued("grow"+sa_postfix); // while growing, do not change action // do_duck() will take care of cancelling growing manually // update() will take care of cancelling when growing completed } else if (climbing) { - sprite->set_action(sa_prefix+((dir == LEFT)?"-skid-left":"-skid-right")); + sprite->set_action(sa_prefix+"-skid"+sa_postfix); } else if (backflipping) { - sprite->set_action(sa_prefix+((dir == LEFT)?"-backflip-left":"-backflip-right")); + sprite->set_action(sa_prefix+"-backflip"+sa_postfix); } else if (duck && is_big()) { - sprite->set_action(sa_prefix+((dir == LEFT)?"-duck-left":"-duck-right")); + sprite->set_action(sa_prefix+"-duck"+sa_postfix); } else if (skidding_timer.started() && !skidding_timer.check()) { - sprite->set_action(sa_prefix+((dir == LEFT)?"-skid-left":"-skid-right")); + sprite->set_action(sa_prefix+"-skid"+sa_postfix); } else if (kick_timer.started() && !kick_timer.check()) { - sprite->set_action(sa_prefix+((dir == LEFT)?"-kick-left":"-kick-right")); + sprite->set_action(sa_prefix+"-kick"+sa_postfix); } - else if (butt_jump && is_big()) { - sprite->set_action(sa_prefix+((dir == LEFT)?"-buttjump-left":"-buttjump-right")); + else if ((wants_buttjump || does_buttjump) && is_big()) { + sprite->set_action(sa_prefix+"-buttjump"+sa_postfix); } else if (!on_ground()) { - sprite->set_action(sa_prefix+((dir == LEFT)?"-jump-left":"-jump-right")); + sprite->set_action(sa_prefix+"-jump"+sa_postfix); } else { if (fabsf(physic.get_velocity_x()) < 1.0f) { -// if(idle_timer.check()) { -// sprite->set_action(sa_prefix+((dir == LEFT)?"-idle-left":"-idle-right")); -// } else { - sprite->set_action(sa_prefix+((dir == LEFT)?"-stand-left":"-stand-right")); -// } + // Determine which idle stage we're at + if (sprite->get_action().find("-stand-") == std::string::npos && sprite->get_action().find("-idle-") == std::string::npos) { + idle_stage = 0; + idle_timer.start(IDLE_TIME[idle_stage]/1000.0f); + + sprite->set_action_continued(sa_prefix+("-" + IDLE_STAGES[idle_stage])+sa_postfix); + } + else if (idle_timer.check() || (IDLE_TIME[idle_stage] == 0 && sprite->animation_done())) { + idle_stage++; + if (idle_stage >= IDLE_STAGE_COUNT) + idle_stage = 1; + + idle_timer.start(IDLE_TIME[idle_stage]/1000.0f); + + if (IDLE_TIME[idle_stage] == 0) + sprite->set_action(sa_prefix+("-" + IDLE_STAGES[idle_stage])+sa_postfix, 1); + else + sprite->set_action(sa_prefix+("-" + IDLE_STAGES[idle_stage])+sa_postfix); + } + else { + sprite->set_action_continued(sa_prefix+("-" + IDLE_STAGES[idle_stage])+sa_postfix); + } } else { - sprite->set_action(sa_prefix+((dir == LEFT)?"-walk-left":"-walk-right")); + sprite->set_action(sa_prefix+"-walk"+sa_postfix); } } @@ -962,10 +1041,6 @@ Player::draw(DrawingContext& context) } */ - if(dying) { - sprite->set_action("gameover"); - } - /* Draw Tux */ if (safe_timer.started() && size_t(game_time*40)%2) ; // don't draw Tux @@ -1009,8 +1084,8 @@ Player::collision_solid(const CollisionHit& hit) floor_normal = hit.slope_normal; // Butt Jump landed - if (butt_jump) { - butt_jump = false; + if (does_buttjump) { + does_buttjump = false; physic.set_velocity_y(-300); on_ground_flag = false; Sector::current()->add_object(new Particles( @@ -1083,7 +1158,7 @@ Player::collision(GameObject& other, const CollisionHit& hit) void Player::make_invincible() { - sound_manager->play("sounds/invincible.wav"); + sound_manager->play("sounds/invincible_start.ogg"); invincible_timer.start(TUX_INVINCIBLE_TIME); Sector::current()->play_music(HERRING_MUSIC); } @@ -1098,6 +1173,8 @@ Player::kill(bool completely) if(!completely && (safe_timer.started() || invincible_timer.started())) return; + growing = false; + sound_manager->play("sounds/hurt.wav"); if (climbing) stop_climbing(*climbing); @@ -1113,6 +1190,7 @@ Player::kill(bool completely) safe_timer.start(TUX_SAFE_TIME /* + GROWING_TIME */); adjust_height(30.8f); duck = false; + backflipping = false; set_bonus(NO_BONUS, true); } else if(player_status->bonus == NO_BONUS) { safe_timer.start(TUX_SAFE_TIME); @@ -1221,6 +1299,12 @@ Player::add_velocity(const Vector& velocity, const Vector& end_speed) physic.set_velocity_y(std::max(physic.get_velocity_y() + velocity.y, end_speed.y)); } +Vector +Player::get_velocity() +{ + return physic.get_velocity(); +} + void Player::bounce(BadGuy& ) {