[SOLVED] Separating game and UI logic

I have separated all code in my game into game model and logic and UI logic (using JME). I’m trying to find an elegant way of getting the game objects referenced when a user interacts with a Spatial. I’ve tried the following:

  1. Currently I extend Node to ItemNode, EnemyNode (etc.) storing a reference to the relevant game object. I then use instanceof to work out what the Node actually is. This seems a hack.

  2. I have tried using setUserData but it assumes a certain serialisation model that doesn’t apply to my game objects (I use a custom serialisation).

  3. I have also tried storing the reference in the associated controls (ItemControl, EnemyControl etc.) and then finding out if the Spatial is a specific type of object using getControl(ItemControl.class). Then I can get the game object using control.getItem() or equivalent. This seems a pretty indirect method to me but perhaps it’s what is intended?

What would be most elegant (IMHO) is if there was a generic version of Node that actually referenced the game object:

class GameNode<T> extends Node {
    GameNode(T entity) { ... }
    public T getEntity() { ... }
}

So that I could, for example, say:

Node itemNode = new GameNode<Item>(item);
itemNode.addControl(new ItemControl(item));

Has something like that been attempted by anyone?

Any guidance would be appreciated.

If you were using an ES then this would be the route as you can just store the entity ID and your system would know how to find the entity.

Else, controls are the “JME way” to do what you are doing.

You might want to lookup the entity system ZayES created for jME by @pspeed

You added this bit after I responded… this is the part that starts to make me uncomfortable. Often developers purport to want separation but then extend node and closely mingle things. In the MVC world, to me, this is like extended JTextField so that you can give it a database connection.

…but I’m so steeped in ES approaches now that I can hardly remember what it was like to do things the hard way. :slight_smile:

1 Like

Ok thanks I’ll stick with controls then. I actually embed the logic inside the Node subclass so it’s pretty well encapsulated anyway.

public static Optional<Creature> asCreature(Spatial spatial) {
    CreatureControl control = spatial.getControl(CreatureControl.class);
    return Optional.ofNullable(control).map(CreatureControl::getCreature);
}

Then I can code like: Creature.asCreature(spatial).ifPresent(Creature::dropItem); and equivalent.