diff --git a/dungeon.vcxproj b/dungeon.vcxproj
index 89e7d94..049998e 100644
--- a/dungeon.vcxproj
+++ b/dungeon.vcxproj
@@ -116,6 +116,7 @@
+
@@ -131,7 +132,6 @@
-
@@ -139,11 +139,11 @@
-
-
-
-
-
+
+
+
+
+
@@ -156,9 +156,11 @@
+
+
@@ -178,7 +180,6 @@
-
@@ -187,11 +188,11 @@
-
-
-
-
-
+
+
+
+
+
@@ -203,16 +204,18 @@
-
-
-
+
+
+
+
+
diff --git a/dungeon.vcxproj.filters b/dungeon.vcxproj.filters
index 366940c..4a58cee 100644
--- a/dungeon.vcxproj.filters
+++ b/dungeon.vcxproj.filters
@@ -54,9 +54,6 @@
Source Files
-
- Source Files
-
Source Files
@@ -78,21 +75,6 @@
Source Files
-
- Source Files
-
-
- Source Files
-
-
- Source Files
-
-
- Source Files
-
-
- Source Files
-
Source Files
@@ -144,6 +126,30 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
@@ -188,9 +194,6 @@
Header Files
-
- Header Files
-
Header Files
@@ -215,21 +218,6 @@
Header Files
-
- Header Files
-
-
- Header Files
-
-
- Header Files
-
-
- Header Files
-
-
- Header Files
-
Header Files
@@ -260,15 +248,6 @@
Header Files
-
- Header Files
-
-
- Header Files
-
-
- Header Files
-
Header Files
@@ -302,5 +281,35 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
\ No newline at end of file
diff --git a/src/App.cpp b/src/App.cpp
index 0933ba8..820ec1b 100644
--- a/src/App.cpp
+++ b/src/App.cpp
@@ -9,11 +9,12 @@
#include
#include
#include "Renderer.h"
-#include "imgui.h"
+#include "imgui/imgui.h"
#include "Input.h"
-#include "Gamestate.h"
#include "PlayState.h"
#include "LuaHandler.h"
+#include "Time.h"
+#include
Uint64 perfFreq;
double currTime() {
@@ -108,12 +109,8 @@ int App::start() {
double accumulator = dt;
bool show_log = false;
- bool running = true;
- Gamestate* nextstate = nullptr;
-
- current = new PlayState();
- current->init(this);
- current->load();
+ running = true;
+ statestack.push(std::unique_ptr(new PlayState(this)));
while (running) {
double newTime = currTime();
@@ -122,19 +119,12 @@ int App::start() {
frametime = 1.0/30;
}
- if (nextstate != nullptr) {
- current->quit();
- delete current;
- current = nextstate;
- current->init(this);
- current->load();
- }
-
currentTime = newTime;
accumulator += frametime;
SDL_Event ev{};
ImGuiIO &io = ImGui::GetIO();
+
renderer->ImguiNewFrame();
while (SDL_PollEvent(&ev)) {
//renderer->ImguiProcessEvents(&ev);
@@ -154,31 +144,31 @@ int App::start() {
case SDL_MOUSEMOTION:
if (!io.WantCaptureMouse) {
InputEvent inputEvent = input->set_mouse_pos(ev.motion.x, ev.motion.y, ev.motion.xrel, ev.motion.yrel);
- current->inputevent(&inputEvent);
+ statestack.input(inputEvent);
}
break;
case SDL_MOUSEBUTTONDOWN:
if (!io.WantCaptureMouse) {
InputEvent inputEvent = input->set_mouse_button(ev.button.button, ev.button.x, ev.button.y, true);
- current->inputevent(&inputEvent);
+ statestack.input(inputEvent);
}
break;
case SDL_MOUSEBUTTONUP:
if (!io.WantCaptureMouse) {
InputEvent inputEvent = input->set_mouse_button(ev.button.button, ev.button.x, ev.button.y, false);
- current->inputevent(&inputEvent);
+ statestack.input(inputEvent);
}
break;
case SDL_KEYDOWN:
if (!io.WantCaptureKeyboard) {
InputEvent inputEvent = input->set_key(ev.key.keysym.sym, (SDL_Keymod) ev.key.keysym.mod, true);
- current->inputevent(&inputEvent);
+ statestack.input(inputEvent);
}
break;
case SDL_KEYUP:
if (!io.WantCaptureKeyboard){
InputEvent inputEvent = input->set_key(ev.key.keysym.sym, (SDL_Keymod) ev.key.keysym.mod, false);
- current->inputevent(&inputEvent);
+ statestack.input(inputEvent);
}
break;
case SDL_QUIT:
@@ -189,13 +179,13 @@ int App::start() {
}
}
while (running && accumulator >= dt) {
- nextstate = current->update(dt);
+ statestack.update(dt);
input->new_frame();
-
+ Time::tick_timers(dt);
accumulator -= dt;
}
renderer->Clear();
- current->draw(accumulator / dt);
+ statestack.draw();
renderer->Present();
SDL_Delay(1);
}
diff --git a/src/App.h b/src/App.h
index a5f0f04..03a7474 100644
--- a/src/App.h
+++ b/src/App.h
@@ -5,7 +5,8 @@
#ifndef DUNGEON_APP_H
#define DUNGEON_APP_H
-class Gamestate;
+#include "statemachine/StateStack.h"
+
class Renderer;
class Input;
@@ -14,9 +15,10 @@ class Input;
#define ADD_QUOTES(s) ADD_QUOTES_HELPER(s)
class App {
+ bool running = true;
public:
const char* version = ADD_QUOTES(GIT_CUR_COMMIT);
- Gamestate* current;
+ StateStack statestack;
Renderer* renderer;
Input* input;
bool init();
diff --git a/src/Gamestate.cpp b/src/Gamestate.cpp
deleted file mode 100644
index 152ff53..0000000
--- a/src/Gamestate.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-//
-// Created by Adrian on 2017-09-19.
-//
-
-#include "Gamestate.h"
-#include "App.h"
-
-void Gamestate::init(App *app) {
- this->app = app;
-}
diff --git a/src/Gamestate.h b/src/Gamestate.h
deleted file mode 100644
index 69c0211..0000000
--- a/src/Gamestate.h
+++ /dev/null
@@ -1,25 +0,0 @@
-//
-// Created by Adrian on 2017-09-19.
-//
-
-#ifndef DUNGEON_GAMESTATE_H
-#define DUNGEON_GAMESTATE_H
-
-class App;
-struct InputEvent;
-
-class Gamestate {
-protected:
- App* app;
-public:
- //virtual ~Gamestate() {};
- void init(App* app);
- virtual void load() = 0;
- virtual Gamestate* update(double delta) = 0;
- virtual void draw(double delta) = 0;
- virtual void quit() = 0;
- virtual void inputevent(InputEvent* event) = 0;
-};
-
-
-#endif //DUNGEON_GAMESTATE_H
diff --git a/src/Logger.cpp b/src/Logger.cpp
new file mode 100644
index 0000000..bf96a23
--- /dev/null
+++ b/src/Logger.cpp
@@ -0,0 +1,39 @@
+#include "Logger.h"
+#include
+#include
+
+Log::LogLevel log_level = Log::LogLevel::Warning;
+
+void Log::set_log_level(LogLevel level) {
+ log_level = level;
+}
+
+void Log::error(string tag, string message) {
+ if (log_level <= LogLevel::Error) {
+ printf("[ERR] <%s> %s\n", tag, message);
+ }
+}
+
+void Log::warning(string tag, string message) {
+ if (log_level <= LogLevel::Warning) {
+ printf("[WRN] <%s> %s\n", tag, message);
+ }
+}
+
+void Log::info(string tag, string message) {
+ if (log_level <= LogLevel::Info) {
+ printf("[INF] <%s> %s\n", tag, message);
+ }
+}
+
+void Log::debug(string tag, string message) {
+ if (log_level <= LogLevel::Debug) {
+ printf("[DBG] <%s> %s\n", tag, message);
+ }
+}
+
+void Log::trace(string tag, string message) {
+ if (log_level <= LogLevel::Trace) {
+ printf("[TRC] <%s> %s\n", tag, message);
+ }
+}
diff --git a/src/Logger.h b/src/Logger.h
index a00b49d..ccc175a 100644
--- a/src/Logger.h
+++ b/src/Logger.h
@@ -1,5 +1,23 @@
#pragma once
+#include
-namespace Logger {
+namespace Log {
+ using std::string;
-}
\ No newline at end of file
+ enum LogLevel {
+ Error,
+ Warning,
+ Info,
+ Debug,
+ Trace,
+ };
+
+ void set_log_level(LogLevel level);
+ //void enable_log_to_file(bool enable);
+ //void set_log_path(string path);
+ void error(string tag, string message);
+ void warning(string tag, string message);
+ void info(string tag, string message);
+ void debug(string tag, string message);
+ void trace(string tag, string message);
+}
diff --git a/src/PlayState.cpp b/src/PlayState.cpp
index a9b5c5f..fe555be 100644
--- a/src/PlayState.cpp
+++ b/src/PlayState.cpp
@@ -10,7 +10,7 @@
#include "SpriteAtlas.h"
#include "Mapgen.h"
#include "FieldOfView.h"
-#include "imgui.h"
+#include "imgui/imgui.h"
#include "Hero.h"
#include "Goblin.h"
#include "Shaman.h"
@@ -23,13 +23,14 @@ InputAction player_action;
TileSet tileset;
LuaHandler handler;
-void PlayState::load() {
+void PlayState::enter() {
SDL_LogVerbose(SDL_LOG_CATEGORY_SYSTEM, "Creating ascii tileset...\n");
ascii = new SpriteAtlas(app->renderer, "./assets/12x12.bmp", 192, 192, 12, 12);
SDL_LogVerbose(SDL_LOG_CATEGORY_SYSTEM, "Created ascii tileset.\n");
handler.load_module("data", &tileset);
+ // TODO: Load all this from Lua
app->input->bind_key(SDLK_ESCAPE, ACTION_ESCAPE_MENU);
// Movement: keypad
@@ -71,6 +72,10 @@ void PlayState::load() {
new_game();
}
+PlayState::PlayState(App * app) {
+ this->app = app;
+}
+
void PlayState::new_game() {
player_action = ACTION_NONE;
@@ -104,7 +109,7 @@ void PlayState::new_game() {
}
}
-Gamestate *PlayState::update(double delta) {
+StateResult PlayState::update(float delta) {
while (!is_player_turn || player_action != ACTION_NONE) {
std::vector* actors = tilemap->get_actor_list();
Actor* actor = actors->at(current_entity_index);
@@ -128,14 +133,17 @@ Gamestate *PlayState::update(double delta) {
if (tilemap->get_tile(pos.x, pos.y).has_tag("exit")) {
current_level++;
tilemap = &world.GetMap(current_level, tileset);
- return nullptr;
+ return StateResult::None();
}
else {
- return nullptr;
+ return StateResult::None();
}
break;
}
- default: player_action = ACTION_NONE; SDL_LogVerbose(SDL_LOG_CATEGORY_SYSTEM, "Turn aborted: no player action.\n"); return nullptr; // abort turn
+ default:
+ player_action = ACTION_NONE;
+ SDL_LogVerbose(SDL_LOG_CATEGORY_SYSTEM, "Turn aborted: no player action.\n");
+ return StateResult::None(); // abort turn
}
if (dir != vec2i(0,0)) {
if (!actor->move(dir.x, dir.y, tilemap)) {
@@ -152,7 +160,7 @@ Gamestate *PlayState::update(double delta) {
if(!attacked) {
SDL_LogVerbose(SDL_LOG_CATEGORY_SYSTEM, "Turn aborted: invalid player action.\n");
player_action = ACTION_NONE;
- return nullptr; // unable to move and nothing to attack == abort turn
+ return StateResult::None(); // unable to move and nothing to attack == abort turn
}
}
}
@@ -173,10 +181,10 @@ Gamestate *PlayState::update(double delta) {
fov.calc(player_actor->get_position(), 6);
}
}
- return nullptr;
+ return StateResult::None();
}
-void PlayState::draw(double delta) {
+void PlayState::draw() {
if (debug) {
{
ImGui::BeginMainMenuBar();
@@ -286,17 +294,17 @@ void PlayState::draw(double delta) {
}
}
-void PlayState::quit() {
+void PlayState::exit() {
}
-void PlayState::inputevent(InputEvent *event) {
- if (event->type == INPUT_KEY_EVENT && event->pressed) {
- switch (event->action) {
+void PlayState::input(InputEvent &event) {
+ if (event.type == INPUT_KEY_EVENT && event.pressed) {
+ switch (event.action) {
case ACTION_TOGGLE_DEBUG: debug = !debug; break;
case ACTION_RESET: new_game(); break;
case ACTION_ESCAPE_MENU: break; // TODO
case ACTION_NONE: break;
- default: player_action = event->action; break;
+ default: player_action = event.action; break;
}
}
}
diff --git a/src/PlayState.h b/src/PlayState.h
index a6465cf..ca63db9 100644
--- a/src/PlayState.h
+++ b/src/PlayState.h
@@ -1,14 +1,15 @@
#pragma once
-#include "Gamestate.h"
+#include "statemachine/StateStack.h"
#include "Tilemap.h"
#include "FieldOfView.h"
#include "World.h"
class SpriteAtlas;
class Actor;
+class App;
-class PlayState : public Gamestate {
+class PlayState : public IState {
SpriteAtlas* ascii;
World world;
Tilemap* tilemap;
@@ -25,11 +26,14 @@ class PlayState : public Gamestate {
bool debug_settings = false;
bool debug_disable_fov = false;
+ App* app;
+
public:
+ PlayState(App* app);
void new_game();
- void load() override;
- Gamestate* update(double delta) override;
- void draw(double delta) override;
- void quit() override;
- void inputevent(InputEvent* event) override;
+ void enter() override;
+ StateResult update(float delta) override;
+ void draw() override;
+ void exit() override;
+ void input(InputEvent& event) override;
};
diff --git a/src/Renderer.cpp b/src/Renderer.cpp
index a73d5f4..3be6024 100644
--- a/src/Renderer.cpp
+++ b/src/Renderer.cpp
@@ -6,8 +6,8 @@
#include
#include
-#include "imgui.h"
-#include "imgui_impl_sdl_gl3.h"
+#include "imgui/imgui.h"
+#include "imgui/imgui_impl_sdl_gl3.h"
#include
#include
#include
diff --git a/src/Time.cpp b/src/Time.cpp
new file mode 100644
index 0000000..bab77b2
--- /dev/null
+++ b/src/Time.cpp
@@ -0,0 +1,67 @@
+#include "Time.h"
+#include
+
+std::vector timers;
+
+void Time::Timer::tick(float dt) {
+ time_current += dt;
+ if (continuous) {
+ callback();
+ }
+ else if (time_current >= duration) {
+ callback();
+ if (loop && !is_finished()) {
+ count++;
+ time_current -= duration;
+ }
+ }
+}
+
+bool Time::Timer::is_finished() {
+ return (loop && count >= limit) || (!loop && time_current >= duration);
+}
+
+void Time::tick_timers(float dt) {
+ for (int i = timers.size() - 1; i >= 0; i--) {
+ timers[i].tick(dt);
+ if (timers[i].is_finished()) {
+ timers.erase(timers.begin() + i);
+ }
+ }
+}
+
+void Time::after(float seconds, TimerCallback callback) {
+ timers.emplace_back(Timer {
+ false,
+ false,
+ 0,
+ 0,
+ 0,
+ seconds,
+ callback,
+ });
+}
+
+void Time::every(float seconds, int limit, TimerCallback callback) {
+ timers.emplace_back(Timer{
+ true,
+ false,
+ limit,
+ 0,
+ 0,
+ seconds,
+ callback,
+ });
+}
+
+void Time::during(float seconds, TimerCallback callback) {
+ timers.emplace_back(Timer{
+ false,
+ true,
+ 0,
+ 0,
+ 0,
+ seconds,
+ callback,
+ });
+}
diff --git a/src/Time.h b/src/Time.h
new file mode 100644
index 0000000..37906bd
--- /dev/null
+++ b/src/Time.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include
+
+namespace Time {
+ typedef std::function TimerCallback;
+ struct Timer {
+ bool loop;
+ bool continuous;
+ int limit;
+ int count;
+ float time_current;
+ float duration;
+ TimerCallback callback;
+ void tick(float dt);
+ bool is_finished();
+ };
+
+ void tick_timers(float dt);
+ void after(float seconds, TimerCallback callback);
+ void every(float seconds, int limit, TimerCallback callback);
+ void during(float seconds, TimerCallback callback);
+}
diff --git a/src/imconfig.h b/src/imgui/imconfig.h
similarity index 100%
rename from src/imconfig.h
rename to src/imgui/imconfig.h
diff --git a/src/imgui.cpp b/src/imgui/imgui.cpp
similarity index 100%
rename from src/imgui.cpp
rename to src/imgui/imgui.cpp
diff --git a/src/imgui.h b/src/imgui/imgui.h
similarity index 100%
rename from src/imgui.h
rename to src/imgui/imgui.h
diff --git a/src/imgui_demo.cpp b/src/imgui/imgui_demo.cpp
similarity index 100%
rename from src/imgui_demo.cpp
rename to src/imgui/imgui_demo.cpp
diff --git a/src/imgui_draw.cpp b/src/imgui/imgui_draw.cpp
similarity index 100%
rename from src/imgui_draw.cpp
rename to src/imgui/imgui_draw.cpp
diff --git a/src/imgui_impl_sdl_gl3.cpp b/src/imgui/imgui_impl_sdl_gl3.cpp
similarity index 100%
rename from src/imgui_impl_sdl_gl3.cpp
rename to src/imgui/imgui_impl_sdl_gl3.cpp
diff --git a/src/imgui_impl_sdl_gl3.h b/src/imgui/imgui_impl_sdl_gl3.h
similarity index 100%
rename from src/imgui_impl_sdl_gl3.h
rename to src/imgui/imgui_impl_sdl_gl3.h
diff --git a/src/imgui_internal.h b/src/imgui/imgui_internal.h
similarity index 100%
rename from src/imgui_internal.h
rename to src/imgui/imgui_internal.h
diff --git a/src/imgui_user.cpp b/src/imgui/imgui_user.cpp
similarity index 100%
rename from src/imgui_user.cpp
rename to src/imgui/imgui_user.cpp
diff --git a/src/imgui_user.h b/src/imgui/imgui_user.h
similarity index 100%
rename from src/imgui_user.h
rename to src/imgui/imgui_user.h
diff --git a/src/stb_rect_pack.h b/src/imgui/stb_rect_pack.h
similarity index 100%
rename from src/stb_rect_pack.h
rename to src/imgui/stb_rect_pack.h
diff --git a/src/stb_textedit.h b/src/imgui/stb_textedit.h
similarity index 100%
rename from src/stb_textedit.h
rename to src/imgui/stb_textedit.h
diff --git a/src/stb_truetype.h b/src/imgui/stb_truetype.h
similarity index 100%
rename from src/stb_truetype.h
rename to src/imgui/stb_truetype.h
diff --git a/src/statemachine/StateStack.cpp b/src/statemachine/StateStack.cpp
new file mode 100644
index 0000000..f2976ed
--- /dev/null
+++ b/src/statemachine/StateStack.cpp
@@ -0,0 +1,69 @@
+#include "StateStack.h"
+
+void StateStack::update(float dt) {
+ update_state(stack.size() - 1, dt);
+}
+
+void StateStack::draw() {
+ draw_state(stack.size() - 1);
+}
+
+void StateStack::push(std::unique_ptr state) {
+ state->enter();
+ stack.emplace_back(std::move(state));
+}
+
+void StateStack::swap(std::unique_ptr state) {
+ pop();
+ push(std::move(state));
+}
+
+void StateStack::pop() {
+ stack.back()->exit();
+ stack.pop_back();
+}
+
+void StateStack::input(InputEvent & input_event) {
+ input_state(stack.size() - 1, input_event);
+}
+
+void StateStack::draw_state(unsigned int i) {
+ IState &state = *stack[i];
+ if (state.should_draw_previous() && i > 0) {
+ draw_state(i - 1);
+ }
+ state.draw();
+}
+
+void StateStack::update_state(unsigned int i, float dt) {
+ IState &state = *stack[i];
+ if (state.should_update_previous() && i > 0) {
+ update_state(i - 1, dt);
+ }
+ StateResult r = state.update(dt);
+
+
+ if (r.action != StateAction::None && i+1 != stack.size()) {
+ while (i < stack.size()) {
+ pop();
+ }
+ }
+ switch (r.action) {
+ case StateAction::Pop:
+ pop();
+ case StateAction::Push:
+ push(std::move(r.state.value()));
+ case StateAction::Swap:
+ swap(std::move(r.state.value()));
+ default:
+ break;
+ }
+}
+
+void StateStack::input_state(unsigned int i, InputEvent & input_event) {
+ IState &state = *stack[i];
+ if (state.should_update_previous() && i > 0) {
+ input_state(i - 1, input_event);
+ }
+ state.input(input_event);
+}
diff --git a/src/statemachine/StateStack.h b/src/statemachine/StateStack.h
new file mode 100644
index 0000000..a09b8e2
--- /dev/null
+++ b/src/statemachine/StateStack.h
@@ -0,0 +1,66 @@
+#pragma once
+
+#include
+#include
+#include
+
+#include "../Input.h"
+
+class StateStack;
+class IState;
+
+enum class StateAction {
+ None,
+ Push,
+ Pop,
+ Swap,
+};
+
+struct StateResult {
+ StateResult(StateAction action, std::optional> state) {
+ this->action = action;
+ this->state.swap(state);
+ }
+
+ StateAction action;
+ std::optional> state;
+
+ static StateResult None() {
+ return StateResult(StateAction::None, nullptr);
+ }
+
+ static StateResult Pop() {
+ return StateResult(StateAction::Pop, nullptr);
+ }
+};
+
+ class IState {
+public:
+ IState() = default;
+ virtual ~IState() = default;
+ virtual void enter() = 0;
+ virtual void exit() = 0;
+ virtual StateResult update(float dt) = 0;
+ virtual bool should_update_previous() { return false; };
+ virtual void draw() = 0;
+ virtual bool should_draw_previous() { return false; };
+ virtual void input(InputEvent &const event) = 0;
+ virtual bool should_input_previous() { return false; };
+};
+
+class StateStack {
+public:
+ StateStack() = default;
+ ~StateStack() = default;
+ void update(float dt);
+ void draw();
+ void push(std::unique_ptr state);
+ void swap(std::unique_ptr state);
+ void pop();
+ void input(InputEvent& input_event);
+private:
+ void draw_state(unsigned int i);
+ void update_state(unsigned int i, float dt);
+ void input_state(unsigned int i, InputEvent &input_event);
+ std::vector> stack;
+};