- Home /
Physics-Based character glitch?
I am setting up a physics-based animation system I came up with, where I will have Empty Objects for the 4 limbs of a character I created. Each limb will try to have the hand/foot be in the position of the empty, with IK and it rotating towards it with Atan2. The character is set up with HingeJoints with Springs. I animate the character by changing the Target Angle of the HingeJoint's Spring. The Inverse Kinematics works great, but there is a glitch with the rotating toward the empty.
Here is the glitch: https://giphy.com/gifs/indie-gamedev-unity3d-8BlCFV14RDlRkpNzsx
Here is the Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EmptyTranslationArms : MonoBehaviour {
public HingeJoint Hinge1;
public HingeJoint Hinge2;
public HingeJoint Hinge3;
public HingeJoint Hinge4;
public HingeJoint Hinge5;
public HingeJoint Hinge6;
public GameObject targets;
public bool positive;
public bool negative;
public GameObject target;
public GameObject handfoot;
public GameObject upperlimb;
public float maxDistance;
public float minDistance;
public float currentDistance;
public float totalDistance;
public float distance;
public float DistancePercent;
public GameObject maxDistanceObject;
public GameObject minDistanceObject;
public Vector3 v;
public float a_rad;
public float a_deg;
// Use this for initialization
void Start () {
maxDistanceObject = new GameObject("Empty");
maxDistanceObject.transform.position = handfoot.transform.position;
maxDistanceObject.transform.parent = targets.transform;
minDistanceObject = new GameObject("Empty");
minDistanceObject.transform.position = upperlimb.transform.position;
minDistanceObject.transform.parent = targets.transform;
maxDistance = maxDistanceObject.transform.position.x;
minDistance = minDistanceObject.transform.position.x;
}
// Update is called once per frame
void Update () {
totalDistance = maxDistance - minDistance;
distance = target.transform.localPosition.x - minDistance;
DistancePercent = distance / totalDistance;
DistancePercent = DistancePercent * 90 + -90;
DistancePercent = Mathf.Clamp(DistancePercent,-90, 0);
v = target.transform.localPosition - upperlimb.transform.localPosition;
a_rad = Mathf.Atan2(v.z,v.x);
a_deg = -a_rad * Mathf.Rad2Deg;
a_deg = -180 + a_deg;
if (a_deg < -180)
{
a_deg = a_deg + 360;
}
float rotationY = target.transform.localRotation.x * Mathf.Rad2Deg;
if (rotationY < -180)
{
rotationY = rotationY = 360;
}
JointSpring spring3 = Hinge3.spring;
spring3.targetPosition = a_deg + rotationY;
Hinge3.spring = spring3;
v = target.transform.localPosition - upperlimb.transform.localPosition;
a_rad = Mathf.Atan2(v.y, v.x);
a_deg = -a_rad * Mathf.Rad2Deg;
a_deg = -180 + a_deg;
if (a_deg < -180)
{
a_deg = a_deg + 360;
}
JointSpring spring2 = Hinge2.spring;
spring2.targetPosition = DistancePercent + -a_deg;
Hinge2.spring = spring2;
JointSpring spring4 = Hinge4.spring;
spring4.targetPosition = -DistancePercent * 2;
Hinge4.spring = spring4;
float rotationX = target.transform.localRotation.x * Mathf.Rad2Deg;
if (rotationX < -180)
{
rotationX = rotationX = 360;
}
JointSpring spring1 = Hinge1.spring;
spring1.targetPosition = rotationX;
Hinge1.spring = spring1;
Debug.Log(Hinge2.spring.targetPosition);
}
}
@$$anonymous$$1010, I've not fully analyzed the problem, but before we can get there this needs attention:
float rotationY = target.transform.localRotation.x * $$anonymous$$athf.Rad2Deg;
if (rotationY < -180)
{
rotationY = rotationY = 360;
}
Inside transform, localRotation is a Quaternion. The various members of the Quaternion are related to quaternion algebra, and probably have no meaning to your code. Specifically, x, y and z have no relationship to angles. The conversion from radians to degrees, therefore, makes no sense, because x is not an angle. You can search quaternion on the Internet to see what quaternions are, and they are fascinating. In the subject of linear algebra (the math behind vectors and matrices representing graph positions, rotations and scaling), quaternions have a peculiar and special place in history. They were 'invented' in the 1850's (or sometime thereabouts) as a solution to gimbal lock (Google provides). However, when they were invented they were considered a curiosity without a purpose. Existing linear algebra solutions worked fine, and hardly anyone studied or knew anything about quaternions for over a hundred years.
Except for mathematical historians and PhD's. At some point in the early game development, the problem of gimbal lock was beco$$anonymous$$g a real issue, and someone brought up the subject of quaternions as a solution. Soon after they became a standard.
However, we still need to use Euler angles. Euler was a famous, ancient mathematician (pronounced 'oiler'). Euler angles are those you intend, especially when expressed in degrees of rotation. To get a rotation on the X axis from a Quaternion in Unity, you must use:
float angle_degrees = localRotation.eulerAngles.x;
Note, this property returns degrees, not radians, so no conversion is required. Perhaps this is related to your problem, and perhaps not, but whatever this is supposed to do can't function as written. You must first get the eulerAngles to have a chance to make that work.
I was thinking about your advice from the other question, about joints not being reliable, and so I tested not using joints, and just rotation of the parts. It still has 1 rigid body, and all of the colliders, so it still uses physics. It is now working a bit smoother., it is working pretty well, I will tell you if I need any help. Thanks!
:) Sometimes, not always, but sometimes I do have a point to offer....lol
@$$anonymous$$1010
I suppose you got my point about Quaternions and Euler's angles?
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Friction in unity? 2 Answers
Distribute terrain in zones 3 Answers