Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411670 Posts in 69397 Topics- by 58452 Members - Latest Member: homina

May 16, 2024, 12:31:13 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Component Fail!
Pages: [1] 2
Print
Author Topic: Component Fail!  (Read 5263 times)
BlueSweatshirt
Level 10
*****

the void


View Profile WWW
« on: February 09, 2010, 02:13:45 PM »

I'm using the STL vectors, trying to achieve a polymorphism-based component architecture in my game.  Outraged

Here's the code I currently have:
component.h
Code:
#ifndef COMPONENT_H_INCLUDED
#define COMPONENT_H_INCLUDED

#include <vector>

namespace Z4R
{
    class Component
    {
        public:
        virtual void Run() {}
        private:
    };

    class C_Sprite : public Component
    {
        public:
        void Run() {}
        private:
    };

    class ComponentList
    {
        public:
        std::vector<Component*> List;
        void addComponent(Component* add) {
            List.push_back(add);
        }
        void runComponents() {
            for(std::vector<Component*>::iterator i = List.begin(); i != List.end(); ++i) {
                i->Run();
            }
        }
        private:
    };
}

#endif // COMPONENT_H_INCLUDED

And here are my errors:
Code:
<directory snip>component.h|31|error: request for member `Run' in `*(&i)->__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator-> [with _Iterator = Z4R::Component**, _Container = std::vector<Z4R::Component*, std::allocator<Z4R::Component*> >]()', which is of non-class type `Z4R::Component*'|

I have a feeling vectors just aren't a good container to try to achieve polymorphism in, or I'm doing something hilariously wrong.
Logged

David Pittman
Level 2
**


MAEK GAEM


View Profile WWW
« Reply #1 on: February 09, 2010, 02:29:54 PM »

I think you just need to dereference your iterator:
Code:
(*i)->Run();

But I haven't used STL vecs in quite a while so if I'm wrong, feel free to call me on it.  Shrug
Logged

BlueSweatshirt
Level 10
*****

the void


View Profile WWW
« Reply #2 on: February 09, 2010, 02:40:21 PM »

 Shocked Beer!

You're pretty sharp for being rusty.
Thanks!
Logged

skyy
Level 2
**


[ SkyWhy ]


View Profile
« Reply #3 on: February 09, 2010, 02:53:10 PM »

Beat me to it.  Durr...?
Logged

JParkWildPockets
Level 0
**


View Profile
« Reply #4 on: February 09, 2010, 03:14:36 PM »

Off-topic, but }; looks like a very sad face D:
Logged
BlueSweatshirt
Level 10
*****

the void


View Profile WWW
« Reply #5 on: February 09, 2010, 03:48:51 PM »

New problem:
In the effort to make components hold a pointer to the object holding them, I've had to do a lot of code separation and have ultimately ended up with:

game_object.h
Code:
#ifndef GAME_OBJECT_H_INCLUDED
#define GAME_OBJECT_H_INCLUDED

#include "component_list.h"

namespace Z4R
{
    class GameObject
    {
        public:
        ComponentList myComponents;
        void Logic();
        GameObject();
        virtual ~GameObject();
        private:
    };
}

#endif // GAME_OBJECT_H_INCLUDED

with the error:
Code:
<directory snip>game_object.h|11|error: `ComponentList' does not name a type|

ComponentList is declared in component_list.h, and defined in component_list.cpp, so I see no problems. I get an incomplete type error when I try to add a prototype line of ComponentList in front of the declaration of GameObject.

Any ideas?
« Last Edit: February 09, 2010, 04:04:59 PM by Jakman4242 » Logged

Draknek
Level 6
*


"Alan Hazelden" for short


View Profile WWW
« Reply #6 on: February 09, 2010, 04:19:49 PM »

Complete guess: did you copy ComponentList from component.h into component_list.h without changing the include guard?
Logged

BlueSweatshirt
Level 10
*****

the void


View Profile WWW
« Reply #7 on: February 09, 2010, 04:21:52 PM »

Nope!
No need to do that, anyway, since CodeBlocks automatically generates header gaurds. Pretty nifty.  Hand Thumbs Up Left Smiley
Logged

resistor
Level 0
**


View Profile
« Reply #8 on: February 09, 2010, 05:23:13 PM »

Is ComponentList declared inside a namespace that either needs to be explicit or marked as "using"?
Logged
BlueSweatshirt
Level 10
*****

the void


View Profile WWW
« Reply #9 on: February 09, 2010, 05:28:35 PM »

I think it's called for to just post the code for ComponentList:
Code:
#ifndef COMPONENT_LIST_H_INCLUDED
#define COMPONENT_LIST_H_INCLUDED

#include "component.h"

namespace Z4R
{
    class ComponentList
    {
        public:
        std::vector<Component*> List;
        void addComponent(Component* add);
        void runComponents();
        ~ComponentList();
        private:
    };
}

#endif // COMPONENT_LIST_H_INCLUDED
« Last Edit: February 09, 2010, 05:35:12 PM by Jakman4242 » Logged

resistor
Level 0
**


View Profile
« Reply #10 on: February 09, 2010, 05:37:46 PM »

You're missing an #ifndef at the beginning.  But otherwise, works for me just fine.
Logged
Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW
« Reply #11 on: February 09, 2010, 06:24:33 PM »

I think you just need to dereference your iterator:
Code:
(*i)->Run();

But I haven't used STL vecs in quite a while so if I'm wrong, feel free to call me on it.  Shrug

I prefer this, if you want to avoid the giant for loop:
Code:
std::for_each(List.begin(), List.end(), std::mem_fun(&Component::Run));

Requires <algorithm> and <functional>, if memory serves.
Logged



What would John Carmack do?
BlueSweatshirt
Level 10
*****

the void


View Profile WWW
« Reply #12 on: February 09, 2010, 06:49:10 PM »

I finally figured it out.

It was because component_list.h was trying to include component.h which was trying to include game_object.h which was trying to include component_list.h, which couldn't because component_list.h had already been declared.

I just had to break the chain, and it all ended up A-OK.  Hand Thumbs Up Left Smiley
Logged

BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #13 on: February 10, 2010, 01:15:43 PM »

How are you handling object destruction? Seeing pointers in a container is usually a red flag, imho. You'd make your life easier if you used smart pointers or a smart container. Or used a garbage collector, if you aren't.
Logged
BlueSweatshirt
Level 10
*****

the void


View Profile WWW
« Reply #14 on: February 10, 2010, 04:46:45 PM »

Code:
Z4R::ComponentList::~ComponentList() {
    for(std::vector<Component*>::iterator i = List.begin(); i != List.end(); ++i) {
        delete (*i);
    }
}

I took a shot in the dark, I'm not sure if that's correct or not yet. I'm probably going to end up rebuilding this component system.
Logged

Crimsontide
Level 5
*****


View Profile
« Reply #15 on: February 10, 2010, 06:21:09 PM »

Code:
Z4R::ComponentList::~ComponentList() {
    for(std::vector<Component*>::iterator i = List.begin(); i != List.end(); ++i) {
        delete (*i);
    }
}

I took a shot in the dark, I'm not sure if that's correct or not yet. I'm probably going to end up rebuilding this component system.

That'll do it. 

My general feelings are that using smart pointer containers should be approached with caution, as none of the implementations are flaw-less (they all have 'caveats').  In this case ComponentList handles RAII, so there's no need for them IMHO.
Logged
BlueSweatshirt
Level 10
*****

the void


View Profile WWW
« Reply #16 on: February 10, 2010, 08:34:10 PM »

What's a good way to help components interact with each other?

I figure there's two basic ways. You can either have a way to directly check the component and access it's data, or you can create a system to hold "flags", which you can set to notate that a certain action was done in a certain component.

Option A allows much more flexibility, while making the code a bit messier and less 'secure'.
Option B allows less flexibility,(IE the ability to work with straight data from the component itself) but at the same time it simplifies things and keeps your code cleaner.

I'm already creating a prototype of option B, and I'm already set up to work with option A. What are your opinions on each of the methods? Of course, I can use both of them together as well.
Logged

Crimsontide
Level 5
*****


View Profile
« Reply #17 on: February 10, 2010, 09:53:32 PM »

What's a good way to help components interact with each other?

I figure there's two basic ways. You can either have a way to directly check the component and access it's data, or you can create a system to hold "flags", which you can set to notate that a certain action was done in a certain component.

Option A allows much more flexibility, while making the code a bit messier and less 'secure'.
Option B allows less flexibility,(IE the ability to work with straight data from the component itself) but at the same time it simplifies things and keeps your code cleaner.

I'm already creating a prototype of option B, and I'm already set up to work with option A. What are your opinions on each of the methods? Of course, I can use both of them together as well.

Hehe... you've just looked into Pandora's box.

That said a good place to start is: 
http://en.wikipedia.org/wiki/Design_Patterns_%28book%29

A word of caution.  Many programmers will claim (when it comes to design patterns in particular) that A pattern is better than B, or that you should never use patter C (*cough* singletons *cough*).  Take everything you read or hear with a grain of salt so to speak.  Bottom line is there is never one right way, the fun about programming is finding your own way.

That said for interactive systems (aka games) I'm partial to the Actor Model:
http://en.wikipedia.org/wiki/Actor_model, but it can be a bit complex for beginners.
Logged
Mikademus
Level 10
*****


The Magical Owl


View Profile
« Reply #18 on: February 11, 2010, 06:24:46 AM »

About:
Code:
Z4R::ComponentList::~ComponentList() {
    for(std::vector<Component*>::iterator i = List.begin(); i != List.end(); ++i) {
        delete (*i);
    }
}
Dude, do yourself a bit favour and look up smart pointers. Basically NEVER store raw pointers to dynamically allocated memory anywhere, that's a C-legacy that WILL cause you memory leaks no matter how careful you think you are.

Boost has a solid shared_ptr implementation, and the C++ Technical Report 1 (TR1) includes one based on this in their draft for the next STL version. Most STL implementations already includes some or most of this in the std::tr1 namespace.

Then again, as Crimsontide implied, smart pointers aren't the solutions to all memory management, but for your needs, and in fact for some 90% of all situations, they're exactly what you need.

In sum: Store smart pointers, not naked pointers, in STL containers (and most everywhere else, too).

As for "two basic ways for objects to interact", well, two is correct, but you're perhaps three magnitudes off... Smiley I'd really recommend you to look over either of "Head First Design Patterns" or the deservedly famous "Design Patters" by Gamma et àl. This will help you on your path to enlightenment!
Logged

\\\"There\\\'s a tendency among the press to attribute the creation of a game to a single person,\\\" says Warren Spector, creator of Thief and Deus Ex. --IGN<br />My compilation of game engines for indies
Crimsontide
Level 5
*****


View Profile
« Reply #19 on: February 11, 2010, 07:48:17 AM »

But Mik his ComponentList is RAII compliant the way he's using it (unless I missed something?).  Not to mention u can't use std::auto_ptr in containers.  Now obviously boost has a whole selection of smart pointer containers, but none of them come free (there's always a trade-off).  Not to mention boost itself is not what I would consider appropriate for a beginner (as awesome as it is).
Logged
Pages: [1] 2
Print
Jump to:  

Theme orange-lt created by panic