SoulKarl

(EDIT: Proper terms I meant to ask about are the Skeleton Utility that has Spawn Hierarchy. This is the method to access bounding boxes.)

Does anyone know if there is currently no way to separate the skeleton in a SkeletonGraphic? Is this some kind of limitation with Unity's UI canvas system?

Also, does anyone have a suggestion for a workaround for this? I have UI elements that need to work with other skeletongraphics (ie: be rendered in the overlay or screen space ideally) but that also need to have their bounding boxes accessible for raycasting. If the only option is to use SkeletonAnimations instead, is there a good way to handle this so that it basically still treats it like its UI? (maybe a seperate camera just for rendering all SpineAnimations I want to treat as UI and then just never use SkeletonGraphic?)

Cheers!
SoulKarl
Posts: 11

Pharan

Currently, no.
But if you just need the bounding boxes and following bones, Spawn Hierarchy should be unnecessary and even overkill.

We do have the SkeletonGraphic version of BoneFollower (BoneFollowerGraphic).
I haven't tested BoundingBoxFollower if it works properly with SkeletonGraphic. If it doesn't, it's theoretically simple to implement.

Those two should be enough. I'll give it a quick check.

-- 07 Sep 2017 1:11 am --
Checking the Unity docs, Physics colliders in UI space isn't really recommended for a number of technical reasons (no separate physics worlds, and the usually ~100x scale of UI objects) so it would be irresponsible to include that solution in the unitypackage.

But if you just needed a UI click/tap target, Spawn Hierarchy would have been overkill and the SkeletonBounds API would work much better.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

using Spine;
using Spine.Unity;
using Spine.Unity.Modules;

namespace Spine.Unity.Examples {
public class SkeletonBoundsSample : MonoBehaviour {

public SkeletonGraphic skeletonGraphic;
public UnityEvent OnClick;

SkeletonBounds skeletonBounds = new SkeletonBounds();

#if UNITY_EDITOR
void OnValidate () {
if (this.skeletonGraphic == null) this.skeletonGraphic = GetComponent<SkeletonGraphic>();
}
#endif

void Update () {
if (Input.GetMouseButtonUp(0)) { // Detect click

// 1. Get the Skeleton-Space Point.
var mousePosition = Input.mousePosition; // or touch?
Camera mainCamera = Camera.main; // In actual implementation, cache this. Camera.main does a GameObject.FindGameObjectWithTag internally.
var viewportResolution = new Vector2(mainCamera.pixelWidth, mainCamera.pixelHeight); // Source of viewport resolution may vary depending on device setup.
var skeletonSpacePoint = ScreenToUITransformLocal(mousePosition, viewportResolution, skeletonGraphic);

// 2. Check SkeletonBounds.
skeletonBounds.Update(skeletonGraphic.Skeleton, true);
BoundingBoxAttachment bba = skeletonBounds.ContainsPoint(skeletonSpacePoint.x, skeletonSpacePoint.y);

// 3. Do your stuff.
bool boundingBoxWasDetected = (bba != null);
if (boundingBoxWasDetected) {
Debug.Log(bba.Name);
OnClick.Invoke();
}
}
}

/// <summary>Converts a screen space point to a Spine Skeleton-space point based on UI.</summary>
public static Vector2 ScreenToUITransformLocal (Vector2 screenPoint, Vector2 viewportResolution, SkeletonGraphic skeletonGraphic) {
Rect canvasRect = skeletonGraphic.canvas.pixelRect;

// Convert screen point to world point from screen space rect.
Vector2 rectPos = new Vector2(screenPoint.x * canvasRect.width / viewportResolution.x, screenPoint.y * canvasRect.height / viewportResolution.y);

// Convert from world point to Skeleton Transform point (scaled by Canvas scaling, as applied to SkeletonGraphic).
Vector2 localPos = skeletonGraphic.rectTransform.InverseTransformPoint(rectPos) / skeletonGraphic.canvas.referencePixelsPerUnit;
return localPos;
}
}

}
User avatar
Pharan

Pharan
Posts: 4502

SoulKarl

Awesome! Thanks a bunch Pharan
SoulKarl
Posts: 11


Return to Unity