Designing a player-class

Ok, I've got some simple interfaces in my game like Thrustable, Fireable etc. And now I'm trying creating a player class, which should be able to fire & thrust or fire / thrust. I planned to extend the Player from Entity-class and pass an entity to it in it's constructor. The player would the delegate all relevant stuff to the passed entity (render it, update it etc.). Now I could just do something like this in fire() / thrust() -methods:

if(controlledEntity instanceof Fireable) {

((Fireable)controlledEntity).fire(x,y);

}

or

try {

((Fireable)controlledEntity).fire(x,y);

} catch (Exception e) { }

I've read that it's nearly always a bad idea to use instanceof and that downcasting is a bad idea. But is this downcasting? Both the Fireable and Thrustable are not related in anyway to entities or each others. But I guess it's bad anyway.

Note that I'm not trying to make all things the right OOP way, but I'm still in the process of getting grasp of the interfaces in Java, so I'd like to hear the "right way" to do this. I guess this involves more than just a one Player-class?

Thanks

[1171 byte] By [mc3712a] at [2007-10-1 20:51:46]
# 1

> Ok, I've got some simple interfaces in my game like

> Thrustable, Fireable etc. And now I'm trying creating

> a player class, which should be able to fire & thrust

> or fire / thrust.

I'm not following the "or" part of that sentence. What's the difference between "fire & thrust" and "fire/thrust"?

Does the word "fire" mean "shooting a gun" or "turning on a rocket motor" to you?

Do you use the word "thrust" in the propulsion sense or as in swordplay ("parry and thrust")?

> I planned to extend the Player from

> Entity-class and pass an entity to it in it's

> constructor.

its constructor - the possessive is "its". it's == it is.

So Player can wrap another Entity. You can pass an Entity to a Player's constructor and get different behavior. Right?

The player would the delegate all

> relevant stuff to the passed entity (render it,

> update it etc.). Now I could just do something like

> this in fire() / thrust() -methods:

>

> if(controlledEntity instanceof Fireable) {

>((Fireable)controlledEntity).fire(x,y);

> }

>

> or

>

> try {

>((Fireable)controlledEntity).fire(x,y);

> } catch (Exception e) { }

>

> I've read that it's nearly always a bad idea to use

> instanceof

Yes, it's not very object-oriented.

> and that downcasting is a bad idea.

It's casting, not downcasting, but it might still be a bad idea.

> But is

> this downcasting? Both the Fireable and Thrustable

> are not related in anyway to entities or each others.

> But I guess it's bad anyway.

You don't need more than one Player class, because you can change the behavior by passing in different Entity implementations.

Why not pass in a Fireable and Thrustable instance, too? Since Player implements both interfaces, it will defer to its data members for behavior there.

Now you'll have no-op Fireable and Thrustable implementations for those Players who are unlucky enough to not be able to fire or thrust. But then there are others who will get the Mach 2 thruster class and kick butt.

A Player implementation will have to implement both interfaces. Some just won't fire or thrust much. No need for instanceof, no casting. Just defer to the data member that handles that behavior for you. That's one way to do it. I'm sure there are others.

%

duffymoa at 2007-7-13 2:49:24 > top of Java-index,Other Topics,Patterns & OO Design...
# 2
PS - NEVER have an empty catch block in your code. It's a sure way to drive yourself crazy. If an exception's thrown you'll never know it, but your code will fail and you won't know why.%
duffymoa at 2007-7-13 2:49:24 > top of Java-index,Other Topics,Patterns & OO Design...
# 3

Sorry, I wasn't very clear. Fireables are things that can fire bullets and have fire(x,y) and isFiring() -methods. Thrustable is simply a thing that can thrust itself forward - like a spacecraft. It has just a thrust()-method. The players should be able to control things that are either Thrustables or Fireables or both.

>So Player can wrap another Entity. You can pass an Entity to a Player's >constructor and get different behavior. Right?

Yeah, the idea was to pass an entity to player and interact only through the Player with it.

>Why not pass in a Fireable and Thrustable instance, too? Since Player >implements both interfaces, it will defer to its data members for >behavior there.

So you mean something like this?

public class Player extends Entity implements Thrustable, Fireable {

Entity entity;

Fireable fireable;

Thrustable thrustable;

public Player(Entity entity, Thrustable thrustable) {

this(entity, thrustable, null);

}

public Player(Entity entity, Fireable fireable) {

this(entity, null, fireable);

}

public Player(Entity entity, Thrustable thrustable, Fireable fireable) {

this.thrustable = thrustable

...

..

}

public void thrust() {

if(thrustable != null) {

thrustable.thrust();

}

}

...

}

}

and then, to create players:

Astronaut astronaut = new Astronaut(); // just thrustable

FiringSpaceShip ship = new FiringSpaceShip(); // thrustable & fireable

Player player1 = new Player(astronaut, astronaut);

Player player2 = new Player(ship, ship, ship);

Now I'd have slightly weird constructors (+ null checks), maybe I misunderstood you. I think this would also be a bit awkward if there'd be more interfaces.(though maybe a combined interface should be created in that case?) This already makes a lot more sense than using instanceof everywhere, though.

mc3712a at 2007-7-13 2:49:24 > top of Java-index,Other Topics,Patterns & OO Design...
# 4

Hum... Those contructors really seem very strange :|

Why not add a method to the Entity that would check if they can perform a certain action? something like :

public boolean mayPerformAction(short action){

return MyAppAuxiliarWhatever.getActionClass( action).isAssignableFrom( this.getClass());

}

This way it would be necessary only to pass the entity to the Player constructor, and no need to place the instanceof or the try catch to check if the entity implements any of the actions.

renkrada at 2007-7-13 2:49:24 > top of Java-index,Other Topics,Patterns & OO Design...
# 5
Yeah, I guess that'd be a fine solution. However I just ended up making one public constructor which takes an Entity and uses instanceof to route the Thrustables & Fireables to dummy implementations which do nothing - in case the Entity doesn't implement them.
mc3712a at 2007-7-13 2:49:24 > top of Java-index,Other Topics,Patterns & OO Design...