0

I am trying to make a simulation that simulates simple creatures and carnivorous creatures.

I have a class called creature and a subclass called carnCreature. I have a method in creature called eat, that takes in a one type of object, but I need the eat method in the carnCreature class to take in a list of creatures. I tried naming the method the same as it is named in the creature class, but when I try to call it, java doesn't accept the updated parameters.

package simulationObjects;

import java.awt.Color;
import java.util.List;
import java.util.Random;

import java.lang.Math.*;

public class Creature {

    public int x;
    public int y;

    public int maxTilesX;
    public int maxTilesY;

    public Color color;

    public float health = 50;
    public int life = 0;

    public Creature (int x, int y, Color color, int maxTilesX, int maxTilesY) {
        this.x = x;
        this.y = y;
        this.color = color;
        this.maxTilesX = maxTilesX;
        this.maxTilesY = maxTilesY;
    }

    public void update(Tile tile) {
        eat(tile);
        life++;
        health-=1;
    }


    public void eat(Tile currentTile) {
        if (currentTile.color == this.color) {
            health += 3;
            currentTile.color = Color.GRAY;
        }  
    }

    public boolean isCarnivore() {
        return false;
    }
}




package simulationObjects;

import java.awt.Color;
import java.util.List;

public class CarnCreature extends Creature{


    private static final boolean CANABOLIC = false;

    public CarnCreature(int x, int y, Color color, int maxTilesX, int maxTilesY) {
        super(x, y, color, maxTilesX, maxTilesY);
        // TODO Auto-generated constructor stub
    }

    public void update(List<Creature> creatures) {
        eat(creatures);
        life++;
        health-=1;
    }

    public void eat(List<Creature> creatures) {
        for (Creature creature : creatures) {
            if (CANABOLIC) {
                if (creature.color == this.color) {
                    health += 3;
                    creature.health = 0;
                } 
            } else {
                if (creature.color == this.color && creature.isCarnivore() == false) {
                    health += 3;
                    creature.health = 0;
                }
            }

        }

    }

    public boolean isCarnivore() {
        return true;
    }

}

The eat function is being called later like this:

    for (Creature creature : creatures) {
        if (creature.isCarnivore()) {
            creature.upadte(creatures);
        } else {
            creature.update(tiles.get(creature.x).get(creature.y));
        }
    }

I am trying to store the creatures and the carnCreatures in the same list, "creatures." Is this the problem, and do I need to store them in separate lists?

Thanks

  • 1
    You have to cast the object back to carnCreature in order to get access to that version of eat() – NAMS Aug 10 '18 at 20:36
  • You could consider using a [varargs parameter list](https://stackoverflow.com/a/519756/2301416) for update (and/or eat). Then you could override the base `update`, because both would have the same signature (as mentioned in @borjab's answer) and polymorphism would kick in. `creatures`, however, would have to be an array. – MyiEye Aug 10 '18 at 20:47

2 Answers2

2

The isCarnivore() test will not spare you to cast to the subclass type as you manipulate as declared type the Creature the base class :

for (Creature creature : creatures) {
    if (creature.isCarnivore()) {
        ((CarnCreature)creature).update(creatures);
    } else {
        creature.update(tiles.get(creature.x).get(creature.y));
    }
}

So the isCarnivore() appear helpless as if (instanceof CarnCreature) would have the same effect and consequences.

Is this the problem, and do I need to store them in separate lists?

It would be better as you don't want manipulate them in an uniform way.
Using the base class to group them in a unique List make your task harder.

But in fact you have a deeper issue. Here eat() is not a overrided method but an overloaded method in the subclass. Same thing for update(). It means that in both cases the two methods are defined in the subclass.
Such a design will not allow to benefit from a polymorphism feature because you want to invoke the first method on the base class instance and invoke the overloaded method on the subclass instance.
In terms of concept, a carnivore creature IS not a creature. Their type of behavior is very different : one consumes a thing (a tile) and the other consumes a very different thing (a list of creature).
To benefit from polymorphism you should re-design the base class and the subclass to override the methods and not overload them. But as you pass really different types in the parameters, you are stuck.
So in your case I think that I would not even create a inheritancy relation between theses classes.

davidxxx
  • 125,838
  • 23
  • 214
  • 215
2

You have a two options:

  • Once you know if the creature is carnivore cast it and access the method
  • Create a method with the same "signature", that is, same name AND arguments.

The second option is the more elegant. Using the "magic" of polymorphism each class will have its method called and you won't need to check the class with the isCarnivore() method. But you will need to get the list of creatures from the tile.

borjab
  • 11,149
  • 6
  • 71
  • 98