Running Code After Input Listeners Are Called [SOLVED]

I’m working on a turn based strategy game in which each unit has a small info graphic rendered in the GUI queue bucket. The screen coordinates of each info card is updated every frame in a loop that I’m running from the simpleUpdate(float tpf) method, running it in this method ensures that the info card coordinates are updated after all unit Abstract Controls have been processed.

However; the camera is moved using an input listener, the WASD keys, and it would appear that the code in the input listener is run after simpleUpdate() so when I move the camera the info cards are one frame behind in updating their screen coordinates. Is there a way to ensure that a block of code is run after all AbstractControls and Input Listeners?

normally the frame-rate would be high enough that it wouldn’t be an issue. Even at 30fps I doubt you would notice. Unless I’m missing something?

EDIT: Actually, after reading a few times, i’m not entirely sure I understand your situation clearly enough. Could you maybe post a screenshot or even better a video?

I think you have this exactly backwards, in fact.

Order is:
-queued tasks
-input listeners
-audio renderer
-app states update()
-simpleUpdate()
-root node control update
-gui node control update
-root node geometric update
-gui node geometric update
-app states render()
-render manager render
-simpleRender()
-app states postRender()

So you can see the input is processed first and controls are run last… even after simpleUpdate().

You should probably update your positions in a control and rip out the other stuff.

Hmmm, I guess I did get the order wrong, thought I had it right because the info cards appear in their correct positions when units are moving, but not when the camera is moving so I assumed controls were executed before simpleUpdate, but perhaps the info cards are not in the correct positions, it is only that the difference is not noticeable because the units are not moving very far from one frame to the next as Jayfella said.

Nonetheless this doesn’t explain why the info cards are one frame behind when moving the camera. The camera moves pretty fast, much faster than units otherwise moving the camera from one end of the map to the other would take too long. Because the camera moves so fast the fact that the info cards are one frame behind is noticeable.

basically I have an abstract control attached to a node and this hosts most of my camera related methods along with an input listener for moving/zooming the camera. Actually I have about ten cameras setup right now, not all of them are being used for direct viewing of the game world, those that are used for viewing the game world use CameraNodes to track the node the abstract control is attached to.

Whenever I want to move the game cameras I use an input listener setup in the camera’s abstract control so, for instance, when I press ‘w’ the node the control is attached to moves along the z-axis, of course the CameraNodes, setup with CameraControl.ControlDirection.SpatialToCamera, follow this node.

My info card update loop in the simpleUpdate() method does a few calculations, but the one pertinent to this issue is:

Camera.getScreenCoordinates(unit.getLocalTranslation(), Vector3f store);

The value returned from that method is used in placing the info card in screen space coordinates.

The units themselves generally don’t have any controllers attached to them, I’m using a custom class that extends the Node class for storing unit information and housing unit related methods. However, when a unit needs to animate, such as when moving, I attach a control to the unit which animates that unit frame by frame and is then detached when the control is no longer needed (this is a turn based strategy). Anyway when a unit is moving or stationary and the camera is stationary the info cards appear in the correct screen space coordinates. When I move the camera left, for example, the info cards appear slightly to the left of where they should be or apparently in the position they would be if the getScreenCoordinates() method were called before the camera’s new position was calculated in the input listener. When the camera stops moving the info cards pop back into their proper coordinates.

Edit: Okay, I get it, it’s not the input listener that’s causing the problem, it’s the CameraNode. A CameraNode is used so that a Camera can essentially be parented to a spatial or, in this case, a Node or vise versa. Looking at JME source it would appear that a CameraNode uses a CameraControl, abstract control, to achieve this. So the camera’s movement is being executed along with the abstract controls, not the input listeners.

This presents a problem then, if I use an abstract control to run my info card update loop I need to ensure that control runs after all other abstract controls. How would I ensure a particular abstract control is executed last?

Add it last.

So I guess my question then would be would I need to attach the control to the object after I’ve attached all other controls to all other objects or attach the object in which the control is attached to the scene after all other objects with controls are added into the scene?

Since I’m attaching and detaching spatials and controls throughout the game this would mean, I suppose, that I’d have to detach the info card control & spatial every time I attach another control & spatial then reattach it. Seems like there could be a way to avoid this. I guess I’ll just keep looking for a better solution, worse comes to worse I’ll just re-write it so I’m not using abstract controls and instead write my own abstract control class and insert the loop for those controls where ever I want.

Anyway here’s a quick screen cap of my game so far if you’re interested. Still a lotta work to do, recently polished off the AI. Info cards are turned off in this shot.

Well, there is a lot to dislike about camera node in this case. There is only one camera (generally) so it seems more appropriate for an app state to me.

Also, part of the issue is that you seem to be mixing game objects and visualization objects… which in some ways JME kind of encourages but it can lead to these sorts of chicken-and-egg timing issues. For example, if you had separate game objects then they would all be updated together (possible as part of an “game logic” app state) then the various controls just update the spatials based on their game objects. This way one view objects isn’t trying to sync itself to another view object… they’d both be synched to the “model” (in an MVC sense).

I mean, I’m only guessing but these problems usually stem from treating Spatial as a game object and not just the visible state of a game object.

I should note that in my previous posts when I said “object” I generally meant “Spatial.” I use Blender a lot so I sometimes interchange terminology. For the most part an object in Blender represents everything a spatial in JME represents as in the transformations applied to a mesh or other item in a scene. I mean the mesh contains information like the location of verticies relative to vector3.zero, normals, texture coordinates, etcetera and the spatial, or geometry, classes just store information and methods that modify the location of the meshes origin, the scale of the mesh which basically just multiplies the location of the verticies around vector3.zero before adding in the translation and the rotation of the mesh.

So the mesh is data that is used for the visual representation of a model while the spatial, or object as it is referred to in Blender, is used to modify that data so that the mesh can be visualized in a particular location and rotation with a given scale in the game world.

You were right in your first reply, I was merely mistaken about the order of execution in JME because I made assumptions about that order without fully researching it in the source because I didn’t realize the CameraNode class was using an AbstractControl to achieve its effect.

I have a couple of ideas on how I might work around not being able to directly modify the list of AbstractControls. Your suggestion of using an AppState might prove useful, essentially instead of using an AbstractControl I’d just make my own similar implementation and add those objects, “object” as in object oriented programming, to a list this new AppState would iterate over.

Another approach would be to maintain a couple of variables that keep track of which AbstractControl was added last and in the control’s update method check to see if this.equals(lastAttachedEnabledControl) and if so run the info card loop from that control.

P.S. In my last post I was inquiring about needing to add the AbstractControl or Spatial the control is attached to last. Meaning I wasn’t sure if JME iterates over all attached AbstractControls or if it iterates over all attached Spatials looking for attached AbstractControls.

for (AbstractControl control : abstractControls) {
    control.controlUpdate(tpf);
}

or

for (Spatial spatial : rootNode.getChildren()) {
    for (AbstractControl control : spatial.getControls()) {
        control.controlUpdate(tpf);
    }
}

Well, since the things are in the guiBucket, you are already having to remap their position every frame to 2D screen space. So you could also just put those gui things in the guiNode and have them refer to their 3D counterparts to update their positions. guiNode is always updated after rootNode.

…though I think you probably missed my point about game objects versus spatials, I won’t belabor the point.

1 Like

I might look into using the guiNode, but I’m using NiftyGUI for my GUI and I think I read somewhere that anything in the guiNode is rendered after anything Nifty renders and I want my info cards to be rendered before Nifty.

I think it’s the other way around… but only testing would be sure.

Edit: and even still, there are ways around that I think.

Running a quick search turned up this post Render guiNode BEFORE niftygui - #9 by nehon

Apparently guiNode is indeed rendered after Nifty, but that can be changed when initializing the application.

Thanks for your input pspeed.

Edit: Now that I think about it I wouldn’t even have to attach the info cards to the guiNode, I could just use my existing code and move the info card update loop from simpleUpdate to a control attached to the guiNode.

Or do it in the render() method of an app state if you intend to do it globally like that.

1 Like

Even better, thanks again pspeed!

You know there was a reason I decided to update these things globally and for the life of me I can’t remember what that reason was. I actually finished up the AI, and I use the term finished loosely, back in December then put this project aside while I worked on creating and updating a few other projects. Now I’m coming back to this project, Carpe Diem, and am basically just reaclimating myself with JME and what I have written so far.

Oops, that didn’t work. Updating the screen positions of the info cards in an app state’s render method doesn’t work because the render method is called after the viewport root node’s updateGeometricState() method is called.

I did end up fixing the problem though. The info cards are attached to a root node in one of my custom cameras, not the default rootNode, so I just inserted the update loop after that node’s updateLogicalState(tpf) method and before that node’s updateGeometricState() method.