#include "player.h" Player::Player(SDL_Renderer* renderer) : renderer{renderer} , sprites{ Animation{renderer, "rest.bmp", 256, 1.0, true}, Animation{renderer, "takeoff.bmp", 256, 0.3, false}, Animation{renderer, "flight.bmp", 256, 1.3, false}, Animation{renderer, "landing.bmp", 256, 0.3, false}, Animation{renderer, "walk.bmp", 256, 1.0, true}, Animation{renderer, "fall.bmp", 256, 1.0, true} } { } void Player::set_state(const States& s) { timestamp = Clock::now(); state = s; if (state != States::FLIGHT && state != States::WALK) { speed.x = 0; } else if (state == States::WALK) { speed.x = backwards ? -150 : 150; } else if (state == States::FLIGHT) { speed.y = jump.y; speed.x = backwards ? -jump.x : jump.x; } } void Player::handle_keyboard() { const Uint8* kbstate{SDL_GetKeyboardState(nullptr)}; if (state == States::WALK && !kbstate[SDL_SCANCODE_RIGHT] && !kbstate[SDL_SCANCODE_LEFT]) { set_state(States::REST); } if ((state == States::REST || state == States::WALK) && kbstate[SDL_SCANCODE_UP]) { if (kbstate[SDL_SCANCODE_LEFT] || kbstate[SDL_SCANCODE_RIGHT]) { jump.x = 200; // long jump jump.y = -200; } else { jump.x = 50; // high jump jump.y = -300; } set_state(States::TAKEOFF); } if (state == States::REST && (kbstate[SDL_SCANCODE_LEFT] || kbstate[SDL_SCANCODE_RIGHT])) { backwards = kbstate[SDL_SCANCODE_LEFT]; set_state(States::WALK); } } const Animation& Player::sprite(const States& state) { return sprites.at(static_cast(state)); } void Player::update_state(const double dt, const Map& map) { // takeoff -> flight if (state == States::TAKEOFF && sprite(state).animation_ended(timestamp)) { set_state(States::FLIGHT); } // landing -> rest if (state == States::LANDING && sprite(state).animation_ended(timestamp)) { set_state(States::REST); } // put free falling sprite if no ground under the feet if (state != States::FLIGHT && map.is_empty(pos.x / map.tile_size.w, pos.y / map.tile_size.h + 1)) { set_state(States::FALL); } // prior to collision detection pos.x += dt * speed.x; // horizontal collision detection if (!map.is_empty(pos.x / map.tile_size.w, pos.y / map.tile_size.h)) { // snap the coorinate to the boundary of last free tile int snap = std::round(pos.x / map.tile_size.w) * map.tile_size.w; // be careful to snap to the left or to the right side of the free tile pos.x = snap + (snap > pos.x ? 1 : -1); // stop speed.x = 0; } // prior to collision detection pos.y += dt * speed.y; // gravity speed.y += dt * 300; // vertical collision detection if (!map.is_empty(pos.x / map.tile_size.w, pos.y / map.tile_size.h)) { // snap the coorinate to the boundary of last free tile int snap = std::round(pos.y / map.tile_size.h) * map.tile_size.h; // be careful to snap to the top or the bottom side of the free tile pos.y = snap + (snap > pos.y ? 1 : -1); // stop speed.y = 0; if (state == States::FLIGHT || state == States::FALL) { set_state(States::LANDING); } } } void Player::draw() { const SDL_Rect src{sprite(state).rect(timestamp)}; const SDL_Rect dest{ static_cast(pos.x) - sprite_size.w / 2, static_cast(pos.y) - sprite_size.h, sprite_size.w, sprite_size.h }; SDL_RenderCopyEx( renderer, sprite(state).texture, &src, &dest, 0, nullptr, backwards ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE ); }