From c055eeef6d41269d11b2ddf7f9aba6f8867da65d Mon Sep 17 00:00:00 2001 From: Nikita Kostovsky Date: Tue, 23 Dec 2025 15:28:05 +0100 Subject: initial commit --- core/src/cpp/player.cpp | 154 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 core/src/cpp/player.cpp (limited to 'core/src/cpp/player.cpp') diff --git a/core/src/cpp/player.cpp b/core/src/cpp/player.cpp new file mode 100644 index 0000000..ce2b421 --- /dev/null +++ b/core/src/cpp/player.cpp @@ -0,0 +1,154 @@ +#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 + ); +} -- cgit v1.2.3-70-g09d2