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;
|
this->character = character;
|
||||||
}
|
}
|
||||||
|
|
||||||
Character::Character(Tile location, CharacterLogic *logic, CharacterData stats)
|
Character::Character(Tile location, CharacterLogic *logic, CharacterData const *stats)
|
||||||
: data{stats}
|
: data{stats}
|
||||||
, health{stats.health}
|
, health{stats->health}
|
||||||
, location{location}
|
, location{location}
|
||||||
, world{nullptr}
|
, world{nullptr}
|
||||||
, logic{logic} {
|
, logic{logic} {
|
||||||
|
@ -36,7 +36,7 @@ void Character::act() {
|
||||||
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);
|
||||||
} else if(!tile.is_wall) { // if empty, move
|
} else if(!tile.is_wall) { // if empty, move
|
||||||
this->location = target;
|
this->location = target;
|
||||||
} // if wall, do nothing
|
} // if wall, do nothing
|
||||||
|
@ -44,7 +44,7 @@ void Character::act() {
|
||||||
|
|
||||||
void Character::draw() {
|
void Character::draw() {
|
||||||
if(this->health > 0) {
|
if(this->health > 0) {
|
||||||
Render::draw(this->location, this->data.sprite);
|
Render::draw(this->location, this->data->sprite);
|
||||||
} // else { // draw gore pile
|
} // else { // draw gore pile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,20 +2,24 @@
|
||||||
#define ROGUE_CHARACTER_H
|
#define ROGUE_CHARACTER_H
|
||||||
|
|
||||||
#include "core/roguedefs.h"
|
#include "core/roguedefs.h"
|
||||||
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace rogue {
|
namespace rogue {
|
||||||
class World;
|
class World;
|
||||||
class Character;
|
class Character;
|
||||||
|
|
||||||
|
// Character Logic, abstract Subclass Sandbox Pattern implementation that declares the necessary bits to communicate with the character
|
||||||
struct CharacterLogic {
|
struct CharacterLogic {
|
||||||
virtual ~CharacterLogic();
|
virtual ~CharacterLogic();
|
||||||
|
|
||||||
virtual Tile move() = 0;
|
virtual Tile move() = 0;
|
||||||
protected:
|
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:
|
private:
|
||||||
friend class Character;
|
friend class Character; // hide the character
|
||||||
void set_character(Character *character);
|
void set_character(Character *character);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,22 +29,44 @@ struct CharacterData {
|
||||||
Sprite sprite{0};
|
Sprite sprite{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Character class, serves as the primary entity type in the game
|
||||||
struct Character {
|
struct Character {
|
||||||
Character() = default;
|
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 act();
|
||||||
void draw();
|
void draw();
|
||||||
bool deal_damage(int damage);
|
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};
|
int health{1};
|
||||||
Tile location{0, 0};
|
Tile location{0, 0};
|
||||||
World *world{nullptr};
|
World *world{nullptr};
|
||||||
private:
|
private:
|
||||||
|
// The Subclass Sandbox Pattern instance that implements the behavioural logic of this character.
|
||||||
std::shared_ptr<CharacterLogic> logic{nullptr};
|
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 {
|
struct NullCharacterLogic : public CharacterLogic {
|
||||||
virtual Tile move() override;
|
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.y += border;
|
||||||
area.h -= border * 2;
|
area.h -= border * 2;
|
||||||
area.w = ((area.w - border * 2) * current) / max;
|
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);
|
SDL_RenderFillRect(Render::data->renderer, &area);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ public:
|
||||||
static void clear(Tile camera_center, unsigned fov = 10);
|
static void clear(Tile camera_center, unsigned fov = 10);
|
||||||
static void draw(Tile world_space_tile, Sprite sprite);
|
static void draw(Tile world_space_tile, Sprite sprite);
|
||||||
static void draw_menu(Sprite menu);
|
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();
|
static void present();
|
||||||
private:
|
private:
|
||||||
static Tile camera_center;
|
static Tile camera_center;
|
||||||
|
|
|
@ -63,7 +63,7 @@ void World::act() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::render() {
|
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) {
|
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),
|
||||||
|
@ -75,7 +75,7 @@ void World::render() {
|
||||||
}
|
}
|
||||||
boss.draw();
|
boss.draw();
|
||||||
player.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) {
|
Room &World::get_room(Chunk chunk) {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#ifndef ROGUE_WORLD_H
|
#ifndef ROGUE_WORLD_H
|
||||||
#define ROGUE_WORLD_H
|
#define ROGUE_WORLD_H
|
||||||
|
|
||||||
#include <optional>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <SDL2/SDL_rect.h>
|
#include <SDL2/SDL_rect.h>
|
||||||
|
@ -58,9 +57,9 @@ 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(std::function<Character(Tile)> spawner);
|
WorldGenerator &with_player(Character::Spawner spawner);
|
||||||
WorldGenerator &with_enemy(std::function<Character(Tile)> spawner, int inv_frequency);
|
WorldGenerator &with_enemy(Character::Spawner spawner, int inv_frequency);
|
||||||
WorldGenerator &with_boss(std::function<Character(Tile)> spawner);
|
WorldGenerator &with_boss(Character::Spawner spawner);
|
||||||
WorldGenerator &with_connecting_chance(unsigned num);
|
WorldGenerator &with_connecting_chance(unsigned num);
|
||||||
std::unique_ptr<World> generate();
|
std::unique_ptr<World> generate();
|
||||||
private:
|
private:
|
||||||
|
@ -69,9 +68,9 @@ private:
|
||||||
void add_enemies(std::unique_ptr<World> &world, Chunk const &chunk, Room &room);
|
void add_enemies(std::unique_ptr<World> &world, Chunk const &chunk, Room &room);
|
||||||
void setup_player(std::unique_ptr<World> &world, Chunk spawn_chunk);
|
void setup_player(std::unique_ptr<World> &world, Chunk spawn_chunk);
|
||||||
private:
|
private:
|
||||||
std::function<Character(Tile)> player_spawner{};
|
Character::Spawner player_spawner{};
|
||||||
std::function<Character(Tile)> boss_spawner{};
|
Character::Spawner boss_spawner{};
|
||||||
std::vector<std::pair<std::function<Character(Tile)>, int>> enemy_spawners{};
|
std::vector<std::pair<Character::Spawner, int>> enemy_spawners{};
|
||||||
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};
|
||||||
unsigned connecting_chance{1};
|
unsigned connecting_chance{1};
|
||||||
|
|
24
src/main.cpp
24
src/main.cpp
|
@ -18,13 +18,13 @@ enum GameState {
|
||||||
};
|
};
|
||||||
|
|
||||||
CharacterData const player_data{
|
CharacterData const player_data{
|
||||||
.health = 20,
|
.health = 30,
|
||||||
.damage = 2,
|
.damage = 2,
|
||||||
.sprite = 3
|
.sprite = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
CharacterData const boss_data{
|
CharacterData const boss_data{
|
||||||
.health = 10,
|
.health = 1,
|
||||||
.damage = 3,
|
.damage = 3,
|
||||||
.sprite = 0
|
.sprite = 0
|
||||||
};
|
};
|
||||||
|
@ -35,23 +35,19 @@ CharacterData const critte_data{
|
||||||
.sprite = 2
|
.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[]) {
|
int main(int argc, char *argv[]) {
|
||||||
GameState game_state{GameState::MainMenu};
|
GameState game_state{GameState::MainMenu};
|
||||||
WorldGenerator generator{WorldGenerator()
|
WorldGenerator generator{WorldGenerator()
|
||||||
.with_world_size(10)
|
.with_world_size(6)
|
||||||
.with_chunk_size(10)
|
.with_chunk_size(8)
|
||||||
.with_room_size(6, 10)
|
.with_room_size(5, 8)
|
||||||
.with_connecting_chance(5)
|
.with_connecting_chance(5)
|
||||||
.with_player(std::bind(&create_character<PlayerCharacterLogic>, player_data, std::placeholders::_1))
|
.with_player(Character::make_factory<PlayerCharacterLogic>(player_data))
|
||||||
.with_enemy(std::bind(&create_character<CritteLogic>, critte_data, std::placeholders::_1), 2)
|
.with_enemy(Character::make_factory<CritteLogic>(critte_data), 2)
|
||||||
.with_enemy(std::bind(&create_character<CritteLogic>, critte_data, std::placeholders::_1), 2)
|
.with_enemy(Character::make_factory<CritteLogic>(critte_data), 3)
|
||||||
.with_enemy(std::bind(&create_character<CritteLogic>, critte_data, std::placeholders::_1), 2)
|
.with_enemy(Character::make_factory<CritteLogic>(critte_data), 10)
|
||||||
.with_boss(std::bind(&create_character<CritteLogic>, boss_data, std::placeholders::_1))};
|
.with_boss(Character::make_factory<CritteLogic>(boss_data))};
|
||||||
RenderData data{RenderDataSetup()
|
RenderData data{RenderDataSetup()
|
||||||
// create window and renderer, allowing for texture creation
|
// create window and renderer, allowing for texture creation
|
||||||
.with_window("roguelike", SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_FULLSCREEN)
|
.with_window("roguelike", SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_FULLSCREEN)
|
||||||
|
|
Loading…
Reference in a new issue