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!