Sign in to follow this  
bedtime

Composition Based Game Outline. Would like input

Recommended Posts

bedtime    159
I'm redesigning a 2D mario style side-scolling game from scratch. The code compiles with no warnings on -Wall and using C++11. I didn't include .cpp files as they were all blank and just include there header file.

Before I really get into this I would like some input on what I have so far. I'm wondering if I've got the right idea on how to implement composition:

[source lang="cpp"]//main.cpp
#include <iostream>
#include "character.h"

int main()
{

// create character object
Character obj(Name(Title::goodguy), Point(1, 2));

// lets add body parts to build our character
obj.getElement()->makeNew(eName::head);
obj.getElement()->makeNew(eName::arms);
obj.getElement()->makeNew(eName::waist);
obj.getElement()->makeNew(eName::legs);

// print out x position
std::cout << "Point X: " << obj.getPoint()->getX() << std::endl;

// now we'll move the character
obj.getPoint()->setXY(10, 4);

std::cout << "Point X: " << obj.getPoint()->getX() << std::endl;
std::cout << "Dist moved: " << obj.getPoint()->getXDistMoved() << std::endl;

std::cout << "Number of Elements (body parts): " <<
obj.getElement()->getNumElements() << std::endl;

// leg was damaged in fight
obj.getElement()->getElementName(eName::legs)->setHealth(40);

// report on health of legs
std::cout << "Health of legs: " <<
obj.getElement()->getElementName(eName::legs)->getHealth() << std::endl;

// delete the arms because they were shot off
obj.getElement()->deleteElementName(eName::arms);

// how many elements do we have now?
std::cout << "Number of Elements: " <<
obj.getElement()->getNumElements() << std::endl;

std::cout << "" << std::endl;
}[/source]


[source lang="cpp"]// character.h
#ifndef CHARACTER_H
#define CHARACTER_H
#include "name.h"
#include "number.h"
#include "point.h"
#include "element.h"

class Character
{
private:

Name name;
Number ID;
Number player;
Point point;
Point platformPoint;
Element element;

public:

Character() {}

Character(const Name& name, const Point& point)
: name(name), point(point) {}

Character(const Name& name, const Point& pointIn, const Element& element)
: name(name), point(point), element(element) {}

// characters features
Name* getName() { return &name; }
Number* getID() { return &ID; }
Number* getPlayerNum() { return &player; }
Point* getPoint() { return &point; }
Point* getPlatformPoint() { return &platformPoint; }
Element* getElement() { return &element; }

};
#endif[/source]
[source lang="cpp"]//element.h
#ifndef ELEMENT_H
#define ELEMENT_H
#include <map>
#include "properties.h"

enum class eName // element name
{
none,

// good & bad character parts
head,
leftArm,
rightArm,
arms,
waist,
legs,
leftLeg,
rightLeg,

// board & scenery
top,
bottom,
left,
right
};

class Element
{
private:

std::multimap<eName, Properties> vElement; // map array to store elements

public:

Element() {}

Element(const eName& name) {
Properties properties;
vElement.insert({ name, properties });
}

Element(const eName& name, Properties& properties) {
vElement.insert({ name, properties });
}

void makeNew(const eName& name) {
Properties properties;
vElement.insert({ name, properties });
}

void makeNew(const eName& name, Properties& properties) {
vElement.insert({ name, properties });
}


unsigned int getNumElements() const { return vElement.size(); }

// search
Properties* getElementName(eName name) {

std::multimap<eName, Properties>::iterator it;
it = vElement.find(name);

// make sure element exists
if(it != vElement.end())
return &it->second;

// element name doesn't exist so make a new one
Properties *properties = new Properties;
vElement.insert({ name, (*properties) });

return properties;
}


// delete
void deleteElementName(eName name) { vElement.erase(name); }

};

#endif[/source]
[source lang="cpp"]// name.h
#ifndef NAME_H
#define NAME_H

enum class Title
{
goodguy,
badguy,
scenery,
item,
weapon,
custom,
null
};

class Name
{
private:

Title title;

public:

Name(const Title& name = Title::null) : title(name) {};
~Name() {}

};

#endif[/source]
[source lang="cpp"]// properties.h
#ifndef PROPERTIES_H
#define PROPERTIES_H
#include "point.h"

enum class viscosity { normal, slippery, sticky};
enum class solidity { solid, upPass, downPass, rightPass, leftPass, invisible, semi };
enum class visibility { visible, invisible, semiVisisble };

class Properties
{
private:

Point relativePoint; // xy point relative to general xy position
unsigned int health;

public:

// constructor/destructor
Properties() : health(100) {};
~Properties() {}

void setHealth(const unsigned int& i) { health = i; }
unsigned int getHealth() { return health; }


};

#endif[/source]
[source lang="cpp"]// point.h
#ifndef POINT_H
#define POINT_H

class Point
{
private:

int x;
int y;
int lastX;
int lastY;

public:

// constructor/destructor
Point(const int& x = 0, const int& y = 0) : x(x), y(y), lastX(0), lastY(0) {};
~Point() {}

// set/get individually
void setX(const int& i) { lastX = x; x = i; }
int getX() const { return x; }
void setY(const int& i) { lastY = y; y = i; }
int getY() const { return y; }

// set/get as a pair
void setXY(const int& x, const int& y){
lastX = this->x;
lastY = this->y;
this->x = x;
this->y = y;
}

// set/get using an object
void setTo(Point& point){
lastX = x;
lastY = y;
x = point.getX();
y = point.getY();
}

// compare x/y difference to another object
int getCompareX(Point& point) { return point.getX() - this->x; }
int getCompareY(Point& point) { return point.getY() - this->y; }

// calculate distance moved
int getXDistMoved() { return this->x - lastX; }
int getYDistMoved() { return this->y - lastY; }

// @TODO - record function records all moves

};

#endif[/source]

[source lang="cpp"]// number.h
#ifndef NUMBER_H
#define NUMBER_H

class Number
{
private:

int num;

public:

// constructor/destructor
Number(const int& num = 0) : num(num) {}

// set/get individually
void setNum(const int& num) { this->num = num; }
int getNum() const { return num; }

};

#endif[/source]

Share this post


Link to post
Share on other sites
bedtime    159
[quote name='kd7tck' timestamp='1353489255' post='5002870']
keeping track of limbs might be too much. Just use sprite sheets and animate that way, simple sometimes is better.
[/quote]
Thanks. I havent used a graphics program yet so I didnt know this. Though I question if they will allow the same kind of flexibility and options I'm getting right now.

All,

No other comments? I assume I'm way off base here when I don't get replies.

Share this post


Link to post
Share on other sites
uglybdavis    1065
There is no right or wrong answer. Whatever makes sense to you is the right way. Do it, and learn from your mistakes.

With that being said, i think your idea of composition is a little too textbook (Personal opinion). Maybe look at some tutorials of what other people are doing. I think this one does a good job of showing how you can use composition in a 2d engine (Obvious issues with the code, but you should be able to work past that) http://www.inverted-keystrokes.com/2012/02/11/2d-game-engine-tutorial-component-based-entity-systems/ It's worth reading all the posted parts of the tutorial.

Share this post


Link to post
Share on other sites
BeerNutts    4401
I've been into CBES (Component-Based Entity Systems) for a while. What you have would not be called a CBES. You're Character Object is a traditional object which has defined parts to it. Rather, you should have a totally Generic Entity which hold different components types, like:
Player: This Component is what makes your Player be the Hero.
Animation: This defines how your player animates based on the Player's State
PhysicalObject: This is what holds all the physical properties of your player; Location, Velocity, Mass, Size, etc.
Weapon: This handles the weapon the player uses
etc.

Then, there are 2 schools of though on how to control the component; One if the components have all the logic in them, but this requires communication between components (ie, the Weapon Component needs to know where the player is in the world from the PhysicalObject to fire a bullet form that location). It's doable (see my Journal for examples), but I believe I prefer the 2nd method
You can also have the components ONLY hold data, and design Systems that act on and modify the data. So, you would have a Weapon System that gets updated with the entity, and it handles firing the bullet for any entity that has the Weapon component.

You are welcome to look at my Journal (link in my sig) as I've detailed both methods of CBES. It takes a bit to get your head around to really thinking in Components making up the entities, but once you do, you'll be able to see the benefits.

BTW, [url="http://blog.wujitouch.com/post/ComponentEntity-System-Frameworks.aspx"]here's a link[/url] to some articles about Entity Systems, and links to some externally developed Entity Systems Edited by BeerNutts

Share this post


Link to post
Share on other sites
bedtime    159
[quote name='uglybdavis' timestamp='1353521782' post='5002966']
There is no right or wrong answer. Whatever makes sense to you is the right way. Do it, and learn from your mistakes.

With that being said, i think your idea of composition is a little too textbook (Personal opinion). Maybe look at some tutorials of what other people are doing. I think this one does a good job of showing how you can use composition in a 2d engine (Obvious issues with the code, but you should be able to work past that) [url="http://www.inverted-keystrokes.com/2012/02/11/2d-game-engine-tutorial-component-based-entity-systems/"]http://www.inverted-...entity-systems/[/url] It's worth reading all the posted parts of the tutorial.
[/quote]
Thank you so much for that link. I've read the article and have been implimenting the changes. It took me a couple reads to understand what was going on but I finally get it. I wanted to make sure I understood before I replied again.

[quote name='BeerNutts' timestamp='1353531956' post='5003020']
I've been into CBES (Component-Based Entity Systems) for a while. What you have would not be called a CBES. You're Character Object is a traditional object which has defined parts to it. Rather, you should have a totally Generic Entity which hold different components types, like:
Player: This Component is what makes your Player be the Hero.
Animation: This defines how your player animates based on the Player's State
PhysicalObject: This is what holds all the physical properties of your player; Location, Velocity, Mass, Size, etc.
Weapon: This handles the weapon the player uses
etc.

Then, there are 2 schools of though on how to control the component; One if the components have all the logic in them, but this requires communication between components (ie, the Weapon Component needs to know where the player is in the world from the PhysicalObject to fire a bullet form that location). It's doable (see my Journal for examples), but I believe I prefer the 2nd method
You can also have the components ONLY hold data, and design Systems that act on and modify the data. So, you would have a Weapon System that gets updated with the entity, and it handles firing the bullet for any entity that has the Weapon component.

You are welcome to look at my Journal (link in my sig) as I've detailed both methods of CBES. It takes a bit to get your head around to really thinking in Components making up the entities, but once you do, you'll be able to see the benefits.

BTW, [url="http://blog.wujitouch.com/post/ComponentEntity-System-Frameworks.aspx"]here's a link[/url] to some articles about Entity Systems, and links to some externally developed Entity Systems
[/quote]

I used information from uglybdavis's link and now there is a generic entity. As for the controlling components I am likely going to go with components only holding the data and being modified by another system. I haven't yet looked at your link, but I will. This is kinda information overload for me ATM as I'm new to this.

I do see the results already. It's so much easier to make changes. The classes are much smaller and easier to manage. And I've made a number class and point class that have made great use of reusing code and go by the philosopy 'do one thing and do it well'. I much prefere this approach.

Share this post


Link to post
Share on other sites
bedtime    159
I've looked into Cistron and while it looks awesome and seems to be what I'm looking for I have a tr1 compatibility issue in Linux so it's useless to me unless I can find a way to install. A bug report was sent about a year ago on the issue. Seems to be a Duke Nukem forever sitation.

Apart from that I've spent days trying to fingure out how to use pure virtual functions without issues and it's becoming frustrating. I'm doing something wrong. Anyways, starting from scratch again...

If anyone knows of a really simple example with all files included (main as well) and without SDL included I would be grateful. At this point I'm just causing myself a headache. Sorry to sound so bummed.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this