- Home /
Rotatating a character
Hi - so I have a character (a cube) that moves around a world based on the keyboard controls. But right now he just slides across the ground. I want him to rotate 90 degrees in the direction of the keyboard (right rotates him 90 to the right, in a sense so that he sort of flops over on his side). This sort of works with the code below (except that the rotation happens around the center, instead of the edge of the cube closest to the direction of movement), but the biggest problem is that if my character gets attacked, he gets flipped around and stuff, so when that happens, right might no longer be right, because the character has been spun. How would I accomplish this?
What I'm after is something like this game (worth getting if you have an iPhone / iPad) : http://www.youtube.com/watch?v=qNUcD-FXgDI&feature=player_embedded
I'd settle for a good reference to a comprehensive tutorial on character movement too.
//REVISED SOLUTION
Here's the code I ended up using. I'm sure it could be cleaned up a lot, but it seems to work anyway.
function Update() {
var x = Input.GetAxis("Horizontal") * Time.deltaTime * speed;
var z = Input.GetAxis("Vertical") * Time.deltaTime * speed;
cubeContainerRef.transform.Translate(x, 0, z, Space.World);
var moveRight = Input.GetKey(KeyCode.RightArrow);
var moveLeft = Input.GetKey(KeyCode.LeftArrow);
var moveUp = Input.GetKey(KeyCode.UpArrow);
var moveDown = Input.GetKey(KeyCode.DownArrow);
if (moveRight){
cubeRef.transform.Rotate(Vector3(0, 0 , -90) * Time.deltaTime * speed, Space.World);
cubeRef.rigidbody.AddForce (1, 0 , 0);
} else if (moveLeft){
cubeRef.transform.Rotate(Vector3(0, 0 , 90) * Time.deltaTime * speed, Space.World);
cubeRef.rigidbody.AddForce (-1, 0 , 0);
} else if (moveUp){
cubeRef.transform.Rotate(Vector3(90, 0 , 0) * Time.deltaTime * speed, Space.World);
cubeRef.rigidbody.AddForce (0, 0 , 1);
} else if (moveDown){
cubeRef.transform.Rotate(Vector3(-90, 0 , 0) * Time.deltaTime * speed, Space.World);
cubeRef.rigidbody.AddForce (0, 0 , -1);
}
var theForce : Vector3 = new Vector3 (x, 0, z);
cubeRef.rigidbody.AddForce(theForce * force);
}
So when ever your character is attacked, it gets knocked around alot. Are you wanting to prevent being knocked around? Or just want to reset to the original position it was in before hit?
I actually want it to be knocked around, and end up in whatever position the explosions and things cause it to be in, but I want the arrow keys to always move him in the exact same direction regardless of his orientation. So even if the cube is rotated 45 degrees around the y axis, pushing the right arrow would move him straight right (relative to the game board, not the character), flipping him over whatever edge/vertices was closest to that direction.
Answer by Eli-Davis · Jul 30, 2011 at 05:56 PM
Well if your using transform.translate you would do it something like...
transform.Translate(0, Time.deltaTime, 0, Space.World);
Or if it has a rigidbody you can use the rigidbody.AddForce
If this doesnt work please tell me, I'd love to figure this out and put it on my blog
Nice - I didn't realize I could add another parameter to specify to what the direction is relative to. It doesn't address the rotation I was going for, but I played around with things and ended up going with the revised code above. I'd still love to figure out how to make an object's rotation happen around a specific vertex / edge rather than around its center (or some way to move the center of origin programmatically), but this is a good start. Thanks for your help! Your blog is really helpful too, by the way.
http://unity3d.com/support/documentation/ScriptReference/Transform.RotateAround.html
that's something for rotating around. I'm not sure how to do what your saying though. And thanks
Answer by aldonaletto · Aug 03, 2011 at 05:09 AM
The game you've linked in your question doesn't use a regular physics engine; it probably fakes the physical rules it needs to work, including collision detection and gravity. Trying to reproduce exactly the same behaviour would be a really hard work, but if you just want the "flopping" walk style, the script below can do the job. Just create a cube and attach this script to it. If you want the flop sound, add an AudioSource and assign an appropriate sound to it (footstep4 from the FPS Tutorial is fine).
The idea is to flop the block using RotateAround, like @EliDavis suggested. When some movement key is pressed, the routine Flop defines around which point and axis the block will rotate, then does a 90 degrees rotation during the time defined by speed. To avoid accumulated errors, the routine AlignBlock is called prior moving. This routine forces orientation alignment to the axes by rounding the eulerAngles to multiples of 90 degrees. It also forces the position alignment to multiples of the block size (defined by size) thus the block will always walk in a grid with size spacing.
If the block has no rigidbody, it will be a really nice guy, flopping precisely over the grid positions - but will not be constrained by collisions nor be affected by gravity. If you add a rigidbody, it will collide and fall, but the flopping action will become somewhat weird (it sometimes stops for a while before ending the 90 degrees rotation). Anyway, the AlignBlock routine will always bring it back to the right position before moving.
NOTE: if a rigidbody is added, AlignBlock ignores Y to not interfere with gravity.
var speed: float = 4; // flops per second var size: float = 1; // block size var flopping = false;
function Update(){
var move = Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
if (move.magnitude > 0.2) Flop(move);
}
function Flop(movDir: Vector2){
var pivot: Vector3;
var axis: Vector3;
var fDir: float;
if (flopping) return; // ignore other commands while flopping
flopping = true; // signals it's flopping
if (movDir.y > 0){ // move forward?
axis = Vector3.right; // will rotate around x axis
pivot = Vector3(0,-1,1); // defines point around which rotate
fDir = 1; // angle of rotation positive
}
else
if (movDir.y < 0){
axis = Vector3.right;
pivot = Vector3(0,-1,-1);
fDir = -1;
}
else
if (movDir.x < 0){
axis = Vector3.forward;
pivot = Vector3(-1,-1,0);
fDir = 1;
}
else
if (movDir.x > 0){
axis = Vector3.forward;
pivot = Vector3(1,-1,0);
fDir = -1;
}
AlignBlock(); // aligns block to grid before flopping
// calculates the point around which the block will flop
pivot = transform.position + (pivot * size / 2);
var a: float = 0;
while (a < 1){
var dt = Time.deltaTime * speed;
a += dt;
// rotates +/- 90 degrees around axis
transform.RotateAround(pivot, axis, fDir*90*dt);
yield;
}
if (audio) audio.Play(); // makes the flop sound
flopping = false;
}
private function AlignBlock(){
var angles = transform.eulerAngles;
// forces euler angles to be multiples of 90
angles.x = 90 * Mathf.RoundToInt(angles.x / 90);
angles.y = 90 * Mathf.RoundToInt(angles.y / 90);
angles.z = 90 * Mathf.RoundToInt(angles.z / 90);
transform.eulerAngles = angles;
var pos = transform.position;
// forces x and z to be in a grid
pos.x = size * Mathf.RoundToInt(pos.x / size);
pos.z = size * Mathf.RoundToInt(pos.z / size);
// doesn't modify y if the block has a rigidbody
if (!rigidbody) pos.y = size * Mathf.RoundToInt(pos.y / size);
transform.position = pos; // comment out this line to ignore grid positioning
}
Your answer
Follow this Question
Related Questions
transform.Translate but Transform has Rotation!=0 1 Answer
World and Local Axis out of Alignment 1 Answer
How do I translate my ship left and right and have it rotate at the same time? 1 Answer
Simultaneously translating and rotating 2D sprite? 1 Answer
Move child objects in the opposite direction of parent object 0 Answers