I have balls that roll around and run into each other. When they hit, they should stick together (one becomes the child of the other). I attachChild() and set the child’s local translation (to 3f, 0f, 0f for example) but the world translations go way off - by hundreds. I also get a change in scale which is not reflected in the output (crazy, I know). Is it possible to upload a zip file?
//sample output
collision (Ant#2 and Ant#3)
nodeList[0]=FormNode [Ant#3, #3, 3, x=0.0, y=0.0, z=3.0, color=Color[0.2677251, 0.3141973, 0.19586271, 1.0]]
set to =0.0, 0.0, 3.0
child world trans before=(3.549219, 0.099999994, 0.64092755)
child local trans before=(3.549219, 0.099999994, 0.64092755)
Ant#2.attachChild(Ant#3) code is 6
child local trans after=(0.0, 0.0, 3.0)
parent world trans after=(3.7876701, 0.099999994, 0.6678786)
child world trans after=(3.7876701, 0.099999994, -186.47888)
child local scale after=(10.0, 10.0, 10.0)
//children
Models/Ant/AntSphere.blend, (0.0, 0.0, 0.0)
Processor, (0.0, 0.0, 0.0)
Battery, (0.0, 0.0, 0.0)
GPS, (0.0, 0.0, 0.0)
Radio, (0.0, 0.0, 0.0)
Ant#3, (0.0, 0.0, 3.0)
Here is my test case. It works great.
But, in program, it doesn’t work. I’m thinking it may be a relationship between the model and the node that holds it but, it looks ok to me.
package mygame;
import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
//animation
import com.jme3.animation.AnimChannel;
import com.jme3.animation.AnimControl;
import com.jme3.animation.AnimEventListener;
import com.jme3.animation.LoopMode;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Sphere;
import java.awt.Frame;
import javax.swing.JFrame;
/**
* test
* @author normenhansen
*/
public class Main extends SimpleApplication{
private AnimChannel channel;
private AnimControl control;
//Node wedge;
//Color skyblue = new Colorf(.5f, .5f, .5f);
static JFrame window;
public static void main(String[] args) {
Main app = new Main();
app.start();
}
@Override
public void simpleInitApp() {
//super();
System.out.println("simpleInitApp()");
Node[] ball = new Node[3];
flyCam.setMoveSpeed(50);
viewPort.setBackgroundColor(ColorRGBA.LightGray);
DirectionalLight dl = new DirectionalLight();
dl.setDirection(new Vector3f(-0.1f, -1f, -1).normalize());
rootNode.addLight(dl);
//scene objects
for (int i = 0;i < ball.length;i++){
ball[i] = new Node("ball" + i);
Sphere sphere = new Sphere(20, 20, 1);
Geometry geo = new Geometry("sphere" + i, sphere);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
geo.setMaterial(mat);
mat.setColor("Color", ColorRGBA.randomColor());
ball[i].attachChild(geo);
//ball[i] = new Node();
if (i == 0){
//leave at 0, 0, 0 and 0, 0, 0
ball[i].setUserData("waiting", new Boolean(true));
ball[i].setUserData("walking", new Boolean(false));
ball[i].addControl(new RollControl(ball));
rootNode.attachChild(ball[i]);
}
else if (i == 1){
ball[i].setLocalTranslation(2f, 0f, 0f);
ball[0].attachChild(ball[i]);
ball[i].setUserData("waiting", new Boolean(false));
ball[i].setUserData("walking", new Boolean(false));
ball[i].addControl(new RollControl(ball));
}
else if (i == 2){
ball[i].setUserData("waiting", new Boolean(false));
ball[i].setUserData("walking", new Boolean(true));
ball[i].setLocalTranslation(-5f, 0f, 0f);
ball[i].addControl(new RollControl(ball));
rootNode.attachChild(ball[i]);
}
}
initKeys();
}
public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName){
if (animName.equals("Walk")){
channel.setAnim("stand", 0.50f);
channel.setLoopMode(LoopMode.DontLoop);
channel.setSpeed(1f);
}
}
public void onAnimChange(AnimControl control, AnimChannel channel, String animName){
//unused
}
private void initKeys(){
inputManager.addMapping("Walk", new KeyTrigger(KeyInput.KEY_SPACE));
inputManager.addListener(actionListener, "Walk");
}
private ActionListener actionListener = new ActionListener(){
public void onAction(String name, boolean keyPressed, float tpf){
if(name.equals("Walk") && !keyPressed){
if(!channel.getAnimationName().equals("Walk")){
channel.setAnim("Walk", 0.50f);
channel.setLoopMode(LoopMode.Loop);
}
}
}
};
@Override
public void simpleUpdate(float tpf) {
//TODO: add update code
}
@Override
public void simpleRender(RenderManager rm) {
//TODO: add render code
}
}
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mygame;
//http://vormplus.be/blog/article/drawing-a-cylinder-with-processing
//import com.jme3.scene.Geometry;
//import com.jme3.material.Material;
import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.Control;
import com.jme3.util.BufferUtils;
import java.util.List;
import java.io.IOException;
//cylinder
/**
*
* @author Peter
*/
//0 front, 1 back, 2 right, left 3, top, 4, bottom 5,
//body 0, cap 1
//body 0, top 1, bottom 2
public class RollControl extends AbstractControl{
float speed = 1;
Node[] ball = new Node[3];
private final Quaternion lookRotation = new Quaternion();
//}
public RollControl(){
}
public RollControl(Node[] ball){
this.ball = ball;
}
@Override
protected void controlUpdate(float tpf){
if ((Boolean)spatial.getUserData("walking")){
Vector3f aim = ball[0].getWorldTranslation();
Vector3f dist = aim.subtract(spatial.getWorldTranslation());//my location
if (dist.length() < 2) {
spatial.setUserData("walking", new Boolean(false));
} else {
dist.normalizeLocal();
lookRotation.lookAt(dist, Vector3f.UNIT_Y);
spatial.setLocalRotation(lookRotation);
spatial.move(dist.multLocal(speed * tpf));
}
}
if ((Boolean)spatial.getUserData("waiting")){
Vector3f aim = ball[2].getWorldTranslation();
Vector3f dist = aim.subtract(spatial.getWorldTranslation());//my location
if (dist.length() < 2) {
spatial.setUserData("waiting", new Boolean(false));
System.out.println("ready!");
ball[0].attachChild(ball[2]);
ball[2].setLocalTranslation(-2f, 0f, 0f);
List list = ball[0].getChildren();
for (int i = 0;i < list.size();i++){
Spatial thing = (Spatial)list.get(i);
System.out.println(thing.getName());
}
ball[2].setUserData("walking", new Boolean(false));
spatial.setUserData("walking", new Boolean(true));
} else {
//just wait
}
}
}
protected void setSpeed(float speed){
this.speed = speed;
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
//Only needed for rendering-related operations,
//not called when spatial is culled.
}
public Control cloneForSpatial(Spatial spatial) {
RollControl control = new RollControl();
//TODO: copy parameters to new Control
return control;
}
@Override
public void read(JmeImporter im) throws IOException {
super.read(im);
InputCapsule in = im.getCapsule(this);
//TODO: load properties of this Control, e.g.
//this.value = in.readFloat("name", defaultValue);
}
@Override
public void write(JmeExporter ex) throws IOException {
super.write(ex);
OutputCapsule out = ex.getCapsule(this);
//TODO: save properties of this Control, e.g.
//out.write(this.value, "name", defaultValue);
}
}
//parent
public boolean connectToTarget(float tpf){
for (int a = 0;a < targetList.length;a++){//for each string/join
if (!nodeList[a].getName().isEmpty()){//ingore ends with no links
//check dist
Vector3f aim = targetList[a].getWorldTranslation();//other location - sent from loc request
Vector3f dist = aim.subtract(spatial.getWorldTranslation());//my location
//check distance of nodes moving to you
if (dist.length() < (0.25)) {
System.out.println("collision (" + ant.getName() + " and " + targetList[a].getName() + ")");
//find who hit you
Node node = spatial.getParent();
if (node != null) {
final List<Spatial> ants = new LinkedList<Spatial>();
node.depthFirstTraversal(new SceneGraphVisitor() {
@Override
public void visit(Spatial spatial) {
ants.add(spatial);
}
});
//repare to attachChild
Ant tempParent = ant;//me
//search target's name
Ant tempChild = null;
for (int b = 0;b < ants.size();b++){
if (ants.get(b).getName().equals(targetList[a].getName())) {
tempChild = (Ant)ants.get(b);
}
}
//checking shortcut to get child
tempChild = targetList[a];
//got both - parent and child
if (tempParent != null && tempChild != null){
//print attach data
System.out.println("nodeList[" + a + "]=" + nodeList[a]);
System.out.println("set to =" + nodeList[a].getX() + ", " + nodeList[a].getY() + ", " + nodeList[a].getZ());
System.out.println("child world trans before=" + tempChild.getWorldTranslation());
System.out.println("child local trans before=" + tempChild.getLocalTranslation());
//attach and reset local trans
int h = tempParent.attachChild(tempChild);
tempChild.setLocalTranslation(nodeList[a].getX(), nodeList[a].getY(), nodeList[a].getZ());
//check attachment (returns num of obj in list)
System.out.println(tempParent.getName() + ".attachChild(" + tempChild.getName() + ") code is " + h);
//check local trans
System.out.println("child local trans after=" + tempChild.getLocalTranslation());
System.out.println("parent world trans after=" + tempParent.getWorldTranslation());
System.out.println("child world trans after=" + tempChild.getWorldTranslation());
System.out.println("child local scale after=" + tempChild.getLocalScale());
//check attachement
List list = ant.getChildren();
for (int i = 0;i < list.size();i++){
Spatial thing = (Spatial)list.get(i);
System.out.println(thing.getName() + ", " + thing.getLocalTranslation());
}
tempParent.setWalking(false);
tempParent.setMoving(false);
tempParent.setStanding(true);
//turn everything off
tempChild.setInvited(false);
tempChild.setStanding(false);
tempChild.setMoving(false);
tempChild.setWalking(false);
tempChild.setGrouped(true);
System.out.println();
spatial.move(0f, 0f, 0f);//maybe this will cause a recalc of childs LT (nope!)
}
else{
//if (ant.getID() == 0 || ant.getID() == 1) System.out.println(tempParent.getName() + ".attachChild(" + tempChild.getName() + ") code is " + h);
}
}//null node
}//dist
}//is empty
//}
}//not grouped
return(true);
}