• Editor
  • FindBone() finding the right bone on a different object...

This could be my rotten coding, but I'm finding some odd behaviour in Unity with my animations.

PlayerBody has a SkeletonAnimation component, and a child object called PlayerHead, which also has a SkeletonAnimation. As a nice way of having the head animate separately to the body (for facial expressions/ talking etc) I'm setting its position and rotation every tick, to a Bone on the body animation:

public class LockToBone : MonoBehaviour {

public SkeletonAnimation ParentAnimation; // set in inspector
public string ParentBone; // set in inspector "HeadBone"
public string ourBone; // set in inspector "HeadBone"

private Skeleton parentSkeleton;
private Skeleton ourSkeleton;
private Bone parentBone;
private Bone tiedBone;

// Use this for initialization
void Start () {
	
	parentSkeleton = ParentAnimation.skeleton;
	parentBone = parentSkeleton.FindBone(ParentBone);
	ourSkeleton = GetComponent<SkeletonAnimation>().skeleton;
	tiedBone = ourSkeleton.FindBone(ourBone);
}

// Update is called once per frame
void Update () {

	tiedBone.data.rotation = parentBone.worldRotation;
	tiedBone.data.x = parentBone.worldX;
	tiedBone.data.y = parentBone.worldY;

}
}

Works great. Unless I spawn TWO of the objects. In which case each Head skeleton is set to the position of the opposite Body's bone, not its own! So Head#1 moves in accordance with Body#2's position/rotation, and Head#2 moves in accordance with Body#1's position/ rotation.

Am I doing something mind-blowingly stupid here, or have I misunderstood how FindBone works?

Any help much appreciated!

d

Related Discussions
...
  • Đã chỉnh sửa

Hmmm... digging around... presumably this is because Skeleton is a shared object between the two, and not unique to the SkeletonAnimation component?

SkeletonData (and BoneData) is shared, Skeleton (and Bone) is not. You can see the separation here:
http://esotericsoftware.com/spine/files ... iagram.png

You could load the SkeletonData twice, though this is a bit wasteful. I think you can do this:

	override public void UpdateSkeleton () {
		// Apply the animation.
		state.Update(Time.deltaTime * timeScale);
		state.Apply(skeleton);

	// Add this:
	tiedBone.rotation += parentBone.worldRotation;
	tiedBone.x += parentBone.worldX;
	tiedBone.y += parentBone.worldY;

	// Call overridden method to call skeleton Update and UpdateWorldTransform.
	base.UpdateSkeleton();
}

This poses the skeleton using the AnimationState, then adjusts the bones relatively.

Note you could also probably solve this particular problem differently, using a single skeleton. Animate your skeleton body without keying the head. Animate your skeleton head without keying the body. Then apply both animations at the same time using different AnimationState tracks:

public const int BODY = 0;
public const int HEAD = 1;
...
state.setAnimation(BODY, "run", true);
state.setAnimation(HEAD, "laugh", false);
state.addAnimation(HEAD, "idle", true, 0);

An animation only affects the bones and slots for which it has keyframes, so there is no problem applying multiple animations each frame.

Interesting, thanks Nate. Will have a poke around.

Option 2 actually probably seems most sensible, but does HEAD in your example actually need to be set to 1 rather than zero? Is that how indices work?

Works a charm, I think. Thanks!

Ha, yes, should have been 1. 🙂