Class inheritance?

Started by
11 comments, last by ChaosEngine 10 years, 3 months ago

Hello everybody,

It's been a while since i have visited this forum, good to see it is still so active.

I have recently picked up game programming again and i am currently working in C# (XNA). I try to create a simple flying shooter game (Raptor clone).

Right now i am implementing the enemies and i would like to know what the best programming standard is for implementing the different types of enemies. I have already created a class "Enemy" which holds all the functions and variables needed for the enemies (such as the movement function, etc.)

I will create different subtypes of enemies, which differ in (for example): image, speed, firing rate, hitpoints, and so on.

What is the best way to implement is? I was first thinking of creating a separate class for each enemy type, which inherits from the enemy class, but that might be cumbersome.

Another option could be to just use the enemy class and assign every enemy a type when it is constructed, then work with lots of switch statements in the class based on the enemy type.

Is this the best way? Or is there a better way to do this? I feel a better way should be possible, but i cant really figure out how yet.

Thank you in advance for your replies.

My personal blog on game development!

Black Wolf Game Development

Advertisement

Another option is to load the enemy data from a data file. Then the constructor only needs to know the name of the file (or index into an archive, etc.).

Thank you, i will look into that. I thought that such a method should exist but have never worked with if before. What is a good file format to use for such a file? XML? Any examples would be very much appreciated.

My personal blog on game development!

Black Wolf Game Development


I will create different subtypes of enemies, which differ in (for example): image, speed, firing rate, hitpoints, and so on.

All the examples you cite above can be accomplished with just a single enemy class. There's no custom functionality at all, so no need to create new classes that inherit from enemy (and even if there were, composition would probably be a better solution than inheritance).

Just create new instances of the Enemy class with the required information (image, speed, etc...) supplied in the constructor. You could load that data from a file (as SiCrane suggests), but that's functionality that could be added later - it doesn't enable anything new, it just makes it easier to add enemy types or modify enemies without making code changes.


Another option could be to just use the enemy class and assign every enemy a type when it is constructed, then work with lots of switch statements in the class based on the enemy type.

People seem to be overlooking this statement. Why do you need the switches? Is it because each enemy will behave differently? If so, then this will be where either inheritance or composition will take place. Inheritance is easy to think about in this example and since you are using C# can be just as dynamic if you make a plug-in system for each enemy and dynamically create enemies by class name. If you go the composition route you could store an AI interface class object inside Enemy and then have different AI objects that implement that interface. Each different AI class would be the functionality that you want. To use Left 4 Dead as an example you would have iAI interface with function like Update(). Then you would make classes that implement this interface like: ZombieAI, HunterAI, BoomerAI, SmokerAI, Tank, etc.

If you find yourself doing a bunch of switches then there is most likely a better way. Switch statements aren't very dynamic. You don't want to have to remember to update switch statements when you think of a new enemy type.


interface iAI
{
    void Update();
}
 
class ZombieAI : iAI
{
    void Update()
    {
        // zombies behave differently than other enemies so they get their own class
    }
}

class TankAI : iAI
{
    void Update()
    {
        // tanks behave differently than other enemies so they get their own class
    }
}
 
class Enemy
{
    private iAI ai;
    private Image img;
 
    // inject the ai into the enemy class so that it can be more than 1 type
    public Enemey(iAI a, Image i) { ai = a; img = i; }
 
    public Update() { ai.Update(); }
};
 
// read from a text file or db to get the type of enemy you want to make. I would then dynamically create an instance based on string name using reflection
List<Enemy> enemies = new List<Enemy>();
 
// this enemy now acts like a zombie
enemies.Add(new Enemy(new ZombieAI(), new Image(filename));
 
// this enemy now acts like a zombie
enemies.Add(new Enemy(new TankAI(), new Image(filename));

Here is a decent example that compares the 2 approaches: http://www.javaworld.com/article/2076814/core-java/inheritance-versus-composition--which-one-should-you-choose-.html


What is a good file format to use for such a file? XML?

XML is stil bloated, still costly to parse, and still has a couple of features that doesn't help in this use case. The major opinion is to create a customized binary file format fitted to your needs *if* you speak of the load file format; it is something other if you speak of file formats for the development phase where interchangeability plays a role.

Yeah, it seems you wouldn't need another class. You could just put the type in the constructor so that each enemy has a type. I don't know how it is done in C# but I lua I would implement it like so:

badGuy = Enemy(type)

They call me the Tutorial Doctor.

All right, thank you very much for responding everybody :-)

If i try to summarize your findings, i come to the following conclusions:

  • If the behaviour of all the different enemies is the same, the best way to code everything is one of the following:
    1. Pass the type to the constructor, then use a switch statement in the constructor to set the different values
    2. Pass the different values directly to the constructor

When considering these methods i prefer the first one, since it will allow me to create new enemies easier. An even more advanced approach would be to dynamically generate the enemies by loading them from an external data file.

  • If the behaviour of the enemies is different, composition is the best option. This is something new to me (i am not yet very experienced) but something i will definitely look into.

I hope the above is correct. Thank you very much for all your replies.

My personal blog on game development!

Black Wolf Game Development


If the behaviour of all the different enemies is the same, the best way to code everything is one of the following:
1) Pass the type to the constructor, then use a switch statement in the constructor to set the different values
2) Pass the different values directly to the constructor
When considering these methods i prefer the first one, since it will allow me to create new enemies easier. An even more advanced approach would be to dynamically generate the enemies by loading them from an external data file.

Except with the first one, you need to go change the Enemy class every time you create a new enemy type.

I don't understand why he would have to change the enemy class every time he creates a new enemy. If the class is designed correctly, everything could be adjusted outside of the class.

This is pseudocode for how it could be done (python)


class Enemy():
def _init_(self) pass
self.hitpoints = hit_points;
self.image_speed = image_speed;

badGuy = Enemy()
badGuy2 = Enemy()

print (badGuy.hit_points)
print (badGuy2.hit_points)





If you wanted to specify a type, you could make the type a boolean value and make that an argument of the object.


badGuy = Enemy(sniper)


In the class you would have:


sniper = false

And you would have a switch or conditional statement in the class like:


if (sniper == true)
{}
else if (bomber == true)
{}
else if (tank == true)

etc


class Enemy()

The boolean type would be in the constructor of the class, and it is designated upfront. All you do is check the type in the class, and perform whatever actions you want to do if a certain type is chosen.

You'd create all of your enemy functions inside the class, so that once a type is selected, then those functions are triggered.

They call me the Tutorial Doctor.

This topic is closed to new replies.

Advertisement