PixelBrothers

Hi friends,

I've got some questions for you, for more experienced of you using Spine & Unity:

1. If I got a lot of Spine animation in one scene let's say hundreds (150-300), what is the best way to achieve best performance:

a) using sqrMagnitude distance between player & animation for triggering (enabling) SkeletonAnimation:
My example code:
SkeletonAnimation ska;

void Awake()
{
ska = GetComponent<SkeletonAnimation>();
}

void LateUpdate()
{
AnimateTest();
}

private void AnimateTest()
{
//CALCULATE THE DISTANCE FROM PLAYER TO THE ANIMATION
float tempDist = (player.transform.position - transform.position).sqrMagnitude;
distance = tempDist;

//ANIMATE
if (player != null)
{
if (distance < _animateDistance )
{
if (!ska.enabled)
{
ska.enabled = true;
}
ska.loop = true;
ska.AnimationName = animAttack;
ska.timeScale = 0.7f;

Debug.DrawLine(transform.position, player.transform.position, Color.red);
Debug.Log("THE DISTANCE BETWEEN PLAYER & ANIM_OBJ: " + distance);
}
}
if (distance <= 40)
{
transform.rotation = Quaternion.Euler(0f, -180f, 0f);
}
else if (distance > _animateDistance )
{
ska.enabled = false;
ska.loop = false;
ska.timeScale = 0f;
Debug.DrawLine(transform.position, player.transform.position, Color.green);
Debug.Log("THE DISTANCE BETWEEN PLAYER & ANIM_OBJ: " + distance);
}
}
b) activate the SkeletonAnimation using colliders (2D in my case) e.g:
void OnTriggerEnter2D(Collider2D o)
{
if(o.gameObject.tag == "Player")
{
ska.enabled = true;
}
}
*P.S: I'm developing for mobile devices !

Any advice & feedback will be much appreciated, thanks in advance ! :handshake: :beer:
Аватара пользователя
PixelBrothers
  • Сообщения: 32

Majicpanda

Setting the SkeletonAnimation script disabled does save quite a bit of CPU from what I can tell and that's going to be my plan. We are making a Diablo sized world in 1 scene and have to use area of influence like this as well. We don't put this in update though, we just check every second as that's typically enough time to flag something active or not if your distance is set up correctly. SqrMag is definitely cheaper than a .Distance, but you should probably still throttle it a bit more.

I wouldn't use screen sized colliders constantly interacting with your world, that's one of my Unity dev pet peeves when people use hundreds of colliders constantly checking for things.. even if they are properly set up with collision layers.

If you wanted to take it a step further you wouldn't even have your characters spawned in yet if it's a bunch of monsters, you would pool them all and then make them visible + animation any time the player got in range of that area.
Majicpanda
  • Сообщения: 189

mr_malee

Try: http://docs.unity3d.com/ScriptReference/MonoBehaviour.OnBecameVisible.html

You'll need a Renderer on the GameObject which will receive these events

*Be aware that running in the Editor will also cause the events to occur from the scene camera
mr_malee
  • Сообщения: 12

wholovesthesun?

I suggest to use bool SkeletonAnimation.valid instead of SkeletonAnimation.enabled or GameObject.SetActive(bool state). Because when using last two mentioned, void MonoBehaviour.OnEnabled() is called and it eats up a lot of CPU initialising some thing that are needed just for the first time...

When SkeletonAnimation.valid = false that SkeletonAnimation is initialised but ignored when rendering.

This saved my app from freezing when activating SkeletonAnimation.
wholovesthesun?
  • Сообщения: 4

Pharan

(1)
This is a complex matter. But you just need to know what things cost a lot of compute, and avoid those.

On the CPU side: Use as few bones and images as possible. If you're going to use meshes, give them as few verts as possible.
In animations, don't key things that aren't animated. Avoid FFD. Avoid image swaps (if you don't use image swaps/hiding, you can check "Immutable Triangles" under the Advanced foldout and that'll save a lot of array juggling on SkeletonRenderer).
Avoid the string API. Cache object references. And cache all your animation references and use so the Spine runtime doesn't need to keep searching for animations by name every time you play an animation.
Read up on Unity performance in general. There are a lot of things that are okay in normal/modern C#, but that cause Unity's Mono to slow down. This mostly concerns garbage collection and old libraries.
On the GPU side, make sure your images are pre-trimmed. If you have meshes, reduce fill rate pressure by making sure the meshes cut out as much of the empty/transparent areas as possible. Use pre-multipled alpha blending (and the Spine\Skeleton shader). Don't use lighting. Don't use shadows.

None of this is "best practice". It's just a list of things that can cost some amount to calculate and can scale badly in terms of runtime performance the more you use them.
"Best practice" would mean a workflow that's easy and you can great results. If it's for your singular main character, this arguably doesn't matter. It's probably much more important that it looks great and is easy to make changes and add animations and movements to. All the restrictions above means it's a lot harder to figure out the construction of the images, skeleton and animation. The extra cost there is time working on the assets and possibly more complicated code.

Also, 150-300 animations on mobile, I'd say Unity might not be the best engine right now.
But I guess that depends on what you mean by "mobile". Flagship phones and tablets will probably handle that fine. I don't really know.

(2)
using UnityEngine;
using System.Collections;

public class SkeletonAnimationCuller : MonoBehaviour {
#region Inspector
public SkeletonAnimation skeletonAnimation;

void Reset () {
skeletonAnimation = GetComponent<SkeletonAnimation>();
}
#endregion

void OnBecameVisible () { skeletonAnimation.enabled = true; }
void OnBecameInvisible () { skeletonAnimation.enabled = false; }

}
This is the cleaner way to achieve part of what you were doing.
Setting the animation and changing the rotation, you can still use the distance calculation if you want in a separate script.

Note that timeScale = 0 doesn't mean it will stop updating. But enabled = false; does.
There's no reason for you to change timeScale unless you're actually trying to slow down an animation.
Аватара пользователя
Pharan
  • Сообщения: 5366


Вернуться в Unity