• Unity
  • Ficker angles bone with spawn hierarchy

Related Discussions
...

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.