- Home /
Can someone explain this part of the PlayerMoveController.js script in the AngryBots demo?
Hey guys, I'm trying to go through and understand the controller script used in the Photon AngryBots multiplayer demo (PlayerMoveController.js).
The lines i'm having problems with are as follows:
function Start()
{
....
// it's fine to calculate this on Start () as the camera is static in rotation
screenMovementSpace = Quaternion.Euler (0, mainCameraTransform.eulerAngles.y, 0);
screenMovementForward = screenMovementSpace * Vector3.forward;
screenMovementRight = screenMovementSpace * Vector3.right;
}
And then these variables are used in the Update function as well:
function Update()
{
....
motor.movementDirection = Input.GetAxis ("Horizontal")
* screenMovementRight + Input.GetAxis ("Vertical")
* screenMovementForward;
}
I understand the call to Quaternion.Euler, which I think captures just the the y plane rotation of the main camera into a Quaternion.
I don't understand what the result of the next line, what is the result of a Quaternion object * Vector3 object?
The movementDirection comes from another script called MovementMotor.js.
Thanks!!
Answer by Radius9 · Dec 24, 2012 at 09:40 PM
The start function takes the main camera's rotation and stores it as a quaternion in screenMovementSpace. The variable screenMovementForward takes a forward vector (likely (0,0,1), but may vary depending on the space we are in) and rotates it by the camera transform. This will give you a vector of length 1, rotated in the forward direction of the camera. The same thing is done with screenMovementRight. What this gives you is 2 vectors, one that is forward in the direction of the camera, and the other is right from the direction the camera is facing. By taking the input in update, and multiplying it by these vectors, you are essentially scaling a vector pointing straight out right from the camera by the amount of horizontal controller movement, and adding in another vector that is the forward from the camera vector scaled by the amount of vertical controller input. This gives you input from the controller transformed into camera relative space. If you didn't do this, the vertical and horizontal movement of the controllers would be mapped to movement without rotation. Up on the controller would move in the same direction regardless of the direction you are looking.
Answer by aldonaletto · Dec 24, 2012 at 07:00 PM
As you've suspected, the first line gets the camera rotation considering only the horizontal plane (rotation about Y). The second and third lines apply this rotation to the vectors forward and right - this way, screenMovementForward points to the camera's forward direction in the horizontal plane, and screenMovementRight points to the camera's right direction also in the horizontal plane (multiplying a quaternion by a vector results in a vector rotated by the quaternion).
These direction vectors are used in Update to move the character: the "Horizontal" and "Vertical" axes control movement in the screenMovementRight and screenMovementForward directions. Input.GetAxis returns -1, 0 or +1, allowing left/right/forth/back and diagonal movements relative to the camera direction.
Answer by Crypton · Dec 26, 2012 at 02:26 PM
I'm doing the same thing. Digging in its guts :).
I've played around with the code but still don't fully understand how this works. (especially the quaternion part)
I've seen that as the player is rigidbody, physics apply to it, so x,y,z axis behave as they logically should. x,z plane is the ground, y is gravity.
At first tested the movement with back view camera: x,y,z=0 Euler angles, positioned a bit behind the player. This is the so to speak origin, so that Vector3.forward and -right or -up behave as they should. Quaternion makes no difference (it can be all zeros)
Difference only occurs when the camera is turned by y. So saving camera's y rotation makes sense.
Following this I could be able to rotate the whole level, lets say 90deg on the side and changing the forward and right with the quaternion and everything should work! ?
Maybe I'm not that skilled but didn't manage to do that. Set everything again the same as the first time, only the whole perspective is now rotated by z-axis - I rotated everything on z-axis 270 deg. Leaving the movement on y,z plane. In simpler terms: Forward is positive z-axis and right is negative y-axis. (world coordinates)
Just to make sure I don't fall somewhere I had to modify the physics, so in Start() before the ScreenMovementSpace calculation: Physics.gravity = Vector3(-1.0, 0, 0);
x-axis is now the new up-down axis? (actually not sure, resetting the plane rotation, didn't realy change anything)
When the first time I put y-axis into the quaternion, to take x,z plane into account where to move, I used x-axis this time in the quaternion(when I rotate around x I change my forward direction) and... smth is not right.
screenMovementSpace = Quaternion.Euler(mainCameraTransform.eulerAngles.x, 0, 0);
(not taking the wierd mouse movement into account) Player Does move beatifully forward and back but not to the sides, instead it goes up and down.
Probably the most positive result was when I did this:
screenMovementSpace = Quaternion.Euler(0, 0, mainCameraTransform.eulerAngles.z);
(Moving forward right in this picture) Camera is rotated with x to actually see whetver the forward actually works
With this configuration, the values all made sense. y changed when moving forward and backward, z changed when moving to the sides.
But WHY? How come that at first I had to save quaternion on y axis (on x,z plane) and now instead of x-axis (y,z plane) I had to save z-axis rotation (x,y plane)?
Hopefully someone can follow this little experiment and answer this dilemma.
I'm not sure I know what exactly is going on, but I have a suspicion. It seems like you are now working in 2 different transforms. Conceptually, your idea is correct, but there is a step missing in your math. In the code, there is the following snippet:
screen$$anonymous$$ovementSpace = Quaternion.Euler (0, mainCameraTransform.eulerAngles.y, 0); screen$$anonymous$$ovementForward = screen$$anonymous$$ovementSpace Vector3.forward; screen$$anonymous$$ovementRight = screen$$anonymous$$ovementSpace Vector3.right;
What this does is take the camera's rotation that you are interested in, and generate a new "forward" and "right" vector relative to the camera's Y rotation. When your rotated your entire scene, everything rotated 270" on X. The problem is that in your math, you are still using a "forward" and "right" vector that is NOT rotated. You either need to make sure that your screen$$anonymous$$ovementSpace variable takes BOTH rotations into account (the 270" degrees on Z AND the X rotation of the camera), or you need to adjust your "forward" and "right" vectors to be in the space you are working in. Since adding multiple rotations to screen$$anonymous$$ovementSpace is likely to problematic (you can introduce order of rotation issues, etc.), I would rotate your "forward" and "right" vectors by 270" on Z. Your forward can stay the same, but if you change your "right" vector to be a "down" vector (since it's in world space), your code should work the way you expect it to.
Seems so indeed! As forward, right and up are constants then yes, that makes sense.
So I got it working in this way:
screen$$anonymous$$ovementSpace = Quaternion.Euler(mainCameraTransform.eulerAngles.x, 0, 270);
So I just plugged in the rotation by which I had rotated everything. (or use player's rotation.z value. I used gameObject.transform.rotation.z but didn't work. But I'm not good with pointing at things the moment anyway) BUT for movement to work I had to change another variable in Free$$anonymous$$ovement$$anonymous$$otor also.
deltaVelocity.x = 0;
Ins$$anonymous$$d of y which was the gravity axis before, had to be changed to x, which I had turned $$anonymous$$e into.
So cool, experiment does work and now I understand that piece of code in quite many aspects. Awesome! Definitely this is going into my "programmer's toolbox".