0

I'm currently not sure how inheritance would best fit into my Java program, or whether it would best be implemented using interfaces or not. An example of the context I'm talking about is below.

Imagine that I'm making a game, and I have enemies in my game. These enemies all have various variables and behaviours in common, but are all unique in some way. For example, Enemy1,

class Enemy1 {

    float x, y, width, height;

    public Component(float x, float y, float width, float height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }
    public void AI() {
        //some code
    }
}

and Enemy2,

class Enemy2 {

    float x, y, width, height;

    public Component(float x, float y, float width, float height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }
    public void AI() {
        //some different code
    }
}

So with these two separate enemies, I understand (or at least believe) that I can change Enemy2 to resemble

class Enemy2 extends Enemy1 {
    @Override
    public void AI() {
        //some different code
    }
}

But, what now if I have five different types of AI code each enemy could have, and then instead of defining the code for the AI behaviour within the class for each enemy, I want to have another class which contains all of the AIs, allowing me to extend/implement the AI class/interface and select the one I want.

I'm not sure what the best way to do any of this is. In a nutshell, I want to have different enemies which share properties, each which would have similar, but different, functions within them (such as the AI code), but overall would still be quite unique. Would it be most efficient to do this with only classes? Interfaces? And how would I go about doing this? Would I have a class drawing off a class drawing off a class? Or just a class extending a class and implementing an interface at the same time? I'm not quite sure what the best inheritance structure would be to use.

Sorry if I have made any fundamental misunderstandings or mistakes.

Any help would be much appreciated.

PeterG
  • 1
  • It may be better to use an interface for this.. That, or an abstract class – Luke Thistlethwaite Aug 19 '17 at 12:04
  • can an enemy have different combinations of a set of methods? e.g. 7 enemies with different combos of 4 methods? or does having 1 type of AI method mean having 3 other corresponding methods? (for example) – inarilo Aug 19 '17 at 12:11
  • maybe related: https://stackoverflow.com/questions/2869222/use-of-java-interfaces-abstract-classes/2870094#2870094 also i have coded up some dnd type classes that include character classes at http://tayek.com/ray/zombie.zip – Ray Tayek Aug 20 '17 at 01:23

2 Answers2

1

class Enemy2 extends Enemy1

Does that semantically make sense though? Is Enemy2 also an Enemy1? Knowing nothing of the game, let's say Enemy1 is a Dire Wolf and Enemy2 is a Bear. A Bear is not also a Dire Wolf, so this structure would make no sense. But if Enemy2 is, say, a Dire Wolf Pack Leader then this would make sense, because it is also a Dire Wolf.

I want to have another class which contains all of the AIs

That just sounds weird to me. One object which contains all of the logic for your other objects, and they pull their logic from it? That sounds pretty close to the "God object" anti-pattern. You should probably keep the logic on the objects which own it.


Based on the description, it sounds like you want an abstract class. A base Enemy class which itself can't be instantiated, but which holds the commonalities of all enemies. Something like:

abstract class Enemy {

    float x, y, width, height;

    public Enemy(float x, float y, float width, float height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }

    abstract public void AI();
}

Then any enemy would inherit from that:

class DireWolf extends Enemy {
    public DireWolf(float x, float y, float width, float height) {
        super(x, y, width, height);
    }
    public void AI () {
        //...
    }
}

Indeed, any class which extends Enemy would be required by the compiler to implement AI(). So the common functionality and common interface is held in the abstract base class, and each class which inherits from it will provide its implementation to that interface.

EDIT

This approach requires a constructor for every child class. This may work to your advantage, for example, if every DireWolf is the same size, the constructor could look like this:

    public DireWolf(float x, float y) {
        super(x, y, 64, 64);
    }

Then you could initialize your wolf as follows:

Enemy wolf = new DireWolf(0, 0);
Jonathan
  • 949
  • 1
  • 11
  • 13
David
  • 208,112
  • 36
  • 198
  • 279
  • Thanks for the answer, I wasn't quite thinking properly when I posted the question - posting it with an Enemy1 and Enemy2 extending off a main Enemy would've been more my intention, but it was rather late at night. In the case that I have, why would I use an abstract class? What are the benefits of using an abstract class as opposed to an actual class or an interface? In addition, what happens if I have 5 completely separate enemies which run the same AI code? Then I would have to type out the same code multiple times... How would I solve this problem? Thanks – PeterG Aug 19 '17 at 20:44
  • @PeterG: The benefit of an abstract class is to have a common parent class which itself is never instantiated and requires child classes to implement things. If all "enemies" share certain qualities, it allows you to organize those qualities in one place instead of repeating it across many different classes. As for several enemies sharing even more qualities, that sounds like an additional level in your hierarchy. Perhaps another abstract class which itself inherits from `Enemy` (let's say something like `FlyingEnemy`), imparts common logic for its children, and can itself be inherited. – David Aug 19 '17 at 21:10
1

You could make an abstract AI class with a process function:

abstract class AI
{
   public abstract void process(Enemy en);
}

And then you can extend it.

class AISipleMovement extends AI
{
   @Override
   public void process(Enemy en)
   {
        en.moveRandomly(); //Insert actual code here
   }
}

or just:

class AIStayFrozen extends AI
{
   @Override
   public void process(Enemy en)
   {

   }
}

And in the Enemy class:

class Enemy1 {
    float x, y, width, height;
    AI ai;

    public Enemy1(float x, float y, float width, float height, AI ai) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.setAI(ai)
    }

    public void setAI(AI aiIn)
    {
        this.ai = aiIn;
    }

    public void AI() {
        ai.process(this);
    }
}

Of course, this is minimal example, you should cover if ai isn't null to prevent NullPointerException and similar stuff.

Tefek
  • 162
  • 1
  • 10