SceneComposer: Custom Control's properties wrongly initialized in Property Panel

Hi,

To experiment SceneComposer as Level Design Tool :

  1. I create a Custom Control (private/protected field + getter/setter generated by lombok prepocessor + read/write method override manually).
  2. I add my Custom Control to a node in SceneComposer

In the property panel on the Custom Control, initial values are the default value of field, but are not

  • the default value I set in the constructor
  • the default value of in read(…) (from Savable) <-- Bug ?
  • the previous saved value <-- Bug (IMO)

When I change the value in the property panel :

  • the behavior on 3D view changes as expected
  • the value are load correctly in running game (from load of the scene)

May be I doing something wrong.

PS: where is the right place to request/discuss features for SceneComposer (I can contribute code).

  • You cannot use any but the empty constructor from the default UI
  • read() is only used when the Control is loaded from a j3o file and you have to care that it sets up the object correctly

I wrote a “wrong” sentence , I don’t have any constructor (like in the default Template for Control).

[java]

@ToString
public class ControlTranslationAnim extends AbstractControl {

@Getter
@Setter
Vector3f offset = new Vector3f();
@Getter
@Setter
long duration = 2000;
@Getter
@Setter
boolean pingpong = true;
private Vector3f t0;
private Vector3f tmp0 = new Vector3f();

@Override
protected void controlUpdate(float tpf) {

[/java]

Where is the issue (in my code or in SDK) ?

So combining your two posts the only possible problem seems to be that you didn’t implement your read/write methods.

Thanks for the quick reply, sorry for the “pingpong”

The full code :
[java]
package vdrones;

import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.Control;
import java.io.IOException;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@ToString
public class ControlTranslationAnim extends AbstractControl {

@Getter
@Setter
Vector3f offset = new Vector3f();
@Getter
@Setter
long duration = 2000;
@Getter
@Setter
boolean pingpong = true;
private Vector3f t0;
private Vector3f tmp0 = new Vector3f();

@Override
protected void controlUpdate(float tpf) {
    if (t0 == null) {
        t0 = spatial.getLocalTranslation().clone();
    }
    float ratio = (System.currentTimeMillis() % duration) / ((float) duration);
    if (pingpong) {
        ratio = Math.abs(ratio - 0.5f) * 2.0f;
    }
    tmp0.set(offset).multLocal(ratio);
    spatial.getLocalRotation().multLocal(tmp0);
    tmp0.addLocal(t0);
    spatial.setLocalTranslation(tmp0);
    //System.out.println("ratio : " + ratio + " .. " + spatial.getLocalTranslation() + ".." + spatial.getName());
}

@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
    //Only needed for rendering-related operations,
    //not called when spatial is culled.
}

@Override
public Control cloneForSpatial(Spatial spatial) {
    ControlTranslationAnim control = new ControlTranslationAnim();
    control.setSpatial(spatial);
    control.duration = duration;
    control.offset = offset;
    control.pingpong = pingpong;
    control.t0 = t0;
    return control;
}

@Override
public void read(JmeImporter im) throws IOException {
    super.read(im);
    InputCapsule in = im.getCapsule(this);
    this.enabled = in.readBoolean("enabled", true);
    //this.duration = in.readLong("duration", 2000);
    this.offset = (Vector3f) in.readSavable("offset", new Vector3f());
    this.pingpong = in.readBoolean("pingpong", false);
}

@Override
public void write(JmeExporter ex) throws IOException {
    super.write(ex);
    OutputCapsule out = ex.getCapsule(this);
    out.write(this.enabled, "enabled", true);
    out.write(this.duration, "duration", 1.0f);
    out.write(this.offset, "offset", new Vector3f());
    out.write(this.pingpong, "pingpong", false);
}

}

[/java]

When I load the scene from j3o in the game the value set in SceneComposer are correct (So I imagine the read/write method are correct.

No idea, looks like your render thread in the SDK crashed or something. Do you get any updates of the properties? (E.g. when your control moves the spatial, does the spatial position update about every second?)

The spatial position is updated (on 3D view and on property panel).
Everything works except the initial values of Control (on add, on open of the scene).

Else where is the right place for feature request (before coding, PR) for SceneComposer ?

Maybe your processor doesn’t work right? Did you try adding the getters and setters manually? (Theres a refactor command for that)

A side bugs of the controler, when the scene is saved, the position modified by the control is saved so if I re-open the scene the initial position of the spatial is different.

@david.bernard.31 said: A side bugs of the controler, when the scene is saved, the position modified by the control is saved so if I re-open the scene the initial position of the spatial is different.

Thats not a bug, it just saves the scene as it is. Its basically the point of the editor. Imagine you would edit something and it wasn’t saved. Did you try manual getters/setters?

Same result with explicit getter + setter.
Same result with 3.0 (stable) and git version (1a1d74f83ebd6cb9aea0f307defbc556a537c23c Mon Jun 2 23:25:31 2014 -0400) of SDK.

About side-bug. I understand the cause. Any workaround/idea. I original though about using SceneComposer as level editor like in Unity. And use Control to define/ to tune game’s behavior. Is it the wrong way, I’m new to jmonkeyengine3, what do you used as level editor ?

@david.bernard.31 said: About side-bug. I understand the cause. Any workaround/idea. I original though about using SceneComposer as level editor like in Unity. And use Control to define/ to tune game's behavior. Is it the wrong way, I'm new to jmonkeyengine3, what do you used as level editor ?

Sure you can do that but why does your control move anything when theres nothing happening? And if thats needed to test things, just don’t save the scene when you try out game mechanics?

My control animate spatial in scene (traps, NPC). I want to use the SceneComposer to tune the animation, to create trigger zone,… and I whish to save from SceneComposer the value of Spatial, Control, UserData. I didn’t see in the SceneComposer a mode to setup and a mode to “play”.

Well there is none. Again, when you try out your Controls actions theres no need to save the scene. If you need your controls to be able to reset the spatial location, add such a function to them.

So attaching Control / behavior to a spatial can’t be done in SceneComposer and should not be saved in j3o ?
And I have to attach all Controls and set every properties manually each time I want to use SceneComposer ?

Will I have the same issue if import a model + animation from blender in the scene ?

@david.bernard.31 said: So attaching Control / behavior to a spatial can't be done in SceneComposer and should not be saved in j3o ? And I have to attach all Controls and set every properties manually each time I want to use SceneComposer ?

Will I have the same issue if import a model + animation from blender in the scene ?

Sure it can be done and its meant to be saved in the j3o, the question remains why your game logic would start immediately when you attach the scene to the rootNode. If I was you, I would make the Control so that I can set the values and then setEnabled(true) or something to actually have it start do stuff. This way you can set the values, save the scene and then enable the control to check the results and not save the changes it has done.

Generally, for game logic AppStates probably make more sense anyway but I can’t say what you are doing exactly.

To explain further, in this example I save the Control along with the j3o but the Control on the character doesn’t do anything when its not attached to a terrain so I don’t run into the issues you have because your game logic starts as soon as you attach the Control.

I saw this video, it’s the main cause of my current experimentation (I’ll view it again, I may have miss something).

My custom control has the same role of the one that rotate in the blades. In my case it’s a mobile wall in a race or labyrinth. It’s part of the level. I place the wall and tel move here to here. In my previous “prototype” (home-made web engine) I used entity-component-system approach, doing the same with AppState/Control/UserData will be translated into define properties into UserData and “update” code into AppState (where I’ll full scan the scenegraph to search matching UserData before update), it seems overkill and using Control a better match.

I can’t edit enable of Control via Property panel. And I can disable the Control before save then the save state will be disable, And As you wrote, I’ll have to enable it in game (and take care to not enable Control that should say disable).

To be able to edit any property via the properties window it needs proper getters/setters, then you can edit it. Simple solution:

[java]private boolean doGameStuff = false;

public void update(float tpf){
if(doGameStuff){
//do game stuff
}
}

public void setDoGameStuff(boolean enabled){
this.doGameStuff = enabled;
}

public boolean isDoGameStuff(){
return doGameStuff;
}[/java]