Reputation: 4228
I am in a very early stage of game development. It is some sort of turn based game like Warhammer or Warcraft. Some creatures can regenerate the damage they have suffered and to represent this I have a interface like this
public interface Regenerative {
void regenerates();
}
So a creature that regenerates is
public class SomeMonster() extends BaseCreature implements Regeneative{
//Code
private int hitPoints;
public void regenerates(){
hitPoints = hitPoints + regenerateValue;
}
}
The problem I face is that not all the creatures regenerates the same ammount of hit points so I have to place that amount (regenerateValue) somewhere. Since I cannot put it on the interface (because I don't want the ammount to be the same to all the creatures) I have thought in adding a new property to the creature class
public class SomeMonster() extends BaseCreature implements Regeneative{
//Code
private int regenerateValue;
public void regenerates(){
hitPoints = hitPoints + regenerateValue;
}
}
but I don't like it this way (why a creature that doesn't regenerate should have a regenerateValue of 0?). I think it is giving a class unnecesary properties and thus a bad design. What do you think is the best approach for this case?
Upvotes: 1
Views: 143
Reputation: 4337
The solution i use may be a bit over-ingeniered, but this allow for a lot of extension (regeneration, poison, protection...)
I use of interface "CreatureProperties" that define a integer value along with an id, and can perform action on a monster at each turn. You subclass those properties to perform a given property
abstract class CreatureProperties {
protected String id = "";
protectd int propertyValue = 0;
public void actOn(BaseMonster);
// plus setter and getter
}
public RegenerationProperty implements CreatureProperties {
final public REGENERATION_ID = "Regeneration";
int regenerationValue = 0;
public RegenerationProperty(int value){
id = REGENERATION_ID;
propertyValue= value;
}
public void actOn(BaseMonster monster){
monster.setHitPoint(monster.getHitPoints()+propertyValue);
}
}
in the BaseMonster class, you manage a set of MonsterProperty, initially empty.
class BaseMonster {
protected List<CreatureProperties> properties =
new ArrayList<CreatureProperties>();
// plus management of propeties : add remove, iterator...
public void update(){
// perform all properties-linked update to monster
foreach (CreatureProperty property : properties){
property.actOn(this);
}
}
}
in the subclass for SomeMonster, you simply add during instanciation the set of properties for this type of monster.
class SomeMonster extends BaseMonster {
public SomeMonster(){
properties.add(new RegenerationProperty(5)); // presto : monster regenerate
}
}
I'm using the Id in some case where the property is not used each tick (ie nothing in the update), but for example damage reduction (id="LightningReduction"), or to modify the list of existing properties (a property that remove all regenerationProperty and add PoisonProperty of same value...).
Upvotes: 1
Reputation: 3621
The question you should ask yourself is this: if a creature should regenerate, how do you know that? Will it implement a different (or extending) base class? one that implements Regenerative?
If the answer is that you will extend the base class (to something like BaseRegeneratingCreature) and all regenerating creatures will extend that class, then this is your answer: BaseRegeneratingCreature should implement that interface, and have all properties required for regenerating.
All non-regenerating creatures should directly extend BaseCreature (or another extending class), and will not need the regeneration related properties.
Then, your base class could have some method like:
OnStartOfTurn();
which will, in BaseRegeneratingCreature, call regenerates() (and then probably call super()), and in BaseCreature do something else or call other methods.
Upvotes: 0
Reputation: 348
What if all monster regenerate, but some of them with 0 regenerate value (the same as not regenerating)?
So you don't need the inferface:
public class SomeMonster() extends BaseCreature {
//Code
protected int regenerateValue; //protected, so that subclasses can override the value
public void regenerates(){
hitPoints = hitPoints + regenerateValue;
}
}
The regenerateValue starts with 0, so you have to override the value in subclasses that want to actually regenerate
Edited to remove the " implements Regeneative"
Upvotes: 1
Reputation: 2017
I think your design is probably ok, as you would only need to include a regenerateValue in the classes that implement the Regenerative interface. So there would be no need to include a regenerateValue.
Otherwise you could look at more complex design patterns that favor composition over inheritance. This way you could cater for the possibility of dynamically adding Regenerative abilities to a monster along with other 'abilities' during the game, rather than having to recompile the game each time you need to make change the behaviour of your monster.
Upvotes: 1
Reputation: 533492
I would add it to the abstract
BaseCreature and not worry about it too much. Your BaseCreature may end up with lots of properties which are effectively "turned off" but the alternative is to create a complex inheritance tree. As Java doesn't support multiple inheritance this will frustrate your ability to abstract all the combinations you might like away.
Upvotes: 2
Reputation: 1500225
The problem I face is that not all the creatures regenerates the same ammount of hit points so I have to place that amount (regenerateValue) somewhere.
Why does it have to be a field anywhere? Some implementations of the interface might use a different value per instance; others might use a constant value.
This is an implementation detail - and thus inappropriate for the interface. You could potentially put it in an abstract superclass which implements the interface, of course.
Code which knows about the interface almost certainly shouldn't know or care the details of how much a creature regenerates - maybe they regenerate in terms of magic rather than just hit points, for example, or maybe the level of regeneration depends on some other function of their state. Callers shouldn't care.
Upvotes: 3
Reputation: 2610
You could add a method in your interface, like getRegnerationValue(), making sure all creatures with that interface have this method that holds the value or formula if that is something you would like to work with.
Upvotes: 0