Page 2 of 2
Re: Game Engine Troubles
Posted: Sun Dec 19, 2010 11:04 am
by lotios611
I have another problem with my game engine. I'm trying to implement a component system, but I can't get it to work. I have a base component class that's empty and a RenderComponent class that inherits from it and adds a char* called text. When I try to change the value of the char* I get this error:
error C2039: 'text' : is not a member of 'SE::Component'
Here's some code:
main.cpp
Code: Select all
#include "SE_RenderComponent.h"
#include "SE_Entity.h"
#include "SE_Engine.h"
#include "SDL.h"
int main()
{
SE::Engine engine;
SE::RenderComponent *renderComponent;
SE::Entity entity;
entity.addComponent(renderComponent);
entity.getComponent(renderComponent)->text = "This was a triumph";
SDL_Delay(1000);
entity.getComponent(renderComponent)->text = "I'm making a note here";
SDL_Delay(1000);
entity.getComponent(renderComponent)->text = "HUGE SUCCESS";
SDL_Delay(2000);
return engine.mainLoop();
}
SE_Entity.h
Code: Select all
#ifndef SE_ENITY_H
#define SE_ENTIY_H
#include <vector>
#include <algorithm>
#include "SE_Component.h"
namespace SE
{
class Entity
{
public:
void addComponent(SE::Component* component);
SE::Component* getComponent(SE::Component* component);
private:
std::vector<SE::Component*> components;
};
}
#endif
SE_Entity.cpp
Code: Select all
#include "SE_Entity.h"
void SE::Entity::addComponent(SE::Component* component)
{
components.push_back(component);
}
SE::Component* SE::Entity::getComponent(SE::Component* component)
{
for (int i = 0; i < (int)*components.end(); i++)
{
if (components.at(i) == component)
{
return component;
}
}
}
SE_Component.h
Code: Select all
#ifndef SE_COMPONENT_H
#define SE_COMPONENT_H
namespace SE
{
class Component
{
public:
};
}
#endif
SE_RenderComponent.h
Code: Select all
#ifndef SE_RENDER_COMPONENT_H
#define SE_RENDER_COMPONENT_H
#include "SE_Component.h"
namespace SE
{
class RenderComponent : public Component
{
public:
char *text;
private:
};
}
#endif
Re: Game Engine Troubles
Posted: Sun Dec 19, 2010 11:13 am
by thejahooli
This is because your 'getComponent' function returns a Component object, not a RenderComponent, so you can only access the Component section of renderComponent.
You could fix this by casting it as a RenderComponent as such
Code: Select all
((RenderComponent)entity.getComponent(renderComponent))->text = "This was a triumph";
However I do not personally think this is the best option, but I cannot think of an alternative off the top of my head.
Re: Game Engine Troubles
Posted: Mon Dec 20, 2010 5:24 am
by lotios611
That code works, but I also don't know if that's the best solution.
Re: Game Engine Troubles
Posted: Mon Dec 20, 2010 6:53 am
by MrDeathNote
The only problem is type checking, if you cast the component without knowing the type, bad thing's can happen. In mine i have a type variable so i can check the type before a cast(but i never like to do this and i haven't done it at all in my engine so far), but all my component's also inherit from an abstract base class which defines the functions i'll need. Then i just work my distinct components into the limitations of the base class meaning every component will have those functions.
Re: Game Engine Troubles
Posted: Mon Dec 20, 2010 2:02 pm
by Falco Girgis
Welcome to having no runtime type-identification and no metatdata in a statically compiled language.
Even the Unity Engine requires you cast its components down when using the generic "getComponent()" function. You have a few options:
1) deal with it
2) activate runtime-type identification and down cast before returning the component in your getComponent() (bad idea)
3) give your Entity class getRenderComponent(), getCollisionComponent(), and get methods returning specific types
4) template your getComponent method to return a specific component depending on the type (essentially the same as above with syntactic candy).
Personally, in ES, we use method #3. I know it seems counterintuitive, as you are no longer able to dynamically add components that weren't part of the engine, but that's not quite the case with ES. Every user-defined component inherits from "Behavior" (which inherits from "Component"). So we are able to hardcode get functions for components that are part of the engine then use down-casting with getBehavior for user-defined components that were added at run-time.
Re: Game Engine Troubles
Posted: Mon Dec 20, 2010 3:55 pm
by XianForce
GyroVorbis wrote:Welcome to having no runtime type-identification and no metatdata in a statically compiled language.
Even the Unity Engine requires you cast its components down when using the generic "getComponent()" function. You have a few options:
1) deal with it
2) activate runtime-type identification and down cast before returning the component in your getComponent() (bad idea)
3) give your Entity class getRenderComponent(), getCollisionComponent(), and get methods returning specific types
4) template your getComponent method to return a specific component depending on the type (essentially the same as above with syntactic candy).
Personally, in ES, we use method #3. I know it seems counterintuitive, as you are no longer able to dynamically add components that weren't part of the engine, but that's not quite the case with ES. Every user-defined component inherits from "Behavior" (which inherits from "Component"). So we are able to hardcode get functions for components that are part of the engine then use down-casting with getBehavior for user-defined components that were added at run-time.
Hmm, I never thought about using a template on that method... That's a great idea though :D.
But just to do a bit of prodding; So your Behavior class is just a base for scripted components? Or for statically compiled code that's separate for the engine? Or perhaps both
?
Re: Game Engine Troubles
Posted: Mon Dec 20, 2010 3:59 pm
by Falco Girgis
XianForce wrote:GyroVorbis wrote:Welcome to having no runtime type-identification and no metatdata in a statically compiled language.
Even the Unity Engine requires you cast its components down when using the generic "getComponent()" function. You have a few options:
1) deal with it
2) activate runtime-type identification and down cast before returning the component in your getComponent() (bad idea)
3) give your Entity class getRenderComponent(), getCollisionComponent(), and get methods returning specific types
4) template your getComponent method to return a specific component depending on the type (essentially the same as above with syntactic candy).
Personally, in ES, we use method #3. I know it seems counterintuitive, as you are no longer able to dynamically add components that weren't part of the engine, but that's not quite the case with ES. Every user-defined component inherits from "Behavior" (which inherits from "Component"). So we are able to hardcode get functions for components that are part of the engine then use down-casting with getBehavior for user-defined components that were added at run-time.
Hmm, I never thought about using a template on that method... That's a great idea though :D.
But just to do a bit of prodding; So your Behavior class is just a base for scripted components? Or for statically compiled code that's separate for the engine? Or perhaps both
?
Both. We support the ability to dynamically add components as statically compiled C++ classes or as Lua scripts. They both inherit from behavior.
Re: Game Engine Troubles
Posted: Mon Dec 20, 2010 6:38 pm
by eatcomics
GyroVorbis wrote:XianForce wrote:
Hmm, I never thought about using a template on that method... That's a great idea though :D.
But just to do a bit of prodding; So your Behavior class is just a base for scripted components? Or for statically compiled code that's separate for the engine? Or perhaps both
?
Both. We support the ability to dynamically add components as statically compiled C++ classes or as Lua scripts. They both inherit from behavior.
mmmm, juicy
God am I glad I picked now to get back to programming...
Re: Game Engine Troubles
Posted: Mon Dec 20, 2010 10:22 pm
by XianForce
eatcomics wrote:GyroVorbis wrote:XianForce wrote:
Hmm, I never thought about using a template on that method... That's a great idea though :D.
But just to do a bit of prodding; So your Behavior class is just a base for scripted components? Or for statically compiled code that's separate for the engine? Or perhaps both
?
Both. We support the ability to dynamically add components as statically compiled C++ classes or as Lua scripts. They both inherit from behavior.
mmmm, juicy
God am I glad I picked now to get back to programming...
Same thing is going through my mind right now :D
Re: Problems Encountered While Developing a Game Engine
Posted: Mon Dec 27, 2010 6:30 pm
by lotios611
I've decided to rename this thread so that if anybody has issues with designing a game engine, they can come to this thread to ask questions. I'm going to ask the first question.
As you all know, I've been developing a game engine for the past few weeks and have been trying to implement a Component System. I'm almost done with my implementation, but unfortunately my code won't compile when I test out my game engine. I get the following error messages:
c:\programming\c++\splinter games\splinter sdk\splinterengine\source\se_entity.h(12) : error C2011: 'SE::Entity' : 'class' type redefinition
c:\programming\c++\splinter games\splinter sdk\splinterengine\source\se_entity.h(12) : see declaration of 'SE::Entity'
c:\programming\c++\splinter games\pickin' sticks\main.cpp(11) : error C2079: 'entity' uses undefined class 'SE::Entity'
c:\programming\c++\splinter games\pickin' sticks\main.cpp(13) : error C2228: left of '.addComponent' must have class/struct/union
type is 'int'
c:\programming\c++\splinter games\pickin' sticks\main.cpp(14) : error C2664: 'SE::System::addEntity' : cannot convert parameter 1 from 'int' to 'SE::Entity'
Source or target has incomplete type
c:\programming\c++\splinter games\pickin' sticks\main.cpp(16) : error C2228: left of '.getRenderComponent' must have class/struct/union
type is 'int'
c:\programming\c++\splinter games\pickin' sticks\main.cpp(16) : error C2228: left of '.text' must have class/struct/union
c:\programming\c++\splinter games\pickin' sticks\main.cpp(18) : error C2228: left of '.getRenderComponent' must have class/struct/union
type is 'int'
c:\programming\c++\splinter games\pickin' sticks\main.cpp(18) : error C2228: left of '.text' must have class/struct/union
c:\programming\c++\splinter games\pickin' sticks\main.cpp(20) : error C2228: left of '.getRenderComponent' must have class/struct/union
type is 'int'
c:\programming\c++\splinter games\pickin' sticks\main.cpp(20) : error C2228: left of '.text' must have class/struct/union
I'm guessing that the most important error is the first one.
Here's my main.cpp:
Code: Select all
#include "SE_RenderSystem.h"
#include "SE_RenderComponent.h"
#include "SE_Entity.h"
#include "SE_Engine.h"
#include "SDL.h"
int main(int argc, char **argv)
{
SE::Engine engine;
SE::RenderSystem system;
SE::Entity entity;
SE::RenderComponent renderComponent;
entity.addComponent(renderComponent);
system.addEntity(entity);
engine.addSystem(system);
entity.getRenderComponent().text = "This was a triumph";
SDL_Delay(1000);
entity.getRenderComponent().text = "I'm making a note here";
SDL_Delay(1000);
entity.getRenderComponent().text = "HUGE SUCCESS";
SDL_Delay(2000);
return engine.mainLoop();
}
And here's my SE_Entity.h
Code: Select all
#ifndef SE_ENITY_H
#define SE_ENTIY_H
#include <map>
#include <string>
#include "SE_Component.h"
#include "SE_RenderComponent.h"
namespace SE
{
class Entity
{
public:
void addComponent(std::string componentType, SE::Component component);
SE::Component getComponent(std::string componentType);
void addRenderComponent(SE::RenderComponent renderComponent);
SE::RenderComponent getRenderComponent();
private:
std::map<std::string, SE::Component> components;
SE::RenderComponent _renderComponent;
};
}
#endif
If I haven't provided enough code, please tell me.
Re: Problems Encountered While Developing a Game Engine
Posted: Mon Dec 27, 2010 7:16 pm
by Falco Girgis
I'm going to go ahead and guess that you have recursively defined "Entity" by including an include that includes entity.
You should be forward declaring any class that doesn't not require a header to be included. Unless you're declaring an instance of the object on the stack or are inheriting from the class, you shouldn't need the header.
Re: Problems Encountered While Developing a Game Engine
Posted: Tue Dec 28, 2010 7:48 am
by lotios611
I tried to forward declare the classes, but now my game engine doesn't compile. I have an Engine.h that includes System.h that includes Entity.h. When I try to forward declare both Entity in System.h and System in Engine.h, I get this error:
c:\programming\c++\splinter games\splinter sdk\splinterengine\source\se_engine.cpp(22) : error C2027: use of undefined type 'SE::System'
c:\programming\c++\splinter games\splinter sdk\splinterengine\source\se_engine.h(9) : see declaration of 'SE::System'
c:\programming\c++\splinter games\splinter sdk\splinterengine\source\se_engine.cpp(22) : error C2227: left of '->update' must point to class/struct/union/generic type
c:\programming\c++\splinter games\splinter sdk\splinterengine\source\se_rendersystem.cpp(7) : error C2027: use of undefined type 'SE::Entity'
c:\programming\c++\splinter games\splinter sdk\splinterengine\source\se_system.h(8) : see declaration of 'SE::Entity'
c:\programming\c++\splinter games\splinter sdk\splinterengine\source\se_rendersystem.cpp(7) : error C2227: left of '->getRenderComponent' must point to class/struct/union/generic type
I've tried just forward declaring one or the other, but I get the same errors.
Re: Problems Encountered While Developing a Game Engine
Posted: Tue Dec 28, 2010 8:30 am
by Falco Girgis
lotios611 wrote:I tried to forward declare the classes, but now my game engine doesn't compile. I have an Engine.h that includes System.h that includes Entity.h. When I try to forward declare both Entity in System.h and System in Engine.h, I get this error:
c:\programming\c++\splinter games\splinter sdk\splinterengine\source\se_engine.cpp(22) : error C2027: use of undefined type 'SE::System'
c:\programming\c++\splinter games\splinter sdk\splinterengine\source\se_engine.h(9) : see declaration of 'SE::System'
c:\programming\c++\splinter games\splinter sdk\splinterengine\source\se_engine.cpp(22) : error C2227: left of '->update' must point to class/struct/union/generic type
c:\programming\c++\splinter games\splinter sdk\splinterengine\source\se_rendersystem.cpp(7) : error C2027: use of undefined type 'SE::Entity'
c:\programming\c++\splinter games\splinter sdk\splinterengine\source\se_system.h(8) : see declaration of 'SE::Entity'
c:\programming\c++\splinter games\splinter sdk\splinterengine\source\se_rendersystem.cpp(7) : error C2227: left of '->getRenderComponent' must point to class/struct/union/generic type
I've tried just forward declaring one or the other, but I get the same errors.
You
forward declare the class in the header file and actually
include the header in the .cpp file.