feat: documentation and balancing
This commit is contained in:
parent
f22927e124
commit
7ff9756dcc
|
@ -11,9 +11,9 @@ void CharacterLogic::set_character(Character *character) {
|
|||
this->character = character;
|
||||
}
|
||||
|
||||
Character::Character(Tile location, CharacterLogic *logic, CharacterData stats)
|
||||
Character::Character(Tile location, CharacterLogic *logic, CharacterData const *stats)
|
||||
: data{stats}
|
||||
, health{stats.health}
|
||||
, health{stats->health}
|
||||
, location{location}
|
||||
, world{nullptr}
|
||||
, logic{logic} {
|
||||
|
@ -36,7 +36,7 @@ void Character::act() {
|
|||
TileData tile{world->query_tile(target)};
|
||||
// if character, deal damage
|
||||
if(tile.character != nullptr) {
|
||||
tile.character->deal_damage(this->data.damage);
|
||||
tile.character->deal_damage(this->data->damage);
|
||||
} else if(!tile.is_wall) { // if empty, move
|
||||
this->location = target;
|
||||
} // if wall, do nothing
|
||||
|
@ -44,7 +44,7 @@ void Character::act() {
|
|||
|
||||
void Character::draw() {
|
||||
if(this->health > 0) {
|
||||
Render::draw(this->location, this->data.sprite);
|
||||
Render::draw(this->location, this->data->sprite);
|
||||
} // else { // draw gore pile
|
||||
}
|
||||
|
||||
|
|
|
@ -2,20 +2,24 @@
|
|||
#define ROGUE_CHARACTER_H
|
||||
|
||||
#include "core/roguedefs.h"
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace rogue {
|
||||
class World;
|
||||
class Character;
|
||||
|
||||
// Character Logic, abstract Subclass Sandbox Pattern implementation that declares the necessary bits to communicate with the character
|
||||
struct CharacterLogic {
|
||||
virtual ~CharacterLogic();
|
||||
|
||||
virtual Tile move() = 0;
|
||||
protected:
|
||||
Character *character{nullptr};
|
||||
// CharacterLogic doesn't need to do anything else,
|
||||
//so we limit their interaction with the world to just the character (which exposes the parent World instance)
|
||||
Character const *character{nullptr};
|
||||
private:
|
||||
friend class Character;
|
||||
friend class Character; // hide the character
|
||||
void set_character(Character *character);
|
||||
};
|
||||
|
||||
|
@ -25,22 +29,44 @@ struct CharacterData {
|
|||
Sprite sprite{0};
|
||||
};
|
||||
|
||||
// Character class, serves as the primary entity type in the game
|
||||
struct Character {
|
||||
Character() = default;
|
||||
Character(Tile location, CharacterLogic *logic, CharacterData stats);
|
||||
|
||||
Character(Tile location, CharacterLogic *logic, CharacterData const *stats);
|
||||
typedef std::function<Character(Tile)> Spawner; // <functional> style Factory Pattern
|
||||
void act();
|
||||
void draw();
|
||||
bool deal_damage(int damage);
|
||||
|
||||
CharacterData data{};
|
||||
CharacterData const *data{}; // Type Object pattern implemented as a Flyweight
|
||||
// marked constant as it is shared between instances of the same type.
|
||||
int health{1};
|
||||
Tile location{0, 0};
|
||||
World *world{nullptr};
|
||||
private:
|
||||
// The Subclass Sandbox Pattern instance that implements the behavioural logic of this character.
|
||||
std::shared_ptr<CharacterLogic> logic{nullptr};
|
||||
public:
|
||||
// Simplifies creating a new character logic instance for construction of a Character
|
||||
// bind into a Factory object using make_factory to pass to world generators
|
||||
template <typename TLogicType>
|
||||
static Character create(CharacterData const &stats, Tile tile);
|
||||
// binds Character::create into a std::function,
|
||||
// making a Factory Pattern object to pass to WorldGenerator as a spawner
|
||||
template <typename TLogicType>
|
||||
static Spawner make_factory(CharacterData const &stats);
|
||||
};
|
||||
|
||||
template <typename TLogicType>
|
||||
Character Character::create(CharacterData const &stats, Tile tile) {
|
||||
return Character(tile, new TLogicType, &stats);
|
||||
}
|
||||
|
||||
template <typename TLogicType>
|
||||
Character::Spawner Character::make_factory(CharacterData const &stats) {
|
||||
return std::bind(&Character::create<TLogicType>, stats, std::placeholders::_1);
|
||||
}
|
||||
|
||||
struct NullCharacterLogic : public CharacterLogic {
|
||||
virtual Tile move() override;
|
||||
};
|
||||
|
|
|
@ -144,7 +144,7 @@ void Render::draw_healthbar(int current, int max, SDL_Rect area, int border) {
|
|||
area.y += border;
|
||||
area.h -= border * 2;
|
||||
area.w = ((area.w - border * 2) * current) / max;
|
||||
SDL_SetRenderDrawColor(Render::data->renderer, 200,200, 200, 255);
|
||||
SDL_SetRenderDrawColor(Render::data->renderer, 100,100, 100, 255);
|
||||
SDL_RenderFillRect(Render::data->renderer, &area);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
static void clear(Tile camera_center, unsigned fov = 10);
|
||||
static void draw(Tile world_space_tile, Sprite sprite);
|
||||
static void draw_menu(Sprite menu);
|
||||
static void draw_healthbar(int current, int max, SDL_Rect area = {0, 0, 500, 100}, int border = 5);
|
||||
static void draw_healthbar(int current, int max, SDL_Rect area={0,0,500,50}, int border=10);
|
||||
static void present();
|
||||
private:
|
||||
static Tile camera_center;
|
||||
|
|
|
@ -63,7 +63,7 @@ void World::act() {
|
|||
}
|
||||
|
||||
void World::render() {
|
||||
Render::clear(this->player.location, 100);
|
||||
Render::clear(this->player.location, 20);
|
||||
for(size_t i{0}; i < this->rooms.size(); ++i) {
|
||||
this->rooms[i].draw({
|
||||
.x = int(i % this->shear * this->chunk_size),
|
||||
|
@ -75,7 +75,7 @@ void World::render() {
|
|||
}
|
||||
boss.draw();
|
||||
player.draw();
|
||||
Render::draw_healthbar(player.health, player.data.health);
|
||||
Render::draw_healthbar(player.health, player.data->health);
|
||||
}
|
||||
|
||||
Room &World::get_room(Chunk chunk) {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef ROGUE_WORLD_H
|
||||
#define ROGUE_WORLD_H
|
||||
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <SDL2/SDL_rect.h>
|
||||
|
@ -58,9 +57,9 @@ public:
|
|||
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);
|
||||
WorldGenerator &with_player(std::function<Character(Tile)> spawner);
|
||||
WorldGenerator &with_enemy(std::function<Character(Tile)> spawner, int inv_frequency);
|
||||
WorldGenerator &with_boss(std::function<Character(Tile)> spawner);
|
||||
WorldGenerator &with_player(Character::Spawner spawner);
|
||||
WorldGenerator &with_enemy(Character::Spawner spawner, int inv_frequency);
|
||||
WorldGenerator &with_boss(Character::Spawner spawner);
|
||||
WorldGenerator &with_connecting_chance(unsigned num);
|
||||
std::unique_ptr<World> generate();
|
||||
private:
|
||||
|
@ -69,9 +68,9 @@ private:
|
|||
void add_enemies(std::unique_ptr<World> &world, Chunk const &chunk, Room &room);
|
||||
void setup_player(std::unique_ptr<World> &world, Chunk spawn_chunk);
|
||||
private:
|
||||
std::function<Character(Tile)> player_spawner{};
|
||||
std::function<Character(Tile)> boss_spawner{};
|
||||
std::vector<std::pair<std::function<Character(Tile)>, int>> enemy_spawners{};
|
||||
Character::Spawner player_spawner{};
|
||||
Character::Spawner boss_spawner{};
|
||||
std::vector<std::pair<Character::Spawner, int>> enemy_spawners{};
|
||||
int chunk_side_length{0}, world_side_length{0};
|
||||
int max_room_size{0}, min_room_size{0};
|
||||
unsigned connecting_chance{1};
|
||||
|
|
24
src/main.cpp
24
src/main.cpp
|
@ -18,13 +18,13 @@ enum GameState {
|
|||
};
|
||||
|
||||
CharacterData const player_data{
|
||||
.health = 20,
|
||||
.health = 30,
|
||||
.damage = 2,
|
||||
.sprite = 3
|
||||
};
|
||||
|
||||
CharacterData const boss_data{
|
||||
.health = 10,
|
||||
.health = 1,
|
||||
.damage = 3,
|
||||
.sprite = 0
|
||||
};
|
||||
|
@ -35,23 +35,19 @@ CharacterData const critte_data{
|
|||
.sprite = 2
|
||||
};
|
||||
|
||||
template <typename TLogicType>
|
||||
static Character create_character(CharacterData const &stats, Tile tile) {
|
||||
return Character(tile, new TLogicType, stats);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
GameState game_state{GameState::MainMenu};
|
||||
WorldGenerator generator{WorldGenerator()
|
||||
.with_world_size(10)
|
||||
.with_chunk_size(10)
|
||||
.with_room_size(6, 10)
|
||||
.with_world_size(6)
|
||||
.with_chunk_size(8)
|
||||
.with_room_size(5, 8)
|
||||
.with_connecting_chance(5)
|
||||
.with_player(std::bind(&create_character<PlayerCharacterLogic>, player_data, std::placeholders::_1))
|
||||
.with_enemy(std::bind(&create_character<CritteLogic>, critte_data, std::placeholders::_1), 2)
|
||||
.with_enemy(std::bind(&create_character<CritteLogic>, critte_data, std::placeholders::_1), 2)
|
||||
.with_enemy(std::bind(&create_character<CritteLogic>, critte_data, std::placeholders::_1), 2)
|
||||
.with_boss(std::bind(&create_character<CritteLogic>, boss_data, std::placeholders::_1))};
|
||||
.with_player(Character::make_factory<PlayerCharacterLogic>(player_data))
|
||||
.with_enemy(Character::make_factory<CritteLogic>(critte_data), 2)
|
||||
.with_enemy(Character::make_factory<CritteLogic>(critte_data), 3)
|
||||
.with_enemy(Character::make_factory<CritteLogic>(critte_data), 10)
|
||||
.with_boss(Character::make_factory<CritteLogic>(boss_data))};
|
||||
RenderData data{RenderDataSetup()
|
||||
// create window and renderer, allowing for texture creation
|
||||
.with_window("roguelike", SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_FULLSCREEN)
|
||||
|
|
Loading…
Reference in a new issue