Compare commits
No commits in common. "96a5a377332a7b1f5331472a8770cc26828b1fd5" and "7b6855321f787af44dc9b21d0fc5ecab862cf01f" have entirely different histories.
96a5a37733
...
7b6855321f
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "vendor/callable"]
|
||||||
|
path = vendor/callable
|
||||||
|
url = forgejo@git.objectionable.solutions:Sara/cpp-callable.git
|
|
@ -1,39 +1,26 @@
|
||||||
#include "character.h"
|
#include "character.h"
|
||||||
#include "core/renderer.h"
|
#include "core/renderer.h"
|
||||||
#include "world.h"
|
#include "world.h"
|
||||||
#include <cassert>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
namespace rogue {
|
namespace rogue {
|
||||||
CharacterLogic::~CharacterLogic() {}
|
Character::Character(World &world, Tile location, CharacterData stats)
|
||||||
|
|
||||||
void CharacterLogic::set_character(Character *character) {
|
|
||||||
this->character = character;
|
|
||||||
}
|
|
||||||
|
|
||||||
Character::Character(Tile location, CharacterLogic *logic, CharacterData stats)
|
|
||||||
: data{stats}
|
: data{stats}
|
||||||
, logic{logic}
|
|
||||||
, health{stats.health}
|
, health{stats.health}
|
||||||
, location{location}
|
, location{location}
|
||||||
, world{nullptr} {
|
, world{world}
|
||||||
this->logic->set_character(this);
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
void Character::act() {
|
void Character::act() {
|
||||||
assert(this->world != nullptr && "World generation did not initialize character properly");
|
|
||||||
if(this->health < 0) {
|
if(this->health < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->logic->set_character(this);
|
|
||||||
// get motion from logic
|
// get motion from logic
|
||||||
Tile target{this->logic->move()};
|
Tile target{this->data.logic(*this)};
|
||||||
if(target == this->location
|
if(target == this->location) {
|
||||||
|| std::abs(target.x - this->location.x) + std::abs(target.y - this->location.y) != 1) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// check resulting tile
|
// check resulting tile
|
||||||
TileData tile{world->query_tile(target)};
|
TileData tile{world.query_tile(target)};
|
||||||
// if character, deal damage
|
// if character, deal damage
|
||||||
if(tile.character != nullptr) {
|
if(tile.character != nullptr) {
|
||||||
tile.character->deal_damage(this->data.damage);
|
tile.character->deal_damage(this->data.damage);
|
||||||
|
@ -51,8 +38,7 @@ void Character::draw() {
|
||||||
bool Character::deal_damage(int damage) {
|
bool Character::deal_damage(int damage) {
|
||||||
return (this->health -= damage) <= 0;
|
return (this->health -= damage) <= 0;
|
||||||
}
|
}
|
||||||
|
Tile null_character_logic_function(Character &character) {
|
||||||
Tile NullCharacterLogic::move() {
|
return character.location;
|
||||||
return this->character->location;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,46 +2,34 @@
|
||||||
#define ROGUE_CHARACTER_H
|
#define ROGUE_CHARACTER_H
|
||||||
|
|
||||||
#include "core/roguedefs.h"
|
#include "core/roguedefs.h"
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace rogue {
|
namespace rogue {
|
||||||
class World;
|
class World;
|
||||||
class Character;
|
class Character;
|
||||||
|
|
||||||
struct CharacterLogic {
|
typedef Tile(&CharacterLogicFunction)(Character &character);
|
||||||
virtual ~CharacterLogic();
|
|
||||||
|
|
||||||
virtual Tile move() = 0;
|
|
||||||
protected:
|
|
||||||
Character *character{nullptr};
|
|
||||||
private:
|
|
||||||
friend class Character;
|
|
||||||
void set_character(Character *character);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CharacterData {
|
struct CharacterData {
|
||||||
int health{1};
|
int health{1};
|
||||||
int damage{1};
|
int damage{1};
|
||||||
Sprite sprite{0};
|
Sprite sprite{0};
|
||||||
|
CharacterLogicFunction logic;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Character {
|
struct Character {
|
||||||
Character(Tile location, CharacterLogic *logic, CharacterData stats);
|
Character(World &world, Tile location, CharacterData stats);
|
||||||
|
|
||||||
void act();
|
void act();
|
||||||
void draw();
|
void draw();
|
||||||
bool deal_damage(int damage);
|
bool deal_damage(int damage);
|
||||||
|
|
||||||
CharacterData const data;
|
CharacterData const data;
|
||||||
std::shared_ptr<CharacterLogic> logic{nullptr};
|
|
||||||
int health{1};
|
int health{1};
|
||||||
Tile location{0, 0};
|
Tile location{0, 0};
|
||||||
World *world{nullptr};
|
World &world;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NullCharacterLogic : public CharacterLogic {
|
extern Tile null_character_logic_function(Character &character);
|
||||||
virtual Tile move() override;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // !ROGUE_CHARACTER_H
|
#endif // !ROGUE_CHARACTER_H
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
#include "input.h"
|
|
||||||
#include <SDL2/SDL_events.h>
|
|
||||||
#include <SDL2/SDL_log.h>
|
|
||||||
#include <SDL2/SDL_scancode.h>
|
|
||||||
|
|
||||||
namespace rogue {
|
|
||||||
InputHandler::InputHandler() {
|
|
||||||
Input::add_handler(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
InputHandler::~InputHandler() {
|
|
||||||
Input::remove_handler(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyEventHandler::KeyEventHandler(std::set<SDL_Scancode> code, Listener listener)
|
|
||||||
: scancode{code}
|
|
||||||
, listener{listener} {}
|
|
||||||
|
|
||||||
void KeyEventHandler::process_event(SDL_Event event) {
|
|
||||||
if((event.type == SDL_KEYDOWN || event.type == SDL_KEYUP) && this->scancode.contains(event.key.keysym.scancode)) {
|
|
||||||
this->listener(event.type == SDL_KEYDOWN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Input::add_handler(InputHandler *handler) {
|
|
||||||
Input::handlers.insert(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Input::remove_handler(InputHandler *handler) {
|
|
||||||
Input::handlers.erase(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Input::process_event(SDL_Event event) {
|
|
||||||
for(InputHandler *handler : Input::handlers) {
|
|
||||||
handler->process_event(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::set<InputHandler*> Input::handlers{};
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
#ifndef ROGUE_INPUT_H
|
|
||||||
#define ROGUE_INPUT_H
|
|
||||||
|
|
||||||
#include <SDL2/SDL_events.h>
|
|
||||||
#include <SDL2/SDL_scancode.h>
|
|
||||||
#include <functional>
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
namespace rogue {
|
|
||||||
struct InputHandler {
|
|
||||||
InputHandler();
|
|
||||||
virtual ~InputHandler();
|
|
||||||
virtual void process_event(SDL_Event event) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct KeyEventHandler : public InputHandler {
|
|
||||||
typedef std::function<void(bool down)> Listener;
|
|
||||||
KeyEventHandler(std::set<SDL_Scancode> code, Listener listener);
|
|
||||||
virtual void process_event(SDL_Event event) override;
|
|
||||||
std::set<SDL_Scancode> scancode{};
|
|
||||||
Listener listener{};
|
|
||||||
};
|
|
||||||
|
|
||||||
class Input {
|
|
||||||
public:
|
|
||||||
static void add_handler(InputHandler *handler);
|
|
||||||
static void remove_handler(InputHandler *handler);
|
|
||||||
static void process_event(SDL_Event event);
|
|
||||||
private:
|
|
||||||
static std::set<InputHandler*> handlers;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // !ROGUE_INPUT_H
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include "core/roguedefs.h"
|
#include "core/roguedefs.h"
|
||||||
#include <SDL2/SDL_log.h>
|
#include <SDL2/SDL_log.h>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace rogue {
|
namespace rogue {
|
||||||
void Room::draw(Tile world_pivot) {
|
void Room::draw(Tile world_pivot) {
|
||||||
|
@ -37,14 +36,6 @@ bool Room::tile_is_wall(Tile local_tile) const {
|
||||||
return is_outside_room && is_outside_hallways;
|
return is_outside_room && is_outside_hallways;
|
||||||
}
|
}
|
||||||
|
|
||||||
World::World()
|
|
||||||
: direction_pressed{{
|
|
||||||
SDL_SCANCODE_H, SDL_SCANCODE_J, SDL_SCANCODE_K, SDL_SCANCODE_L,
|
|
||||||
SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT, SDL_SCANCODE_UP, SDL_SCANCODE_DOWN
|
|
||||||
},
|
|
||||||
std::bind(&World::on_input, this, std::placeholders::_1)
|
|
||||||
} {}
|
|
||||||
|
|
||||||
void World::act() {
|
void World::act() {
|
||||||
for(Character &character : this->characters) {
|
for(Character &character : this->characters) {
|
||||||
character.act();
|
character.act();
|
||||||
|
@ -52,7 +43,7 @@ void World::act() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::render() {
|
void World::render() {
|
||||||
Render::clear(this->player->location);
|
Render::clear({this->chunk_size/2, this->chunk_size/2});
|
||||||
for(size_t i{0}; i < this->rooms.size(); ++i) {
|
for(size_t i{0}; i < this->rooms.size(); ++i) {
|
||||||
this->rooms[i].draw({
|
this->rooms[i].draw({
|
||||||
.x = int(i % this->shear * this->chunk_size),
|
.x = int(i % this->shear * this->chunk_size),
|
||||||
|
@ -83,12 +74,6 @@ TileData World::query_tile(Tile tile) {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::on_input(bool pressed) {
|
|
||||||
if(!pressed) {
|
|
||||||
this->act();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WorldGenerator &WorldGenerator::with_chunk_size(unsigned side_length) {
|
WorldGenerator &WorldGenerator::with_chunk_size(unsigned side_length) {
|
||||||
assert(this->chunk_side_length == 0);
|
assert(this->chunk_side_length == 0);
|
||||||
assert(side_length > 0);
|
assert(side_length > 0);
|
||||||
|
@ -112,25 +97,22 @@ WorldGenerator &WorldGenerator::with_room_size(unsigned min_side_length, unsigne
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldGenerator &WorldGenerator::with_player(Character character) {
|
World WorldGenerator::generate() {
|
||||||
this->player.emplace(character);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<World> WorldGenerator::generate() {
|
|
||||||
assert(this->chunk_side_length > 0 && "Chunk size is required to generate world");
|
assert(this->chunk_side_length > 0 && "Chunk size is required to generate world");
|
||||||
assert(this->min_room_size > 0 && "Room size is required to generate world");
|
assert(this->min_room_size > 0 && "Room size is required to generate world");
|
||||||
assert(this->min_room_size < this->max_room_size && "Room size is required to generate world");
|
assert(this->min_room_size < this->max_room_size && "Room size is required to generate world");
|
||||||
assert(this->world_side_length > 0 && "World size is required to generate world");
|
assert(this->world_side_length > 0 && "World size is required to generate world");
|
||||||
assert(this->player.has_value() && "World cannot be generated without a player");
|
World world{};
|
||||||
std::unique_ptr<World> world{new World()};
|
world.chunk_size = this->chunk_side_length;
|
||||||
world->characters.push_back(player.value());
|
world.shear = this->world_side_length;
|
||||||
world->player = &world->characters[0];
|
world.characters.push_back(Character(world, {this->chunk_side_length/2, this->chunk_side_length/2}, CharacterData {
|
||||||
world->player->world = world.get();
|
.health = 1,
|
||||||
world->chunk_size = this->chunk_side_length;
|
.damage = 1,
|
||||||
world->shear = this->world_side_length;
|
.sprite = 0,
|
||||||
world->rooms.reserve(this->world_side_length * this->world_side_length);
|
.logic = null_character_logic_function
|
||||||
world->rooms.push_back(Room {
|
}));
|
||||||
|
world.rooms.reserve(this->world_side_length * this->world_side_length);
|
||||||
|
world.rooms.push_back(Room {
|
||||||
.hallway_paths = Directions(Directions::NORTH | Directions::EAST),
|
.hallway_paths = Directions(Directions::NORTH | Directions::EAST),
|
||||||
.chunk_size = this->chunk_side_length,
|
.chunk_size = this->chunk_side_length,
|
||||||
.rect = {
|
.rect = {
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
#ifndef ROGUE_WORLD_H
|
#ifndef ROGUE_WORLD_H
|
||||||
#define ROGUE_WORLD_H
|
#define ROGUE_WORLD_H
|
||||||
|
|
||||||
#include <optional>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <SDL2/SDL_rect.h>
|
#include <SDL2/SDL_rect.h>
|
||||||
#include "character.h"
|
#include "character.h"
|
||||||
#include "core/input.h"
|
|
||||||
#include "core/roguedefs.h"
|
#include "core/roguedefs.h"
|
||||||
|
|
||||||
namespace rogue {
|
namespace rogue {
|
||||||
|
@ -28,21 +26,18 @@ struct Room {
|
||||||
|
|
||||||
struct World {
|
struct World {
|
||||||
friend class WorldGenerator;
|
friend class WorldGenerator;
|
||||||
World();
|
|
||||||
~World() = default;
|
~World() = default;
|
||||||
void act();
|
void act();
|
||||||
void render();
|
void render();
|
||||||
Room &get_room(Chunk chunk);
|
Room &get_room(Chunk chunk);
|
||||||
TileData query_tile(Tile tile);
|
TileData query_tile(Tile tile);
|
||||||
void on_input(bool);
|
|
||||||
private:
|
private:
|
||||||
int chunk_size{1};
|
int chunk_size{1};
|
||||||
unsigned shear{0};
|
unsigned shear{0};
|
||||||
Character *player{nullptr};
|
|
||||||
std::vector<Room> rooms{};
|
std::vector<Room> rooms{};
|
||||||
std::vector<Character> characters{};
|
std::vector<Character> characters{};
|
||||||
KeyEventHandler direction_pressed;
|
|
||||||
private:
|
private:
|
||||||
|
World() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WorldGenerator {
|
class WorldGenerator {
|
||||||
|
@ -51,10 +46,8 @@ public:
|
||||||
WorldGenerator &with_chunk_size(unsigned side_length);
|
WorldGenerator &with_chunk_size(unsigned side_length);
|
||||||
WorldGenerator &with_world_size(unsigned side_length);
|
WorldGenerator &with_world_size(unsigned side_length);
|
||||||
WorldGenerator &with_room_size(unsigned min_side_length, unsigned max_side_length);
|
WorldGenerator &with_room_size(unsigned min_side_length, unsigned max_side_length);
|
||||||
WorldGenerator &with_player(Character character);
|
World generate();
|
||||||
std::unique_ptr<World> generate();
|
|
||||||
private:
|
private:
|
||||||
std::optional<Character> player;
|
|
||||||
int chunk_side_length{0}, world_side_length{0};
|
int chunk_side_length{0}, world_side_length{0};
|
||||||
int max_room_size{0}, min_room_size{0};
|
int max_room_size{0}, min_room_size{0};
|
||||||
};
|
};
|
||||||
|
|
18
src/main.cpp
18
src/main.cpp
|
@ -1,26 +1,14 @@
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#include <memory>
|
|
||||||
#include "core/character.h"
|
|
||||||
#include "core/input.h"
|
|
||||||
#include "core/renderer.h"
|
#include "core/renderer.h"
|
||||||
#include "core/world.h"
|
#include "core/world.h"
|
||||||
#include "player_logic.h"
|
|
||||||
|
|
||||||
using namespace rogue;
|
using namespace rogue;
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
std::unique_ptr<World> world{WorldGenerator()
|
World world{WorldGenerator()
|
||||||
.with_world_size(5)
|
.with_world_size(5)
|
||||||
.with_chunk_size(9)
|
.with_chunk_size(9)
|
||||||
.with_room_size(2, 5)
|
.with_room_size(2, 5)
|
||||||
.with_player(Character({9/2, 9/2},
|
|
||||||
new PlayerCharacterLogic(),
|
|
||||||
CharacterData {
|
|
||||||
.health = 1,
|
|
||||||
.damage = 1,
|
|
||||||
.sprite = 0
|
|
||||||
}
|
|
||||||
))
|
|
||||||
.generate()
|
.generate()
|
||||||
};
|
};
|
||||||
RenderData data{RenderDataSetup()
|
RenderData data{RenderDataSetup()
|
||||||
|
@ -34,13 +22,11 @@ int main(int argc, char *argv[]) {
|
||||||
Render::provide_render_data(data);
|
Render::provide_render_data(data);
|
||||||
SDL_Event evt;
|
SDL_Event evt;
|
||||||
for(;;) {
|
for(;;) {
|
||||||
world->render();
|
world.render();
|
||||||
Render::present();
|
Render::present();
|
||||||
if(SDL_WaitEvent(&evt)) {
|
if(SDL_WaitEvent(&evt)) {
|
||||||
if(evt.type == SDL_QUIT) {
|
if(evt.type == SDL_QUIT) {
|
||||||
goto main_loop;
|
goto main_loop;
|
||||||
} else {
|
|
||||||
Input::process_event(evt);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} main_loop:
|
} main_loop:
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
#include "player_logic.h"
|
|
||||||
#include <SDL2/SDL_log.h>
|
|
||||||
|
|
||||||
namespace rogue {
|
|
||||||
PlayerCharacterLogic::PlayerCharacterLogic()
|
|
||||||
: up{{SDL_SCANCODE_K, SDL_SCANCODE_UP}, std::bind(&PlayerCharacterLogic::on_up, this, std::placeholders::_1)}
|
|
||||||
, down{{SDL_SCANCODE_J, SDL_SCANCODE_DOWN}, std::bind(&PlayerCharacterLogic::on_down, this, std::placeholders::_1)}
|
|
||||||
, right{{SDL_SCANCODE_L, SDL_SCANCODE_RIGHT}, std::bind(&PlayerCharacterLogic::on_right, this, std::placeholders::_1)}
|
|
||||||
, left{{SDL_SCANCODE_H, SDL_SCANCODE_LEFT}, std::bind(&PlayerCharacterLogic::on_left, this, std::placeholders::_1)}
|
|
||||||
{}
|
|
||||||
|
|
||||||
Tile PlayerCharacterLogic::move() {
|
|
||||||
return {
|
|
||||||
this->character->location.x + input_x,
|
|
||||||
this->character->location.y + input_y
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerCharacterLogic::on_up(bool pressed) {
|
|
||||||
if(pressed) {
|
|
||||||
input_x = 0;
|
|
||||||
input_y = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerCharacterLogic::on_down(bool pressed) {
|
|
||||||
if(pressed) {
|
|
||||||
input_x = 0;
|
|
||||||
input_y = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerCharacterLogic::on_left(bool pressed) {
|
|
||||||
if(pressed) {
|
|
||||||
input_x = -1;
|
|
||||||
input_y = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerCharacterLogic::on_right(bool pressed) {
|
|
||||||
if(pressed) {
|
|
||||||
input_x = 1;
|
|
||||||
input_y = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,27 +0,0 @@
|
||||||
#ifndef PLAYER_LOGIC_H
|
|
||||||
#define PLAYER_LOGIC_H
|
|
||||||
|
|
||||||
#include "core/character.h"
|
|
||||||
#include "core/input.h"
|
|
||||||
#include "core/roguedefs.h"
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
namespace rogue {
|
|
||||||
class PlayerCharacterLogic : public CharacterLogic {
|
|
||||||
public:
|
|
||||||
PlayerCharacterLogic();
|
|
||||||
private:
|
|
||||||
virtual Tile move() override;
|
|
||||||
void on_up(bool pressed);
|
|
||||||
void on_down(bool pressed);
|
|
||||||
void on_left(bool pressed);
|
|
||||||
void on_right(bool pressed);
|
|
||||||
int input_x{0}, input_y{0};
|
|
||||||
KeyEventHandler up;
|
|
||||||
KeyEventHandler down;
|
|
||||||
KeyEventHandler right;
|
|
||||||
KeyEventHandler left;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // !PLAYER_LOGIC_H
|
|
1
vendor/callable
vendored
Submodule
1
vendor/callable
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit ea96247ecb258ea9938f038f410e0fd2739aa5de
|
Loading…
Reference in a new issue