132 lines
3.1 KiB
C++
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>();
|
|
}
|