diff --git a/src/GameState.cpp b/src/GameState.cpp new file mode 100644 index 0000000..b8493a9 --- /dev/null +++ b/src/GameState.cpp @@ -0,0 +1,23 @@ +/* + * GameState.cpp + * + * Created on: Nov 30, 2016 + * Author: tibi + */ +#include + +namespace farmlands { + +GameState GameState::s_current; + +GameState& farmlands::GameState::current() +{ + return s_current; +} + +void farmlands::GameState::setCurrent(GameState& state) +{ + s_current = state; +} + +} diff --git a/src/GameState.h b/src/GameState.h index 5d4cbb7..b345bfc 100644 --- a/src/GameState.h +++ b/src/GameState.h @@ -8,11 +8,10 @@ #ifndef MODEL_GAMESTATE_H_ #define MODEL_GAMESTATE_H_ +#include +#include #include #include -#include -#include -#include #include #include @@ -20,32 +19,18 @@ namespace farmlands { - struct ViewportState - { - bool initialized; - int width, height; - }; - - struct Camera - { - float posX, posY; - float scale; - }; - struct GuiState { - }; - struct GameState + class GameState { - // Resource layer - resources::ResourceManager resManager; + public: + static GameState& current(); + static void setCurrent(GameState& state); - // Graphics layer - graphics::SdlRenderer sdlRenderer; - graphics::GuiRenderer guiRenderer; - graphics::GameRenderer gameRenderer; + // Render context + base::RenderContext renderContext; // Gui GuiState gui; @@ -54,13 +39,14 @@ namespace farmlands { model::Configuration config; // Current game - ViewportState viewport; - Camera camera; model::Player player; model::Level* currentLevel; + base::GameObject root; float elapsedTime; + private: + static GameState s_current; }; } diff --git a/src/assets/Ground.h b/src/assets/Ground.h new file mode 100644 index 0000000..a8c925e --- /dev/null +++ b/src/assets/Ground.h @@ -0,0 +1,44 @@ +/* + * Ground.h + * + * Created on: Nov 30, 2016 + * Author: tibi + */ + +#ifndef ASSETS_GROUND_H_ +#define ASSETS_GROUND_H_ + +namespace farmlands { +namespace assets { + + /** + * Maps tiles to ground name + */ + enum class Ground + { + Dirt = 0, + DirtVariation0 = 1, + DirtVariation1 = 2, + DirtVariation2 = 3, + DirtVariation3 = 4, + DirtVariation4 = 5, + DirtVariation5 = 6, + DirtVariation6 = 7, + DirtVariation7 = 8, + DirtVariation8 = 9, + + SoilCenter = 30, + + SoilWet = 36 + }; + + inline bool groundIsDirt(int cell) { return cell >= Ground::Dirt && cell <= Ground::DirtVariation8; } + inline bool groundIsDrySoil(int cell) { return cell == Ground::SoilCenter; } + inline bool groundIsWetSoil(int cell) { return cell == Ground::SoilWet; } + +} +} + + + +#endif /* ASSETS_GROUND_H_ */ diff --git a/src/base/Camera.h b/src/base/Camera.h new file mode 100644 index 0000000..d612780 --- /dev/null +++ b/src/base/Camera.h @@ -0,0 +1,24 @@ +/* + * Camera.h + * + * Created on: Nov 30, 2016 + * Author: tibi + */ + +#ifndef MODEL_CAMERA_H_ +#define MODEL_CAMERA_H_ + +#include + +namespace farmlands { +namespace base { + + struct Camera : public Component + { + float scale; + }; + +} +} + +#endif /* MODEL_CAMERA_H_ */ diff --git a/src/base/Component.cpp b/src/base/Component.cpp new file mode 100644 index 0000000..27aad10 --- /dev/null +++ b/src/base/Component.cpp @@ -0,0 +1,59 @@ +/* + * Component.cpp + * + * Created on: Nov 30, 2016 + * Author: tibi + */ + +#include + +namespace farmlands { +namespace base { + +Component::Component() + : gameObject(nullptr) +{ +} + +Component::~Component() +{ +} + +void Component::onCreate() +{ +} + +void Component::onInitialize() +{ +} + +bool Component::onEvent(SDL_Event& event) +{ + return false; +} + +void Component::onUpdateLogic() +{ +} + +void Component::onPreRender() +{ +} + +void Component::onRender() +{ +} + +void Component::onPostRender() +{ +} + +void Component::onDestroy() +{ +} + +} +/* namespace base */ +} /* namespace farmlands */ + + diff --git a/src/base/Component.h b/src/base/Component.h new file mode 100644 index 0000000..423ea46 --- /dev/null +++ b/src/base/Component.h @@ -0,0 +1,41 @@ +/* + * Component.h + * + * Created on: Nov 30, 2016 + * Author: tibi + */ + +#ifndef COMPONENT_H_ +#define COMPONENT_H_ + +#include + +namespace farmlands { +namespace base { + + class GameObject; + + class Component + { + public: + Component(); + virtual ~Component(); + + // Game object methods + virtual void onCreate(); + virtual void onInitialize(); + virtual bool onEvent(SDL_Event& event); + virtual void onUpdateLogic(); + virtual void onPreRender(); + virtual void onRender(); + virtual void onPostRender(); + virtual void onDestroy(); + + GameObject* gameObject; + }; + +} +/* namespace base */ +} /* namespace farmlands */ + +#endif /* COMPONENT_H_ */ diff --git a/src/base/GameObject.cpp b/src/base/GameObject.cpp new file mode 100644 index 0000000..faebbbd --- /dev/null +++ b/src/base/GameObject.cpp @@ -0,0 +1,155 @@ +/* + * GameObject.cpp + * + * Created on: Nov 30, 2016 + * Author: tibi + */ + +#include +#include + +namespace farmlands { +namespace base { + +GameObject::GameObject() + : m_components(), + m_children(), + m_parent(nullptr) +{ +} + +GameObject::~GameObject() +{ + // Delete children + for (auto child : m_children) + { + child->onDestroy(); + delete child; + } + + // Delete components + for (auto pair : m_components) + { + pair.second->onDestroy(); + delete pair.second; + } +} + +void GameObject::addChild(GameObject* obj) +{ + m_children.push_back(obj); + obj->m_parent = this; +} + +GameObject* GameObject::removeChild(size_t index) +{ + GameObject* child = m_children.at(index); + child->m_parent = nullptr; + + m_children.erase(m_children.begin() + index); + + return child; +} + +size_t GameObject::childrenCount() const +{ + return m_children.size(); +} + +GameObject* GameObject::child(size_t index) +{ + return m_children.at(index); +} + +GameObject* GameObject::parent() +{ + return m_parent; +} + +void GameObject::onCreate() +{ + // Call components + for (auto pair : m_components) + pair.second->onCreate(); + + // Call children + for (auto child : m_children) + child->onCreate(); +} + +void GameObject::onInitialize() +{ + // Call components + for (auto pair : m_components) + pair.second->onInitialize(); + + // Call children + for (auto child : m_children) + child->onInitialize(); +} + +bool GameObject::onEvent(SDL_Event& event) +{ + bool handled = false; + + // Call components + for (auto it = m_components.begin(); it != m_components.end() && !handled; it++) + handled = it->second->onEvent(event); + + // Call children + for (auto it = m_children.begin(); it != m_children.end() && !handled; it++) + handled = (*it)->onEvent(event); + + return handled; +} + +void GameObject::onUpdateLogic() +{ + // Call components + for (auto pair : m_components) + pair.second->onUpdateLogic(); + + // Call children + for (auto child : m_children) + child->onUpdateLogic(); +} + +void GameObject::onPreRender() +{ + // Call components + for (auto pair : m_components) + pair.second->onPreRender(); + + // Call children + for (auto child : m_children) + child->onPreRender(); +} + +void GameObject::onRender() +{ + // Call components + for (auto pair : m_components) + pair.second->onRender(); + + // Call children + for (auto child : m_children) + child->onRender(); +} + +void GameObject::onPostRender() +{ + // Call components + for (auto pair : m_components) + pair.second->onPostRender(); + + // Call children + for (auto child : m_children) + child->onPostRender(); +} + +void GameObject::onDestroy() +{ +} + +} /* namespace base */ +} /* namespace farmlands */ diff --git a/src/base/GameObject.h b/src/base/GameObject.h new file mode 100644 index 0000000..ef5de83 --- /dev/null +++ b/src/base/GameObject.h @@ -0,0 +1,97 @@ +/* + * GameObject.h + * + * Created on: Nov 30, 2016 + * Author: tibi + */ + +#ifndef GAMEOBJECT_H_ +#define GAMEOBJECT_H_ + +#include + +#include + +#include +#include +#include + +namespace farmlands { +namespace base { + + class Component; + class RenderContext; + + class GameObject + { + public: + // Constructors + GameObject(); + virtual ~GameObject(); + + // Components API + template void addComponent(T* component); + template T* component(); + template void removeComponent(); + + // Tree methods + void addChild(GameObject* obj); + GameObject* removeChild(size_t index); + void destroyChild(size_t index); + GameObject* child(size_t index); + size_t childrenCount() const; + GameObject* parent(); + + // Game object methods + void onCreate(); + void onInitialize(); + bool onEvent(SDL_Event& event); + void onUpdateLogic(); + void onPreRender(); + void onRender(); + void onPostRender(); + void onDestroy(); + + private: + std::unordered_map m_components; + + std::vector m_children; + GameObject* m_parent; + }; + + template + void GameObject::addComponent(T* component) + { + std::type_index typeIndex(typeid(T)); + Assert(m_components.count(typeIndex) == 0, "A component of the same type already exists!"); + + m_components.emplace(typeIndex, component); + component->gameObject = this; + } + + + template + T* GameObject::component() + { + // Compute type index + std::type_index typeIndex(typeid(T)); + Assert(m_components.count(typeIndex) != 0, "Component doesn't exist!"); + + // Get component + T* comp = dynamic_cast (m_components.at(typeIndex)); + Assert(comp != nullptr, "This is bad!!! Type of component is really messed up!!!"); + + return comp; + } + + template + void GameObject::removeComponent() + { + std::type_index typeIndex(typeid(T)); + return m_components.erase(typeIndex); + } + +} /* namespace base */ +} /* namespace farmlands */ + +#endif /* GAMEOBJECT_H_ */ diff --git a/src/base/RenderContext.cpp b/src/base/RenderContext.cpp new file mode 100644 index 0000000..fbf40c9 --- /dev/null +++ b/src/base/RenderContext.cpp @@ -0,0 +1,47 @@ +/* + * RenderContext.cpp + * + * Created on: Nov 30, 2016 + * Author: tibi + */ +#include +#include +#include +#include + +namespace farmlands { +namespace base { + +float RenderContext::xToWorld(float x) +{ + float cellW = viewport.pixelsPerUnitX * m_camera->scale; + return (x - viewport.width / 2) / cellW + m_cameraTransform->x; +} + +float RenderContext::yToWorld(float y) +{ + float cellH = viewport.pixelsPerUnitY * m_camera->scale; + return (y - viewport.height / 2) / cellH + m_cameraTransform->y; +} + +float RenderContext::xToScreen(float x) +{ + float cellW = viewport.pixelsPerUnitX * m_camera->scale; + return (x - m_cameraTransform->x) * cellW + viewport.width / 2; +} + +float RenderContext::yToScreen(float y) +{ + float cellH = viewport.pixelsPerUnitY * m_camera->scale; + return (y - m_cameraTransform->y) * cellH + viewport.height / 2; +} + +void RenderContext::setCamera(GameObject* camera) +{ + m_cameraObj = camera; + m_cameraTransform = camera->component(); + m_camera = camera->component(); +} + +} +} diff --git a/src/base/RenderContext.h b/src/base/RenderContext.h new file mode 100644 index 0000000..af020c9 --- /dev/null +++ b/src/base/RenderContext.h @@ -0,0 +1,49 @@ +/* + * RenderContext.h + * + * Created on: Nov 30, 2016 + * Author: tibi + */ + +#ifndef GRAPHICS_RENDERCONTEXT_H_ +#define GRAPHICS_RENDERCONTEXT_H_ + +#include + +namespace farmlands { +namespace base { + + class GameObject; + struct Transform; + struct Camera; + + class RenderContext + { + public: + float xToWorld(float x); + float yToWorld(float y); + float xToScreen(float x); + float yToScreen(float y); + + inline GameObject* cameraObj() { return m_cameraObj; } + inline Camera* camera() { return m_camera; } + inline Transform* cameraTransform() { return m_cameraTransform; } + + void setCamera(GameObject* camera); + + /** + * Screen properties + */ + Viewport viewport; + float uiScale = 1.0f; + + private: + Transform* m_cameraTransform; + Camera* m_camera; + GameObject* m_cameraObj; + }; + +} +} + +#endif /* GRAPHICS_RENDERCONTEXT_H_ */ diff --git a/src/model/Sprite.cpp b/src/base/Sprite.cpp similarity index 97% rename from src/model/Sprite.cpp rename to src/base/Sprite.cpp index 3d57a74..0e7d3c1 100644 --- a/src/model/Sprite.cpp +++ b/src/base/Sprite.cpp @@ -5,16 +5,17 @@ * Author: tibi */ -#include +#include #include #include namespace farmlands { -namespace model { +namespace base { Sprite::Sprite() : anchorX(0), anchorY(0), + name(), m_states(), m_currentState(0), m_currentFrame(0), diff --git a/src/model/Sprite.h b/src/base/Sprite.h similarity index 97% rename from src/model/Sprite.h rename to src/base/Sprite.h index 3cb3588..f166032 100644 --- a/src/model/Sprite.h +++ b/src/base/Sprite.h @@ -14,7 +14,7 @@ #include namespace farmlands { -namespace model { +namespace base { /** * Defines an animation frame @@ -72,6 +72,7 @@ namespace model { // Public fields float anchorX, anchorY; + std::string name; private: std::vector m_states; diff --git a/src/base/Transform.h b/src/base/Transform.h new file mode 100644 index 0000000..e68b1ac --- /dev/null +++ b/src/base/Transform.h @@ -0,0 +1,24 @@ +/* + * Transform.h + * + * Created on: Nov 30, 2016 + * Author: tibi + */ + +#ifndef BASE_TRANSFORM_H_ +#define BASE_TRANSFORM_H_ + +#include + +namespace farmlands { +namespace base { + + struct Transform: public Component + { + float x, y; + }; + +} /* namespace base */ +} /* namespace farmlands */ + +#endif /* BASE_TRANSFORM_H_ */ diff --git a/src/base/Viewport.h b/src/base/Viewport.h new file mode 100644 index 0000000..f3cbaae --- /dev/null +++ b/src/base/Viewport.h @@ -0,0 +1,24 @@ +/* + * Viewport.h + * + * Created on: Nov 30, 2016 + * Author: tibi + */ + +#ifndef MODEL_VIEWPORT_H_ +#define MODEL_VIEWPORT_H_ + +namespace farmlands { +namespace base { + + struct Viewport + { + bool initialized = false; + int width, height; + float pixelsPerUnitX, pixelsPerUnitY; + }; + +} +} + +#endif /* MODEL_VIEWPORT_H_ */ diff --git a/src/controller/DebugController.cpp b/src/controller/DebugController.cpp new file mode 100644 index 0000000..1caf747 --- /dev/null +++ b/src/controller/DebugController.cpp @@ -0,0 +1,53 @@ +/* + * DebugController.cpp + * + * Created on: Nov 30, 2016 + * Author: tibi + */ + +#include +#include +#include +#include + +using namespace farmlands::input; + +namespace farmlands { +namespace controller { + +static const float ScaleVelocity = 0.5f; +static const float ScaleShiftVelocity = 2.0f; + +DebugController::DebugController() +{ +} + +DebugController::~DebugController() +{ +} + +void DebugController::onInitialize() +{ + m_camera = GameState::current().renderContext.camera(); +} + +void DebugController::onUpdateLogic() +{ + // Compute velocity + float vel = ScaleVelocity; + + if (Input::instance().pressed(GameKey::Run)) + vel = ScaleShiftVelocity; + + // Time independent + vel *= GameState::current().elapsedTime; + + if (Input::instance().pressed(GameKey::Debug_ZoomIn)) + m_camera->scale *= 1 + vel; + + if (Input::instance().pressed(GameKey::Debug_ZoomOut)) + m_camera->scale *= 1 - vel; +} + +} /* namespace controller */ +} /* namespace farmlands */ diff --git a/src/controller/DebugController.h b/src/controller/DebugController.h new file mode 100644 index 0000000..b62a8f1 --- /dev/null +++ b/src/controller/DebugController.h @@ -0,0 +1,33 @@ +/* + * DebugController.h + * + * Created on: Nov 30, 2016 + * Author: tibi + */ + +#ifndef CONTROLLER_DEBUGCONTROLLER_H_ +#define CONTROLLER_DEBUGCONTROLLER_H_ + +#include +#include + +namespace farmlands { +namespace controller { + + class DebugController: public base::Component + { + public: + DebugController(); + virtual ~DebugController(); + + virtual void onInitialize() override; + virtual void onUpdateLogic() override; + + private: + base::Camera* m_camera; + }; + +} /* namespace controller */ +} /* namespace farmlands */ + +#endif /* CONTROLLER_DEBUGCONTROLLER_H_ */ diff --git a/src/controller/FarmlandsGame.cpp b/src/controller/FarmlandsGame.cpp index e2cca9e..dcfd32c 100644 --- a/src/controller/FarmlandsGame.cpp +++ b/src/controller/FarmlandsGame.cpp @@ -5,7 +5,13 @@ * Author: tibi */ -#include "FarmlandsGame.h" +#include +#include +#include +#include +#include +#include +#include #include #include @@ -14,65 +20,123 @@ #include #include +using namespace farmlands::base; +using namespace farmlands::graphics; +using namespace farmlands::graphics::backend; +using namespace farmlands::resources; + namespace farmlands { namespace controller { FarmlandsGame::FarmlandsGame() : m_running(true), - m_gameState(), - m_time(0), - m_guiController(), - m_playerController() + m_time(0) { } +void FarmlandsGame::createScene() +{ + // Create camera + Transform* cameraTransform = new Transform(); + cameraTransform->x = 120; + cameraTransform->y = 100 - 1; + + Camera* camera = new Camera(); + camera->scale = 4.0f; + + GameObject* cameraObj = new GameObject(); + cameraObj->addComponent(cameraTransform); + cameraObj->addComponent(camera); + + GameState::current().root.addChild(cameraObj); + GameState::current().renderContext.setCamera(cameraObj); + cameraObj->onCreate(); + + // Create background + BackgroundRenderer* backRenderer = new BackgroundRenderer(); + backRenderer->level = GameState::current().currentLevel; + + GameObject* backObj = new GameObject(); + backObj->addComponent(backRenderer); + + GameState::current().root.addChild(backObj); + backObj->onCreate(); + + // Create player + Transform* playerTransform = new Transform(); + playerTransform->x = 120; + playerTransform->y = 100; + + SpriteRenderer* playerRender = new SpriteRenderer(); + playerRender->sprite = ResourceManager::instance().sprite(R::Sprites::Player); + + PlayerController* playerCtrl = new PlayerController(); + + GameObject* playerObj = new GameObject(); + playerObj->addComponent(playerTransform); + playerObj->addComponent(playerRender); + playerObj->addComponent(playerCtrl); + + GameState::current().root.addChild(playerObj); + playerObj->onCreate(); + + // Create debug object + DebugController* dbgController = new DebugController(); + + GameObject* dbgObj = new GameObject(); + dbgObj->addComponent(dbgController); + + GameState::current().root.addChild(dbgObj); + dbgObj->onCreate(); + +} + bool FarmlandsGame::initialize() { - // Initialize game state - m_gameState.viewport.initialized = false; - m_gameState.camera.scale = 4; + bool ok = true; // Initialize render system - if (!m_gameState.sdlRenderer.initialize(&m_gameState)) + ok &= SdlRenderer::instance().initialize(&GameState::current().renderContext); + if (!ok) return false; - m_gameState.gameRenderer.initialize(&m_gameState); - m_gameState.guiRenderer.initialize(&m_gameState); - - // Initialize controllers - m_guiController.initialize(&m_gameState); - m_playerController.initialize(&m_gameState); - // Initialize & load resources - m_gameState.resManager.initialize(&m_gameState); - m_gameState.resManager.loadGameAssets(); - m_gameState.resManager.loadLevel(resources::R::Levels::Farm); - m_gameState.currentLevel = m_gameState.resManager.level(resources::R::Levels::Farm); + ResourceManager::instance().initialize(); + ResourceManager::instance().loadGameAssets(); + ResourceManager::instance().loadLevel(resources::R::Levels::Farm); + GameState::current().currentLevel = ResourceManager::instance().level(resources::R::Levels::Farm); + GameState::current().renderContext.viewport.pixelsPerUnitX = GameState::current().currentLevel->m_cellWidth; + GameState::current().renderContext.viewport.pixelsPerUnitY = GameState::current().currentLevel->m_cellHeight; + + // Set up scene + createScene(); + + // Finish initialization + GameState::current().root.onInitialize(); return true; } void FarmlandsGame::onUpdateLogic() { - m_playerController.updateLogic(); + GameState::current().root.onUpdateLogic(); +} + +void FarmlandsGame::onPreRender() +{ + GameState::current().root.onPreRender(); + SdlRenderer::instance().renderBegin(); } void FarmlandsGame::onRender() { - m_gameState.sdlRenderer.renderBegin(); - m_gameState.gameRenderer.render(); -// m_gameState.guiRenderer.render(); - m_guiController.render(); - m_gameState.sdlRenderer.renderEnd(); + GameState::current().root.onRender(); } void FarmlandsGame::onEvent(SDL_Event& event) { // Let controllers handle event - if (m_guiController.processEvent(event)) - return; - - if (m_playerController.processEvent(event)) + if (GameState::current().root.onEvent(event)) return; // Nobody? Handle global events @@ -92,9 +156,16 @@ void FarmlandsGame::onEvent(SDL_Event& event) } } +void FarmlandsGame::onPostRender() +{ + SdlRenderer::instance().renderEnd(); + GameState::current().root.onPostRender(); +} + void FarmlandsGame::stop() { m_running = false; + GameState::current().root.onDestroy(); } int FarmlandsGame::run() @@ -108,7 +179,7 @@ int FarmlandsGame::run() { // Update elapsed time Uint32 now = SDL_GetTicks(); - m_gameState.elapsedTime = (now - m_time) * 0.001f; + GameState::current().elapsedTime = (now - m_time) * 0.001f; m_time = now; SDL_Event event; @@ -116,7 +187,9 @@ int FarmlandsGame::run() onEvent(event); onUpdateLogic(); + onPreRender(); onRender(); + onPostRender(); } // Cleanup diff --git a/src/controller/FarmlandsGame.h b/src/controller/FarmlandsGame.h index 33b665f..b360700 100644 --- a/src/controller/FarmlandsGame.h +++ b/src/controller/FarmlandsGame.h @@ -11,8 +11,6 @@ #include #include #include -#include -#include #include #include @@ -29,19 +27,19 @@ namespace controller { protected: bool initialize(); - void onUpdateLogic(); - void onRender(); void onEvent(SDL_Event& event); + void onUpdateLogic(); + void onPreRender(); + void onRender(); + void onPostRender(); void stop(); private: - bool m_running; - GameState m_gameState; - Uint32 m_time; + void createScene(); - GuiController m_guiController; - PlayerController m_playerController; + bool m_running; + Uint32 m_time; }; } diff --git a/src/controller/GuiController.cpp b/src/controller/GuiController.cpp index 0346602..24e71a7 100644 --- a/src/controller/GuiController.cpp +++ b/src/controller/GuiController.cpp @@ -7,18 +7,15 @@ #include #include -#include #include -#include - namespace farmlands { namespace controller { GuiController::GuiController() - : m_gameState(nullptr) + : m_canvas() { } @@ -26,15 +23,12 @@ GuiController::~GuiController() { } -void GuiController::initialize(GameState* gameState) +void GuiController::onInitialize() { - assert(gameState != nullptr); - assert(gameState->viewport.initialized); - - m_gameState = gameState; + m_context = &GameState::current().renderContext; // Set up canvas - m_canvas.setSize(m_gameState->viewport.width, m_gameState->viewport.height); + m_canvas.setSize(m_context->viewport.width, m_context->viewport.height); // Add a text element auto text = new gui::widgets::TextArea(); @@ -50,7 +44,7 @@ void GuiController::initialize(GameState* gameState) m_canvas.addChild(text); } -bool GuiController::processEvent(SDL_Event& event) +bool GuiController::onEvent(SDL_Event& event) { bool handled = m_canvas.handleEvent(event); @@ -69,18 +63,11 @@ bool GuiController::processEvent(SDL_Event& event) return handled; } -void GuiController::render() +void GuiController::onRender() { // Compute render context - gui::RenderContext renderContext = - { - .sdlRenderer = &m_gameState->sdlRenderer, - .resManager = &m_gameState->resManager, - .uiScale = 1, - }; - // Render - m_canvas.render(renderContext); + m_canvas.render(m_context); } } /* namespace controller */ diff --git a/src/controller/GuiController.h b/src/controller/GuiController.h index 9ca825e..d426d71 100644 --- a/src/controller/GuiController.h +++ b/src/controller/GuiController.h @@ -8,18 +8,16 @@ #ifndef CONTROLLER_GUICONTROLLER_H_ #define CONTROLLER_GUICONTROLLER_H_ +#include +#include #include #include namespace farmlands { - -// Forward declarations -struct GameState; - namespace controller { - class GuiController + class GuiController : public base::Component { public: GuiController(); @@ -28,21 +26,13 @@ namespace controller { /** * Initializes game renderer */ - void initialize(GameState* gameState); - - /** - * Processes an UI event - */ - bool processEvent(SDL_Event& event); - - /** - * Renders the GUI - */ - void render(); + virtual void onInitialize() override; + virtual bool onEvent(SDL_Event& event) override; + virtual void onRender() override; private: - GameState* m_gameState; gui::layout::Canvas m_canvas; + base::RenderContext* m_context; }; } /* namespace controller */ diff --git a/src/controller/PlayerController.cpp b/src/controller/PlayerController.cpp index 9b0f23b..ee7172e 100644 --- a/src/controller/PlayerController.cpp +++ b/src/controller/PlayerController.cpp @@ -7,13 +7,48 @@ #include #include +#include +#include #include +using namespace farmlands::input; +using namespace farmlands::graphics; +using namespace farmlands::model; + namespace farmlands { namespace controller { +/** + * The default velocity of the player when walking (units/sec). + */ +static const float PlayerWalkVelocity = 2.0f; + +/** + * The default velocity of the player when running (units/sec). + */ +static const float PlayerRunVelocity = 4.0f; + +/* + * Movement speed when attacking. + */ +static const float PlayerAttackVelocity = 0.1f; + +/** + * Direction enum based on sign of velocity on x and y + */ +static const Direction VelocitySignDirections[3][3] = +{ + { Direction::NorthWest, Direction::West, Direction::SouthWest }, + { Direction::North, Direction::None, Direction::South }, + { Direction::NorthEast, Direction::East, Direction::SouthEast }, +}; + + PlayerController::PlayerController() - : m_gameState(nullptr) + : m_transform(nullptr), + m_attackTimeLeft(0), + m_vx(0), m_vy(0), + m_facingDirection(Direction::South) { } @@ -21,61 +56,88 @@ PlayerController::~PlayerController() { } -void PlayerController::initialize(GameState* gameState) +void PlayerController::onInitialize() { - Assert(gameState != nullptr, "Game state must not be NULL!"); - - m_gameState = gameState; + m_transform = gameObject->component(); } -bool PlayerController::processEvent(SDL_Event& event) +bool PlayerController::onEvent(SDL_Event& event) { + bool attack1 = (Input::instance().down(GameKey::Action, event)); + bool attack2 = (Input::instance().down(GameKey::Action2, event)); + + if (m_attackTimeLeft == 0 && (attack1 || attack2)) + { + attack(); + m_attackTimeLeft = 20 + attack2 * 20; + } + return false; } -void PlayerController::updateLogic() +void PlayerController::onUpdateLogic() { - // Get keyboard status - const Uint8* keys = SDL_GetKeyboardState(NULL); + // Compute movement velocity + float velMultiplier = PlayerWalkVelocity; - float deltaX = 0; - float deltaY = 0; + if (Input::instance().pressed(GameKey::Run)) + velMultiplier = PlayerRunVelocity; - // Compute movement delta multiplier - float deltaMultiplier = 5.0f * m_gameState->elapsedTime; // Equivalent to units per second - if (keys[m_gameState->config.keys.Run]) - deltaMultiplier *= 5; - - // Handle scale changes (debugging only) - if (keys[m_gameState->config.keys.Debug_ZoomOut]) - m_gameState->camera.scale *= 1.0f - 0.05f * deltaMultiplier; - if (keys[m_gameState->config.keys.Debug_ZoomIn]) - m_gameState->camera.scale *= 1.0f + 0.05f * deltaMultiplier; - - // Handle movement - if (keys[m_gameState->config.keys.Right] || keys[m_gameState->config.keys.AltRight]) - deltaX += 1; - if (keys[m_gameState->config.keys.Up] || keys[m_gameState->config.keys.AltUp]) - deltaY -= 1; - if (keys[m_gameState->config.keys.Left] || keys[m_gameState->config.keys.AltLeft]) - deltaX -= 1; - if (keys[m_gameState->config.keys.Down] || keys[m_gameState->config.keys.AltDown]) - deltaY += 1; - - float newX = m_gameState->player.posX + deltaX * deltaMultiplier; - float newY = m_gameState->player.posY + deltaY * deltaMultiplier; - - if (canMove(newX, newY)) + if (m_attackTimeLeft) { - m_gameState->player.posX = newX; - m_gameState->player.posY = newY; - m_gameState->player.lastDeltaX = deltaX * deltaMultiplier; - m_gameState->player.lastDeltaY = deltaY * deltaMultiplier; - setDirection(deltaX, deltaY); - - m_gameState->camera.posX = m_gameState->player.posX; - m_gameState->camera.posY = m_gameState->player.posY - 1; + velMultiplier = PlayerAttackVelocity; + --m_attackTimeLeft; } + + // Make movement time independent + velMultiplier *= GameState::current().elapsedTime; + + // Get velocity of axes + float vx = Input::instance().getX() * velMultiplier; + float vy = Input::instance().getY() * velMultiplier; + + // Check if we can move to the new position + float newX = m_transform->x + m_vx; + float newY = m_transform->y + m_vy; + if ((vx || vy) && canMove(newX, newY)) + { + m_vx = vx; + m_vy = vy; + m_transform->x = newX; + m_transform->y = newY; + + m_facingDirection = getDirection(vx, vy); + + base::Transform* cam = GameState::current().renderContext.cameraTransform(); + cam->x = newX; + cam->y = newY - 1; + } + else + { + m_vx = 0; + m_vy = 0; + } +} + +void PlayerController::onPreRender() +{ + // Get sprite + SpriteRenderer* spriteRenderer = gameObject->component(); + + // Compute current state + bool idle = (m_vx == 0 && m_vy == 0); + std::string stateName = (idle) ? "Idle " : "Walking "; + + if (m_facingDirection & Direction::East) + stateName += "right"; + else if (m_facingDirection & Direction::West) + stateName += "left"; + else if (m_facingDirection & Direction::North) + stateName += "up"; + else + stateName += "down"; + + spriteRenderer->sprite->setState(stateName); } bool PlayerController::canMove(float x, float y) @@ -84,20 +146,17 @@ bool PlayerController::canMove(float x, float y) return true; } -static const model::Direction directions[3][3] = +Direction PlayerController::getDirection(float vx, float vy) { - { model::Direction::NorthWest, model::Direction::West, model::Direction::SouthWest }, - { model::Direction::North, model::Direction::South, model::Direction::South }, - { model::Direction::NorthEast, model::Direction::East, model::Direction::SouthEast }, -}; + int xx = (0 < vx) - (vx < 0); + int yy = (0 < vy) - (vy < 0); -void PlayerController::setDirection(float dx, float dy) + return VelocitySignDirections[xx + 1][yy + 1]; +} + +void PlayerController::attack() { - int xx = (0 < dx) - (dx < 0); - int yy = (0 < dy) - (dy < 0); - - if (xx != 0 || yy != 0) - m_gameState->player.direction = directions[xx + 1][yy + 1]; + // For now - nothing } } /* namespace controller */ diff --git a/src/controller/PlayerController.h b/src/controller/PlayerController.h index 0530ff8..f176f8f 100644 --- a/src/controller/PlayerController.h +++ b/src/controller/PlayerController.h @@ -8,6 +8,8 @@ #ifndef CONTROLLER_PLAYERCONTROLLER_H_ #define CONTROLLER_PLAYERCONTROLLER_H_ +#include +#include #include namespace farmlands { @@ -17,34 +19,27 @@ struct GameState; namespace controller { - class PlayerController + class PlayerController : public base::Component { public: PlayerController(); virtual ~PlayerController(); - /** - * Initializes game renderer - */ - void initialize(GameState* gameState); - - /** - * Processes an event. - * - * @returns true if the event was handled, or false otherwise. - */ - bool processEvent(SDL_Event& event); - - /** - * Called at the update logic step for every frame - */ - void updateLogic(); + virtual void onInitialize() override; + virtual bool onEvent(SDL_Event& event) override; + virtual void onUpdateLogic() override; + virtual void onPreRender() override; private: - bool canMove(float x, float y); - void setDirection(float dx, float dy); + static model::Direction getDirection(float vx, float vy); - GameState* m_gameState; + bool canMove(float x, float y); + void attack(); + + base::Transform* m_transform; + uint32_t m_attackTimeLeft; + float m_vx, m_vy; + model::Direction m_facingDirection; }; } /* namespace controller */ diff --git a/src/graphics/BackgroundRenderer.cpp b/src/graphics/BackgroundRenderer.cpp new file mode 100644 index 0000000..329bffb --- /dev/null +++ b/src/graphics/BackgroundRenderer.cpp @@ -0,0 +1,108 @@ +/* + * BackgroundRenderer.cpp + * + * Created on: Nov 30, 2016 + * Author: tibi + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace farmlands::graphics::backend; +using namespace farmlands::resources; + +namespace farmlands { +namespace graphics { + +BackgroundRenderer::BackgroundRenderer() + : level(nullptr), + m_context(nullptr) +{ +} + +BackgroundRenderer::~BackgroundRenderer() +{ +} + +void BackgroundRenderer::onInitialize() +{ + Assert(gameObject != nullptr, "Component not properly initialized!"); + + m_context = &GameState::current().renderContext; +} + +void BackgroundRenderer::onRender() +{ + float cellW = m_context->viewport.pixelsPerUnitX * m_context->camera()->scale; + float cellH = m_context->viewport.pixelsPerUnitY * m_context->camera()->scale; + + // Compute how many cells fit on the screen + float cellsOnScreenX = m_context->viewport.width / cellW; + float cellsOnScreenY = m_context->viewport.height / cellH; + + int minCellX = floorf(m_context->cameraTransform()->x - cellsOnScreenX / 2); + int maxCellX = ceilf(m_context->cameraTransform()->x + cellsOnScreenX / 2); + int minCellY = floorf(m_context->cameraTransform()->y - cellsOnScreenY / 2); + int maxCellY = ceilf(m_context->cameraTransform()->y + cellsOnScreenY / 2); + + // Clamp cell positions + minCellX = clamp(minCellX, 0, (int)level->columnCount() - 1); + maxCellX = clamp(maxCellX, 0, (int)level->columnCount() - 1); + minCellY = clamp(minCellY, 0, (int)level->rowCount() - 1); + maxCellY = clamp(maxCellY, 0, (int)level->rowCount() - 1); + + // Draw each layer + for (size_t i = 0; i < level->layerCount(); i++) + { + int textureId = level->texture(i); + + // Render only visible tiles + for (int y = minCellY; y <= maxCellY; y++) + for (int x = minCellX; x <= maxCellX; x++) + { + int cellId = level->cell(i, y, x); + + // Obtain texture + SDL_Texture* texture = ResourceManager::instance().texture(textureId); + + // Calculate source rect + SDL_Rect src; + getCell(texture, cellId, &src.x, &src.y); + src.w = m_context->viewport.pixelsPerUnitX; + src.h = m_context->viewport.pixelsPerUnitY; + + // Compute destination rect + SDL_Rect dest; + dest.x = floorf(m_context->xToScreen(x)); + dest.y = floorf(m_context->yToScreen(y)); + dest.w = ceilf(cellW); + dest.h = ceilf(cellH); + + // Blit + SdlRenderer::instance().renderTexture(texture, &src, &dest); + } + } +} + +void BackgroundRenderer::getCell(SDL_Texture* texture, uint32_t cell, int* outX, int* outY) +{ + int texWidth, texHeight; + SdlRenderer::instance().getTextureSize(texture, &texWidth, &texHeight); + + int ppuX = m_context->viewport.pixelsPerUnitX; + int ppuY = m_context->viewport.pixelsPerUnitY; + + // Compute texture coordinates + *outX = (cell * ppuX) % texWidth; + *outY = ((cell * ppuX) / texWidth) * ppuY; +} + +} /* namespace graphics */ +} /* namespace farmlands */ diff --git a/src/graphics/BackgroundRenderer.h b/src/graphics/BackgroundRenderer.h new file mode 100644 index 0000000..0d9087a --- /dev/null +++ b/src/graphics/BackgroundRenderer.h @@ -0,0 +1,41 @@ +/* + * BackgroundRenderer.h + * + * Created on: Nov 30, 2016 + * Author: tibi + */ + +#ifndef GRAPHICS_BACKGROUNDRENDERER_H_ +#define GRAPHICS_BACKGROUNDRENDERER_H_ + +#include +#include +#include +#include + +namespace farmlands { +namespace graphics { + +class BackgroundRenderer: public base::Component +{ +public: + BackgroundRenderer(); + virtual ~BackgroundRenderer(); + + virtual void onInitialize() override; + virtual void onRender() override; + + // Public fields + model::Level* level; + +private: + void getCell(SDL_Texture* texture, uint32_t cell, int* outX, int* outY); + + // Private fields + base::RenderContext* m_context; +}; + +} /* namespace graphics */ +} /* namespace farmlands */ + +#endif /* GRAPHICS_BACKGROUNDRENDERER_H_ */ diff --git a/src/graphics/GameRenderer.cpp b/src/graphics/GameRenderer.cpp deleted file mode 100644 index 33feb36..0000000 --- a/src/graphics/GameRenderer.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/* - * GameRenderer.cpp - * - * Created on: Nov 13, 2016 - * Author: tibi - */ -#include -#include -#include -#include - -namespace farmlands { -namespace graphics { - -GameRenderer::GameRenderer() - : m_gameState(nullptr) -{ -} - -GameRenderer::~GameRenderer() -{ -} - -void GameRenderer::initialize(GameState* gameState) -{ - m_gameState = gameState; -} - -void GameRenderer::render() -{ - prepareRender(); - renderTileLayers(); - renderPlayer(); -} - -void GameRenderer::prepareRender() -{ - m_cellW = m_gameState->currentLevel->m_cellWidth * m_gameState->camera.scale; - m_cellH = m_gameState->currentLevel->m_cellHeight * m_gameState->camera.scale; -} - -void GameRenderer::renderTileLayers() -{ - // Compute how many cells fit on the screen - float cellsOnScreenX = m_gameState->viewport.width / m_cellW; - float cellsOnScreenY = m_gameState->viewport.height / m_cellH; - - int minCellX = floorf(m_gameState->camera.posX - cellsOnScreenX / 2); - int minCellY = floorf(m_gameState->camera.posY - cellsOnScreenY / 2); - int maxCellX = ceilf(m_gameState->camera.posX + cellsOnScreenX / 2); - int maxCellY = ceilf(m_gameState->camera.posY + cellsOnScreenY / 2); - - // Clamp cell positions - minCellX = clamp(minCellX, 0, (int)m_gameState->currentLevel->columnCount() - 1); - minCellY = clamp(minCellY, 0, (int)m_gameState->currentLevel->rowCount() - 1); - maxCellX = clamp(maxCellX, 0, (int)m_gameState->currentLevel->columnCount() - 1); - maxCellY = clamp(maxCellY, 0, (int)m_gameState->currentLevel->rowCount() - 1); - - // Draw each layer - for (size_t i = 0; i < m_gameState->currentLevel->layerCount(); i++) - { - int textureId = m_gameState->currentLevel->texture(i); - - // Render only visible tiles - for (int y = minCellY; y <= maxCellY; y++) - for (int x = minCellX; x <= maxCellX; x++) - { - int cellId = m_gameState->currentLevel->cell(i, y, x); - - // Obtain texture - int texWidth, texHeight; - SDL_Texture* texture = m_gameState->resManager.texture(textureId); - SDL_QueryTexture(texture, NULL, NULL, &texWidth, &texHeight); - - // Compute texture coordinates - int cellCol = (cellId * m_gameState->currentLevel->m_cellWidth) % texWidth; - int cellRow = ((cellId * m_gameState->currentLevel->m_cellWidth) / texWidth) * m_gameState->currentLevel->m_cellHeight; - - // Calculate source position - SDL_Rect src = - { - cellCol, - cellRow, - (int) m_gameState->currentLevel->m_cellWidth, - (int) m_gameState->currentLevel->m_cellHeight - }; - - // Calculate destination position - SDL_Rect dest = - { - (int) xToScreen(x), - (int) yToScreen(y), - (int) ceilf(m_cellW), - (int) ceilf(m_cellH) - }; - - // Blit - SDL_RenderCopy(m_gameState->sdlRenderer.internalRenderer(), texture, &src, &dest); - } - } -} - -void GameRenderer::renderSprite(model::Sprite* sprite, float destX, float destY) -{ - float posX = xToScreen(destX); - float posY = yToScreen(destY); - - // Obtain texture - int texId = sprite->currentFrame().tileSetId; - SDL_Texture* texture = m_gameState->resManager.texture(texId); - - // Compute src rectangle - SDL_Rect src; - getCell(texture, sprite->currentFrame().tileSetCell, &src.x, &src.y); - src.w = sprite->currentFrame().width * m_gameState->currentLevel->m_cellWidth; - src.h = sprite->currentFrame().height * m_gameState->currentLevel->m_cellHeight; - - // Compute destination rectangle - SDL_Rect dest; - dest.x = posX - sprite->anchorX * src.w * m_gameState->camera.scale; - dest.y = posY - sprite->anchorY * src.h * m_gameState->camera.scale; - dest.w = src.w * m_gameState->camera.scale; - dest.h = src.h * m_gameState->camera.scale; - - // Draw - SDL_RenderCopy(m_gameState->sdlRenderer.internalRenderer(), texture, &src, &dest); - - // Advance animation frame - sprite->advanceTime(1); -} - -void GameRenderer::renderPlayer() -{ - // Compute current state - model::Sprite* sprite = m_gameState->resManager.sprite(resources::R::Sprites::Player); - - bool walking = (m_gameState->player.lastDeltaX != 0 || m_gameState->player.lastDeltaY != 0); - std::string stateName = (walking) ? "Walking " : "Idle "; - - switch(m_gameState->player.direction) - { - case model::Direction::SouthEast: - case model::Direction::East: - case model::Direction::NorthEast: - stateName += "right"; - break; - - case model::Direction::North: - stateName += "up"; - break; - - case model::Direction::NorthWest: - case model::Direction::West: - case model::Direction::SouthWest: - stateName += "left"; - break; - - case model::Direction::South: - stateName += "down"; - break; - } - sprite->setState(stateName); - - // Draw - renderSprite(sprite, m_gameState->player.posX, m_gameState->player.posY); -} - -void GameRenderer::getCell(SDL_Texture* texture, int cell, int* outX, int* outY) -{ - int texWidth, texHeight; - SDL_QueryTexture(texture, NULL, NULL, &texWidth, &texHeight); - - // Compute texture coordinates - *outX = (cell * m_gameState->currentLevel->m_cellWidth) % texWidth; - *outY = ((cell * m_gameState->currentLevel->m_cellWidth) / texWidth) * m_gameState->currentLevel->m_cellHeight; -} - -float GameRenderer::xToWorld(float x) -{ - return (x - m_gameState->viewport.width / 2) / m_cellW + m_gameState->camera.posX; -} - -float GameRenderer::yToWorld(float y) -{ - return (y - m_gameState->viewport.height / 2) / m_cellH + m_gameState->camera.posY; -} - -float GameRenderer::xToScreen(float x) -{ - return (x - m_gameState->camera.posX) * m_cellW + m_gameState->viewport.width / 2; -} - -float GameRenderer::yToScreen(float y) -{ - return (y - m_gameState->camera.posY) * m_cellH + m_gameState->viewport.height / 2; -} - -} /* namespace graphics */ -} /* namespace farmlands */ diff --git a/src/graphics/GameRenderer.h b/src/graphics/GameRenderer.h deleted file mode 100644 index bb4eb05..0000000 --- a/src/graphics/GameRenderer.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * GameRenderer.h - * - * Created on: Nov 13, 2016 - * Author: tibi - */ - -#ifndef GRAPHICS_GAMERENDERER_H_ -#define GRAPHICS_GAMERENDERER_H_ - -#include -#include -#include - -#include - -#include - -namespace farmlands { - -// Forward declarations -struct GameState; - -namespace graphics { - - class GameRenderer - { - public: - GameRenderer(); - virtual ~GameRenderer(); - - /** - * Initializes game renderer - */ - void initialize(GameState* gameState); - - /** - * Renders everything - */ - void render(); - - private: - void prepareRender(); - void renderTileLayers(); - void renderPlayer(); - void renderSprite(model::Sprite* sprite, float destX, float destY); - - float xToWorld(float x); - float yToWorld(float y); - float xToScreen(float x); - float yToScreen(float y); - - void getCell(SDL_Texture* texture, int cell, int* outX, int* outY); - - GameState* m_gameState; - - // Size of a cell (scaled) - float m_cellW, m_cellH; - }; - -} /* namespace graphics */ -} /* namespace farmlands */ - -#endif /* GRAPHICS_GAMERENDERER_H_ */ diff --git a/src/graphics/GuiRenderer.cpp b/src/graphics/GuiRenderer.cpp deleted file mode 100644 index 0aeaa75..0000000 --- a/src/graphics/GuiRenderer.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * GuiRenderer.cpp - * - * Created on: Nov 13, 2016 - * Author: tibi - */ - -#include -#include -#include - -#include - -#include - -namespace farmlands -{ -namespace graphics -{ - -GuiRenderer::GuiRenderer() - : m_gameState(nullptr), - m_fps(0), - m_fpsIndex(0) -{ -} - -GuiRenderer::~GuiRenderer() -{ -} - -void GuiRenderer::initialize(GameState* gameState) -{ - m_gameState = gameState; -} - -void GuiRenderer::render() -{ - computeFps(); - - // Prepare stuff - TTF_Font* font = m_gameState->resManager.font(resources::R::Fonts::DejaVuSans, 10); - SDL_Color white = { 255, 255, 255, 255 }; - SDL_Rect dest = { 10, 10, 0, 0 }; - - // Figure out what text to print - std::stringstream textStream; - textStream << "FPS: " << m_fps; - - // Render text - SDL_Texture* fpsText = m_gameState->sdlRenderer.renderText(textStream.str(), font, white); - SDL_QueryTexture(fpsText, NULL, NULL, &dest.w, &dest.h); - SDL_RenderCopy(m_gameState->sdlRenderer.internalRenderer(), fpsText, NULL, &dest); -} - -void GuiRenderer::computeFps() -{ - // Compute FPS - m_fpsVals[m_fpsIndex++] = 1.0f / m_gameState->elapsedTime; - if (m_fpsIndex >= GUIRENDERER_FPS_VALS) - { - m_fpsIndex = 0; - - m_fps = 0; - for (int i = 0; i < GUIRENDERER_FPS_VALS; i++) - m_fps += m_fpsVals[i]; - m_fps /= GUIRENDERER_FPS_VALS; - } -} - -} /* namespace graphics */ -} /* namespace farmlands */ diff --git a/src/graphics/GuiRenderer.h b/src/graphics/GuiRenderer.h deleted file mode 100644 index b27558b..0000000 --- a/src/graphics/GuiRenderer.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * GuiRenderer.h - * - * Created on: Nov 13, 2016 - * Author: tibi - */ - -#ifndef GRAPHICS_GUIRENDERER_H_ -#define GRAPHICS_GUIRENDERER_H_ - -#define GUIRENDERER_FPS_VALS 30 - -namespace farmlands { - -// Forward declarations -struct GameState; - -namespace graphics { - - class GuiRenderer - { - public: - GuiRenderer(); - virtual ~GuiRenderer(); - - /** - * Initializes game renderer - */ - void initialize(GameState* gameState); - - /** - * Renders the GUI - */ - void render(); - - private: - void computeFps(); - - GameState* m_gameState; - float m_fpsVals[GUIRENDERER_FPS_VALS]; - float m_fps; - int m_fpsIndex; - }; - -} /* namespace graphics */ -} /* namespace farmlands */ - -#endif /* GRAPHICS_GUIRENDERER_H_ */ diff --git a/src/graphics/SpriteRenderer.cpp b/src/graphics/SpriteRenderer.cpp new file mode 100644 index 0000000..f79b02f --- /dev/null +++ b/src/graphics/SpriteRenderer.cpp @@ -0,0 +1,86 @@ +/* + * SpriteRenderer.cpp + * + * Created on: Nov 30, 2016 + * Author: tibi + */ + +#include +#include +#include +#include +#include +#include + +using namespace farmlands::graphics::backend; + +namespace farmlands { +namespace graphics { + +SpriteRenderer::SpriteRenderer() + : sprite(nullptr), + m_transform(nullptr), + m_context(nullptr) +{ +} + +SpriteRenderer::~SpriteRenderer() +{ +} + +void SpriteRenderer::onInitialize() +{ + Assert(gameObject != nullptr, "Component not properly initialized!"); + + m_transform = gameObject->component(); + m_context = &GameState::current().renderContext; +} + +void SpriteRenderer::onRender() +{ + float posX = m_context->xToScreen(m_transform->x); + float posY = m_context->yToScreen(m_transform->y); + + // Obtain texture + int texId = sprite->currentFrame().tileSetId; + SDL_Texture* texture = resources::ResourceManager::instance().texture(texId); + + // Compute src rectangle + SDL_Rect src; + getCell(texture, sprite->currentFrame().tileSetCell, &src.x, &src.y); + src.w = sprite->currentFrame().width * m_context->viewport.pixelsPerUnitX; + src.h = sprite->currentFrame().height * m_context->viewport.pixelsPerUnitY; + + // Compute destination rectangle + float scale = m_context->camera()->scale; + + SDL_Rect dest; + dest.x = posX - sprite->anchorX * src.w * scale; + dest.y = posY - sprite->anchorY * src.h * scale; + dest.w = src.w * scale; + dest.h = src.h * scale; + + // Draw + SdlRenderer::instance().renderTexture(texture, &src, &dest); +} + +void SpriteRenderer::onPostRender() +{ + sprite->advanceTime(1); +} + +void SpriteRenderer::getCell(SDL_Texture* texture, uint32_t cell, int* outX, int* outY) +{ + int texWidth, texHeight; + SdlRenderer::instance().getTextureSize(texture, &texWidth, &texHeight); + + int ppuX = m_context->viewport.pixelsPerUnitX; + int ppuY = m_context->viewport.pixelsPerUnitY; + + // Compute texture coordinates + *outX = (cell * ppuX) % texWidth; + *outY = ((cell * ppuX) / texWidth) * ppuY; +} + +} /* namespace graphics */ +} /* namespace farmlands */ diff --git a/src/graphics/SpriteRenderer.h b/src/graphics/SpriteRenderer.h new file mode 100644 index 0000000..abcbdbf --- /dev/null +++ b/src/graphics/SpriteRenderer.h @@ -0,0 +1,45 @@ +/* + * SpriteRenderer.h + * + * Created on: Nov 30, 2016 + * Author: tibi + */ + +#ifndef GRAPHICS_SPRITERENDERER_H_ +#define GRAPHICS_SPRITERENDERER_H_ + +#include +#include +#include +#include + +#include + +namespace farmlands { +namespace graphics { + + class SpriteRenderer: public base::Component + { + public: + SpriteRenderer(); + virtual ~SpriteRenderer(); + + virtual void onInitialize() override; + virtual void onRender() override; + virtual void onPostRender() override; + + // Public fields + base::Sprite* sprite; + + private: + void getCell(SDL_Texture* texture, uint32_t cell, int* outX, int* outY); + + // Private fields + base::Transform* m_transform; + base::RenderContext* m_context; + }; + +} /* namespace graphics */ +} /* namespace farmlands */ + +#endif /* GRAPHICS_SPRITERENDERER_H_ */ diff --git a/src/graphics/SdlRenderer.cpp b/src/graphics/backend/SdlRenderer.cpp similarity index 67% rename from src/graphics/SdlRenderer.cpp rename to src/graphics/backend/SdlRenderer.cpp index ddb04db..7e64200 100644 --- a/src/graphics/SdlRenderer.cpp +++ b/src/graphics/backend/SdlRenderer.cpp @@ -6,7 +6,7 @@ */ #include -#include +#include #include #include @@ -15,15 +15,21 @@ #include #include -namespace farmlands -{ -namespace graphics +namespace farmlands { +namespace graphics { +namespace backend { + +// Singleton instance +SdlRenderer SdlRenderer::s_instance; + +SdlRenderer& SdlRenderer::instance() { + return s_instance; +} SdlRenderer::SdlRenderer() : m_sdlWindow(nullptr), - m_sdlRenderer(nullptr), - m_gameState(nullptr) + m_sdlRenderer(nullptr) { } @@ -38,10 +44,8 @@ SdlRenderer::~SdlRenderer() SDL_Quit(); } -bool SdlRenderer::initialize(GameState* gameState) +bool SdlRenderer::initialize(base::RenderContext* renderContext) { - m_gameState = gameState; - if (SDL_Init(SDL_INIT_VIDEO) != 0) { std::cerr << "Failed to initialize SDL!\n"; return false; @@ -58,10 +62,10 @@ bool SdlRenderer::initialize(GameState* gameState) return false; } - m_gameState->viewport.initialized = true; - m_gameState->viewport.width = 1024; - m_gameState->viewport.height = 768; - m_sdlWindow = SDL_CreateWindow("Farmlands", 0, 0, m_gameState->viewport.width, m_gameState->viewport.height, SDL_WINDOW_SHOWN); + renderContext->viewport.initialized = true; + renderContext->viewport.width = 1024; + renderContext->viewport.height = 768; + m_sdlWindow = SDL_CreateWindow("Farmlands", 0, 0, renderContext->viewport.width, renderContext->viewport.height, SDL_WINDOW_SHOWN); if (!m_sdlWindow) { std::cerr << "Failed to create main window!\n"; return false; @@ -88,6 +92,11 @@ void SdlRenderer::renderEnd() SDL_RenderPresent(m_sdlRenderer); } +void SdlRenderer::renderTexture(SDL_Texture* texture, SDL_Rect* src, SDL_Rect* dest) +{ + SDL_RenderCopy(m_sdlRenderer, texture, src, dest); +} + SDL_Texture* SdlRenderer::renderText(const std::string& text, TTF_Font* font, SDL_Color color) { assert(font != nullptr); @@ -102,7 +111,12 @@ SDL_Texture* SdlRenderer::renderText(const std::string& text, TTF_Font* font, SD return texture; } +void SdlRenderer::getTextureSize(SDL_Texture* texture, int* width, int* height) +{ + SDL_QueryTexture(texture, NULL, NULL, width, height); +} + +} } /* namespace graphics */ } /* namespace farmlands */ - diff --git a/src/graphics/SdlRenderer.h b/src/graphics/backend/SdlRenderer.h similarity index 70% rename from src/graphics/SdlRenderer.h rename to src/graphics/backend/SdlRenderer.h index b73e27a..c9b0e21 100644 --- a/src/graphics/SdlRenderer.h +++ b/src/graphics/backend/SdlRenderer.h @@ -8,30 +8,30 @@ #ifndef GRAPHICS_SDLRENDERER_H_ #define GRAPHICS_SDLRENDERER_H_ +#include + #include #include #include namespace farmlands { - -// Forward declarations -struct GameState; - namespace graphics { +namespace backend { class SdlRenderer { public: - SdlRenderer(); - virtual ~SdlRenderer(); + static SdlRenderer& instance(); + + ~SdlRenderer(); /** * Initializes the game renderer. * * @returns true if successful, false otherwise. */ - bool initialize(GameState* gameState); + bool initialize(base::RenderContext* renderContext); /** * Performs steps for beginning to render. @@ -48,6 +48,16 @@ namespace graphics { */ SDL_Texture* renderText(const std::string& text, TTF_Font* font, SDL_Color color); + /** + * Renders a textue + */ + void renderTexture(SDL_Texture* texture, SDL_Rect* src, SDL_Rect* dest); + + /** + * Returns the size of a texture + */ + void getTextureSize(SDL_Texture* texture, int* width, int* height); + // Getters /** * Gets the internal SDL renderer object; @@ -56,12 +66,15 @@ namespace graphics { private: + SdlRenderer(); + SDL_Window* m_sdlWindow; SDL_Renderer* m_sdlRenderer; - GameState* m_gameState; + static SdlRenderer s_instance; }; +} } /* namespace graphics */ } /* namespace farmlands */ diff --git a/src/gui/RenderContext.h b/src/gui/RenderContext.h deleted file mode 100644 index 8676ed9..0000000 --- a/src/gui/RenderContext.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * RenderContext.h - * - * Created on: Nov 27, 2016 - * Author: tibi - */ - -#ifndef GUI_PRIMITIVES_RENDERCONTEXT_H_ -#define GUI_PRIMITIVES_RENDERCONTEXT_H_ - -#include -#include - -namespace farmlands { -namespace gui { - - struct RenderContext - { - graphics::SdlRenderer* sdlRenderer; - resources::ResourceManager* resManager; - float uiScale; - }; - -} -} - -#endif /* GUI_PRIMITIVES_RENDERCONTEXT_H_ */ diff --git a/src/gui/layout/Canvas.cpp b/src/gui/layout/Canvas.cpp index 9560f49..805a928 100644 --- a/src/gui/layout/Canvas.cpp +++ b/src/gui/layout/Canvas.cpp @@ -19,7 +19,7 @@ Canvas::~Canvas() { } -void Canvas::render(RenderContext& context) +void Canvas::render(base::RenderContext* context) { for (auto child : m_children) child->render(context); diff --git a/src/gui/layout/Canvas.h b/src/gui/layout/Canvas.h index 165e17a..d46d9fd 100644 --- a/src/gui/layout/Canvas.h +++ b/src/gui/layout/Canvas.h @@ -9,7 +9,6 @@ #define GUI_PRIMITIVES_CANVAS_H_ #include -#include namespace farmlands { namespace gui { @@ -21,7 +20,7 @@ namespace layout { Canvas(); virtual ~Canvas(); - virtual void render(RenderContext& context) override; + virtual void render(base::RenderContext* context) override; }; } diff --git a/src/gui/primitives/UIElement.cpp b/src/gui/primitives/UIElement.cpp index 539ee03..f113ab0 100644 --- a/src/gui/primitives/UIElement.cpp +++ b/src/gui/primitives/UIElement.cpp @@ -5,8 +5,11 @@ * Author: tibi */ +#include #include +using namespace farmlands::graphics::backend; + namespace farmlands { namespace gui @@ -24,7 +27,7 @@ UIElement::~UIElement() { } -void UIElement::render(RenderContext& context) +void UIElement::render(base::RenderContext* context) { if (m_backColor.a > 0) { @@ -36,8 +39,8 @@ void UIElement::render(RenderContext& context) (int) m_h }; - SDL_SetRenderDrawColor(context.sdlRenderer->internalRenderer(), m_backColor.r, m_backColor.g, m_backColor.b, m_backColor.a); - SDL_RenderFillRect(context.sdlRenderer->internalRenderer(), &rect); + SDL_SetRenderDrawColor(SdlRenderer::instance().internalRenderer(), m_backColor.r, m_backColor.g, m_backColor.b, m_backColor.a); + SDL_RenderFillRect(SdlRenderer::instance().internalRenderer(), &rect); } } diff --git a/src/gui/primitives/UIElement.h b/src/gui/primitives/UIElement.h index 6e4fc5b..7facf2a 100644 --- a/src/gui/primitives/UIElement.h +++ b/src/gui/primitives/UIElement.h @@ -10,7 +10,7 @@ #include -#include +#include namespace farmlands { namespace gui { @@ -22,7 +22,7 @@ namespace primitives { UIElement(); virtual ~UIElement(); - virtual void render(RenderContext& context); + virtual void render(base::RenderContext* context); virtual bool handleEvent(SDL_Event& event); // Getters & setters diff --git a/src/gui/widgets/TextArea.cpp b/src/gui/widgets/TextArea.cpp index acf7ab9..8188af4 100644 --- a/src/gui/widgets/TextArea.cpp +++ b/src/gui/widgets/TextArea.cpp @@ -5,8 +5,10 @@ * Author: tibi */ +#include #include #include +#include #include #include @@ -14,12 +16,12 @@ #include -namespace farmlands -{ -namespace gui -{ -namespace widgets -{ +using namespace farmlands::graphics::backend; +using namespace farmlands::resources; + +namespace farmlands { +namespace gui { +namespace widgets { TextArea::TextArea() : m_text(), @@ -39,12 +41,12 @@ TextArea::~TextArea() { } -void TextArea::render(RenderContext& context) +void TextArea::render(base::RenderContext* context) { UIElement::render(context); // Obtain font - TTF_Font* font = context.resManager->font(m_fontId, m_fontSize * context.uiScale); + TTF_Font* font = ResourceManager::instance().font(m_fontId, m_fontSize * context->uiScale); if (font == nullptr) return; // TODO: handle error (maybe log it) @@ -94,7 +96,7 @@ void TextArea::render(RenderContext& context) dest.y = y() + totalH; // Draw - SDL_RenderCopy(context.sdlRenderer->internalRenderer(), lineTexture, NULL, &dest); + SdlRenderer::instance().renderTexture(lineTexture, NULL, &dest); totalH += lineH; } @@ -256,7 +258,7 @@ void TextArea::wrapText(TTF_Font* font) m_wrappedText.erase(m_wrappedText.size() - 1); } -void TextArea::renderLines(RenderContext& context, TTF_Font* font) +void TextArea::renderLines(base::RenderContext* context, TTF_Font* font) { // Clean up old textures for (SDL_Texture* tex : m_renderedLines) @@ -270,7 +272,7 @@ void TextArea::renderLines(RenderContext& context, TTF_Font* font) for (std::string line : lines) { // Render line - SDL_Texture* tex = context.sdlRenderer->renderText(line, font, m_color); + SDL_Texture* tex = SdlRenderer::instance().renderText(line, font, m_color); m_renderedLines.push_back(tex); } } diff --git a/src/gui/widgets/TextArea.h b/src/gui/widgets/TextArea.h index 2d8d524..c04a6a7 100644 --- a/src/gui/widgets/TextArea.h +++ b/src/gui/widgets/TextArea.h @@ -49,7 +49,7 @@ namespace widgets { TextArea(); virtual ~TextArea(); - virtual void render(RenderContext& context) override; + virtual void render(base::RenderContext* context) override; // Getters and setters inline std::string text() const { return m_text; } @@ -71,7 +71,7 @@ namespace widgets { private: void wrapText(TTF_Font* font); - void renderLines(RenderContext& context, TTF_Font* font); + void renderLines(base::RenderContext* context, TTF_Font* font); std::string m_text; std::string m_wrappedText; diff --git a/src/input/GameKey.h b/src/input/GameKey.h new file mode 100644 index 0000000..683000e --- /dev/null +++ b/src/input/GameKey.h @@ -0,0 +1,40 @@ +/* + * GameKeys.h + * + * Created on: Nov 30, 2016 + * Author: tibi + */ + +#ifndef INPUT_GAMEKEY_H_ +#define INPUT_GAMEKEY_H_ + +namespace farmlands { +namespace input { + + enum GameKey + { + Right, + Up, + Left, + Down, + + Action, + Action2, + Run, + + AltRight, + AltUp, + AltLeft, + AltDown, + + Debug_ZoomIn, + Debug_ZoomOut, + + _Count + }; +} +} + + + +#endif /* INPUT_GAMEKEY_H_ */ diff --git a/src/input/GameKeyConfiguration.cpp b/src/input/GameKeyConfiguration.cpp new file mode 100644 index 0000000..36a43a1 --- /dev/null +++ b/src/input/GameKeyConfiguration.cpp @@ -0,0 +1,40 @@ +/* + * GameKeyConfiguration.cpp + * + * Created on: Nov 30, 2016 + * Author: tibi + */ + +#include