Jump to content

  • Log In with Google      Sign In   
  • Create Account


Composition Based Game Outline. Would like input


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
6 replies to this topic

#1 bedtime   Members   -  Reputation: 159

Like
0Likes
Like

Posted 20 November 2012 - 12:31 PM

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 elementspublic: 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_Henum 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_Hclass 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_Hclass 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]

Sponsor:

#2 kd7tck   Members   -  Reputation: 715

Like
1Likes
Like

Posted 21 November 2012 - 03:14 AM

keeping track of limbs might be too much. Just use sprite sheets and animate that way, simple sometimes is better.

#3 bedtime   Members   -  Reputation: 159

Like
0Likes
Like

Posted 21 November 2012 - 04:56 AM

keeping track of limbs might be too much. Just use sprite sheets and animate that way, simple sometimes is better.

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.

#4 uglybdavis   Members   -  Reputation: 901

Like
1Likes
Like

Posted 21 November 2012 - 12:16 PM

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.

#5 BeerNutts   Crossbones+   -  Reputation: 2758

Like
1Likes
Like

Posted 21 November 2012 - 03:05 PM

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, here's a link to some articles about Entity Systems, and links to some externally developed Entity Systems

Edited by BeerNutts, 21 November 2012 - 03:36 PM.

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

#6 bedtime   Members   -  Reputation: 159

Like
0Likes
Like

Posted 22 November 2012 - 07:56 AM

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-...entity-systems/ It's worth reading all the posted parts of the tutorial.

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.

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, here's a link to some articles about Entity Systems, and links to some externally developed Entity Systems


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.

#7 bedtime   Members   -  Reputation: 159

Like
0Likes
Like

Posted 24 November 2012 - 09:15 AM

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.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS