Reorganized classes & namespaces. Made sprite a component.

This commit is contained in:
2016-12-02 22:20:04 +02:00
parent f255905c73
commit 33de4a8d1f
51 changed files with 648 additions and 580 deletions

View File

@@ -1,80 +0,0 @@
/*
* Background.cpp
*
* Created on: Dec 1, 2016
* Author: tibi
*/
#include <model/Background.h>
#include <utils/Assert.h>
#include <iostream>
namespace farmlands {
namespace model {
Background::Background(size_t layerCount, size_t rowCount, size_t columnCount)
: m_cells(new Cell[layerCount * rowCount * columnCount]),
m_textures(new resources::ResourceId[layerCount]),
m_layers(layerCount),
m_rows(rowCount),
m_columns(columnCount)
{
}
Background::~Background()
{
delete[] m_cells;
delete[] m_textures;
}
base::Component* Background::clone()
{
Background* clone = new Background(m_layers, m_rows, m_columns);
memcpy(clone->m_cells, m_cells, sizeof(Cell) * m_layers * m_rows * m_columns);
memcpy(clone->m_textures, m_textures, sizeof(resources::ResourceId) * m_layers);
return clone;
}
Cell Background::cell(size_t layer, size_t row, size_t col) const
{
Assert(layer < m_layers, "Layer out of bounds.");
Assert(row < m_rows, "Row out of bounds.");
Assert(col < m_columns, "Column out of bounds.");
return m_cells[layer * m_rows * m_columns + row * m_columns + col];
}
void Background::setCell(size_t layer, size_t row, size_t col, Cell value)
{
Assert(layer < m_layers, "Layer out of bounds.");
Assert(row < m_rows, "Row out of bounds.");
Assert(col < m_columns, "Column out of bounds.");
m_cells[layer * m_rows * m_columns + row * m_columns + col] = value;
}
resources::ResourceId Background::texture(size_t layer) const
{
Assert(layer < m_layers, "Layer out of bounds.");
return m_textures[layer];
}
void Background::setTexture(size_t layer, resources::ResourceId textureId) const
{
Assert(layer < m_layers, "Layer out of bounds.");
m_textures[layer] = textureId;
}
void Background::dump(unsigned level)
{
for (unsigned i = 0; i < level; i++)
std::cout<<" ";
std::cout << " .Component: Background\n";
}
} /* namespace model */
} /* namespace farmlands */

View File

@@ -1,49 +0,0 @@
/*
* Background.h
*
* Created on: Dec 1, 2016
* Author: tibi
*/
#ifndef MODEL_BACKGROUND_H_
#define MODEL_BACKGROUND_H_
#include <base/Component.h>
#include <resources/ResourceManager.h>
namespace farmlands {
namespace model {
typedef int16_t Cell;
class Background: public base::Component
{
public:
Background(size_t layerCount, size_t rowCount, size_t columnCount);
virtual ~Background();
virtual base::Component* clone() override;
virtual void dump(unsigned level) override;
inline size_t layerCount() const { return m_layers; }
inline size_t rowCount() const { return m_rows; }
inline size_t columnCount() const { return m_columns; }
Cell cell(size_t layer, size_t row, size_t col) const;
void setCell(size_t layer, size_t row, size_t col, Cell value);
resources::ResourceId texture(size_t layer) const;
void setTexture(size_t layer, resources::ResourceId textureId) const;
private:
Cell* m_cells;
resources::ResourceId* m_textures;
size_t m_layers;
size_t m_rows;
size_t m_columns;
};
} /* namespace model */
} /* namespace farmlands */
#endif /* MODEL_BACKGROUND_H_ */

67
src/model/Component.cpp Normal file
View File

@@ -0,0 +1,67 @@
/*
* Component.cpp
*
* Created on: Nov 30, 2016
* Author: tibi
*/
#include <model/Component.h>
namespace farmlands {
namespace model {
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()
{
}
void Component::onEnable()
{
}
void Component::onDisable()
{
}
}
/* namespace model */
} /* namespace farmlands */

50
src/model/Component.h Normal file
View File

@@ -0,0 +1,50 @@
/*
* Component.h
*
* Created on: Nov 30, 2016
* Author: tibi
*/
#ifndef COMPONENT_H_
#define COMPONENT_H_
#include <model/ICloneable.h>
#include <model/INonAssignable.h>
#include <SDL2/SDL.h>
namespace farmlands {
namespace model {
class GameObject;
class Component : public INonAssignable, public ICloneable<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();
virtual void onEnable();
virtual void onDisable();
// Print info to screen
virtual void dump(unsigned level) = 0;
GameObject* gameObject;
};
}
/* namespace model */
} /* namespace farmlands */
#endif /* COMPONENT_H_ */

305
src/model/GameObject.cpp Normal file
View File

@@ -0,0 +1,305 @@
/*
* GameObject.cpp
*
* Created on: Nov 30, 2016
* Author: tibi
*/
#include <GameState.h>
#include <model/GameObject.h>
#include <model/Component.h>
#include <iostream>
namespace farmlands {
namespace model {
GameObject::GameObject()
: name("unnamed"),
visible(true),
m_components(),
m_children(),
m_parent(nullptr),
m_enabled(false)
{
}
GameObject* GameObject::clone()
{
GameObject* clone = new GameObject();
clone->visible = visible;
// Clone components
for (auto pair : m_components)
{
Component* compClone = pair.second->clone();
compClone->gameObject = clone;
clone->m_components.emplace(pair.first, compClone);
}
// Clone components
for (auto child : m_children)
clone->addChild(child->clone());
return clone;
}
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;
}
}
GameObject* GameObject::instantiate(GameObject* gameObject, std::string name, GameObject* parent)
{
Assert(gameObject != nullptr, "Can't instantiate a null object!");
Assert(parent != nullptr, "Parent cannot be null!");
// Clone object
GameObject* instance = gameObject->clone();
instance->name = name;
parent->addChild(instance);
// Call methods
instance->onCreate();
if (GameState::current().gameInitialized)
instance->onInitialize();
return instance;
}
void GameObject::addChild(GameObject* obj)
{
m_children.push_back(obj);
obj->m_parent = this;
}
GameObject* GameObject::removeChild(GameObject::iterator it)
{
m_children.erase(it);
return *it;
}
GameObject* GameObject::removeChild(GameObject* obj)
{
for (auto it = m_children.begin(); it != m_children.end(); it++)
{
if (*it == obj)
{
m_children.erase(it);
return *it;
}
}
return nullptr;
}
void GameObject::destroyChild(GameObject::iterator it)
{
delete *it;
m_children.erase(it);
}
void GameObject::destroyChild(GameObject* obj)
{
for (auto it = m_children.begin(); it != m_children.end(); it++)
{
if (*it == obj)
{
delete *it;
m_children.erase(it);
return;
}
}
}
size_t GameObject::childrenSize() const
{
return m_children.size();
}
GameObject::iterator GameObject::childrenBegin()
{
return m_children.begin();
}
GameObject::iterator GameObject::childrenEnd()
{
return m_children.end();
}
GameObject* GameObject::parent()
{
return m_parent;
}
void GameObject::onCreate()
{
// Enable self
setEnabled(true);
// 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++)
if ((*it)->m_enabled)
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)
if (child->m_enabled)
child->onUpdateLogic();
}
void GameObject::onPreRender()
{
// Call components
for (auto pair : m_components)
pair.second->onPreRender();
// Call children
for (auto child : m_children)
if (child->m_enabled && child->visible)
child->onPreRender();
}
void GameObject::onRender()
{
// Call components
for (auto pair : m_components)
pair.second->onRender();
// Call children
for (auto child : m_children)
if (child->m_enabled && child->visible)
child->onRender();
}
void GameObject::onPostRender()
{
// Call components
for (auto pair : m_components)
pair.second->onPostRender();
// Call children
for (auto child : m_children)
if (child->m_enabled && child->visible)
child->onPostRender();
}
void GameObject::onEnable()
{
// Call components
for (auto pair : m_components)
pair.second->onEnable();
// Call children
for (auto child : m_children)
if (child->enabled())
child->onEnable();
}
void GameObject::onDisable()
{
// Call components
for (auto pair : m_components)
pair.second->onDisable();
// Call children
for (auto child : m_children)
if (child->enabled())
child->onDisable();
}
void GameObject::onDestroy()
{
// Don't call onDestroy on children/components
// because it will be called in the destructor
}
void GameObject::setEnabled(bool enabled)
{
// Don't set again
if (m_enabled == enabled)
return;
m_enabled = enabled;
// If parent is disabled, we are disabled
if (m_parent == nullptr || m_parent->enabled())
{
// Call onEnable/onDisable
if (enabled) onEnable();
else onDisable();
}
}
void GameObject::dumpTree(unsigned level)
{
// Print spaces
for (unsigned i = 0; i < level; i++)
std::cout<<" ";
// Game object info
std::cout << "* GameObject: " << name << "[";
std::cout << ((m_enabled) ? "e" : " ") << "][";
std::cout << ((visible) ? "v" : " ") << "]\n";
// Components
for (auto component : m_components)
component.second->dump(level);
for (auto child : m_children)
child->dumpTree(level + 1);
}
} /* namespace model */
} /* namespace farmlands */

143
src/model/GameObject.h Normal file
View File

@@ -0,0 +1,143 @@
/*
* GameObject.h
*
* Created on: Nov 30, 2016
* Author: tibi
*/
#ifndef GAMEOBJECT_H_
#define GAMEOBJECT_H_
#include <model/ICloneable.h>
#include <model/INonAssignable.h>
#include <utils/Assert.h>
#include <SDL2/SDL.h>
#include <typeindex>
#include <vector>
#include <unordered_map>
namespace farmlands {
namespace model {
class Component;
class RenderContext;
class GameObject : public INonAssignable, public ICloneable<GameObject>
{
public:
typedef std::vector<GameObject*>::iterator iterator;
// Constructors
GameObject();
virtual ~GameObject();
virtual GameObject* clone() override;
static GameObject* instantiate(GameObject* gameObject, std::string name, GameObject* parent);
// Components API
template <typename T> T* component();
template <typename T> bool haveComponent();
template <typename T> void addComponent(T* component);
template <typename T> void removeComponent();
// Tree methods
void addChild(GameObject* obj);
GameObject* removeChild(iterator it);
GameObject* removeChild(GameObject* obj);
void destroyChild(iterator it);
void destroyChild(GameObject* obj);
size_t childrenSize() const;
iterator childrenBegin();
iterator childrenEnd();
GameObject* parent();
// Game object methods
void onCreate();
void onInitialize();
bool onEvent(SDL_Event& event);
void onUpdateLogic();
void onPreRender();
void onRender();
void onPostRender();
void onDestroy();
void onEnable();
void onDisable();
// Getters, setters
inline bool enabled() const { return m_enabled; }
void setEnabled(bool enabled);
// Debugging
void dumpTree(unsigned level = 0);
// Other properties
std::string name;
bool visible;
private:
// Components
std::unordered_map<std::type_index, Component*> m_components;
// Tree
std::vector<GameObject*> m_children;
GameObject* m_parent;
// Properties
bool m_enabled;
};
template <typename T>
T* GameObject::component()
{
// Compute type index
std::type_index typeIndex(typeid(T));
// Get component
auto it = m_components.find(typeIndex);
if (it == m_components.end())
return nullptr;
T* comp = dynamic_cast<T*> (it->second);
// Done
Assert(comp != nullptr, "This is bad!!! Type of component is really messed up!!!");
return comp;
}
template <typename T>
bool GameObject::haveComponent()
{
// Compute type index
std::type_index typeIndex(typeid(T));
// Get component
auto it = m_components.find(typeIndex);
return it != m_components.end();
}
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>
void GameObject::removeComponent()
{
std::type_index typeIndex(typeid(T));
return m_components.erase(typeIndex);
}
} /* namespace model */
} /* namespace farmlands */
#endif /* GAMEOBJECT_H_ */

27
src/model/ICloneable.h Normal file
View File

@@ -0,0 +1,27 @@
/*
* ICloneable.h
*
* Created on: Dec 2, 2016
* Author: tibi
*/
#ifndef BASE_ICLONEABLE_H_
#define BASE_ICLONEABLE_H_
namespace farmlands {
namespace model {
template <typename T>
class ICloneable
{
public:
virtual ~ICloneable() { };
virtual T* clone() = 0;
};
}
}
#endif /* BASE_ICLONEABLE_H_ */

View File

@@ -0,0 +1,28 @@
/*
* INonAssignable.h
*
* Created on: Dec 2, 2016
* Author: tibi
*/
#ifndef BASE_INONASSIGNABLE_H_
#define BASE_INONASSIGNABLE_H_
namespace farmlands {
namespace model {
class INonAssignable
{
public:
virtual ~INonAssignable() { };
INonAssignable() { }
INonAssignable(const INonAssignable&) = delete;
INonAssignable& operator=(const INonAssignable&) = delete;
};
}
}
#endif /* BASE_INONASSIGNABLE_H_ */

View File

@@ -1,65 +0,0 @@
/*
* Item.h
*
* Created on: Dec 2, 2016
* Author: tibi
*/
#ifndef MODEL_ITEM_H_
#define MODEL_ITEM_H_
#include <base/Component.h>
#include <iostream>
namespace farmlands {
namespace model {
class Item: public base::Component
{
public:
Item();
virtual ~Item();
virtual base::Component* clone() override;
virtual void dump(unsigned level) override;
std::string name;
std::string description;
uint8_t level;
};
/****** Implementation ******/
inline Item::Item()
: name(), description(),
level(0)
{
}
inline Item::~Item()
{
}
inline base::Component* Item::clone()
{
Item* clone = new Item();
clone->name = name;
clone->description = description;
clone->level = level;
return clone;
}
inline void Item::dump(unsigned level)
{
for (unsigned i = 0; i < level; i++)
std::cout<<" ";
std::cout << " .Component: Item\n";
}
} /* namespace model */
} /* namespace farmlands */
#endif /* MODEL_ITEM_H_ */

View File

@@ -8,7 +8,7 @@
#ifndef MODEL_SCENE_H_
#define MODEL_SCENE_H_
#include <base/GameObject.h>
#include <model/GameObject.h>
#include <vector>
@@ -18,7 +18,7 @@ namespace model {
struct Scene
{
uint32_t cellWidth = 1, cellHeight = 1;
base::GameObject root;
model::GameObject root;
};
} /* namespace model */

24
src/model/Viewport.h Normal file
View 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 model {
struct Viewport
{
bool initialized = false;
int width, height;
float pixelsPerUnitX, pixelsPerUnitY;
};
}
}
#endif /* MODEL_VIEWPORT_H_ */