Rotations problem

Hi!



I’m trying to do a simple Simon3D game in order to get familiar with JME.



I have four boxes that the user has to click just like the simon memory game.







Also, to make it a little more difficult sometimes the boxes turn clockwise or counterclockwise on the Z axis.



I’ve done this using SpatialTransforms with a Node that contains all the boxes attached, and it works ok (just like the HelloAnimation example)



Now, If I want to do other transformations (for example twist the boxes when the user loses the game) and the boxes are already turned, then the transformations is unpredictable.



I supose I have to keep track on what transformations I’ve already made, but I’m not sure how…



Here is the code for the “board”, a node that contains all the boxes:



/**
 * Node that contains all the boxes, plus SpatialTransforms
 */
public class BoardNode extends Node {

    // the boxes
    private SimonBox[] boxes;

    // the transformer
    private SpatialTransformer st;

    private float angle;

    public BoardNode(String name, Renderer renderer) {
        super(name);

        boxes = new SimonBox[4];
        final float dist = 1.4f;

        boxes[0] = new SimonBox("b0", renderer, "Monkey.jpg", "Monkey2.jpg");
        boxes[0].setLocalTranslation(new Vector3f(dist, dist, 0));

        boxes[1] = new SimonBox("b1", renderer, "Monkey.jpg", "Monkey2.jpg");
        boxes[1].setLocalTranslation(new Vector3f(-dist, -dist, 0));

        boxes[2] = new SimonBox("b2", renderer, "jengibre.jpg", "jengibre2.jpg");
        boxes[2].setLocalTranslation(new Vector3f(dist, -dist, 0));

        boxes[3] = new SimonBox("b3", renderer, "jengibre.jpg", "jengibre2.jpg");
        boxes[3].setLocalTranslation(new Vector3f(-dist, dist, 0));

        attachChild(boxes[0]);
        attachChild(boxes[1]);
        attachChild(boxes[2]);
        attachChild(boxes[3]);

        st = new SpatialTransformer(1);
        st.setObject(this, 0, -1);
        st.interpolateMissing();
        addController(st);
        st.setActive(false);

        angle = 0;
    }

    private void rotate(boolean left) {
        if (st.getCurTime() >= st.getMaxTime()) {

            Quaternion x0 = new Quaternion();
            x0.fromAngleAxis(angle, Vector3f.UNIT_Z);

            if (left) {
                angle += FastMath.PI / 2;
            }
            else {
                angle -= FastMath.PI / 2;
            }

            Quaternion x90 = new Quaternion();
            x90.fromAngleAxis(angle, Vector3f.UNIT_Z);

            st.setRotation(0, 0, x0);
            st.setRotation(0, 1, x90);

            st.setActive(true);

            // restart
            st.setCurTime(0);

            for (int i = 0; i < boxes.length; i++) {
                boxes[i].rotate(!left);
            }
        }
    }

    public void rotateLeft() {
        System.out.println("rotateLeft()");
        rotate(true);
    }

    public void rotateRight() {
        System.out.println("rotateRight()");
        rotate(false);
    }

    public SimonBox getBox(int n) {
        return boxes[n];
    }

    public void allOff() {
        // todas vuelven a su textura off
        for (int i = 0; i < boxes.length; i++) {
            boxes[i].off();
        }
    }

    public void twirl() {
        System.out.println("Twirl");
        for (int i = 0; i < boxes.length; i++) {
            boxes[i].twirl();
        }
    }
}



And here is the class for each of the boxes:


public class SimonBox extends Box {

    private Texture on, off;

    private TextureState txState;

    private float angle;

    public SimonBox(String name, Renderer renderer, String textureOn,
            String textureOff) {
        super(name, new Vector3f(-1, -1, -1), new Vector3f(1, 1, 1));
        setModelBound(new BoundingBox());
        updateModelBound();

        ClassLoader cl = SimonBox.class.getClassLoader();
        on = TextureManager.loadTexture(cl.getResource(textureOn),
                Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR);
        off = TextureManager.loadTexture(cl.getResource(textureOff),
                Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR);

        txState = renderer.createTextureState();
        txState.setEnabled(true);
        txState.setTexture(off);
        setRenderState(txState);

        angle = 0;
    }

    public void on() {
        txState.setTexture(on);
    }

    public void off() {
        txState.setTexture(off);
    }

    public boolean isOn() {
        return txState.getTexture() == on;
    }

    public void rotate(boolean left) {
        // borro todos los que haya
        getControllers().clear();

        SpatialTransformer st = new SpatialTransformer(1);
        st.setObject(this, 0, -1);

        Quaternion x0 = new Quaternion();
        x0.fromAngleAxis(angle, Vector3f.UNIT_Z);

        if (left) {
            angle += FastMath.PI / 2;
        }
        else {
            angle -= FastMath.PI / 2;
        }

        if (angle < 0) {
            angle += FastMath.PI * 2;
        }
        if (angle > FastMath.PI * 2) {
            angle -= FastMath.PI * 2;
        }

        Quaternion x90 = new Quaternion();
        x90.fromAngleAxis(angle, Vector3f.UNIT_Z);

        st.setRotation(0, 0, x0);
        st.setRotation(0, 1, x90);

        st.interpolateMissing();

        addController(st);

        if (getName().equals("b0")) {
            printInfo();
        }
    }

    public void twirl() {
        // borro todos los que haya
        getControllers().clear();

        SpatialTransformer st = new SpatialTransformer(1);
        st.setObject(this, 0, -1);

        Quaternion x0 = new Quaternion();
        x0.fromAngleAxis(angle, Vector3f.UNIT_XYZ);

        angle += FastMath.PI;

        Quaternion x180 = new Quaternion();
        x180.fromAngleAxis(angle, Vector3f.UNIT_XYZ);

        angle += FastMath.PI;

        Quaternion x360 = new Quaternion();
        x360.fromAngleAxis(angle, Vector3f.UNIT_XYZ);

        st.setRotation(0, 0, x0);
        st.setRotation(0, 0.5f, x180);
        st.setRotation(0, 1, x360);

        st.interpolateMissing();

        addController(st);

        if (angle < 0) {
            angle += FastMath.PI * 2;
        }
        if (angle > FastMath.PI * 2) {
            angle -= FastMath.PI * 2;
        }

        if (getName().equals("b0")) {
            printInfo();
        }
    }

    private void printInfo() {
        Quaternion local = getLocalRotation();
        Quaternion world = getWorldRotation();

        Vector3f lAxis = new Vector3f();
        Vector3f wAxis = new Vector3f();

        float langle = local.toAngleAxis(lAxis) * FastMath.RAD_TO_DEG;

        float wangle = world.toAngleAxis(wAxis) * FastMath.RAD_TO_DEG;

        System.out.println("Angle: " + FastMath.RAD_TO_DEG * angle);
        System.out.println("local angle: " + langle);
        System.out.println("world angle: " + wangle);
        System.out.println("local axis: " + lAxis);
        System.out.println("world axis: " + wAxis);
    }
}



I'm not sure if I'm doing this the right way (reusing SpatialTransforms for example).

So, If I call rotateLeft on the board and then twirl on a box, it turns into a weird angle.

Any help will be most appreciated!