- Home /
How do I make an object rotate gradually using Rigidbody2D.MoveRotation()
I have designed a cycles of rotational orientations to accomplish a run like movement for this spider character. It looks good, just using MoveRotation the rotations I designated accomplish the desired orientations, but MoveRotation alone shifts the limbs too quickly. when I try to feed the MoveRotation method a Mathf.Lerp or Mathf.LerpAngle algorithm everything gets all jumpy, shuddery and can sometimes rotate to unexpected positions. I want to use Rigidbody2D.MoveRotation so the character has realistic weight, does anyone have any ideas?
Answer by cwalshwarder · Apr 06, 2020 at 06:53 PM
I think the only way to make it look realistic is with the animator. Is there a particular reason you want to use MoveRotation rather than rotating transforms? Could you share the code?
If there are colliders on the limbs, you might need to set it to animate physics and reduce the physics fixed time. If there's a reason not to animate it, maybe you could animate a float field of the script and use that to determine rotation.
Answer by courtesy · Apr 07, 2020 at 07:45 AM
I hear you, but I'm confident if I can establish the right kind of shock absorption and the right pace of rotational movement I can get a totally fluid, adequately realistic outcome.
the first of a cycle of four rotational arrangements:
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow)) {
//the order will be : inner left, outer right, outer left, inner right (this is the cycle of which legs are contacting the ground when)
movingRight = true;
// lerp
if (runCycleDuration >= 0.6f) {
/*lerpingOne = true;
lerpingTwo = false;
lerpingThree = false;
lerpingFour = false;
lerpingFive = false;
lerpingSix = false;
lerpingSeven = false;
lerpingEight = false;*/
innerRightLegTopRigidbody.MoveRotation(/*lerpAngleInnerRightTopOne*/myRigidbody.rotation - 24);
innerRightLegBottomRigidbody.MoveRotation(/*lerpAngleInnerRightBottomOne*/myRigidbody.rotation - 174);
innerLeftLegTopRigidbody.MoveRotation(/*lerpAngleInnerLeftTopSeven*/myRigidbody.rotation - 104);
innerLeftLegBottomRigidbody.MoveRotation(/*lerpAngleInnerLeftBottomOne*/myRigidbody.rotation - 40);
outerRightLegTopRigidbody.MoveRotation(/*lerpAngleOuterRightTopOne*/myRigidbody.rotation - 58);
outerRightLegBottomRigidbody.MoveRotation(/*lerpAngleOuterRightBottomOne*/myRigidbody.rotation - 132);
outerLeftLegTopRigidbody.MoveRotation(/*lerpAngleOuterLeftTopOne*/myRigidbody.rotation - 158);
outerLeftLegBottomRigidbody.MoveRotation(/*lerpAngleOuterLeftBottomOne*/myRigidbody.rotation - 10);
}
this is my cyclical timer function:
void Timers() {
if (movingRight) {
runCycleDuration -= Time.deltaTime;
if (runCycleDuration < 0) {
runCycleDuration = 0.8f;
}
}
if (movingLeft) {
runCycleDurationTwo -= Time.deltaTime;
etc...
}
}
}
then this is how I tried to lerp but failed:
void LerpingOne() {
if (lerpingOne) {
lerpAngleInnerRightTopOne = Mathf.Lerp(innerRightLegTopRigidbody.rotation, myRigidbody.rotation - 24, Time.deltaTime * lerpSpeed);
lerpAngleInnerRightBottomOne = Mathf.Lerp(innerRightLegBottomRigidbody.rotation, myRigidbody.rotation - 174, Time.deltaTime * lerpSpeed);
lerpAngleInnerLeftTopOne = Mathf.Lerp(innerLeftLegTopRigidbody.rotation, myRigidbody.rotation - 104, Time.deltaTime * lerpSpeed);
lerpAngleInnerLeftBottomOne = Mathf.Lerp(innerLeftLegBottomRigidbody.rotation, myRigidbody.rotation - 40, Time.deltaTime * lerpSpeed);
lerpAngleOuterRightTopOne = Mathf.Lerp(outerRightLegTopRigidbody.rotation, myRigidbody.rotation - 58, Time.deltaTime * lerpSpeed);
etc...
}
}
I may work to add more rotational arrangements in the same time frame to solve the problem, but of course that's neither economic, nor pragmatic.
I really wanna say I'm open to non MoveRotation approaches, but I am so close. the only issue is the movement is just a little to fast and a little to forceful. I'm really only asking for help cause it doesn't make sense to me this lerp function doesn't work. for reference I call it in the update.
sorry for some reason it wont let me comment on your message
Is myRigidbody on a parent gameobject, and the joint rigidbodies on children? I'm not sure physics works correctly when a gameobject + its children have multiple rigidbodies.
$$anonymous$$aybe it has something to do with rotations looping every 360 degrees. Try putting all your angles into a method to keep them between 0 to 360 and use LerpAngle rather than Lerp.
public static float ConfineAngle(float angle)
{
return ((angle + 360) % 360); // +360 so % doesn't create a negative number
}
When you set a joint's rotation to a lerp between its current rotation and a target rotation, it won't ever reach that rotation. I assume you call LerpingOne() every update. For example, if x = 1 and then you repeatedly do x = lerp(x, 2, .5) then x = 1.5, 1.75, 1.875, etc. That might look okay, or you might need to lerp from an initial rotation to the target one with t = 0 at initial time and 1 at whatever time it should reach the target rotation.
$$anonymous$$aybe it's related to global versus local coordinates for rigidbody rotation.
This is the code I use to rotate enemies.
public static float AngleToPlayer(float fromX, float fromY)
=> Vector2.SignedAngle(Vector2.up, VectorToPlayer(fromX, fromY)); // up is look direction at 0 deg
// $$anonymous$$ake angle -180 to 180 (Vector2.SignedAngle(...) uses that range)
public static float ConfineAngle(float angle)
{
return ((angle + 540) % 360) - 180;
}
public static float AngleAdd(float x, float y) => ConfineAngle(ConfineAngle(x) + ConfineAngle(y));
public static void RotateTowardsTarget(Rigidbody2D rotatingRb, float target, float degreesPerSec, bool aimOppositeDirection = false)
{
if (degreesPerSec < 0)
{
degreesPerSec = -degreesPerSec;
aimOppositeDirection = !aimOppositeDirection;
}
if (aimOppositeDirection)
target += 180f;
target = ConfineAngle(target);
float angleDifference = ConfineAngle(target - ConfineAngle(rotatingRb.rotation));
float rotDegs = degreesPerSec * Time.fixedDeltaTime;
if (rotDegs >= $$anonymous$$athf.Abs(angleDifference))
{
rotatingRb.rotation = ConfineAngle(rotatingRb.rotation);
rotatingRb.$$anonymous$$oveRotation(target);
}
else if (angleDifference < 0)
rotatingRb.$$anonymous$$oveRotation(rotatingRb.rotation - rotDegs);
else
rotatingRb.$$anonymous$$oveRotation(rotatingRb.rotation + rotDegs);
}
Answer by courtesy · Apr 07, 2020 at 07:48 AM
I hear you, but I'm confident if I can establish the right kind of shock absorption and the right pace of rotational movement I can get a totally fluid, adequately realistic outcome.
the first of a cycle of four rotational arrangements:
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow)) {
//the order will be : inner left, outer right, outer left, inner right (this is the cycle of which legs are contacting the ground when)
movingRight = true;
// lerp
if (runCycleDuration >= 0.6f) {
/*lerpingOne = true;
lerpingTwo = false;
lerpingThree = false;
lerpingFour = false;
lerpingFive = false;
lerpingSix = false;
lerpingSeven = false;
lerpingEight = false;*/
innerRightLegTopRigidbody.MoveRotation(/*lerpAngleInnerRightTopOne*/myRigidbody.rotation - 24);
innerRightLegBottomRigidbody.MoveRotation(/*lerpAngleInnerRightBottomOne*/myRigidbody.rotation - 174);
innerLeftLegTopRigidbody.MoveRotation(/*lerpAngleInnerLeftTopSeven*/myRigidbody.rotation - 104);
innerLeftLegBottomRigidbody.MoveRotation(/*lerpAngleInnerLeftBottomOne*/myRigidbody.rotation - 40);
outerRightLegTopRigidbody.MoveRotation(/*lerpAngleOuterRightTopOne*/myRigidbody.rotation - 58);
outerRightLegBottomRigidbody.MoveRotation(/*lerpAngleOuterRightBottomOne*/myRigidbody.rotation - 132);
outerLeftLegTopRigidbody.MoveRotation(/*lerpAngleOuterLeftTopOne*/myRigidbody.rotation - 158);
outerLeftLegBottomRigidbody.MoveRotation(/*lerpAngleOuterLeftBottomOne*/myRigidbody.rotation - 10);
}
this is my cyclical timer function:
void Timers() {
if (movingRight) {
runCycleDuration -= Time.deltaTime;
if (runCycleDuration < 0) {
runCycleDuration = 0.8f;
}
}
if (movingLeft) {
runCycleDurationTwo -= Time.deltaTime;
etc...
}
}
}
then this is how I tried to lerp but failed:
void LerpingOne() {
if (lerpingOne) {
lerpAngleInnerRightTopOne = Mathf.Lerp(innerRightLegTopRigidbody.rotation, myRigidbody.rotation - 24, Time.deltaTime * lerpSpeed);
lerpAngleInnerRightBottomOne = Mathf.Lerp(innerRightLegBottomRigidbody.rotation, myRigidbody.rotation - 174, Time.deltaTime * lerpSpeed);
lerpAngleInnerLeftTopOne = Mathf.Lerp(innerLeftLegTopRigidbody.rotation, myRigidbody.rotation - 104, Time.deltaTime * lerpSpeed);
lerpAngleInnerLeftBottomOne = Mathf.Lerp(innerLeftLegBottomRigidbody.rotation, myRigidbody.rotation - 40, Time.deltaTime * lerpSpeed);
lerpAngleOuterRightTopOne = Mathf.Lerp(outerRightLegTopRigidbody.rotation, myRigidbody.rotation - 58, Time.deltaTime * lerpSpeed);
etc...
}
}
I may work to add more rotational arrangements in the same time frame to solve the problem, but of course that's neither economic, nor pragmatic.
I really wanna say I'm open to non MoveRotation approaches, but I am so close. the only issue is the movement is just a little to fast and a little to forceful. I'm really only asking for help cause it doesn't make sense to me this lerp function doesn't work. for reference I call it in the update.
sorry for some reason I can't comment on your post