- Home /
Rolling Cube with Rigidbody?
Hi All,
New to Unity3D, a few hours in, so bear with me. I'm trying to create a cube that rolls along its edge based on key input. I've been able to get this working by referencing the code found in the thread, http://answers.unity3d.com/questions/742/rolling-cubes-one-space-and-one-rotation-at-a-time-with-a-delay. The problem I'm having is I'd like this cube to react to physics. Gravity, collisions, etc. For example if the cube is only rotated part way it should fall back into position, lying flat on the plane beneath it. If I attach a Rigidbody to the cube the rolling code does not function as I would like. The cube tries to roll a little then fails, then moves backwards unexpectedly. I'm using RotateAround to roll the cube. I tried experimenting with AddTorque but have been unsuccessful.
I did find that if I check the Is Kinematic option for the rigidbody the cube rolls along successfully and even collides with other objects. However, it is then unaffected by gravity. I feel like there is probably some proper way to do this that I'm unaware of due to lack of experience.
Any help would be appreciated.
Thanks
I'm getting closer. I am able to get the cube rolling if I apply more "oomph" in my RotateAround call. Basically, I just increase the speed. Along with adjusting the mass of the cube I've got quite a nice result. However, things get weird. Occasionally the cube gets into this state where it doesn't roll correctly. I think it's a bug in the way I'm deter$$anonymous$$ing which edge to roll on (the point used in RotateAround).
Answer by Jaap Kreijkamp · Mar 17, 2010 at 12:27 AM
The script from the other answer won't help you much or you have to change a lot. The simplest solution is to give the Cube a rigidbody
and add a script like this:
function FixedUpdate () {
rigidbody.AddTorque(25, 0, 0);
}
of course, when the cube tipps over, it will still rotate but just around the same axis, that's now pointing up/downwards.
You're absolutely right. I failed to realize that when I tried that and it didn't work it was because I didn't put enough torque on it. Playing with the torque values and the mass gives some pretty decent results. I also lock down the rotations on the other axes to keep it from getting too squirrely. I'm almost there. I just need to constrain the position so the cube locks into place. Otherwise if it moves to fast it starts to slip -- That is, it doesn't translate by its entire width during one rotation.
Answer by e-bonneville · Mar 17, 2010 at 01:50 AM
You might want to try transform.Rotate, which rotates the cube. The following script is an example:
function FixedUpdate () {
if (Input.GetButtonDown ("Fire1")) {
transform.Rotate (5, 0, 0);
}
By the way, you might want to check out this tutorial for beginning Unity scripting. Good luck!
Answer by Paul 3 · Mar 18, 2010 at 04:37 AM
Ugh, loosing my mind here. I can't seem to get the cube to lock into place, moving only one grid space per 90 degree rotation. I'm able to get it to work when it travels in the x direction, rotating in the z. But not when it travels in the z and rotates in the x. Here's the code I use for moving the cube along the x axis...
function MoveX(direction: int) {
// get a reference to the x rotation so we can lock it back into place after the torque
var rotationX: float = Mathf.Round(transform.eulerAngles.x);
// add torque
var torque: float = Time.deltaTime * rotationSpeed * direction;
rigidbody.AddTorque(0, 0, torque);
// reset the rotation of the other axes
transform.eulerAngles.x = rotationX;
transform.eulerAngles.y = 0;
// get the angle and transform it so it so it can be used to calculate positioning
var angle: float = Mathf.Round(transform.eulerAngles.z);
if(transform.position.x > xOffset) angle -= 360;
// never really want it to be 360. Should be 0 instead.
if(Mathf.Abs(angle) == 360) angle = 0;
// determine if the cube is actively moving
movingX = !((Mathf.Abs(angle) == 0 || Mathf.Abs(angle) == 90 || Mathf.Abs(angle) == 180 || Mathf.Abs(angle) == 270) && direction == 0);
// determine the position based on the angle
var x: float = -(angle / 360 * 4) + xOffset;
// help
Debug.Log("x " + angle + " " + x + " " + transform.position.x);
// lock the position
transform.position.x = x;
// determine if the cube has completed a total of 4 turns. 340 is used instead of 360 because
// if the cube is traveling too fast it will skip right over 360 and go back to zero. Not sure
// about this logic, seems like there must be a better way to do this.
if(Mathf.Abs(angle) >= 340)
{
transform.position.x = Mathf.Round(transform.position.x);
xOffset = transform.position.x;
transform.eulerAngles.z = 0;
}
}
This code is called from FixedUpdate. The direction is determined by key input and is either -1, 0, or 1. I have a function just like this for moving in the Z as well but the value returned from eulerAngles.x is completely different. In the first rotation the x rotation goes from 0 to 90 as expected. However, the second rotation, in the same direction goes from 90 to 0 instead of 90 to 180. I have no idea why this would be. This happens even when I comment out everything accept the AddTorque and log eulerAngles.x.
Originally I was determining the angle using the rotation Quaternion and a call to ToAngleAxis. This worked great if the cube only ever rotated along one axis (either one). But, when I rotated it along one axis and then the other the it was like the rotational values for the different axes got out of sync or something.
Any suggestions would be greatly appreciated. I feel like I'm probably doing this the hard way but don't know how else I might accomplish what I'm trying to do.
Thanks
This post should be included in the question... not as answer..!
Answer by Free_Ko · Apr 20, 2012 at 03:36 PM
hey you should check out my qeustion How To Make A Cube Roll hope its usefull.
Answer by thomasfriday · Jul 10, 2021 at 03:27 PM
Here's a short Youtube video that covers exactly how to roll a cube on its edges: https://youtu.be/06rs3U2bpy8