feat: implemented characters that exist within the game world

This commit is contained in:
Sara 2025-06-04 00:19:03 +02:00
parent 0be2a3fa2a
commit e3544165e4
5 changed files with 249 additions and 0 deletions

44
src/core/character.cpp Normal file
View file

@ -0,0 +1,44 @@
#include "character.h"
#include "core/renderer.h"
#include "world.h"
namespace rogue {
Character::Character(World &world, Tile location, CharacterData stats)
: data{stats}
, health{stats.health}
, location{location}
, world{world}
{}
void Character::act() {
if(this->health < 0) {
return;
}
// get motion from logic
Tile target{this->data.logic(*this)};
if(target == this->location) {
return;
}
// check resulting tile
TileData tile{world.query_tile(target)};
// if character, deal damage
if(tile.character != nullptr) {
tile.character->deal_damage(this->data.damage);
} else if(!tile.is_wall) { // if empty, move
this->location = target;
} // if wall, do nothing
}
void Character::draw() {
if(this->health > 0) {
Render::draw(this->location, this->data.sprite);
} // else { // draw gore pile
}
bool Character::deal_damage(int damage) {
return (this->health -= damage) <= 0;
}
Tile null_character_logic_function(Character &character) {
return character.location;
}
}

35
src/core/character.h Normal file
View file

@ -0,0 +1,35 @@
#ifndef ROGUE_CHARACTER_H
#define ROGUE_CHARACTER_H
#include "core/roguedefs.h"
namespace rogue {
class World;
class Character;
typedef Tile(&CharacterLogicFunction)(Character &character);
struct CharacterData {
int health{1};
int damage{1};
Sprite sprite{0};
CharacterLogicFunction logic;
};
struct Character {
Character(World &world, Tile location, CharacterData stats);
void act();
void draw();
bool deal_damage(int damage);
CharacterData const data;
int health{1};
Tile location{0, 0};
World &world;
};
extern Tile null_character_logic_function(Character &character);
}
#endif // !ROGUE_CHARACTER_H

85
src/core/world.cpp Normal file
View file

@ -0,0 +1,85 @@
#include "world.h"
#include "core/character.h"
#include <cassert>
namespace rogue {
void Room::draw() {
// TODO: .
}
bool Room::tile_is_wall(Tile local_tile) const {
// TODO: I wonder what
return false;
}
void World::act() {
for(Character &character : this->characters) {
character.act();
}
}
void World::render() {
for(Room &room : this->rooms) {
room.draw();
}
for(Character &character : this->characters) {
character.draw();
}
}
Room &World::get_room(Chunk chunk) {
return rooms[chunk.x + chunk.y * this->shear];
}
TileData World::query_tile(Tile tile) {
Room &room{this->get_room({tile.x / this->chunk_size, tile.y / this->chunk_size})};
TileData out{
.character = nullptr,
.is_wall = room.tile_is_wall({tile.x % this->chunk_size, tile.y % this->chunk_size})
};
for(Character &character : this->characters) {
if(character.location == tile) {
out.character = &character;
return out;
}
}
return out;
}
WorldGenerator &WorldGenerator::with_chunk_size(unsigned side_length) {
assert(this->chunk_side_length == 0);
assert(side_length > 0);
this->chunk_side_length = side_length;
return *this;
}
WorldGenerator &WorldGenerator::with_world_size(unsigned side_length) {
assert(this->world_side_length == 0);
assert(side_length > 0);
this->world_side_length = side_length;
return *this;
}
WorldGenerator &WorldGenerator::with_room_size(unsigned min_side_length, unsigned max_side_length) {
assert(chunk_side_length > 0 && "Chunk size needs to be initialized before room size");
assert(min_side_length < max_side_length);
assert(min_side_length > 0);
this->min_room_size = min_side_length;
this->max_room_size = max_side_length;
return *this;
}
World WorldGenerator::generate() {
// TODO: the rest of the fucking owl
World world{};
Character character{Character(world, {0,0}, CharacterData {
.health = 1,
.damage = 1,
.sprite = 0,
.logic = null_character_logic_function
})};
character.data.logic(character);
world.characters.push_back(character);
return world;
}
}

53
src/core/world.h Normal file
View file

@ -0,0 +1,53 @@
#ifndef ROGUE_WORLD_H
#define ROGUE_WORLD_H
#include <vector>
#include <SDL2/SDL_rect.h>
#include "character.h"
#include "core/roguedefs.h"
namespace rogue {
class Character;
struct TileData {
Character *character{nullptr};
bool is_wall{false};
};
struct Room {
Directions hallway_paths{0};
SDL_Rect rect{0, 0, 1, 1};
void draw();
bool tile_is_wall(Tile local_tile) const;
};
struct World {
friend class WorldGenerator;
~World() = default;
void act();
void render();
Room &get_room(Chunk chunk);
TileData query_tile(Tile tile);
private:
int chunk_size{1};
unsigned shear{0};
std::vector<Room> rooms{};
std::vector<Character> characters{};
private:
World() = default;
};
class WorldGenerator {
public:
WorldGenerator() = default;
WorldGenerator &with_chunk_size(unsigned side_length);
WorldGenerator &with_world_size(unsigned side_length);
WorldGenerator &with_room_size(unsigned min_side_length, unsigned max_side_length);
World generate();
private:
unsigned chunk_side_length{0}, world_side_length{0};
unsigned max_room_size{0}, min_room_size{0};
};
}
#endif // !ROGUE_WORLD_H

View file

@ -1,3 +1,35 @@
#include <SDL2/SDL.h>
#include "core/renderer.h"
#include "core/world.h"
using namespace rogue;
int main(int argc, char *argv[]) {
World world{WorldGenerator().generate()};
RenderData data{RenderDataSetup()
.with_window("roguelike", SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_FULLSCREEN)
.with_renderer(SDL_RENDERER_ACCELERATED)
.with_resource_path("resources/")
.with_sprite("wizard.png")
.build()
};
Render::provide_render_data(data);
SDL_Event evt;
for(;;) {
Render::clear({0, 0});
/*
Render::draw({0, 0}, 0);
Render::draw({1, 0}, 0);
Render::draw({2, 0}, 0);
Render::draw({3, 0}, 0);
*/
world.render();
Render::present();
if(SDL_WaitEvent(&evt)) {
if(evt.type == SDL_QUIT) {
goto main_loop;
}
}
} main_loop:
return 0;
}