Players can move.

main
bog 2023-11-14 20:18:13 +01:00
parent d7a6689cf5
commit b605d7393d
18 changed files with 379 additions and 18 deletions

View File

@ -31,9 +31,12 @@ executable(
'src/ECS.cpp',
'src/BaseComponent.cpp',
'src/BaseSystem.cpp',
'src/EntityFactory.cpp',
# systems
'src/sys/BodySystem.cpp',
'src/sys/ActorSystem.cpp',
'src/sys/PlayerSystem.cpp',
# arena
'src/arena/Arena.cpp',
@ -43,6 +46,9 @@ executable(
'src/gfx/Shaders.cpp',
'src/gfx/Canvas.cpp',
'src/gfx/Texture.cpp',
# input
'src/input/Joystick.cpp',
],
dependencies: [
dependency('glew'),

33
src/EntityFactory.cpp Normal file
View File

@ -0,0 +1,33 @@
#include "EntityFactory.hpp"
#include "comps/BodyC.hpp"
#include "comps/SpriteC.hpp"
#include "comps/PlayerC.hpp"
namespace rid
{
/*explicit*/ EntityFactory::EntityFactory(ECS& ecs)
: m_ecs { ecs }
{
}
/*virtual*/ EntityFactory::~EntityFactory()
{
}
size_t EntityFactory::create_actor(float x, float y)
{
size_t e = m_ecs.create_entity();
m_ecs.attach_component<BodyC>(e, glm::vec2 {x, y});
m_ecs.attach_component<SpriteC>(e, Frame {0, 0, 32, 32}, glm::vec2 {96, 96});
return e;
}
size_t EntityFactory::create_player(int controller, float x, float y)
{
size_t e = create_actor(x, y);
m_ecs.attach_component<PlayerC>(e, controller);
return e;
}
}

23
src/EntityFactory.hpp Normal file
View File

@ -0,0 +1,23 @@
#ifndef rid_ENTITYFACTORY_HPP
#define rid_ENTITYFACTORY_HPP
#include "conf.hpp"
#include "ECS.hpp"
namespace rid
{
class EntityFactory
{
public:
explicit EntityFactory(ECS& ecs);
virtual ~EntityFactory();
size_t create_actor(float x, float y);
size_t create_player(int controller, float x, float y);
private:
ECS& m_ecs;
};
}
#endif

View File

@ -1,14 +1,18 @@
#include "Arena.hpp"
#include "conf.hpp"
#include "../EntityFactory.hpp"
// Components
// ----------
#include "../comps/BodyC.hpp"
#include "../comps/SpriteC.hpp"
#include "../comps/PlayerC.hpp"
// Systems
// -------
#include "../sys/BodySystem.hpp"
#include "../sys/ActorSystem.hpp"
#include "../sys/PlayerSystem.hpp"
namespace rid
{
@ -16,9 +20,11 @@ namespace rid
: BaseScene(game)
{
m_ecs.add_system<BodyC>(std::make_unique<BodySystem>());
m_ecs.add_system<BodyC, SpriteC>(std::make_unique<ActorSystem>());
m_ecs.add_system<PlayerC, BodyC>(std::make_unique<PlayerSystem>());
m_ecs.attach_component<BodyC>(m_ecs.create_entity(), glm::vec2 {64.f, 64.f}, glm::vec2 {64.f, 64.f});
m_ecs.attach_component<BodyC>(m_ecs.create_entity(), glm::vec2 {640.f, 640.f}, glm::vec2 {128.f, 300.f});
EntityFactory factory {m_ecs};
factory.create_player(0, 512.f, 512.f);
}
/*virtual*/ Arena::~Arena()

View File

@ -9,11 +9,13 @@ namespace rid
struct BodyC: public BaseComponent
{
glm::vec2 pos;
glm::vec2 size;
glm::vec2 vel { 0.f, 0.f };
glm::vec2 heading = { 0.f, -1.f};
glm::vec2 side = {-heading.y, heading.x};
float max_speed = 256.f;
explicit BodyC(glm::vec2 _pos, glm::vec2 _size)
explicit BodyC(glm::vec2 _pos)
: pos { _pos }
, size { _size }
{
}
};

28
src/comps/PlayerC.hpp Normal file
View File

@ -0,0 +1,28 @@
#ifndef rid_PLAYERC_HPP
#define rid_PLAYERC_HPP
#include <SDL2/SDL.h>
#include "conf.hpp"
#include "../BaseComponent.hpp"
#include "../input/Joystick.hpp"
namespace rid
{
RID_ERROR(player_error);
struct PlayerC: public BaseComponent
{
std::unique_ptr<Joystick> joystick;
explicit PlayerC(int _index)
: joystick { std::make_unique<Joystick>(_index) }
{
}
virtual ~PlayerC()
{
}
};
}
#endif

39
src/comps/SpriteC.hpp Normal file
View File

@ -0,0 +1,39 @@
#ifndef rid_SPRITEC_HPP
#define rid_SPRITEC_HPP
#include "conf.hpp"
#include "../BaseComponent.hpp"
#include "../gfx/Texture.hpp"
namespace rid
{
struct Frame
{
Frame(int _x, int _y, int _w, int _h)
: x { _x }
, y { _y }
, w { _w }
, h { _h }
{
}
int x;
int y;
int w;
int h;
};
struct SpriteC: public BaseComponent
{
Frame frame;
glm::vec2 size;
explicit SpriteC(Frame _frame, glm::vec2 _size)
: frame { _frame }
, size { _size }
{
}
};
}
#endif

View File

@ -5,6 +5,7 @@
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <optional>
#include <filesystem>
#include <stdexcept>
#include <string>

View File

@ -108,8 +108,8 @@ namespace rid
use();
m_shaders->set_mat4("proj", transform);
auto rot = glm::rotate(glm::mat4 {1.0f}, m_angle, glm::vec3 {0.f, 0.f, 1.f});
auto loc = glm::translate(glm::mat4 {1.0f}, glm::vec3 {m_pos.x, m_pos.y, 0.f});
auto rot = glm::rotate(glm::mat4 {1.0f}, m_angle, glm::vec3 {0.f, 0.f, 1.f});
m_shaders->set_mat4("model", loc * rot);
glDrawArrays(GL_TRIANGLES, 0, m_vertices.size());

View File

@ -22,6 +22,9 @@ namespace rid
void move(glm::vec2 pos);
void rotate(float rad);
void set_pos(glm::vec2 pos) { m_pos = pos; }
void set_angle(float rad) { m_angle = rad; }
void set_texture(std::unique_ptr<Texture> texture);

View File

@ -1,4 +1,5 @@
#include "Window.hpp"
#include "SDL.h"
#include "SDL_image.h"
namespace rid
@ -7,7 +8,8 @@ namespace rid
: m_width { width }
, m_height { height }
{
if (SDL_Init(SDL_INIT_VIDEO) != 0)
if (SDL_Init(SDL_INIT_VIDEO
| SDL_INIT_GAMECONTROLLER) != 0)
{
throw display_error {"Cannot initialize SDL 2."};
}

41
src/input/Joystick.cpp Normal file
View File

@ -0,0 +1,41 @@
#include "Joystick.hpp"
namespace rid
{
/*explicit*/ Joystick::Joystick(int index)
: m_controller { SDL_GameControllerOpen(index) }
{
if (!m_controller)
{
throw joystick_error {"Cannot open game controller '" + std::to_string(index) + "'."};
}
}
/*virtual*/ Joystick::~Joystick()
{
SDL_GameControllerClose(m_controller);
}
bool Joystick::is_pressed(SDL_GameControllerButton btn) const
{
return SDL_GameControllerGetButton(m_controller, btn);
}
bool Joystick::is_just_pressed(SDL_GameControllerButton btn) const
{
bool ok = is_pressed(btn);
if (m_prev_btn != ok)
{
m_prev_btn = ok;
return ok;
}
return false;
}
float Joystick::axis(SDL_GameControllerAxis axis) const
{
return SDL_GameControllerGetAxis(m_controller, axis) / 32767.0f;
}
}

28
src/input/Joystick.hpp Normal file
View File

@ -0,0 +1,28 @@
#ifndef rid_JOYSTICK_HPP
#define rid_JOYSTICK_HPP
#include <SDL2/SDL.h>
#include "conf.hpp"
namespace rid
{
RID_ERROR(joystick_error);
class Joystick
{
public:
explicit Joystick(int index);
virtual ~Joystick();
bool is_pressed(SDL_GameControllerButton btn) const;
bool is_just_pressed(SDL_GameControllerButton btn) const;
float axis(SDL_GameControllerAxis axis) const;
private:
SDL_GameController* m_controller;
mutable bool m_prev_btn = false;
};
}
#endif

45
src/sys/ActorSystem.cpp Normal file
View File

@ -0,0 +1,45 @@
#include "ActorSystem.hpp"
#include "../ECS.hpp"
#include "../comps/SpriteC.hpp"
#include "../comps/BodyC.hpp"
namespace rid
{
/*explicit*/ ActorSystem::ActorSystem()
{
auto texture = std::make_unique<Texture>();
texture->load(RID_DATADIR / "assets" / "images" / "walk_0.png");
m_canvas.set_texture(std::move(texture));
}
/*virtual*/ ActorSystem::~ActorSystem()
{
}
void ActorSystem::update(ECS&, std::vector<size_t> const&) /*override*/
{
}
void ActorSystem::draw(ECS& ecs, std::vector<size_t> const& entities) /*override*/
{
for (auto entity: entities)
{
m_canvas.clear();
auto const& body = ecs.getc<BodyC>(entity);
auto const& sprite = ecs.getc<SpriteC>(entity);
m_canvas.draw_tex(glm::vec2 {0.f},
glm::vec2 {sprite.size.x, sprite.size.y},
glm::vec4 {1, 1, 1, 1},
glm::vec2 {sprite.frame.x, sprite.frame.y},
glm::vec2 {sprite.frame.w, sprite.frame.h});
m_canvas.set_pos(body.pos);
m_canvas.set_angle(std::atan2(body.heading.y, body.heading.x) - M_PI / 2.0f);
ecs.window().draw(m_canvas);
}
}
}

24
src/sys/ActorSystem.hpp Normal file
View File

@ -0,0 +1,24 @@
#ifndef rid_ACTORSYSTEM_HPP
#define rid_ACTORSYSTEM_HPP
#include "conf.hpp"
#include "../gfx/Canvas.hpp"
#include "../BaseSystem.hpp"
namespace rid
{
class ActorSystem: public BaseSystem
{
public:
explicit ActorSystem();
virtual ~ActorSystem();
void update(ECS& ecs, std::vector<size_t> const& entities) override;
void draw(ECS& ecs, std::vector<size_t> const& entities) override;
private:
Canvas m_canvas;
};
}
#endif

View File

@ -13,21 +13,30 @@ namespace rid
{
}
void BodySystem::update(ECS&, std::vector<size_t> const&) /*override*/
void BodySystem::update(ECS& ecs, std::vector<size_t> const& entities) /*override*/
{
}
void BodySystem::draw(ECS& ecs, std::vector<size_t> const& entities) /*override*/
{
Canvas canvas;
for (auto entity: entities)
{
auto const& body = ecs.getc<BodyC>(entity);
auto& body = ecs.getc<BodyC>(entity);
canvas.draw_rect(body.pos, body.size, glm::vec4 {1, 1, 1, 1});
float vel_len = glm::length(body.vel);
if (vel_len > body.max_speed)
{
body.vel = glm::normalize(body.vel) * body.max_speed;
}
body.pos += body.vel * ecs.dt();
if (vel_len > 0.f)
{
body.heading = body.vel / vel_len;
body.side = glm::vec2 {-body.heading.y, body.heading.x};
}
}
}
ecs.window().draw(canvas);
void BodySystem::draw(ECS&, std::vector<size_t> const&) /*override*/
{
}
}

48
src/sys/PlayerSystem.cpp Normal file
View File

@ -0,0 +1,48 @@
#include <SDL2/SDL.h>
#include "PlayerSystem.hpp"
#include "../ECS.hpp"
#include "../comps/PlayerC.hpp"
#include "../comps/BodyC.hpp"
namespace rid
{
/*explicit*/ PlayerSystem::PlayerSystem()
{
}
/*virtual*/ PlayerSystem::~PlayerSystem()
{
}
void PlayerSystem::update(ECS& ecs, std::vector<size_t> const& entities) /*override*/
{
for (auto entity: entities)
{
auto& player = ecs.getc<PlayerC>(entity);
auto& body = ecs.getc<BodyC>(entity);
glm::vec2 dir {
player.joystick->axis(SDL_CONTROLLER_AXIS_LEFTX),
player.joystick->axis(SDL_CONTROLLER_AXIS_LEFTY)
};
float len = glm::length(dir);
float const threshold = 0.25f;
if (len >= threshold)
{
dir /= len;
body.vel = dir * body.max_speed;
}
else
{
body.vel = glm::vec2 {0.f};
}
}
}
void PlayerSystem::draw(ECS&, std::vector<size_t> const&) /*override*/
{
}
}

23
src/sys/PlayerSystem.hpp Normal file
View File

@ -0,0 +1,23 @@
#ifndef rid_PLAYERSYSTEM_HPP
#define rid_PLAYERSYSTEM_HPP
#include "conf.hpp"
#include "../BaseSystem.hpp"
namespace rid
{
class PlayerSystem: public BaseSystem
{
public:
explicit PlayerSystem();
virtual ~PlayerSystem();
void update(ECS& ecs, std::vector<size_t> const& entities) override;
void draw(ECS& ecs, std::vector<size_t> const& entities) override;
private:
};
}
#endif