Skip to content

Instantly share code, notes, and snippets.

@voidproc
Created September 19, 2016 11:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save voidproc/29fa09a7a38bba7b827c45bdd4f39596 to your computer and use it in GitHub Desktop.
Save voidproc/29fa09a7a38bba7b827c45bdd4f39596 to your computer and use it in GitHub Desktop.
Simple game object container
#include <iostream>
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
#include <list>
#include <unordered_map>
using namespace std;
/* ----------------------------------------
Shared data
---------------------------------------- */
struct Data
{
int val = 0;
};
/* ----------------------------------------
Entity
---------------------------------------- */
class Entity
{
public:
Entity() = default;
virtual ~Entity() = default;
virtual void update() {}
static Data data;
};
Data Entity::data;
/* ----------------------------------------
Actor
---------------------------------------- */
class Actor : public Entity
{
public:
Actor() : Entity()
{
}
virtual ~Actor() = default;
virtual void update() override {}
virtual const bool collidable() { return false; }
virtual void collide(Actor* e) {}
int pos = 0;
string name = "";
};
/* ----------------------------------------
Global entity container
---------------------------------------- */
class EntityList
{
public:
template <class T, class ... Args>
static void push_back(const string& tag, Args && ... args)
{
instance().e_[tag].emplace_back(new T(std::forward<Args>(args) ...));
}
static void pop_back(const string& tag)
{
instance().e_[tag].pop_back();
}
static shared_ptr<Entity> back(const string& tag)
{
return instance().e_[tag].back();
}
static const bool empty(const string& tag)
{
return instance().e_[tag].empty();
}
static void update(const string& tag)
{
for (auto& e : instance().e_[tag])
{
e->update();
}
}
static void checkCollision(const string& tag1, const string& tag2)
{
// CAUTION: 'tag1' and 'tag2' groups must be derived from Actor.
for (auto& e1 : instance().e_[tag1])
{
Actor* a1 = dynamic_cast<Actor*>(e1.get());
if (!a1->collidable()) { continue; }
for (auto& e2 : instance().e_[tag2])
{
Actor* a2 = dynamic_cast<Actor*>(e2.get());
if (!a2->collidable()) { continue; }
if (a1->pos == a2->pos)
{
a1->collide(a2);
a2->collide(a1);
}
}
}
}
private:
static EntityList& instance()
{
static EntityList instance;
return instance;
}
unordered_map<string, list<shared_ptr<Entity>>> e_;
};
/* ----------------------------------------
Entities derived
---------------------------------------- */
class Player : public Actor
{
public:
Player(const int pos) : Actor()
{
this->pos = pos;
name = "player";
}
virtual ~Player() = default;
virtual void update() override
{
data.val += 1; // shared data
cout << "Player updated [" << data.val << "]\n";
}
virtual const bool collidable() override { return true; }
virtual void collide(Actor* e) override
{
cout << "Player collide: " << e->name << "\n";
}
};
class Enemy : public Actor
{
public:
Enemy(const string& name, const int pos) : Actor()
{
this->pos = pos;
this->name = name;
}
virtual ~Enemy() = default;
virtual void update() override
{
data.val += 5; // shared data
cout << name << " updated [" << data.val << "]\n";
}
virtual const bool collidable() override { return true; }
virtual void collide(Actor* e) override
{
cout << name << " collide: " << e->name << "\n";
}
};
class Fx : public Actor
{
public:
Fx(const string& name, const int pos) : Actor()
{
this->pos = pos;
this->name = name;
}
virtual ~Fx() = default;
virtual void update() override
{
cout << name << " updated\n";
}
};
class Init : public Entity
{
public:
Init() : Entity()
{
data.val = 100000;
}
virtual ~Init() = default;
};
/* ----------------------------------------
Scenes
---------------------------------------- */
class SceneEnd;
class SceneMain : public Entity
{
public:
SceneMain() : Entity()
{
}
virtual ~SceneMain() = default;
virtual void update() override
{
cout << "Scene 'Main'\n";
// Generate actors
EntityList::push_back<Player>("player", 10);
EntityList::push_back<Enemy>("enemy", "enemy1", 10); // collide this
EntityList::push_back<Enemy>("enemy", "enemy2", 20);
EntityList::push_back<Enemy>("enemy", "enemy3", 30);
EntityList::push_back<Enemy>("enemy", "enemy4", 10); // collide this
EntityList::push_back<Fx>("effect", "fx1", 10);
EntityList::push_back<Fx>("effect", "fx2", 20);
EntityList::push_back<Fx>("effect", "fx3", 30);
// Update actors
EntityList::update("player");
EntityList::update("enemy");
EntityList::update("effect");
EntityList::checkCollision("player", "enemy");
// Change scene
EntityList::pop_back("scene");
EntityList::push_back<SceneEnd>("scene");
}
};
class SceneEnd : public Entity
{
public:
SceneEnd() : Entity()
{
}
virtual ~SceneEnd() = default;
virtual void update() override
{
cout << "Scene 'End'\n";
// Quit app
EntityList::pop_back("scene");
}
};
/* ----------------------------------------
Main
---------------------------------------- */
int main()
{
Init();
// Start
EntityList::push_back<SceneMain>("scene");
while (!EntityList::empty("scene"))
{
EntityList::back("scene")->update();
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment