• Editor
  • Bone Locator

Hi,

I'm a new user to Spine and I'm trying to use it to "track" a bone so that I can attach a particle system to it.

With my script I'm getting some weird behaviour - mainly the position of the bone does not seem to be correct.

using UnityEngine;
using System.Collections;
using Spine;
using System.Collections.Generic;

public class BoneLocator : MonoBehaviour {
	
[SerializeField]public tk2dSpineSkeleton playerSkeleton;
Bone bone;

[SerializeField]private List<Bone> someList = new List<Bone>();

// Use this for initialization
void Start () {
//		//Had to be removed as it seems the list of bones is not ready at this point.
//		someList = playerSkeleton.skeleton.Bones;
//		bone = playerSkeleton.skeleton.FindBone("Head");
//		someList = playerSkeleton.skeleton.Bones;
//		Debug.Log("HERE I AM, I have a list of bones with length: " + someList.Count);
//		
//		for(int i = 0; i < someList.Count;i++){
//			Debug.Log("Bone Name: " + someList[i].Data);
//		}		
	}

// Update is called once per frame
void Update () {
	someList = playerSkeleton.skeleton.Bones;
//		Bone bone = skeletonComponent.skeleton.FindBone("boneName");
//		transform.position = new Vector3(bone.WorldX,bone.WorldY,transform.position.z);
		
//		Debug.Log("HERE I AM, I have a list of bones with length: " + someList.Count);
//		for(int i = 0; i < someList.Count;i++){
//			Debug.Log("Bone Name: " + someList[i].Data);
//		}	
		
	bone = playerSkeleton.skeleton.FindBone("Head");
// I have tried this in several forms, using only bone.x, subtracting its parent and then the below.
// However they all seem incorrect.
		transform.position = new Vector3(bone.X-bone.Parent.X-bone.Parent.Parent.X,
										bone.Y-bone.Parent.Y-bone.Parent.Parent.Y,
										transform.position.z);
		
	Debug.Log("Bone information: " + bone.Data.Name);
	Debug.Log("Bone X: " + bone.X);
	Debug.Log("Bone Y: " + bone.Y);
	Debug.Log("Bone WorldX: " + bone.WorldX);
	Debug.Log("Bone WorldY: " + bone.WorldY);
	Debug.Log("Bone Rotation: " + bone.Rotation);
	Debug.Log("Bone world rotation: " + bone.WorldRotation);
	Debug.Log("Bone worldscale x: " + bone.WorldScaleX);
	Debug.Log("Bone worldscale y: " + bone.WorldScaleY);
	Debug.Log("Bone Parent: " + bone.Parent);
	Debug.Log("PARENT INFO: ");
	Debug.Log("Parent X: " + bone.Parent.X);
	Debug.Log("Parent Y: " + bone.Parent.Y);
	Debug.Log("Parent worldX: " + bone.Parent.WorldX);
	Debug.Log("Parent worldY: " + bone.Parent.WorldY);
	Debug.Log("Parent of parent: " + bone.Parent.Parent.Data.Name);
	Debug.Log("Parent root X: " + bone.Parent.Parent.X);
	Debug.Log("Parent root Y: " + bone.Parent.Parent.Y);
	Debug.Log("Parent root worldX: " + bone.Parent.Parent.WorldX);
	Debug.Log("Parent root worldY: " + bone.Parent.Parent.WorldY);
	
	Debug.Log("End of data!!!!!!!!!!" );
	
}
}
Related Discussions
...
  • Modifié

WorldX and WorldY are actually a bit of a misnomer in Unity.
They're actually the positions relative to the center of the SkeletonComponent's transform. But WorldX is already (recursively?) calculated from the rotation and position of the parent plus that current bone's offset so you don't have to worry about parents and things.

Assuming this script isn't attached to the playerSkeleton's GameObject:
The world-X and world-Y you probably want likely looks something like

realWorldX = bone.WorldX + playerSkeleton.transform.position.x;

and likewise for y.

Then use those x and y to set the particle system's transform.position every update.

Maybe.

I've never tried this before though.

Also, you can call Initialize() on the SkeletonComponent in this script's Start so the bones are ready and you can cache the reference to it.

Thanks Pharan! That should work.

Hmm. Well, I did what you suggested so my code looks like this now (I made a change based on other posts I found in the forums):

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Spine;

public class BoneLocator : MonoBehaviour {
	
public tk2dSpineSkeleton playerSkeleton;
Bone bone;
private List<Bone> someList = new List<Bone>();

// Use this for initialization
void Start () {
	playerSkeleton.Initialize();
	bone = playerSkeleton.skeleton.FindBone("Head");
	someList = playerSkeleton.skeleton.Bones;
}

// Update is called once per frame
void Update () {	
//		transform.position = new Vector3(bone.WorldX,bone.WorldY,transform.position.z);

	float realX = (bone.WorldX * playerSkeleton.transform.localScale.x) + playerSkeleton.transform.position.x;
	float realY = (bone.WorldY * playerSkeleton.transform.localScale.y) + playerSkeleton.transform.position.y;
	
	transform.position = new Vector3(realX, realY, transform.position.z);
	
}
}

However, it still seems to be moving in weird motion. Is it possible that it is something I am doing wrong with the spine animation itself? Is there a good way to account for rotation? From what I can see in skeleton.Data there is rotation, but it is only a float value. Should I assume this is rotation about the Z axis?

Thanks so much.

Does Unity have some method to go from local to parent coordinates? Or from one gameobject coordinates to another?

I would have to try out your code and see how it moves. Can you edit the spineboy example so I can reproduce your issue?

I did this on Spineboy. Same code pattern.

Attached a primitive shape to the right hand bone. Works correctly. Also works fine with the scaling factor in.
Of course, the primitive doesn't rotate since we didn't tell it to.

My suspicion is that your bug has more to do with the transform your script is attached to. Can you describe/show the game object hierarchy setup?

Hi Nate,

Thanks for the suggestion. I tried doing this with the Spineboy animation and found that it is most definitely a scale issue with unity game objects. I'm going to do some more work and if I find success (or not) I will let you know.

More specifically what I found was that while the gameobject and spine animation were all scaled to 20%, the bone location (x,y) were not scaled down to the new coordinates. When I resized the game object to 100% the particle tracked exactly on the bone as expected.

Edit: Oops, didn't refresh to see your reply. Yes I think it is my objects hierarchy. I have a game object (parent) with movement scripts/colliders etc.. on it, and it has one game object (child) that has the Tk2d spine scripts and renderers on it. The parent is scaled to 0.20 because the artist gave me really large assets, and the child is scaled at 1.00.

Thanks again.

Thanks for the help; it was most certainly the scale issue on the parent. When I changed the realX and realY coordinates to scale based on the parent it worked just fine. Sorry for making you guys work on this!

Thanks again.

You can scale down a skeleton by setting the scale on the SkeletonData asset file (in the project/assets panel) in the options that show up in the inspector when you select that file. That'll leave you with cleaner, unscaled transforms in the hierarchy.