summaryrefslogtreecommitdiff
path: root/core/src/cpp/player.cpp
diff options
context:
space:
mode:
authorNikita Kostovsky <nikita@kostovsky.me>2025-12-23 15:28:05 +0100
committerNikita Kostovsky <nikita@kostovsky.me>2025-12-23 15:28:05 +0100
commitc055eeef6d41269d11b2ddf7f9aba6f8867da65d (patch)
treedcd9baaec93c50a8ab49656be86ea248c17421fd /core/src/cpp/player.cpp
initial commitHEADmaster
Diffstat (limited to 'core/src/cpp/player.cpp')
-rw-r--r--core/src/cpp/player.cpp154
1 files changed, 154 insertions, 0 deletions
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<int>(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<int>(pos.x) - sprite_size.w / 2,
+ static_cast<int>(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
+ );
+}