psemek/examples/platformer.cpp
2023-05-13 00:04:41 +03:00

132 lines
3.1 KiB
C++

#include <psemek/app/app.hpp>
#include <psemek/app/main.hpp>
#include <psemek/gfx/painter.hpp>
#include <psemek/gfx/gl.hpp>
#include <psemek/geom/scale.hpp>
#include <psemek/geom/camera.hpp>
#include <psemek/geom/constants.hpp>
#include <psemek/geom/intersection.hpp>
#include <psemek/util/clock.hpp>
#include <psemek/util/to_string.hpp>
using namespace psemek;
struct map
{
std::vector<geom::box<float, 2>> platforms;
};
struct player
{
geom::vector<float, 2> size;
geom::point<float, 2> position;
geom::vector<float, 2> velocity;
geom::box<float, 2> bbox() const
{
return geom::expand(geom::box<float, 2>::singleton(position), size);
}
};
struct platformer_app : app::app
{
platformer_app()
: app("Platformer", 4)
{
map_.platforms.push_back({{{-10.f, 10.f}, {-5.f, -4.f}}});
map_.platforms.push_back({{{-5.f, -3.f}, {-2.5f, -2.f}}});
map_.platforms.push_back({{{-1.f, 1.f}, {-2.f, -1.5f}}});
map_.platforms.push_back({{{ 3.f, 5.f}, {-1.5f, -1.f}}});
map_.platforms.push_back({{{-7.f, -6.f}, {-3.5f, -3.f}}});
player_.size = {0.25f, 0.5f};
player_.position = {0.f, 5.f};
player_.velocity = {0.f, 0.f};
}
void update() override
{
float const dt = frame_clock_.restart().count();
float const gravity = -50.f;
float const acceleration = 50.f;
float const friction = 10.f;
float const jump_speed = 15.f;
if (is_key_down(SDLK_a))
player_.velocity[0] -= acceleration * dt;
if (is_key_down(SDLK_d))
player_.velocity[0] += acceleration * dt;
player_.velocity[0] *= std::exp(- friction * dt);
player_.velocity[1] += dt * gravity;
player_.position += player_.velocity * dt;
bool grounded = false;
for (auto const & platform : map_.platforms)
{
auto const player_box = player_.bbox();
auto const intersection = platform & player_box;
if (intersection.empty()) continue;
if (intersection[0].length() < intersection[1].length())
{
if (intersection[0].center() < player_.position[0])
player_.position[0] += intersection[0].length();
else
player_.position[0] -= intersection[0].length();
player_.velocity[0] = 0.f;
}
else
{
if (intersection[1].center() < player_.position[1])
{
player_.position[1] += intersection[1].length();
grounded = true;
}
else
player_.position[1] -= intersection[1].length();
player_.velocity[1] = 0.f;
}
}
if (grounded && is_key_down(SDLK_w))
player_.velocity[1] += jump_speed;
}
void present() override
{
gl::ClearColor(1.f, 1.f, 1.f, 0.f);
gl::Clear(gl::COLOR_BUFFER_BIT);
for (auto const & box : map_.platforms)
painter_.rect(box, {0, 0, 0, 255});
painter_.rect(player_.bbox(), {255, 0, 0, 255});
float const aspect_ratio = width() * 1.f / height();
float const view_size = 5.f;
geom::box<float, 2> view_box{{{-view_size * aspect_ratio, view_size * aspect_ratio}, {-view_size, view_size}}};
painter_.render(geom::orthographic_camera{view_box}.transform());
}
private:
map map_;
player player_;
util::clock<> frame_clock_;
gfx::painter painter_;
};
int main()
{
return app::main<platformer_app>();
}