This code works as expected if 'missile' is a simple Node.
But wen i use a DynamicsNode the movement is very jittery, it seems that the DynamicsNode always wants to fly into the same direction.
Generally it should be possible to move and rotate a DynamicsNode like this right?
I also tried to clear any dynamics on the missile just to be sure, but it didn't help.
I believe you have to drive the DynamicsNode using forces and torques, as it takes its position from the body. Doing so (and limiting the max torque for turning) will create a more believable physical behavior, too.
If you want to set the velocity and direction yourself, you don't need the simulation of DynamicsNode anyway.
If you don't want to abandon your dynamic physics node, then reset the forces on that node at every update. That should stop it from wanting to go in its own direciton.
make the node a static node and check collisions with other static each frame (see physics pick tests) (+ usgin your your lookAt)
make the node a dynamic node, disable gravity for that node and clear forces each frame (+ usgin your your lookAt)
or if you want more physical behavior (not that hard either)
make the node a dynamic node, disable gravity, apply rotational forces to face the correct direction, apply acceleration force, use some strong dampening (e.g. with FrictionCallback) (not using lookAt)
The jitter may be an update problem. Do you use SimplePhysicsGame? If no, how and when do you update physics, when do you render and when do you update the scenegraph? Can you reproduce the jittering in a SimplePhysicsGame?
I want to rotate my missile using addTorque(Vector3f), but how can i calculate the needed Vector?
I tried something like this, but its obviously wrong.
// simulate a lookAt() to the target, q is set to the desired rotation
Vector3f vec = target.getWorldTranslation().subtract(missile.getPhysicsNode().getWorldTranslation());
Quaternion q = new Quaternion(missile.getPhysicsNode().getLocalRotation());
q.lookAt(vec, Vector3f.UNIT_Y);
// get the difference between the actual and desired direction
Vector3f change = q.getRotationColumn(2).subtract(missile.getPhysicsNode().getLocalRotation().getRotationColumn(2));
// now use change as input for addTorque(change) ...
Well first, somehow it seems i cannot reproduce my 'jittery movement' problem, i talked about in my first post.
But anyway, my question about rotation with torque is still there.
Following is a little test to show the problem.
If you press SPACE, a missile is spawned which chases the target (the Box) and dies after a few seconds.
It works as it is now, because i use missile.lookAt(target) in the MissileMover.
But the code that is commented out (surrounded by TODO) in HomingDevice.update() does not work (and probably does not make much sense). The commented out code should replace the lookAt() call.
It would be cool to rotate the missile using torque instead of lookAt().
So if anyone wants to try and fix it, i would be most grateful
@irrisor you said "localDelta = target.rotation.invert() x delta"
x means crossproduct right? but Quaternion has no cross Method which takes a Vector3f. I am not sure how to correctly get your localDelta Value.
public class HomingMissileTest extends SimplePhysicsGame {
private Node targetNode;
/**
* creates a new missile, represented by an Arrow.
* The missile is accellerated by the HomingDevice Controller.
*/
private void spawnMissile() {
// create missile
Arrow missileModel = new Arrow("arrow", 2, 0.3f);
missileModel.setModelBound(new BoundingBox());
missileModel.updateModelBound();
missileModel.getLocalRotation().fromAngleAxis(90 *
FastMath.DEG_TO_RAD, Vector3f.UNIT_X);
DynamicPhysicsNode missileNode =
getPhysicsSpace().createDynamicNode();
missileNode.attachChild(missileModel);
missileNode.generatePhysicsGeometry();
missileNode.addController(new HomingDevice(missileNode,
targetNode));
// place it infront of the camera
missileNode.setLocalTranslation(cam.getLocation().add(cam.getDirection().mult(5)));
missileNode.getLocalRotation().fromAngleAxis(FastMath.DEG_TO_RAD * 180, Vector3f.UNIT_X);
FrictionCallback fc = new FrictionCallback();
fc.add(missileNode, 100, 80);
getPhysicsSpace().addToUpdateCallbacks(fc);
input.addAction( new InputAction() {
public void performAction( InputActionEvent evt ) {
if ( evt.getTriggerPressed() ) {
spawnMissile();
}
}
}, InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_SPACE,
InputHandler.AXIS_NONE, false );
}
/**
* Controller to move the missile with force and torque.
*/
public class HomingDevice extends Controller {
private DynamicPhysicsNode missile;
private Node target;
private float lifetime = 50;
private float speed = 230;
public HomingDevice(final DynamicPhysicsNode missile,
final Node target) {
this.target = target;
this.missile = missile;
}
/**
* Alter the objects Rotation, so that it points towards
* the Target. Move the object forward.
*
* it should be something like this :
*
* delta = target.location - rocket.location
* localDelta = target.rotation.invert() x delta
* now steer localDelta.x to the left and localDelta.y upwards
* torque = [localDelta.x; localDelta.y; 0] x target.rotation
* rocket.torque = rocket.torque*0.9 + torque*100
*/
@Override
public void update(float time) {
// move the missile forward, along its direction
float currentSpeed = missile.getLinearVelocity(null).dot(
missile.getPhysicsNode().getLocalRotation().getRotationColumn(2));
float thrust = speed - currentSpeed;
if (Math.round(thrust) > 0) {
missile.addForce(new
Vector3f(missile.getLocalRotation().getRotationColumn(2).mult(thrust)));
}
}
}
/**
* The Controller for the target.
* Moves the Target around in a circle.
*/
public class TargetMover extends Controller {
private Node object;
private float speed = 35;
private float roationSpeed = 60;
public TargetMover(final Node object) {
this.object = object;
}
@Override
public void update(float time) {
object.getLocalRotation().multLocal(new Quaternion().fromAngleAxis(roationSpeed * time * FastMath.DEG_TO_RAD, Vector3f.UNIT_Y));
object.getLocalTranslation().addLocal(
object.getLocalRotation().getRotationColumn(2).mult(time * speed));
}
}
public static void main(String[] args) {
new HomingMissileTest().start();
}
}
@irrisor you said "localDelta = target.rotation.invert() x delta"
x means crossproduct right? but Quaternion has no cross Method which takes a Vector3f. I am not sure how to correctly get your localDelat Value.
I just meant multiply with inverse rotation. In Java that'd be something like
The algorithm does not compensate for existing rotational velocity. That's why your "homing arrows" are "confused" by any rotational forces (e.g. by collisions).
If you want to sort that out you need to subtract the current angular velocity from your torque with an appropriate factor.