Moving one object by another

Let’s say, I want one object to copy another’s position (but not orientation).
[java]
Node_A.setLocalTranslation(Node_B.getLocalTranslation());
[/java]

The problem is, it seems to lag one frame, and sometimes jiggle. It’s less noticeable on high fps, and really disturbing with vsync ON.
Same problem accrue with cam.getWorldCoordinates, when i want some object to float in front of camera on certain screen position. It’s lag and jiggle, no matter where I put it: simpleUpdate, simpleRender or InputEvent.

So question is: Is it even a proper way to make complex relations? Like third person camera rig, or weapon/item floating in front of camera.

Thats not the default behavior. Must be something else you do.

I think the easiest way to achieve this effect would be simple parenting. Or even have a common ancestor node.

For example, you have a node with two children: a camera node and a weapon node. When you move the common node, both the camera and the weapon move.

Thats not the default behavior. Must be something else you do.

Yeah, just tried to repeat it in empty simple application, Works perfect. :confused:
Will look more carefully to find my fault, or to repeat it in isolated application.

What he does is fine and is what all internal controls etc. do.

I returned with simple code.
Left and Right keys move camera along X axis. Red cube suppose to be attached to camera, but with Vsync on, its noticeably lag.
What do I do wrong?

[java]
package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.InputListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.CameraControl;

public class camFollowTest extends SimpleApplication {

private Spatial smallbox;
private CameraNode camNode;

public static void main(String[] args){
    camFollowTest app = new camFollowTest();
    app.start(); // start the game
}

@Override
public void simpleInitApp() {
    Box b = new Box(Vector3f.ZERO, 1, 1, 1); // create cube shape at the origin
    Geometry geom = new Geometry("Box", b);
    Material mat = new Material(assetManager,
      "Common/MatDefs/Misc/Unshaded.j3md");  // create a simple material
    mat.setColor("Color", ColorRGBA.Blue);   // set color of material to blue
    geom.setMaterial(mat);                   // set the cube’s material
    rootNode.attachChild(geom);              // make the cube appear in the scene

    Box b2 = new Box(Vector3f.ZERO, 0.1f, 0.1f, 0.1f); // create cube shape at the origin
    smallbox = new Geometry("Box", b2);  // create cube geometry from the shape
    Material mat2 = new Material(assetManager,
      "Common/MatDefs/Misc/Unshaded.j3md");  // create a simple material
    mat2.setColor("Color", ColorRGBA.Red);   // set color of material to blue
    smallbox.setMaterial(mat2);                   // set the cube’s material
    rootNode.attachChild(smallbox);              // make the cube appear in the scene

    //flyCam.setMoveSpeed(60);
    flyCam.setEnabled(false);
    camNode = new CameraNode("Camera Node", cam);
    camNode.setControlDir(CameraControl.ControlDirection.SpatialToCamera);
    rootNode.attachChild(camNode);
    camNode.setLocalTranslation(0, 1.3f, -7);

    inputManager.addMapping("Left",   new KeyTrigger(KeyInput.KEY_LEFT));
    inputManager.addMapping("Right",  new KeyTrigger(KeyInput.KEY_RIGHT));

    inputManager.addListener(analogListener, new String[]{"Left", "Right"});

}

public void simpleUpdate(float tpf) {
    //Vector3f pos = cam.getWorldCoordinates(new Vector2f(200,200), 0.2f);
    //smallbox.setLocalTranslation(pos);
}

@Override
public void simpleRender(RenderManager rm) {
    Vector3f pos = cam.getWorldCoordinates(new Vector2f(200,200), 0.2f);
    smallbox.setLocalTranslation(pos);
}

private AnalogListener analogListener = new AnalogListener() {
public void onAnalog(String name, float value, float tpf) {
    if (name.equals("Left")) {
      camNode.move(1*tpf, 0, 0);
    }
    if (name.equals("Right")) {
      camNode.move(-1*tpf, 0, 0);
    }
}
};

}

[/java]

EDIT: Fixed broken quotes symbols in code.
EDIT2: Not worked, still broken :frowning:

key inputs should really be used with action listeners, as they have a state (pressed or not). Im not sure it works properly with an analog listener (could be wrong)

key inputs should really be used with action listeners
Even tutorial suggests using AnalogListener for movement : https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:beginner:hello_input_system

i stand corrected then ^^

public void simpleRender(RenderManager rm)

In general, if you are overriding this method then you are doing it wrong… always. Try moving your object in simple update instead.

(Caveat that with “until you can argue with me otherwise”.)

Yep, simpleRender is your issue, it causes most of the values to be applied next frame. Just do everything in simpleUpdate(). But thats something that the Hello tutorials already told you I hope :stuck_out_tongue:

As I said in first post, it’s laging in both SimpleUpdate and SimpleRender. It even do, if I place it into analogListner, right next to camNode.move .

Hi.

I think this is just a trouble of propagating information. I solved your lag this way:

[java]
private AnalogListener analogListener = new AnalogListener() {
public void onAnalog(String name, float value, float tpf) {
if (name.equals(“Left”)) {
camNode.move(1tpf, 0, 0);
}
if (name.equals(“Right”)) {
camNode.move(-1
tpf, 0, 0);
}

camNode.updateLogicalState(tpf);
Vector3f pos = cam.getWorldCoordinates(new Vector2f(200,200), 0.2f);
smallbox.setLocalTranslation(pos);

}
};
[/java]

As you can see, I first update the camNode so that information is passed to the embedded camera, so that the getWorldCoordinates work on the new position.
The additional benefit for moving the cube there is that this is only done when the camera moves :wink:

InputListeners are called before simpleUpdate, then the control updates are called.

So when you do it in the analog listener, the camera node hasn’t updated the camera yet. When you do it in simple update, the camera node hasn’t updated the camera yet. So when you set the spatial position right off of the camera (instead of the CameraNode) then it will always be a frame behind. You are setting the small box position to that of the camera last frame. If you set it to the position of the camera node then it shouldn’t lag.

Can you explain more about what you are trying to do and why you are using such a round-about setup? Moving a node to move the camera to move another node is kind of a long way around to go.

As you have it now, some of the code wants camera node to be the primary mover and some wants camera to be.

If you catch yourself calling: camNode.updateLogicalState(tpf);

…then you are doing something wrong in your setup somewhere else.

This is why I suggested parenting the small cube to the camera…
But I can understand that, in particular situations, this may not be possible.

1 Like

There are still numerous ways of avoiding calling updateGeometryState() manually.

1 Like