As a short term solution I am currently represented player velocity with a Vector2f for their x & y offset defining how much to move the player each update.
Well, for the 2D case, you only need to store the angle (in radians) and the magnitude, and you can simply move the character with
position.x += magnitude*Math.cos( angle );
position.y += magnitude*Math.sin( angle );
For the quaternion case, it is a little messier, but here is what I have done before:
double c = orient.w, s = orient.y, a = c*c - s*s, b = 2*c*s;
position.y += y*a - x*b;
position.x += x*a + y*b;
Assuming orient is a normalized quaternion that represents a Y-axis rotation of some amount, and position is a Vector3f (or 2f for that matter). x and y are the movement on the local coordinate system. If you are only interested in forward motion, you can set x = 0, y = magnitude, and this should do the trick (if it does not, then it is y = 0, and x = magnitude :P )
[Edit] changed get methods in the quaternion with w and y fields, get only works with Vector3f :|
Thanks for your reply duenez.
However, before I can even begin to establish the new position of the player (by setting the position.x, position.y co-ordinates), I need to calculate a new velocity based upon a provided acceleration value and the previous velocity (preferrably represented by a rotation quaternion and speed/magnitude float) - then I can look into updating the players localTranslation.
Sorry for not making that clearer eariler.
So, let me see if I understand correctly, you want the acceleration to be represented by a rotation quaternion and a scalar? If that is the case, why not represent it with a vector which is more natural. I guess I don't understand what is it that you want to limit… I thought you wanted to limit the actual update in position so it would not jump around too much (and hence, the speed vector), but if you limit only the acceleration, then the speed is still unbounded. :?
Ok, ive drawn a couple of diagrams which should better illustrate what i’m after, or asking is effective,… sorry for any misunderstanding.
This is what I currently have, the problem with this is that the player may exceed their maximum speed (in this case 5.0f) by moving along the X & Y axis - and I can’t think of a way to limit the players speed without affecting their handling.
So instead I came up with this representation, where the direction and speed are stored seperately.
Ok, here it goes:
From what I understand, you have a direction of speed represented by a quaternion and want to modify this orientation as well as the velocity (magnitude of the speed) with some procedural code.
Now, if you can guarantee that the quaternion is always going to be a Y-axis rotation (i.e. Y-Axis is up, and you always rotate as if it were turning your head around left or right like a regular game camera), then:
double c = direction.w, s = direction.y, a = c*c - s*s, b = 2*c*s;
speed.y = velocity*( y*a - x*b );
speed.x = velocity*( x*a + y*b );
will update your speed vector as desired, where velocity is just a float, and x, y work as I said before (one is forward/back, the other is left/right). Typically you would just use one of them, since the direction is already set by the quaternion.
To change the orientation, you need to have an angle you want to rotate to: if this is a rotation of theta radians (counter-clock-wise) relative to the actual orientation, then
direction.w += Math.cos( theta/2 );
direction.y = 1.0f - direction.w * direction.w;
If the angle is absolute, just replace the += by a simple =, and that should do the trick.
Hope this helps and is what you wanted ;)
Yes the direction Quaternion will always rotate about single axis (Z in this case).
I can't see how the following code you detailed is relevant? As I am trying to get away from speed being defined by two floating values (X and Y). I require a single float…
double c = direction.w, s = direction.y, a = c*c - s*s, b = 2*c*s;
speed.y = velocity*( y*a - x*b );
speed.x = velocity*( x*a + y*b );
I feel there is still a degree of misinterpretation, and I
Ok, this time I might have been the one who did not express my intention correctly… The reason why I have x and y is because they define local direction of speed on top of the already defined direction by the quaternion… Since you only want the direction to be defined by the quaternion, then set y to zero (or maybe x, depending on your coordinate system) in the above formulas an that's it, it will have the speed parametrized by the quaternion and a magnitude.
Ok my bad for being an idiot.
If I were to provide a small template, providing the parameters I am using (dont worry its very simple), including a single InputAction for accelerating, and a Node for updating - would you be able to fill in the gaps for me? I'm on the wrong laptop so I cant provide the template yet.
Thanks.
I would be happy to help… but maybe it is even worth adding it to the Quaternion class. (This is in addition to helping you with your code, of course )
Anybody thinks this is worth having?
A method like
myQuat.getUnitVector();
That would return a unit vector in the direction this quaternion is pointing to, then it could be scaled to whatever is appropriate.
Ok here is a cut down version of how im currently doing it.
Ok here is the template, hope thats everything you need. Please tell me if you need more. I havent attached a Box - so if you want to actually see anything that might be an idea.
import com.jme.input.action.InputActionEvent;
import com.jme.input.action.KeyInputAction;
public class AcceleratationAction extends KeyInputAction {
private TestNode affectedNode;
private float acceleration;
private float maxSpeed;
public AcceleratationAction(TestNode affectedNode) {
this.affectedNode = affectedNode;
acceleration = 10f;
maxSpeed = 5f;
}
public void performAction(InputActionEvent event) {
float time = event.getTime();
// INSERT CODE HERE
//
// Alter magnitude and direction with:
// - time (time per frame)
// - acceleration (acceleration constant)
// - magnitude (velocities magnitude)
// - direction (velocities direction)
// - local rotation (direction in which to accelerate)
if(affectedNode.getMagnitude() > maxSpeed) {
affectedNode.setMagnitude(maxSpeed);
}
}
}
import com.jme.math.Quaternion;
import com.jme.scene.Node;
public class TestNode extends Node {
private Quaternion direction;
private float magnitude;
public TestNode() {
direction = new Quaternion();
magnitude = 0f;
}
public void update(float time) {
// INSERT CODE HERE
//
// Alter local translation of X & Y with:
// - time (time per frame)
// - direction (velocities direction)
// - magnitude (velocities magnitude)
updateGeometricState(time, true);
}
public Quaternion getDirection() {
return direction;
}
public float getMagnitude() {
return magnitude;
}
public void setMagnitude(float magnitude) {
this.magnitude = magnitude;
}
}
Thanks again.
I dont know why it didnt occur to me earlier but i ran across the FlagRush tutorials whilst looking for a HeadlessApp test. They handle velocities more inline with how I would like to:
public void accelerate(float time) {
velocity += time * acceleration;
if(velocity > maxSpeed) {
velocity = maxSpeed;
}
}
public void update(float time) {
localTranslation.addLocal(localRotation.getRotationColumn(2, tempVa).multLocal(velocity * time));
}
Where the velocity (magnitude only) is a float and direction is the localRotation Quaternion. I havent implemented it yet but it looks good. Would still like to hear your proposal.
OK, here I can see where the big problem and misunderstanding came from. You not only want to change the speed of your node, but you want to add some acceleration to it. For this, definitely representing speed with a Quaternion and float, for direction and magnitude, is not going to be trivial. Because you want the speed (which is naturally a vector) to change with acceleration (which also is naturally a vector).
Updating the position with the speed represented by Quat & float is not a big deal (is what I wrote way back). But updating the Quat & float with a vector, is essentially as complex as creating the speed vector from those two and then doing exactly the same they were vector all along.
Haha, sorry if I didnt make myself clear at first.
Regarding your second paragraph…
duenez said:
But updating the Quat & float with a vector, is essentially as complex as creating the speed vector from those two and then doing exactly the same they were vector all along.
I never wanted to update the velocity Quat and float with a vector.
No prob! 8)