SimpleApplication Listener

Hi, simple question:
Is there a (simple) way to add something like a listener to a Node that gets called when a spatial / light is added?
I mean, I could just ask in the update loop: Do you now have more children? And then find out what’s the new, but does anyone know a smarter way?
No big deal if not, I’m just cursious.

Oh and second question, now only forum-related: Will there be (is there) a button to push to mark a topic as solved? Would be useful, or did I just not see it?
Thank you.

Use the decorator design pattern for this. A decorator object adds capabilities to another object that share the same type.

Here’s a basic implementation:

[java]
public class MySpatialDecorator extends Spatial {
private Spatial spat;
private List<MyOnLightAddedListener> listeners;
public MySpatialDecorator(Spatial spat) {
this.spat = spat;
listeners = new ArrayList<MyOnLightAddedListener>();
}

    public void registerListener(MyOnLightAddedListener listener) {
        listeners.add(listener);
    }
    
    public void notifyListeners(MyOnLightAddedEvent event) {
        for(MyOnLightAddedListener l:listeners) {
            l.onLightAdded(event);
        }
    }
    
    //THIS IS THE METHOD THAT ADDS THE CAPABILTY OF NOTIFYING LISTENERS WHEN A LIGHT IS ADDED TO IT
    @Override
    public void addLight(Light light) {
        notifyListeners(new MyOnLightAddedEvent(light));
        spat.addLight(light);
    }
    
    //THESE OTHER METHODS JUST DELEGATES THE FUNCTION TO THE ORIGINAL SPATIAL
    @Override
    public void updateModelBound() {
        spat.updateModelBound();
    }

    @Override
    public void setModelBound(BoundingVolume modelBound) {
        spat.setModelBound(modelBound);
    }

    @Override
    public int getVertexCount() {
        return spat.getVertexCount();
    }

    @Override
    public int getTriangleCount() {
        return spat.getTriangleCount();
    }

    @Override
    public Spatial deepClone() {
        return spat.deepClone();
    }

    @Override
    public void depthFirstTraversal(SceneGraphVisitor visitor) {
        spat.depthFirstTraversal(visitor);
    }

    @Override
    protected void breadthFirstTraversal(SceneGraphVisitor visitor, Queue&lt;Spatial&gt; queue) {
        spat.breadthFirstTraversal(visitor);
    }

    @Override
    public int collideWith(Collidable other, CollisionResults results) throws UnsupportedCollisionException {
        return spat.collideWith(other, results);
    }

}

[/java]

And you use it this way:

[java]
Spatial myDecoratedSpatial = new MySpatialDecorator(mySpatial);
[/java]

Note that you should override the other methods too and delegate them to the original spatial.

1 Like

But really, it’s your code adding the children and lights in the first place… and presumably doing that as the result of some game data change… and that’s where you should setup your own listener stuff.

Keep the view and the model separate (see MVC pattern). Spatials are just the view.

@ glaucomardano thank you, that is of course far more elegant.
@ pspeed Right, but I’m doing that in a lot of classes and methods, so instead of repeating the code that shall be executed when something was added in a lot of classes, I have one method that manages all that, wherever the command comes from.
Hope this is understandable :slight_smile:

@benkibitzer said: @ glaucomardano thank you, that is of course far more elegant. @ pspeed Right, but I'm doing that in a lot of classes and methods, so instead of repeating the code that shall be executed when something was added in a lot of classes, I have one method that manages all that, wherever the command comes from. Hope this is understandable :)

Decorating Spatial will be nothing but trouble in the long run. You will have to map behavior exactly, implement a ton of passthrough methods, etc.

Instead, you could have some observable data structures that have their own proper listeners (way less code to write even) and then even the spatials could be created from listeners.

Watching for spatials being added is a sign that your data model might be completely upside down. But it’s hard to tell from here without more specifics. It seems way way wrong and implementing your own Spatial that wraps other spatials (and already has problems because really you need to wrap Node) will be a big pain. It is the opposite of elegant.

Hum, yeah, wrapping “nodes” is not really elegant, and won’t work at all, because the spatials data structure is not a composite pattern, and then there’s no interface for addChild() and things like that, so wrapping a node will make it lose its composite functions.

Another way (if you want to do it using JME classes) could be to modify the engine’s source code and rebuild it with your listeners. While it may be a little too much for your needs, it’s not really that hard to do.

Or simply screw bloated event systems.

as long as you have less than 5k spatials attached(and you always kinda should to not kill the gpu)
just do the simple for loop locking for new nodes.
Premature optimisation is the root of all evil, and a small loop is really fast.

btw adding /edit to the threads page lets you edit it, might be able to change thetitel as well

1 Like

another thing to consider with the decorator approach is that if a light as added to a parent node, then nothing will get notified about adding the light (even though itll affect the node)