Large refactoring, using the Entity-Component model.
This commit is contained in:
24
src/base/Camera.h
Normal file
24
src/base/Camera.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Camera.h
|
||||
*
|
||||
* Created on: Nov 30, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
|
||||
#ifndef MODEL_CAMERA_H_
|
||||
#define MODEL_CAMERA_H_
|
||||
|
||||
#include <base/Component.h>
|
||||
|
||||
namespace farmlands {
|
||||
namespace base {
|
||||
|
||||
struct Camera : public Component
|
||||
{
|
||||
float scale;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* MODEL_CAMERA_H_ */
|
59
src/base/Component.cpp
Normal file
59
src/base/Component.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Component.cpp
|
||||
*
|
||||
* Created on: Nov 30, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
|
||||
#include <base/Component.h>
|
||||
|
||||
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 */
|
||||
|
||||
|
41
src/base/Component.h
Normal file
41
src/base/Component.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Component.h
|
||||
*
|
||||
* Created on: Nov 30, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
|
||||
#ifndef COMPONENT_H_
|
||||
#define COMPONENT_H_
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
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_ */
|
155
src/base/GameObject.cpp
Normal file
155
src/base/GameObject.cpp
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* GameObject.cpp
|
||||
*
|
||||
* Created on: Nov 30, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
|
||||
#include <base/GameObject.h>
|
||||
#include <base/Component.h>
|
||||
|
||||
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 */
|
97
src/base/GameObject.h
Normal file
97
src/base/GameObject.h
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* GameObject.h
|
||||
*
|
||||
* Created on: Nov 30, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
|
||||
#ifndef GAMEOBJECT_H_
|
||||
#define GAMEOBJECT_H_
|
||||
|
||||
#include <utils/Assert.h>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include <typeindex>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace farmlands {
|
||||
namespace base {
|
||||
|
||||
class Component;
|
||||
class RenderContext;
|
||||
|
||||
class GameObject
|
||||
{
|
||||
public:
|
||||
// Constructors
|
||||
GameObject();
|
||||
virtual ~GameObject();
|
||||
|
||||
// Components API
|
||||
template <typename T> void addComponent(T* component);
|
||||
template <typename T> T* component();
|
||||
template <typename T> 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<std::type_index, Component*> m_components;
|
||||
|
||||
std::vector<GameObject*> m_children;
|
||||
GameObject* m_parent;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
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 <typename T>
|
||||
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<T*> (m_components.at(typeIndex));
|
||||
Assert(comp != nullptr, "This is bad!!! Type of component is really messed up!!!");
|
||||
|
||||
return comp;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void GameObject::removeComponent()
|
||||
{
|
||||
std::type_index typeIndex(typeid(T));
|
||||
return m_components.erase(typeIndex);
|
||||
}
|
||||
|
||||
} /* namespace base */
|
||||
} /* namespace farmlands */
|
||||
|
||||
#endif /* GAMEOBJECT_H_ */
|
47
src/base/RenderContext.cpp
Normal file
47
src/base/RenderContext.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* RenderContext.cpp
|
||||
*
|
||||
* Created on: Nov 30, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
#include <base/Camera.h>
|
||||
#include <base/GameObject.h>
|
||||
#include <base/RenderContext.h>
|
||||
#include <base/Transform.h>
|
||||
|
||||
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<Transform>();
|
||||
m_camera = camera->component<Camera>();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
49
src/base/RenderContext.h
Normal file
49
src/base/RenderContext.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* RenderContext.h
|
||||
*
|
||||
* Created on: Nov 30, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_RENDERCONTEXT_H_
|
||||
#define GRAPHICS_RENDERCONTEXT_H_
|
||||
|
||||
#include <base/Viewport.h>
|
||||
|
||||
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_ */
|
103
src/base/Sprite.cpp
Normal file
103
src/base/Sprite.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Sprite.cpp
|
||||
*
|
||||
* Created on: Nov 29, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
|
||||
#include <base/Sprite.h>
|
||||
#include <utils/Assert.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace farmlands {
|
||||
namespace base {
|
||||
|
||||
Sprite::Sprite()
|
||||
: anchorX(0), anchorY(0),
|
||||
name(),
|
||||
m_states(),
|
||||
m_currentState(0),
|
||||
m_currentFrame(0),
|
||||
m_currentFrameTimeLeft(0)
|
||||
{
|
||||
}
|
||||
|
||||
Sprite::~Sprite()
|
||||
{
|
||||
}
|
||||
|
||||
void Sprite::addState(const SpriteState& state)
|
||||
{
|
||||
Assert(state.frames.size() > 0, "State must have at least one frame!");
|
||||
#ifdef BUILD_DEBUG
|
||||
uint32_t totalDuration = 0;
|
||||
for (auto frame : state.frames)
|
||||
totalDuration += frame.duration;
|
||||
|
||||
Assert(totalDuration > 0, "State must have a frame which last at least one tick.");
|
||||
#endif
|
||||
Assert(m_stateNames.count(state.name) == 0, "A state with the same name already added!");
|
||||
|
||||
m_states.push_back(state);
|
||||
m_stateNames.emplace(state.name, m_states.size() - 1);
|
||||
}
|
||||
|
||||
void Sprite::setState(size_t stateId)
|
||||
{
|
||||
Assert(stateId < m_states.size(), "Inexistent state.");
|
||||
|
||||
// Avoid resetting state
|
||||
if (stateId == m_currentState)
|
||||
return;
|
||||
|
||||
m_currentState = stateId;
|
||||
m_currentFrame = 0;
|
||||
m_currentFrameTimeLeft = currentFrame().duration * 1;
|
||||
}
|
||||
|
||||
void Sprite::setState(const std::string& name)
|
||||
{
|
||||
Assert(m_stateNames.count(name) > 0, "Inexistent state.");
|
||||
setState(m_stateNames.at(name));
|
||||
}
|
||||
|
||||
void Sprite::advanceTime(uint32_t steps)
|
||||
{
|
||||
Assert(m_states.size() > 0, "Sprite must have at least one state!");
|
||||
|
||||
while (steps > 0)
|
||||
{
|
||||
// There is time left in the current frame?
|
||||
if (m_currentFrameTimeLeft > 0)
|
||||
{
|
||||
uint32_t sub = std::min(steps, m_currentFrameTimeLeft);
|
||||
m_currentFrameTimeLeft -= sub;
|
||||
steps -= sub;
|
||||
}
|
||||
|
||||
if (m_currentFrameTimeLeft == 0)
|
||||
{
|
||||
// Move to the next frame
|
||||
if (++m_currentFrame >= currentState().frames.size())
|
||||
m_currentFrame = 0;
|
||||
|
||||
m_currentFrameTimeLeft = currentFrame().duration * 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SpriteState& Sprite::currentState()
|
||||
{
|
||||
Assert(m_states.size() > 0, "Sprite must have at least one state!");
|
||||
return m_states.at(m_currentState);
|
||||
}
|
||||
|
||||
Frame& Sprite::currentFrame()
|
||||
{
|
||||
Assert(currentState().frames.size() > 0, "State must have at least one frame!");
|
||||
return currentState().frames.at(m_currentFrame);
|
||||
}
|
||||
|
||||
} /* namespace model */
|
||||
} /* namespace farmlands */
|
89
src/base/Sprite.h
Normal file
89
src/base/Sprite.h
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Sprite.h
|
||||
*
|
||||
* Created on: Nov 29, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
|
||||
#ifndef MODEL_SPRITE_H_
|
||||
#define MODEL_SPRITE_H_
|
||||
|
||||
#include <utils/Exceptions.h>
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace farmlands {
|
||||
namespace base {
|
||||
|
||||
/**
|
||||
* Defines an animation frame
|
||||
*/
|
||||
struct Frame
|
||||
{
|
||||
uint32_t tileSetId;
|
||||
uint32_t tileSetCell;
|
||||
uint32_t width, height;
|
||||
uint32_t duration;
|
||||
};
|
||||
|
||||
/**
|
||||
* Defines a sprite state (aka an animation).
|
||||
*/
|
||||
struct SpriteState
|
||||
{
|
||||
std::string name;
|
||||
std::vector<Frame> frames;
|
||||
};
|
||||
|
||||
/**
|
||||
* Defines a sprite
|
||||
*/
|
||||
class Sprite
|
||||
{
|
||||
public:
|
||||
Sprite();
|
||||
virtual ~Sprite();
|
||||
|
||||
/**
|
||||
* Adds a state to the sprite.
|
||||
*/
|
||||
void addState(const SpriteState& state);
|
||||
|
||||
/**
|
||||
* Sets the current state.
|
||||
*/
|
||||
void setState(size_t stateId);
|
||||
|
||||
/**
|
||||
* Sets the current state.
|
||||
*/
|
||||
void setState(const std::string& name);
|
||||
|
||||
/**
|
||||
* Advances the current frame
|
||||
*/
|
||||
void advanceTime(uint32_t steps);
|
||||
|
||||
|
||||
// Getters
|
||||
SpriteState& currentState();
|
||||
Frame& currentFrame();
|
||||
|
||||
// Public fields
|
||||
float anchorX, anchorY;
|
||||
std::string name;
|
||||
|
||||
private:
|
||||
std::vector<SpriteState> m_states;
|
||||
std::unordered_map<std::string, size_t> m_stateNames;
|
||||
|
||||
size_t m_currentState;
|
||||
size_t m_currentFrame;
|
||||
uint32_t m_currentFrameTimeLeft;
|
||||
};
|
||||
|
||||
} /* namespace model */
|
||||
} /* namespace farmlands */
|
||||
|
||||
#endif /* MODEL_SPRITE_H_ */
|
24
src/base/Transform.h
Normal file
24
src/base/Transform.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Transform.h
|
||||
*
|
||||
* Created on: Nov 30, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
|
||||
#ifndef BASE_TRANSFORM_H_
|
||||
#define BASE_TRANSFORM_H_
|
||||
|
||||
#include <base/Component.h>
|
||||
|
||||
namespace farmlands {
|
||||
namespace base {
|
||||
|
||||
struct Transform: public Component
|
||||
{
|
||||
float x, y;
|
||||
};
|
||||
|
||||
} /* namespace base */
|
||||
} /* namespace farmlands */
|
||||
|
||||
#endif /* BASE_TRANSFORM_H_ */
|
24
src/base/Viewport.h
Normal file
24
src/base/Viewport.h
Normal file
@ -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_ */
|
Reference in New Issue
Block a user