diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..15dfa32 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +# Don't track content of these folders +.vscode/* +CMakeFiles/* +.vs/* +out/* +.idea/* +cmake-build-cmake-build-w10-msvc-debug/* +cmake-build-debug-wsl/* + +# Compiled source # +################### +*.txt +!*CMakeLists.txt + +# Packages # +############ +# it's better to unpack these files and commit the raw source +# git has its own built in compression methods +#*.7z +#*.dmg \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..5c6c773 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required (VERSION 3.6) +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}") +project(GameEngine) + +# Add some CMake options: +option(BUILD_EXAMPLES "Build example projects" ON) + +set(SFML_BUILD_AUDIO ON) +set(SFML_BUILD_GRAPHICS ON) +set(SFML_BUILD_WINDOW ON) +set(SFML_BUILD_SYSTEM ON) + +find_package(SFML REQUIRED COMPONENTS system main window graphics audio) + +# Link sources +file(GLOB_RECURSE source_list src/*.cpp) +add_library(gameengine STATIC ${source_list}) + +# Link headers +target_include_directories(gameengine PUBLIC include PRIVATE include/gameengine) + +# Link dependencies +target_link_libraries(gameengine PUBLIC sfml-system sfml-main sfml-window OpenGL sfml-network sfml-graphics Freetype OpenAL Vorbis FLAC sfml-audio) + +# Add examples as a target if the user has them enabled +if (BUILD_EXAMPLES) + add_subdirectory(examples) +endif() + +# Set C++ standard to C++17 +set_target_properties(gameengine PROPERTIES CXX_STANDARD 17 CXX_EXTENSIONS OFF) \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..998d087 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +game_engine diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..45ce3e1 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,2 @@ +# Add examples as a subdirectory +add_subdirectory(first) \ No newline at end of file diff --git a/examples/first/CMakeLists.txt b/examples/first/CMakeLists.txt new file mode 100644 index 0000000..bf4abcd --- /dev/null +++ b/examples/first/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required (VERSION 3.6) +project(first_example) + +add_executable(first_example src/main.cpp) + +# Link headers and source files. +file(GLOB_RECURSE source_list src/*.cpp) +target_sources(first_example PRIVATE ${source_list}) +target_include_directories(first_example PUBLIC include) + +# Link gameengine +target_link_libraries(first_example PUBLIC gameengine) + +# Set standard to C++17 +set_target_properties(first_example PROPERTIES CXX_STANDARD 17 CXX_EXTENSIONS OFF) \ No newline at end of file diff --git a/examples/first/src/main.cpp b/examples/first/src/main.cpp new file mode 100644 index 0000000..afe30ea --- /dev/null +++ b/examples/first/src/main.cpp @@ -0,0 +1,78 @@ +// +// Created by SeanOMik on 7/2/2020. +// Github: https://github.com/SeanOMik +// Email: seanomik@gmail.com +// + +#include + +#include +#include +#include + +class PlayerEntity : public simpleengine::Entity { +private: + sf::RectangleShape shape; + float movement_speed; +public: + PlayerEntity() { + shape = sf::RectangleShape(sf::Vector2f(50, 50)); + shape.setFillColor(sf::Color::White); + + movement_speed = 250; + } + + void Move(const float& delta_time, const float& x, const float& y) override { + shape.move(x * movement_speed * delta_time, y * movement_speed * delta_time); + } + + void Update(const float& delta_time) override { + if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) { + Move(delta_time, -1, 0); + } + + if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) { + Move(delta_time, 0, -1); + } + + if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) { + Move(delta_time, 1, 0); + } + + if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) { + Move(delta_time, 0, 1); + } + } + + void Render(sf::RenderTarget* target = nullptr) override { + target->draw(shape); + } +}; + +class PlayerEvent : public simpleengine::Event { +private: + PlayerEntity entity; +public: + explicit PlayerEvent(sf::RenderWindow* window = nullptr) : simpleengine::Event(window) {} + + void CheckForQuit() override { + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)) { + quit = true; + } + } + + void Update(const float& delta_time) override { + entity.Update(delta_time); + } + + void Render(sf::RenderTarget* target = nullptr) override { + entity.Render(target); + } +}; + +int main(int argc, char *argv[]) { + simpleengine::Game game(500, 500, "First Example"); + game.AddEvent(new PlayerEvent()); + + return game.Run(); +} \ No newline at end of file diff --git a/include/gameengine/entity.h b/include/gameengine/entity.h new file mode 100644 index 0000000..75999f6 --- /dev/null +++ b/include/gameengine/entity.h @@ -0,0 +1,24 @@ +// +// Created by SeanOMik on 7/2/2020. +// Github: https://github.com/SeanOMik +// Email: seanomik@gmail.com +// + +#ifndef SIMPLEENGINE_ENTITY_H +#define SIMPLEENGINE_ENTITY_H + +#include + +namespace simpleengine { + class Entity { + public: + Entity() = default; + virtual ~Entity() = default; + + virtual void Move(const float& delta_time, const float& x, const float& y) {}; + virtual void Update(const float& delta_time) = 0; + virtual void Render(sf::RenderTarget* target = nullptr) = 0; + }; +} + +#endif //GAMEENGINE_ENTITY_H diff --git a/include/gameengine/event.h b/include/gameengine/event.h new file mode 100644 index 0000000..ed93088 --- /dev/null +++ b/include/gameengine/event.h @@ -0,0 +1,33 @@ +// +// Created by SeanOMik on 7/2/2020. +// Github: https://github.com/SeanOMik +// Email: seanomik@gmail.com +// + +#ifndef SIMPLEENGINE_EVENT_H +#define SIMPLEENGINE_EVENT_H + +#include + +namespace simpleengine { + class Event { + public: + explicit Event(sf::RenderWindow* window = nullptr) : window(window) {} + virtual ~Event() = default; + + const bool& WantsToQuit() { + return quit; + } + + // Abstract methods + virtual void CheckForQuit() = 0; // Ran every Update to check if we're gonna quit. + virtual void Quiting() {} // Ran when a State is about to be destroyed. + virtual void Update(const float& delta_time) = 0; + virtual void Render(sf::RenderTarget* target = nullptr) = 0; + protected: + sf::RenderWindow* window; + bool quit = false; + }; +} + +#endif //GAMEENGINE_EVENT_H diff --git a/include/gameengine/game.h b/include/gameengine/game.h new file mode 100644 index 0000000..5c97012 --- /dev/null +++ b/include/gameengine/game.h @@ -0,0 +1,43 @@ +// +// Created by SeanOMik on 7/2/2020. +// Github: https://github.com/SeanOMik +// Email: seanomik@gmail.com +// + +#ifndef SIMPLEENGINE_GAME_H +#define SIMPLEENGINE_GAME_H + +#include +#include +#include + +#include + +namespace simpleengine { + class Event; + + class Game { + public: + Game(int w, int h, const std::string& window_name); + virtual ~Game(); + + void UpdateSFMLEvents(); + void Update(); + void RenderWindow(); + void RenderItems(); + void ExitGame(); + int Run(); + + void AddEvent(Event* event); + sf::RenderWindow* GetWindow(); + private: + sf::RenderWindow* window; + + sf::Clock delta_time_clock; // Delta time clock + float delta_time; // Delta time + + std::stack events; + }; +} + +#endif //GAMEENGINE_GAME_H diff --git a/src/game.cpp b/src/game.cpp new file mode 100644 index 0000000..520f14d --- /dev/null +++ b/src/game.cpp @@ -0,0 +1,87 @@ +// +// Created by SeanOMik on 7/2/2020. +// Github: https://github.com/SeanOMik +// Email: seanomik@gmail.com +// + +#include "game.h" +#include "event.h" + +#include + +simpleengine::Game::Game(int w, int h, const std::string& window_name) { + // Create a render window + window = new sf::RenderWindow(sf::VideoMode(w, h), window_name); +} + +simpleengine::Game::~Game() { + delete window; + + while(!events.empty()) { + delete events.top(); + events.pop(); + } +} + +void simpleengine::Game::UpdateSFMLEvents() { + sf::Event event; + while (window->pollEvent(event)) { + switch (event.type) { + case sf::Event::Closed: + window->close(); + } + } +} + +void simpleengine::Game::Update() { + delta_time = delta_time_clock.restart().asSeconds(); // Update delta time + UpdateSFMLEvents(); + + if (!events.empty()) { + events.top()->Update(delta_time); + + // If this state wants to stop, delete it. + if (events.top()->WantsToQuit()) { + events.top()->Quiting(); + + delete events.top(); + events.pop(); + } + } +} + +void simpleengine::Game::RenderWindow() { + window->clear(); + RenderItems(); + window->display(); +} + +void simpleengine::Game::RenderItems() { + if (!events.empty()) { + events.top()->Render(window); + } +} + +int simpleengine::Game::Run() { + sf::CircleShape shape(100); + shape.setFillColor(sf::Color::Green); + + while (window->isOpen()) { + Update(); + RenderWindow(); + } + + return 0; +} + +void simpleengine::Game::AddEvent(simpleengine::Event *event) { + events.push(event); +} + +sf::RenderWindow* simpleengine::Game::GetWindow() { + return window; +} + +void simpleengine::Game::ExitGame() { + window->close(); +}