Example #1
0
 /**
  * Adjusts the bone rotation so the tip is as close to the target position as possible. The target
  * is specified in the world coordinate system.
  */
 public static void apply(Bone bone, float targetX, float targetY, float alpha) {
   float parentRotation =
       (!bone.data.inheritRotation || bone.parent == null) ? 0 : bone.parent.worldRotation;
   float rotation = bone.rotation;
   float rotationIK =
       (float) Math.atan2(targetY - bone.worldY, targetX - bone.worldX) * radDeg - parentRotation;
   bone.rotationIK = rotation + (rotationIK - rotation) * alpha;
 }
Example #2
0
 /**
  * Adjusts the parent and child bone rotations so the tip of the child is as close to the target
  * position as possible. The target is specified in the world coordinate system.
  *
  * @param child Any descendant bone of the parent.
  */
 public static void apply(
     Bone parent, Bone child, float targetX, float targetY, int bendDirection, float alpha) {
   float childRotation = child.rotation, parentRotation = parent.rotation;
   if (alpha == 0) {
     child.rotationIK = childRotation;
     parent.rotationIK = parentRotation;
     return;
   }
   Vector2 position = temp;
   Bone parentParent = parent.parent;
   if (parentParent != null) {
     parentParent.worldToLocal(position.set(targetX, targetY));
     targetX = (position.x - parent.x) * parentParent.worldScaleX;
     targetY = (position.y - parent.y) * parentParent.worldScaleY;
   } else {
     targetX -= parent.x;
     targetY -= parent.y;
   }
   if (child.parent == parent) position.set(child.x, child.y);
   else parent.worldToLocal(child.parent.localToWorld(position.set(child.x, child.y)));
   float childX = position.x * parent.worldScaleX, childY = position.y * parent.worldScaleY;
   float offset = (float) Math.atan2(childY, childX);
   float len1 = (float) Math.sqrt(childX * childX + childY * childY),
       len2 = child.data.length * child.worldScaleX;
   // Based on code by Ryan Juckett with permission: Copyright (c) 2008-2009 Ryan Juckett,
   // http://www.ryanjuckett.com/
   float cosDenom = 2 * len1 * len2;
   if (cosDenom < 0.0001f) {
     child.rotationIK =
         childRotation
             + ((float) Math.atan2(targetY, targetX) * radDeg - parentRotation - childRotation)
                 * alpha;
     return;
   }
   float cos =
       clamp(
           (targetX * targetX + targetY * targetY - len1 * len1 - len2 * len2) / cosDenom, -1, 1);
   float childAngle = (float) Math.acos(cos) * bendDirection;
   float adjacent = len1 + len2 * cos, opposite = len2 * sin(childAngle);
   float parentAngle =
       (float)
           Math.atan2(
               targetY * adjacent - targetX * opposite, targetX * adjacent + targetY * opposite);
   float rotation = (parentAngle - offset) * radDeg - parentRotation;
   if (rotation > 180) rotation -= 360;
   else if (rotation < -180) //
   rotation += 360;
   parent.rotationIK = parentRotation + rotation * alpha;
   rotation = (childAngle + offset) * radDeg - childRotation;
   if (rotation > 180) rotation -= 360;
   else if (rotation < -180) //
   rotation += 360;
   child.rotationIK =
       childRotation + (rotation + parent.worldRotation - child.parent.worldRotation) * alpha;
 }
  public void update() {
    float rotateMix = this.rotateMix,
        translateMix = this.translateMix,
        scaleMix = this.scaleMix,
        shearMix = this.shearMix;
    Bone target = this.target;
    float ta = target.a, tb = target.b, tc = target.c, td = target.d;
    float degRadReflect = ta * td - tb * tc > 0 ? degRad : -degRad;
    float offsetRotation = data.offsetRotation * degRadReflect,
        offsetShearY = data.offsetShearY * degRadReflect;
    Array<Bone> bones = this.bones;
    for (int i = 0, n = bones.size; i < n; i++) {
      Bone bone = bones.get(i);
      boolean modified = false;

      if (rotateMix != 0) {
        float a = bone.a, b = bone.b, c = bone.c, d = bone.d;
        float r = atan2(tc, ta) - atan2(c, a) + offsetRotation;
        if (r > PI) r -= PI2;
        else if (r < -PI) r += PI2;
        r *= rotateMix;
        float cos = cos(r), sin = sin(r);
        bone.a = cos * a - sin * c;
        bone.b = cos * b - sin * d;
        bone.c = sin * a + cos * c;
        bone.d = sin * b + cos * d;
        modified = true;
      }

      if (translateMix != 0) {
        Vector2 temp = this.temp;
        target.localToWorld(temp.set(data.offsetX, data.offsetY));
        bone.worldX += (temp.x - bone.worldX) * translateMix;
        bone.worldY += (temp.y - bone.worldY) * translateMix;
        modified = true;
      }

      if (scaleMix > 0) {
        float s = (float) Math.sqrt(bone.a * bone.a + bone.c * bone.c);
        float ts = (float) Math.sqrt(ta * ta + tc * tc);
        if (s > 0.00001f) s = (s + (ts - s + data.offsetScaleX) * scaleMix) / s;
        bone.a *= s;
        bone.c *= s;
        s = (float) Math.sqrt(bone.b * bone.b + bone.d * bone.d);
        ts = (float) Math.sqrt(tb * tb + td * td);
        if (s > 0.00001f) s = (s + (ts - s + data.offsetScaleY) * scaleMix) / s;
        bone.b *= s;
        bone.d *= s;
        modified = true;
      }

      if (shearMix > 0) {
        float b = bone.b, d = bone.d;
        float by = atan2(d, b);
        float r = atan2(td, tb) - atan2(tc, ta) - (by - atan2(bone.c, bone.a));
        if (r > PI) r -= PI2;
        else if (r < -PI) r += PI2;
        r = by + (r + offsetShearY) * shearMix;
        float s = (float) Math.sqrt(b * b + d * d);
        bone.b = cos(r) * s;
        bone.d = sin(r) * s;
        modified = true;
      }

      if (modified) bone.appliedValid = false;
    }
  }