]> code.bitgloo.com Git - clyne/gamedev2.git/commitdiff
transition to game engine
authortcsullivan <tullivan99@gmail.com>
Wed, 28 Aug 2019 19:35:04 +0000 (15:35 -0400)
committertcsullivan <tullivan99@gmail.com>
Wed, 28 Aug 2019 19:35:04 +0000 (15:35 -0400)
Makefile
src/engine.cpp [new file with mode: 0644]
src/engine.hpp [new file with mode: 0644]
src/gamerun.hpp [new file with mode: 0644]
src/input.hpp [new file with mode: 0644]
src/main.cpp
src/window.hpp [new file with mode: 0644]

index d6a3d3237d0822c7b54f0495aa6f94d4591290ea..615db3d9ccfedbe7c7539bc6f677854c055e2f6b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -35,14 +35,15 @@ CXXOBJ    = $(patsubst $(CXXSRCDIR)/%.cpp, $(CXXOUTDIR)/%.o, $(CXXSRC))
 
 EXEC = main
 
-all: $(EXEC)
+all: $(CXXOUTDIR)
+       @$(MAKE) $(EXEC)
 
 clean:
        @echo "  CLEAN"
        @rm -f $(EXEC)
        @rm -rf out
 
-$(EXEC): $(CXXOUTDIR) $(CXXOUTDIR)/$(CXXOBJ)
+$(EXEC): $(CXXOUTDIR)/$(CXXOBJ)
        @echo "  CXX/LD  main"
        @$(CXX) $(CXXFLAGS) -o $(EXEC) $(CXXOBJ) $(LIBS)
 
diff --git a/src/engine.cpp b/src/engine.cpp
new file mode 100644 (file)
index 0000000..0bc647b
--- /dev/null
@@ -0,0 +1,75 @@
+/**
+ * @file engine.cpp
+ * Manages all game systems.
+ *
+ * Copyright (C) 2019 Clyne Sullivan
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "engine.hpp"
+#include "gamerun.hpp"
+#include "input.hpp"
+#include "window.hpp"
+
+int Engine::init(void)
+{
+       systems.add<GameRunSystem>();
+       systems.add<InputSystem>();
+       systems.add<WindowSystem>();
+
+       systems.configure();
+       return 0;
+}
+
+void Engine::logicLoop(void)
+{
+       using namespace std::chrono_literals;
+
+       entityx::TimeDelta dt = 0;
+
+       while (shouldRun()) {
+               systems.update<InputSystem>(dt);
+               std::this_thread::sleep_for(100ms);
+       }
+}
+
+void Engine::renderLoop(void)
+{
+       while (shouldRun()) {
+               systems.update<WindowSystem>(0);
+               std::this_thread::yield();
+       }
+}
+
+void Engine::run(void)
+{
+       // Start logic thread
+       logicThread = std::thread([this](void) {
+               logicLoop();
+       });
+
+       // Keep render loop on main thread
+       renderLoop();
+
+       // Done, bring logic thread back
+       logicThread.join();
+}
+
+bool Engine::shouldRun(void)
+{
+       auto grs = systems.system<GameRunSystem>();
+       return grs ? grs->shouldRun() : true;
+}
+
diff --git a/src/engine.hpp b/src/engine.hpp
new file mode 100644 (file)
index 0000000..fb14093
--- /dev/null
@@ -0,0 +1,65 @@
+/**
+ * @file window.hpp
+ * Manages all game systems.
+ *
+ * Copyright (C) 2019 Clyne Sullivan
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef ENGINE_HPP_
+#define ENGINE_HPP_
+
+#include <entityx/entityx.h>
+
+#include <thread>
+
+/**
+ * @class Engine
+ * Manages all game entities, events, and systems.
+ */
+class Engine
+{
+private:
+       entityx::EventManager events;
+       entityx::EntityManager entities;
+       entityx::SystemManager systems;
+
+       std::thread logicThread;
+
+       void logicLoop(void);
+       void renderLoop(void);
+
+       bool shouldRun(void);
+
+public:
+       Engine(void) :
+               entities(events),
+               systems(entities, events) {}
+
+       /**
+        * Initializes the game engine.
+        * @return Zero on success, non-zero otherwise
+        */
+       int init(void);
+
+       /**
+        * Runs the game engine.
+        * Function returns when game is told to end/exit.
+        */
+       void run(void);
+};
+
+#endif // ENGINE_HPP_
+
diff --git a/src/gamerun.hpp b/src/gamerun.hpp
new file mode 100644 (file)
index 0000000..efe6ed9
--- /dev/null
@@ -0,0 +1,76 @@
+/**
+ * @file window.hpp
+ * Handles key press for exiting the game.
+ *
+ * Copyright (C) 2019 Clyne Sullivan
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GAMERUN_HPP_
+#define GAMERUN_HPP_
+
+#include "input.hpp"
+
+#include <entityx/entityx.h>
+
+#include <atomic>
+#include <iostream>
+
+/**
+ * @class GameRunSystem
+ * Listens for a key event to tell the game to exit.
+ */
+class GameRunSystem : public entityx::System<GameRunSystem>,
+       public entityx::Receiver<GameRunSystem> {
+private:
+       std::atomic_bool shouldRunFlag;
+
+public:
+       /**
+        * Configures the system to wait for the exit event.
+        */
+       void configure([[maybe_unused]] entityx::EntityManager& entities,
+               entityx::EventManager& events) {
+               shouldRunFlag.store(true);
+
+               events.subscribe<KeyUpEvent>(*this);
+
+               std::cout << "Press escape to exit." << std::endl;
+       }
+
+       // Unused
+       void update([[maybe_unused]] entityx::EntityManager& entities,
+               [[maybe_unused]] entityx::EventManager& events,
+               [[maybe_unused]] entityx::TimeDelta dt) final {}
+
+       /**
+        * Receiver for key release events, used to listen for game exit key.
+        */
+       void receive(const KeyUpEvent& kue) {
+               if (kue.sym == SDLK_ESCAPE)
+                       shouldRunFlag.store(false);
+       }
+
+       /**
+        * Checks if the game exit key has been pressed.
+        * @return True if the game should exit
+        */
+       inline bool shouldRun(void) const {
+               return shouldRunFlag.load();
+       }
+};
+
+#endif // GAMERUN_HPP_
+
diff --git a/src/input.hpp b/src/input.hpp
new file mode 100644 (file)
index 0000000..39d4045
--- /dev/null
@@ -0,0 +1,88 @@
+/**
+ * @file window.hpp
+ * Handles user input received from SDL.
+ *
+ * Copyright (C) 2019 Clyne Sullivan
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef INPUT_HPP_
+#define INPUT_HPP_
+
+#include <entityx/entityx.h>
+#include <SDL2/SDL.h>
+
+/**
+ * @class KeyUpEvent
+ * Stores info regarding key releases.
+ */
+struct KeyUpEvent {
+       KeyUpEvent(const SDL_Keysym& keysym) :
+               sym(keysym.sym), mod(keysym.mod) {}
+
+       SDL_Keycode sym;
+       Uint16 mod;
+};
+
+/**
+ * @class KeyDownEvent
+ * Stores info regarding key presses.
+ */
+struct KeyDownEvent {
+       KeyDownEvent(const SDL_Keysym& keysym) :
+               sym(keysym.sym), mod(keysym.mod) {}
+
+       SDL_Keycode sym;
+       Uint16 mod;
+};
+
+/**
+ * @class InputSystem
+ * Listens for user input from SDL, and emits input events accordingly.
+ */
+class InputSystem : public entityx::System<InputSystem> {
+public:
+       /**
+        * Prepares the system for running.
+        */
+       void configure([[maybe_unused]] entityx::EntityManager& entities,
+               [[maybe_unused]] entityx::EventManager& events) final {
+       }
+
+       /**
+        * Updates the system by checking for SDL events.
+        */
+       void update([[maybe_unused]] entityx::EntityManager& entities,
+               [[maybe_unused]] entityx::EventManager& events,
+               [[maybe_unused]] entityx::TimeDelta dt) final {
+               for (SDL_Event event; SDL_PollEvent(&event);) {
+                       switch (event.type) {
+                       case SDL_KEYUP:
+                               if (auto key = event.key; key.repeat == 0)
+                                       events.emit<KeyUpEvent>(key.keysym);
+                               break;
+                       case SDL_KEYDOWN:
+                               if (auto key = event.key; key.repeat == 0)
+                                       events.emit<KeyDownEvent>(key.keysym);
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+};
+
+#endif // INPUT_HPP_
+
index 5e5e278f7fa08a9a8bda60846a53303551018bbc..a1c605e6f249180915de6cb04500c756497d054c 100644 (file)
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-#include <entityx/entityx.h>
+#include "engine.hpp"
 
 #include <SDL2/SDL.h>
 
-#include <atomic>
-#include <chrono>
 #include <iostream>
-#include <memory>
-#include <thread>
-
-class Window {
-private:
-       constexpr static const char *title = "gamedev2";
-       constexpr static int width = 640;
-       constexpr static int height = 480;
-
-       static std::unique_ptr<SDL_Window, void (*)(SDL_Window *)> window;
-       static SDL_GLContext context;
-
-       static void destroyWindow(SDL_Window *w) {
-               SDL_GL_DeleteContext(context);
-               SDL_DestroyWindow(w);
-       }
-
-public:
-       static int init(void) {
-               if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
-                       std::cerr << "SDL video failed to initialize: "
-                               << SDL_GetError() << std::endl;
-                       return -1;
-               }
-
-               window.reset(SDL_CreateWindow(title,
-                       SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
-                       width, height,
-                       SDL_WINDOW_OPENGL));
-
-               if (window.get() == nullptr) {
-                       std::cerr << "SDL window creation failed: "
-                               << SDL_GetError() << std::endl;
-                       return -1;
-               }
-
-               context = SDL_GL_CreateContext(window.get());
-
-               return 0;
-       }
-
-       static void render(void) {
-               SDL_GL_SwapWindow(window.get());
-       }
-};
-
-std::unique_ptr<SDL_Window, void (*)(SDL_Window *)> Window::window (nullptr,
-       Window::destroyWindow);
-SDL_GLContext Window::context;
-
-std::atomic_bool shouldRun;
-
-static void renderLoop(void);
-static void logicLoop(void);
 
 int main([[maybe_unused]] int argc, [[maybe_unused]] char *argv[])
 {
@@ -91,46 +35,13 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char *argv[])
                atexit(SDL_Quit);
        }
 
-       // Create our window
-       Window::init();
+       // Create the engine
+       Engine engine;
+       engine.init();
 
-       // Start game
-       shouldRun.store(true);
-       std::thread logic (logicLoop);
-       renderLoop();
-       logic.join();
+       // Go go go!
+       engine.run();
 
        return 0;
 }
 
-void renderLoop(void)
-{
-       while (shouldRun.load()) {
-               Window::render();
-               std::this_thread::yield();
-       }
-}
-
-void logicLoop(void)
-{
-       using namespace std::chrono_literals;
-
-       std::cout << "Press escape to exit." << std::endl;
-
-       while (shouldRun.load()) {
-               for (SDL_Event event; SDL_PollEvent(&event);) {
-                       switch (event.type) {
-                       case SDL_KEYUP:
-                               // Exit game on escape
-                               if (event.key.keysym.sym == SDLK_ESCAPE)
-                                       shouldRun.store(false);
-                               break;
-                       default:
-                               break;
-                       }
-               }
-
-               std::this_thread::sleep_for(100ms);
-       }
-}
-
diff --git a/src/window.hpp b/src/window.hpp
new file mode 100644 (file)
index 0000000..ef6632a
--- /dev/null
@@ -0,0 +1,95 @@
+/**
+ * @file window.hpp
+ * Manages window creation.
+ *
+ * Copyright (C) 2019 Clyne Sullivan
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef WINDOW_HPP_
+#define WINDOW_HPP_
+
+#include <entityx/entityx.h>
+#include <SDL2/SDL.h>
+
+/**
+ * @class WindowSystem
+ * Handles the game's window.
+ */
+class WindowSystem : public entityx::System<WindowSystem> {
+private:
+       constexpr static const char *title = "gamedev2";
+       constexpr static int width = 640;
+       constexpr static int height = 480;
+
+       std::unique_ptr<SDL_Window, void (*)(SDL_Window *)> window;
+       SDL_GLContext context;
+
+public:
+       WindowSystem(void) :
+               window(nullptr, SDL_DestroyWindow) {}
+
+       ~WindowSystem(void) {
+               SDL_GL_DeleteContext(context);
+       }
+
+       /**
+        * Creates and initializes the window.
+        * @return Zero on success, non-zero on error
+        */
+       int init(void) {
+               if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
+                       std::cerr << "SDL video failed to initialize: "
+                               << SDL_GetError() << std::endl;
+                       return -1;
+               }
+
+               // Create window, managed by the unique_ptr
+               window.reset(SDL_CreateWindow(title,
+                       SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
+                       width, height,
+                       SDL_WINDOW_OPENGL));
+
+               if (window.get() == nullptr) {
+                       std::cerr << "SDL window creation failed: "
+                               << SDL_GetError() << std::endl;
+                       return -1;
+               }
+
+               context = SDL_GL_CreateContext(window.get());
+
+               return 0;
+       }
+
+       /**
+        * Prepares the system for running.
+        */
+       void configure([[maybe_unused]] entityx::EntityManager& entities,
+               [[maybe_unused]] entityx::EventManager& events) final {
+               init();
+       }
+
+       /**
+        * Updates/refreshes the window.
+        */
+       void update([[maybe_unused]] entityx::EntityManager& entities,
+               [[maybe_unused]] entityx::EventManager& events,
+               [[maybe_unused]] entityx::TimeDelta dt) final {
+               SDL_GL_SwapWindow(window.get());
+       }
+};
+
+#endif // WINDOW_HPP_
+