• Unity
  • Explosion effect using SkeletonUtility and RigidBody

  • 編集済み
Related Discussions
...

I'm trying to make skeleton partially collapse with Unity physics. I've managed to detach bone using very similar code to this:

var skeletonAnimation = GetComponent<SkeletonAnimation>();
var skeletonUtility = AddComponent<SkeletonUtility>();
var bone = skeletonAnimation.findBone(boneName);

var rootTransform = skeletonUtility.GetBoneRoot();
rootTransform.parent = null; // it's necessary to avoid nested rigidbodies

var boneGameObject = skeletonUtility.SpawnBone(bone, rootTransform, SkeletonUtilityBone.Mode.Override, true, true, true);

skeletonUtility.CollectBones();

var boneRigidBody = boneGameObject.AddComponent<Rigidbody2D>();
var boneCollider = boneGameObject.AddComponent<CircleCollider2D>();

Though rigid body behaves correctly, bone takes its coordinates like they have been local. I mean when the parent bone is rotated, for example 90 degrees, body falls but detached bone moves right. Is there a way to make any bone entirely independent from its skeleton?

Thanks!

15日 後

Could you please create a minimal project that still demonstrates the problem and send it as a zip file to contact@esotericsoftware.com, then we can most efficiently help you.

Note that you can include only your assets and custom code in the package, there is no need to include the Spine-Unity runtime, just let us know which version of the runtime you have been using.


The problem is that in your setup the SkeletonUtilityBone component does not have the Parent Reference set - otherwise it will be interpreted as local transformations.

You can just create a GameObject with a BoneFollower that follows the tail2 node, then set the Parent Reference of tail3 to this BoneFollower GameObject. Then you receive the proper world-space transformations.

I've modified my script to iterate through all bones except root and still no success. 🙁

using Spine;
using Spine.Unity;
using UnityEngine;

public class Explosion : MonoBehaviour {
    BoneFollower rootBoneFollower;
    SkeletonAnimation skeletonAnimation;
    SkeletonUtility skeletonUtility;
    Transform rootTransform;

void Start() {
    var rootGameObject = new GameObject();

    rootBoneFollower = rootGameObject.AddComponent<BoneFollower>();

    skeletonAnimation = GetComponent<SkeletonAnimation>();
    skeletonUtility = gameObject.AddComponent<SkeletonUtility>();

    rootTransform = skeletonUtility.GetBoneRoot();

    int i = 0;

    foreach(var bone in skeletonAnimation.Skeleton.Bones) {
        if(i > 0) {
            generate(bone);
        } else {
            rootBoneFollower.SkeletonRenderer = skeletonAnimation.GetComponent<SkeletonRenderer>(); ;
            rootBoneFollower.bone = bone;
        }

        i++;
    }

    skeletonUtility.CollectBones();
}

void generate(Bone bone) {
    var boneGameObject = skeletonUtility.SpawnBone(bone, rootTransform, SkeletonUtilityBone.Mode.Override, true, true, true);
    var boneSkeletonUtility = boneGameObject.GetComponent<SkeletonUtilityBone>();

    boneSkeletonUtility.transform.parent = rootBoneFollower.transform;

    var boneRigidBody = boneGameObject.AddComponent<Rigidbody2D>();
    var boneCollider = boneGameObject.AddComponent<CircleCollider2D>();

    int value = Random.Range(10, 100);
    int angle = Random.Range(0, 360);

    Vector2 force;
    force.x = value * Mathf.Cos(angle * Mathf.Deg2Rad);
    force.y = value * Mathf.Sin(angle * Mathf.Deg2Rad);

    boneRigidBody.AddForce(force);
}
}

You did not do what I told you. You need one BoneFollower per detachable bone which points to the detachable bone's parent. You pointed it at the root, which is wrong.

Please follow the above description, it worked instantly when I tried it out in the Unity editor:

You can just create a GameObject with a BoneFollower that follows the tail2 node, then set the Parent Reference of tail3 to this BoneFollower GameObject. Then you receive the proper world-space transformations.

I've tried different combinations and whenever I press play textures still don't follow rigid bodies. It's only strange orbital like movement every time.

public class Explosion : MonoBehaviour {
    SkeletonAnimation skeletonAnimation;
    SkeletonUtility skeletonUtility;
    Transform rootTransform;

void Start() {
    skeletonAnimation = GetComponent<SkeletonAnimation>();
    skeletonUtility = gameObject.AddComponent<SkeletonUtility>();

    rootTransform = skeletonUtility.GetBoneRoot();

    int i = 0;

    foreach(var bone in skeletonAnimation.Skeleton.Bones) {
        if(i > 0) {
            generate(bone);
        }

        i++;
    }

    skeletonUtility.CollectBones();
}

void generate(Bone bone) {
    var parentGameObject = new GameObject();

    //parentGameObject.transform.parent = rootTransform;

    var parentBoneFollower = parentGameObject.AddComponent<BoneFollower>();

    parentBoneFollower.SkeletonRenderer = skeletonAnimation.GetComponent<SkeletonRenderer>();
    //parentBoneFollower.followBoneRotation = false;
    //parentBoneFollower.followLocalScale = false;
    //parentBoneFollower.followSkeletonFlip = false;
    //parentBoneFollower.followZPosition = false;
    parentBoneFollower.boneName = bone.parent.data.name;//"root";

    var boneGameObject = skeletonUtility.SpawnBone(bone, rootTransform, SkeletonUtilityBone.Mode.Override, true, true, true);
    var boneSkeletonUtility = boneGameObject.GetComponent<SkeletonUtilityBone>();

    boneSkeletonUtility.transform.parent = parentBoneFollower.transform;

    var boneRigidBody = boneGameObject.AddComponent<Rigidbody2D>();
    var boneCollider = boneGameObject.AddComponent<CircleCollider2D>();

    // Physics stuff
}
}

The problem looks as if it's in setting BoneFollower.boneName at runtime, which only works in the Editor via Awake().

/// <summary>If a bone isn't set in code, boneName is used to find the bone at the beginning. For runtime switching by name, use SetBoneByName. You can also set the BoneFollower.bone field directly.</summary>

You can use the following line instead:

parentBoneFollower.SetBoneByName(bone.parent.data.name)  //"root"
1年 後

Hello! I try to to follow your discussion, but I cant achieve proper result.
My best result is detached bones fly away with very strange trajectory.
All other attempts give me even worst results.
Can you please explain again for not very smart guy?=)

I want to explode skeleton bones on enemy death.

I got that I need to get each bone in current SkeletonAnimation and make its copy with attached SkeletonUtility (SpawnBone), but I need to put each bone in new hierarchy where all bones will be attached to the one root node?
After that I need to create for each bone BoneFollower and follow what?
And then I can to add rigidbody and set explode force for bones.


Ok, i made something very similar to what I want.
One thing steel unclear for me. How to break "weight" relationships between bones?
I throw two bones attached to one sprite in different directions. And I see ugly glitches.

  1. I want to determine from code which bones are connected with weight, then I can throw them together
    OR
  2. I want to break all "weight" relationships before throwing bones from code. Maybe with extra bones deletion
Stabilitron wrote

After that I need to create for each bone BoneFollower and follow what?

When you already have a SkeletonUtilityBone hierarchy, you typically don't need a BoneFollower. The BoneFollower component is providing an easy to use isolated version of a SkeletonUtilityBone (which needs its bone parent for relative movement) with only Follow mode. In your case you want to use a SkeletonUtilityBone with mode Override to override the bone position which would be set from the animation by default.

Stabilitron wrote

I throw two bones attached to one sprite in different directions. And I see ugly glitches.

What do you mean by "throw"?

Stabilitron wrote

1. I want to determine from code which bones are connected with weight, then I can throw them together

What do you mean by "connected with weight"?
You should be able to spawn your SkeletonUtilityBone hierarchy, which is already showing the parent / child relationships. Did you have a look at the spine-unity documentation on the topic?
spine-unity Runtime Documentation: SkeletonUtilityBone

Stabilitron wrote
  1. I want to break all "weight" relationships before throwing bones from code.

What do you mean by "weight relationships"?

10日 後

It will be difficult =)

What do you mean by "throw"?
I want to explode enemy on death. So I throw all bones in random directions.

What do you mean by "weight relationships"?
What do you mean by "connected with weight"?
I call "weight relationships" situation when two bones connected with one sprite (for example body torso). And movement of these bones will deform (stretch and other) body (torso).
The result on random throwing you can see here:

Some of bones thrown normally (legs, hands, head) but some of them ugly deformed attached sprite (body torso).
I want to detect these related bones in code and throw them in same direction to prevent attached sprite deforming.


Harald wrote

What do you mean by "throw"?

Hello Harald!
Can you tell me how to implement the scattering of bones in different directions?
I only have a problem with stretching sprites.

Stabilitron wrote

It will be difficult =)

What do you mean by "throw"?
I want to explode enemy on death. So I throw all bones in random directions.

What do you mean by "weight relationships"?
What do you mean by "connected with weight"?
I call "weight relationships" situation when two bones connected with one sprite (for example body torso). And movement of these bones will deform (stretch and other) body (torso).
The result on random throwing you can see here:

Some of bones thrown normally (legs, hands, head) but some of them ugly deformed attached sprite (body torso).
I want to detect these related bones in code and throw them in same direction to prevent attached sprite deforming.


Harald wrote

What do you mean by "throw"?

Hello Harald!
Can you tell me how to implement the scattering of bones in different directions?
I only have a problem with stretching sprites.

Its hard to help when we don't clearly know what is going on. All you are showing is a screenshot of a bunch of body parts - we don't know what the character originally looked like, or what is going on. Can you record a video?

It seems to me like you might have some images as meshes, and they are bound to multiple bones. If thats the case, and you are moving the bones, the mesh is still weighted to those bones and will stretch it. If thats whats happening, you probably need to specifically decide which bones need to be moved. AKA if you have a foot image that is a mesh, and is bound to 3 footBones, then instead of making all 3 of those footBones move in random directions, you could instead have all 3 of those footBones parented to a single bone, and only move that bone when the explosion happens

Edit: I can't think of a way to automatically figure out which bones you should 'throw' and which you shouldn't - I would instead create a List for the bones you want to 'throw', and drag in only the correct ones in the Inspector (assuming you're using some sort of Skeleton Utility Bones or something to apply the 'throwing' movement)

Thank you.
You have described everything very accurately. It's sad that there is no way to automatically detect such bones. Thank you for the advice to make a special list with bones that I need to throw and leave the rest. It should work! I will try this way.

Stabilitron wrote

Thank you.
You have described everything very accurately. It's sad that there is no way to automatically detect such bones. Thank you for the advice to make a special list with bones that I need to throw and leave the rest. It should work! I will try this way.

No problem. There might be a way to automate it, I just don't know. If there is a way to iterate through all of your meshes and see which bones they are weighted to, and remove those bones from the list of bones to 'throw'. I just don't know if thats worth doing - depends on your circumstances, it might be easier to just manually select the bones you want to 'throw'.

7日 後

Sorry for not replying earlier, I just came back from vacation.
Glad to see that again Jamez0r solved the case, thanks so much again! This is of invaluable help to be able to continue work on bugfixes and features! 8)