- تم التحرير
Ficker angles bone with spawn hierarchy
Hi everyone,
We tried to achieve this smooth effect in the game by moving the mouse around the character:
To do that, we spawn hierarchy on Unity and make a script (based on the law of sines) that allows the character's bones to follow the mouse here is the script:
public class BoneAim
{
[SerializeField]
public string boneName;
[SerializeField]
public float min;
[SerializeField]
public float max;
}
private float boneRotation( BoneAim boneAim, Spine.Bone topBone)
{
/****************************************************************************
* A: Wrist *
* B: Head * DistB = DirAC.magnitude (distance between wrist and target)
* C: Target * DistC = DirAB.magnitude (distance between bones)
****************************************************************************/
//Bone
Spine.Bone bone = skeleton.FindBone(boneAim.boneName);
string name = boneAim.boneName;
//bone.UpdateWorldTransform();
//World Positions:
//wrist
Vector3 A = bone.GetWorldPosition(this.transform);
//Head
Vector3 B = topBone.GetWorldPosition(this.transform);
//target
Vector3 C = GameManager.instance.getCursor().cursorPosition();
//Directions
Vector3 dirAB = B - A;
Vector3 dirAC = C - A;
Vector3 dirBA = A - B;
Vector3 dirBC = C - B;
Vector3 dirCA = A - C;
Vector3 dirCB = B - C;
//Angles (original, debug only, we will change values after recalculate)
float angleA = Vector2.Angle(dirAB, dirAC);
float angleB = Vector2.Angle(dirBC, dirBA);
float angleC = Vector2.Angle(dirCA, dirCB);
/*************
* RECALCULATING *
*************/
//To calculate AngleC we need to knoe distB, distC and anlgeB
//disB / sinB = distC / sinC
//
//sinC = disC * sinB / distB
//after that-> anlgeA = 180 - angleB - angleC
//Rot topBone (correct)
angleB = getBoneWorldRotation(topBone);
Vector2 dirB = angleToVector2(angleB);
dirB.Normalize();
//Origanl head angle (angleB) that's the only angle we know
angleB = Vector2.Angle(dirB, dirBA.normalized);
float distB = dirAC.magnitude;
float distC = dirAB.magnitude;
float sinB = Mathf.Sin(angleB * Mathf.Deg2Rad);
float sinC = distC * sinB / distB;
//AngleC
angleC = Mathf.Asin(sinC) * Mathf.Rad2Deg;
//AngleA (world space)
angleA = 180 - angleC - angleB;
Debuggin.add(name, "angleA:" + angleA);
//Exist the angle
if (!float.IsNaN(angleA))
{
float angleAOriginal = Vector3.Angle(dirAB, dirAC);
//rotation += world andle - originalWorldAngle
float angleRot = angleA - angleAOriginal;
if (angleRot < boneAim.min)
angleRot = boneAim.min;
else if (angleRot > boneAim.max)
angleRot = boneAim.max;
bone.rotation += angleRot;
}
bone.UpdateWorldTransform();
return angleA;
}
private float getBoneWorldRotation(Spine.Bone bone)
{
float _rot = bone.WorldRotationX - 90;
if (_rot < -180)
_rot += 360;
return _rot;
}
public static Vector2 angleToVector2(float degrees)
{
float rad = degrees * Mathf.Deg2Rad;
return new Vector2(Mathf.Cos(rad), Mathf.Sin(rad));
}
But we don't know why, in the game seems like the character has some problem with the angles:
We want to rotate bones in a smooth way, here is our schedule:
Do you have any idea of what could have hapened?
Thanks
skeletonAnim.UpdateLocal += skeletonAnimation_UpdateWorld;
boneRotation is being called in "skeletonAnimation_UpdateWorld", that we added to UpdateLocal from skeletonAnimation.
Here's a bit of information on what those update events are. It might help.
https://github.com/pharan/spine-unity-docs/blob/master/Handling-the-Skeleton.md#skeletonanimation-update-callbacks
Be aware of when the values you are getting or writing to are being updated or may be overwritten.