Jump to content
  • Advertisement
bellamabel2018

Gameplay A little question about polymorphism

Recommended Posts

Hi all,

I was reading Game engine architecture and with that, brushing up some coding theory.

If I recall correct, polymorphism can help you for example to achieve the following:

 

- create a parent class with a virtual function, that needs to implemented in child/ inherited classes

- let's take a shape for example

- I have a triangle and square class implementing their own Draw function, like declared a virtual function in the shape class

 

Now my question is, how do I iterate through all child class objects?

Simplified code:

class Shape
{
public:
	unsigned int someVar;

	virtual void Draw();
};


class Triangle : public Shape
{
public:
	void Draw();
};

class Square : public Shape
{
public:
	void Draw();
};


// some program

std::vector<Triangle> myTriangles;
std::vector<Square> mySquares;

// generate some triangles and squares

for(size_t i=0;i<myTriangles.size();++i) myTriangles[i].Draw();
for(size_t j=0;j<mySquares.size();++j) mySquares[j].Draw();

I believe it should be possible to do the last 2 lines at once.

How would I iterate through them at once, using the advantage that polymorphism should bring here?

Share this post


Link to post
Share on other sites
Advertisement

The specific case of drawing is a bad example because it follows a highly inefficient data path. Drawing is best done in large batches with a small number of calls because each call has an overhead. Calling each object results in tiny batches of size 1 and an enormous number of draw calls, which is the worst case for drawing hardware.

 

There are generally two patterns used.

 

In one situation you would use a shared interface and process them as a group. Instead of making Shape have Draw, you might have an interface called "Drawable"

For a C++ loop, you might have something like this:

...
for( size_t i = 0; i < SceneList.Size(); i++ ) // I'd prefer a newer ranged for loop, but whatever works.
{
  if( Drawable* drawable = dynamic_cast<Drawable*>SceneList.GetItem[i] )
  {
    drawable->Draw();
  }
}

There is a small cost to be paid for the dynamic cast, but since it will return a null pointer if the cast fails and it gracefully handles a bunch of data hierarchy problems, the cost is generally something you would pay anyway if you're detecting that an operation is supported.

 

Alternatively, if you don't want to pay for a conversion or a type test you can provide a function that is called for every object rather than just the specific interface functions, and implement the function differently based on the derived type of object:

For that style of system:

//Do this:
for( size_t actorIdx = 0; actorIdx < actors.count; ++actorIdx )
{
  actors[actorIdx]->DoPrimaryAction();
}

//Not this:
for( size_t actorIdx = 0; actorIdx < actors.count; ++actorIdx )
{
  if(actors[actorIdx]->type == ActorType.Wizard)
    actors[actorIdx]->DoFireball();
  else if(actors[actorIdx]->type == ActorType.Warrior)
    actors[actorIdx]->DoSwordSwing();
  else if(actors[actorIdx]->type == ActorType.Rogue)
    actors[actorIdx]->DoKnifeStab();
  else if(actors[actorIdx]->type == ActorType.Archer)
    actors[actorIdx]->DoFireBow();
...
}

In both cases your code would not know or care about the concrete class it has.  There are a collection of things that all implement the same interface. You have a factor method somewhere that created the things for you. The things might be triangles or squares or circles, but you don't care because you only care about shapes.  Or the things might be wizards and warriors and rogues, but you don't care because you only care about actor objects.  When you follow SOLID principles, you should generally be focused on abstractions, not the actual objects.

Share this post


Link to post
Share on other sites

I think the pointer way can work, as suggested above. Since Triangle and Square both is a Shape, we can use one list/vector to hold all kind of Shape.

And maybe we use pure virtual function: virtual void Draw() = 0; at the parent class Shape.

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

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!