mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-06 07:14:55 +08:00
Merge branch '3.6-beta' of https://github.com/esotericsoftware/spine-runtimes into 3.6-beta
This commit is contained in:
commit
bdce56767e
@ -64,6 +64,7 @@ struct spTrackEntry {
|
||||
float* timelinesRotation;
|
||||
int timelinesRotationCount;
|
||||
void* rendererObject;
|
||||
void* userData;
|
||||
|
||||
#ifdef __cplusplus
|
||||
spTrackEntry() :
|
||||
|
||||
@ -845,7 +845,7 @@ namespace Spine {
|
||||
}
|
||||
|
||||
class EventQueue {
|
||||
private readonly ExposedList<EventQueueEntry> eventQueueEntries = new ExposedList<EventQueueEntry>();
|
||||
private readonly List<EventQueueEntry> eventQueueEntries = new List<EventQueueEntry>();
|
||||
public bool drainDisabled;
|
||||
|
||||
private readonly AnimationState state;
|
||||
@ -905,11 +905,11 @@ namespace Spine {
|
||||
drainDisabled = true;
|
||||
|
||||
var entries = this.eventQueueEntries;
|
||||
var entriesItems = entries.Items;
|
||||
AnimationState state = this.state;
|
||||
|
||||
for (int i = 0, n = entries.Count; i < n; i++) {
|
||||
var queueEntry = entriesItems[i];
|
||||
// Don't cache entries.Count so callbacks can queue their own events (eg, call SetAnimation in AnimationState_Complete).
|
||||
for (int i = 0; i < entries.Count; i++) {
|
||||
var queueEntry = entries[i];
|
||||
TrackEntry trackEntry = queueEntry.entry;
|
||||
|
||||
switch (queueEntry.type) {
|
||||
|
||||
@ -32,38 +32,47 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spine {
|
||||
/// <summary>Stores attachments by slot index and attachment name.</summary>
|
||||
/// <summary>Stores attachments by slot index and attachment name.
|
||||
/// <para>See SkeletonData <see cref="Spine.SkeletonData.DefaultSkin"/>, Skeleton <see cref="Spine.Skeleton.Skin"/>, and
|
||||
/// <a href="http://esotericsoftware.com/spine-runtime-skins">Runtime skins</a> in the Spine Runtimes Guide.</para>
|
||||
/// </summary>
|
||||
public class Skin {
|
||||
internal String name;
|
||||
private Dictionary<AttachmentKeyTuple, Attachment> attachments =
|
||||
new Dictionary<AttachmentKeyTuple, Attachment>(AttachmentKeyTupleComparer.Instance);
|
||||
|
||||
public String Name { get { return name; } }
|
||||
public string Name { get { return name; } }
|
||||
public Dictionary<AttachmentKeyTuple, Attachment> Attachments { get { return attachments; } }
|
||||
|
||||
public Skin (String name) {
|
||||
public Skin (string name) {
|
||||
if (name == null) throw new ArgumentNullException("name", "name cannot be null.");
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void AddAttachment (int slotIndex, String name, Attachment attachment) {
|
||||
public void AddAttachment (int slotIndex, string name, Attachment attachment) {
|
||||
if (attachment == null) throw new ArgumentNullException("attachment", "attachment cannot be null.");
|
||||
attachments[new AttachmentKeyTuple(slotIndex, name)] = attachment;
|
||||
}
|
||||
|
||||
/// <returns>May be null.</returns>
|
||||
public Attachment GetAttachment (int slotIndex, String name) {
|
||||
public Attachment GetAttachment (int slotIndex, string name) {
|
||||
Attachment attachment;
|
||||
attachments.TryGetValue(new AttachmentKeyTuple(slotIndex, name), out attachment);
|
||||
return attachment;
|
||||
}
|
||||
|
||||
public void FindNamesForSlot (int slotIndex, List<String> names) {
|
||||
/// <summary>Finds the skin keys for a given slot. The results are added to the passed List(names).</summary>
|
||||
/// <param name="slotIndex">The target slotIndex. To find the slot index, use <see cref="Spine.Skeleton.FindSlotIndex"/> or <see cref="Spine.SkeletonData.FindSlotIndex"/>
|
||||
/// <param name="names">Found skin key names will be added to this list.</param>
|
||||
public void FindNamesForSlot (int slotIndex, List<string> names) {
|
||||
if (names == null) throw new ArgumentNullException("names", "names cannot be null.");
|
||||
foreach (AttachmentKeyTuple key in attachments.Keys)
|
||||
if (key.slotIndex == slotIndex) names.Add(key.name);
|
||||
}
|
||||
|
||||
/// <summary>Finds the attachments for a given slot. The results are added to the passed List(Attachment).</summary>
|
||||
/// <param name="slotIndex">The target slotIndex. To find the slot index, use <see cref="Spine.Skeleton.FindSlotIndex"/> or <see cref="Spine.SkeletonData.FindSlotIndex"/>
|
||||
/// <param name="attachments">Found Attachments will be added to this list.</param>
|
||||
public void FindAttachmentsForSlot (int slotIndex, List<Attachment> attachments) {
|
||||
if (attachments == null) throw new ArgumentNullException("attachments", "attachments cannot be null.");
|
||||
foreach (KeyValuePair<AttachmentKeyTuple, Attachment> entry in this.attachments)
|
||||
|
||||
@ -664,14 +664,24 @@ public class SkeletonViewer extends ApplicationAdapter {
|
||||
button.addListener(trackButtonListener);
|
||||
|
||||
Gdx.input.setInputProcessor(new InputMultiplexer(stage, new InputAdapter() {
|
||||
float offsetX;
|
||||
float offsetY;
|
||||
|
||||
public boolean touchDown (int screenX, int screenY, int pointer, int button) {
|
||||
touchDragged(screenX, screenY, pointer);
|
||||
offsetX = screenX;
|
||||
offsetY = Gdx.graphics.getHeight() - screenY;
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean touchDragged (int screenX, int screenY, int pointer) {
|
||||
skeletonX = screenX;
|
||||
skeletonY = Gdx.graphics.getHeight() - screenY;
|
||||
float deltaX = screenX - offsetX;
|
||||
float deltaY = Gdx.graphics.getHeight() - screenY - offsetY;
|
||||
|
||||
skeletonX += deltaX;
|
||||
skeletonY += deltaY;
|
||||
|
||||
offsetX = screenX;
|
||||
offsetY = Gdx.graphics.getHeight() - screenY;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -69,7 +69,7 @@ public class SkeletonSprite extends DisplayObject {
|
||||
}
|
||||
|
||||
override public function render (painter:Painter) : void {
|
||||
alpha *= this.alpha * skeleton.color.a;
|
||||
painter.state.alpha *= skeleton.a;
|
||||
var originalBlendMode:String = painter.state.blendMode;
|
||||
var r:Number = skeleton.color.r * 255;
|
||||
var g:Number = skeleton.color.g * 255;
|
||||
@ -164,6 +164,7 @@ public class SkeletonSprite extends DisplayObject {
|
||||
mesh.setTexCoords(ii, uvs[iii], uvs[iii+1]);
|
||||
}
|
||||
vertexData.numVertices = verticesCount;
|
||||
painter.state.blendMode = blendModes[slot.data.blendMode.ordinal];
|
||||
// FIXME set smoothing/filter
|
||||
painter.batchMesh(mesh);
|
||||
}
|
||||
@ -180,6 +181,7 @@ public class SkeletonSprite extends DisplayObject {
|
||||
var maxX:Number = -Number.MAX_VALUE, maxY:Number = -Number.MAX_VALUE;
|
||||
var slots:Vector.<Slot> = skeleton.slots;
|
||||
var worldVertices:Vector.<Number> = _tempVertices;
|
||||
var empty:Boolean = true;
|
||||
for (var i:int = 0, n:int = slots.length; i < n; ++i) {
|
||||
var slot:Slot = slots[i];
|
||||
var attachment:Attachment = slot.attachment;
|
||||
@ -196,6 +198,10 @@ public class SkeletonSprite extends DisplayObject {
|
||||
mesh.computeWorldVertices(slot, 0, verticesLength, worldVertices, 0, 2);
|
||||
} else
|
||||
continue;
|
||||
|
||||
if (verticesLength != 0)
|
||||
empty = false;
|
||||
|
||||
for (var ii:int = 0; ii < verticesLength; ii += 2) {
|
||||
var x:Number = worldVertices[ii], y:Number = worldVertices[ii + 1];
|
||||
minX = minX < x ? minX : x;
|
||||
@ -204,6 +210,9 @@ public class SkeletonSprite extends DisplayObject {
|
||||
maxY = maxY > y ? maxY : y;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty)
|
||||
return null;
|
||||
|
||||
var temp:Number;
|
||||
if (maxX < minX) {
|
||||
|
||||
@ -82,7 +82,7 @@ public:
|
||||
UTrackEntry () { }
|
||||
|
||||
void SetTrackEntry (spTrackEntry* entry);
|
||||
spTrackEntry* GetTrackEntry();
|
||||
spTrackEntry* GetTrackEntry() { return entry; }
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Components|Spine|TrackEntry")
|
||||
int GetTrackIndex () { return entry ? entry->trackIndex : 0; }
|
||||
|
||||
@ -31,6 +31,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "SpineSkeletonDataAsset.h"
|
||||
#include "spine/spine.h"
|
||||
#include "SpineSkeletonComponent.generated.h"
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# spine-ue4
|
||||
The spine-ue4 runtime provides functionality to load, manipulate and render [Spine](http://esotericsoftware.com) skeletal animation data using [Unreal Engine 4.15+](https://www.unrealengine.com/). spine-ue4 is based on [spine-c](https://github.com/EsotericSoftware/spine-runtimes/tree/master/spine-c).
|
||||
|
||||
# WARNING This plugin will only work with Unreal Engine 4.15 and later versions as these include a [fix](https://github.com/EpicGames/UnrealEngine/pull/3015) for compiling plain `.c` files in Visual Studio.
|
||||
### WARNING This plugin will only work with Unreal Engine 4.15 and later when this [fix](https://github.com/EpicGames/UnrealEngine/pull/3185) for compiling plain `.c` files is applied.
|
||||
|
||||
## Licensing
|
||||
|
||||
|
||||
@ -93,7 +93,7 @@ namespace Spine.Unity.Examples {
|
||||
|
||||
void Start () {
|
||||
// Register a callback for Spine Events (in this case, Footstep)
|
||||
skeletonAnimation.state.Event += HandleEvent;
|
||||
skeletonAnimation.AnimationState.Event += HandleEvent;
|
||||
}
|
||||
|
||||
void HandleEvent (Spine.TrackEntry trackEntry, Spine.Event e) {
|
||||
|
||||
@ -59,8 +59,8 @@ namespace Spine.Unity.Examples {
|
||||
void Start () {
|
||||
// Make sure you get these AnimationState and Skeleton references in Start or Later. Getting and using them in Awake is not guaranteed by default execution order.
|
||||
skeletonAnimation = GetComponent<SkeletonAnimation>();
|
||||
spineAnimationState = skeletonAnimation.state;
|
||||
skeleton = skeletonAnimation.skeleton;
|
||||
spineAnimationState = skeletonAnimation.AnimationState;
|
||||
skeleton = skeletonAnimation.Skeleton;
|
||||
|
||||
StartCoroutine(DoDemoRoutine());
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ namespace Spine.Unity.Examples {
|
||||
IEnumerator Start () {
|
||||
var skeletonAnimation = GetComponent<SkeletonAnimation>(); if (skeletonAnimation == null) yield break;
|
||||
while (true) {
|
||||
skeletonAnimation.state.SetAnimation(SpineBlinkPlayer.BlinkTrack, blinkAnimation, false);
|
||||
skeletonAnimation.AnimationState.SetAnimation(SpineBlinkPlayer.BlinkTrack, blinkAnimation, false);
|
||||
yield return new WaitForSeconds(Random.Range(minimumDelay, maximumDelay));
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ namespace Spine.Unity.Examples {
|
||||
void Start () {
|
||||
if (skeletonAnimation == null) return;
|
||||
model.ShootEvent += PlayShoot;
|
||||
skeletonAnimation.state.Event += HandleEvent;
|
||||
skeletonAnimation.AnimationState.Event += HandleEvent;
|
||||
}
|
||||
|
||||
void HandleEvent (Spine.TrackEntry trackEntry, Spine.Event e) {
|
||||
@ -104,7 +104,7 @@ namespace Spine.Unity.Examples {
|
||||
}
|
||||
}
|
||||
|
||||
skeletonAnimation.state.SetAnimation(0, nextAnimation, true);
|
||||
skeletonAnimation.AnimationState.SetAnimation(0, nextAnimation, true);
|
||||
}
|
||||
|
||||
void PlayFootstepSound () {
|
||||
@ -114,7 +114,7 @@ namespace Spine.Unity.Examples {
|
||||
|
||||
[ContextMenu("Check Tracks")]
|
||||
void CheckTracks () {
|
||||
var state = skeletonAnimation.state;
|
||||
var state = skeletonAnimation.AnimationState;
|
||||
Debug.Log(state.GetCurrent(0));
|
||||
Debug.Log(state.GetCurrent(1));
|
||||
}
|
||||
@ -122,7 +122,7 @@ namespace Spine.Unity.Examples {
|
||||
#region Transient Actions
|
||||
public void PlayShoot () {
|
||||
// Play the shoot animation on track 1.
|
||||
skeletonAnimation.state.SetAnimation(1, shoot, false);
|
||||
skeletonAnimation.AnimationState.SetAnimation(1, shoot, false);
|
||||
//skeletonAnimation.state.AddEmptyAnimation(1, 0.1f, 0f);
|
||||
gunSource.pitch = GetRandomPitch(gunsoundPitchOffset);
|
||||
gunSource.Play();
|
||||
@ -131,7 +131,7 @@ namespace Spine.Unity.Examples {
|
||||
}
|
||||
|
||||
public void Turn (bool facingLeft) {
|
||||
skeletonAnimation.skeleton.FlipX = facingLeft;
|
||||
skeletonAnimation.Skeleton.FlipX = facingLeft;
|
||||
// Maybe play a transient turning animation too, then call ChangeStableAnimation.
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -47,13 +47,13 @@ namespace Spine.Unity.Examples {
|
||||
healthText.text = currentHealth + "/" + maxHealth;
|
||||
|
||||
if (currentHealth > 0) {
|
||||
spineboy.state.SetAnimation(0, "hit", false);
|
||||
spineboy.state.AddAnimation(0, "idle", true, 0);
|
||||
spineboy.AnimationState.SetAnimation(0, "hit", false);
|
||||
spineboy.AnimationState.AddAnimation(0, "idle", true, 0);
|
||||
gauge.fillPercent = (float)currentHealth/(float)maxHealth;
|
||||
} else {
|
||||
if (currentHealth >= 0) {
|
||||
gauge.fillPercent = 0;
|
||||
spineboy.state.SetAnimation(0, "death", false).TrackEnd = float.PositiveInfinity;
|
||||
spineboy.AnimationState.SetAnimation(0, "death", false).TrackEnd = float.PositiveInfinity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,11 +80,11 @@ namespace Spine.Unity.Examples {
|
||||
} else {
|
||||
if (Input.GetKey(rightKey)) {
|
||||
skeletonAnimation.AnimationName = moveAnimation;
|
||||
skeletonAnimation.skeleton.FlipX = false;
|
||||
skeletonAnimation.Skeleton.FlipX = false;
|
||||
transform.Translate(moveSpeed * Time.deltaTime, 0, 0);
|
||||
} else if(Input.GetKey(leftKey)) {
|
||||
skeletonAnimation.AnimationName = moveAnimation;
|
||||
skeletonAnimation.skeleton.FlipX = true;
|
||||
skeletonAnimation.Skeleton.FlipX = true;
|
||||
transform.Translate(-moveSpeed * Time.deltaTime, 0, 0);
|
||||
} else {
|
||||
skeletonAnimation.AnimationName = idleAnimation;
|
||||
@ -95,9 +95,9 @@ namespace Spine.Unity.Examples {
|
||||
IEnumerator Blink() {
|
||||
while (true) {
|
||||
yield return new WaitForSeconds(Random.Range(0.25f, 3f));
|
||||
skeletonAnimation.skeleton.SetAttachment(eyesSlot, blinkAttachment);
|
||||
skeletonAnimation.Skeleton.SetAttachment(eyesSlot, blinkAttachment);
|
||||
yield return new WaitForSeconds(blinkDuration);
|
||||
skeletonAnimation.skeleton.SetAttachment(eyesSlot, eyesOpenAttachment);
|
||||
skeletonAnimation.Skeleton.SetAttachment(eyesSlot, eyesOpenAttachment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ namespace Spine.Unity.Examples {
|
||||
|
||||
public void Start () {
|
||||
skeletonAnimation = GetComponent<SkeletonAnimation>();
|
||||
headBone = skeletonAnimation.skeleton.FindBone("head");
|
||||
headBone = skeletonAnimation.Skeleton.FindBone("head");
|
||||
skeletonAnimation.UpdateLocal += UpdateLocal;
|
||||
}
|
||||
|
||||
@ -53,16 +53,16 @@ namespace Spine.Unity.Examples {
|
||||
}
|
||||
|
||||
public void OnMouseDown () {
|
||||
skeletonAnimation.skeleton.SetSkin(girlSkin ? "goblin" : "goblingirl");
|
||||
skeletonAnimation.skeleton.SetSlotsToSetupPose();
|
||||
skeletonAnimation.Skeleton.SetSkin(girlSkin ? "goblin" : "goblingirl");
|
||||
skeletonAnimation.Skeleton.SetSlotsToSetupPose();
|
||||
|
||||
girlSkin = !girlSkin;
|
||||
|
||||
if (girlSkin) {
|
||||
skeletonAnimation.skeleton.SetAttachment("right hand item", null);
|
||||
skeletonAnimation.skeleton.SetAttachment("left hand item", "spear");
|
||||
skeletonAnimation.Skeleton.SetAttachment("right hand item", null);
|
||||
skeletonAnimation.Skeleton.SetAttachment("left hand item", "spear");
|
||||
} else
|
||||
skeletonAnimation.skeleton.SetAttachment("left hand item", "dagger");
|
||||
skeletonAnimation.Skeleton.SetAttachment("left hand item", "dagger");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -76,7 +76,7 @@ namespace Spine.Unity.Examples {
|
||||
// Case 1: Create an attachment from an atlas.
|
||||
RegionAttachment newHand = handSource.GetAtlas().FindRegion(handRegion).ToRegionAttachment("new hand");
|
||||
newHand.SetPositionOffset(newHandOffset);
|
||||
newHand.rotation = newHandRotation;
|
||||
newHand.Rotation = newHandRotation;
|
||||
newHand.UpdateOffset();
|
||||
int handSlotIndex = skeleton.FindSlotIndex(handSlot);
|
||||
handTexture = newHand.GetRegion().ToTexture();
|
||||
|
||||
@ -29,7 +29,6 @@
|
||||
*****************************************************************************/
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
using Spine;
|
||||
using Spine.Unity;
|
||||
|
||||
@ -39,21 +38,22 @@ namespace Spine.Unity.Examples {
|
||||
|
||||
public void Start () {
|
||||
skeletonAnimation = GetComponent<SkeletonAnimation>(); // Get the SkeletonAnimation component for the GameObject this script is attached to.
|
||||
var animationState = skeletonAnimation.AnimationState;
|
||||
|
||||
skeletonAnimation.state.Event += HandleEvent;; // Call our method any time an animation fires an event.
|
||||
skeletonAnimation.state.End += (entry) => Debug.Log("start: " + entry.trackIndex); // A lambda can be used for the callback instead of a method.
|
||||
animationState.Event += HandleEvent;; // Call our method any time an animation fires an event.
|
||||
animationState.End += (entry) => Debug.Log("start: " + entry.TrackIndex); // A lambda can be used for the callback instead of a method.
|
||||
|
||||
skeletonAnimation.state.AddAnimation(0, "jump", false, 2); // Queue jump to be played on track 0 two seconds after the starting animation.
|
||||
skeletonAnimation.state.AddAnimation(0, "run", true, 0); // Queue walk to be looped on track 0 after the jump animation.
|
||||
animationState.AddAnimation(0, "jump", false, 2); // Queue jump to be played on track 0 two seconds after the starting animation.
|
||||
animationState.AddAnimation(0, "run", true, 0); // Queue walk to be looped on track 0 after the jump animation.
|
||||
}
|
||||
|
||||
void HandleEvent (TrackEntry trackEntry, Spine.Event e) {
|
||||
Debug.Log(trackEntry.trackIndex + " " + trackEntry.animation.name + ": event " + e + ", " + e.Int);
|
||||
Debug.Log(trackEntry.TrackIndex + " " + trackEntry.Animation.Name + ": event " + e + ", " + e.Int);
|
||||
}
|
||||
|
||||
public void OnMouseDown () {
|
||||
skeletonAnimation.state.SetAnimation(0, "jump", false); // Set jump to be played on track 0 immediately.
|
||||
skeletonAnimation.state.AddAnimation(0, "run", true, 0); // Queue walk to be looped on track 0 after the jump animation.
|
||||
skeletonAnimation.AnimationState.SetAnimation(0, "jump", false); // Set jump to be played on track 0 immediately.
|
||||
skeletonAnimation.AnimationState.AddAnimation(0, "run", true, 0); // Queue walk to be looped on track 0 after the jump animation.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -83,24 +83,6 @@ namespace Spine.Unity.Editor {
|
||||
SpineEditorUtilities.ConfirmInitialization();
|
||||
m_skeletonDataAsset = (SkeletonDataAsset)target;
|
||||
|
||||
// Clear empty atlas array items.
|
||||
{
|
||||
bool hasNulls = false;
|
||||
foreach (var a in m_skeletonDataAsset.atlasAssets) {
|
||||
if (a == null) {
|
||||
hasNulls = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasNulls) {
|
||||
var trimmedAtlasAssets = new List<AtlasAsset>();
|
||||
foreach (var a in m_skeletonDataAsset.atlasAssets) {
|
||||
if (a != null) trimmedAtlasAssets.Add(a);
|
||||
}
|
||||
m_skeletonDataAsset.atlasAssets = trimmedAtlasAssets.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
atlasAssets = serializedObject.FindProperty("atlasAssets");
|
||||
skeletonJSON = serializedObject.FindProperty("skeletonJSON");
|
||||
scale = serializedObject.FindProperty("scale");
|
||||
@ -126,8 +108,8 @@ namespace Spine.Unity.Editor {
|
||||
|
||||
m_skeletonDataAssetGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_skeletonDataAsset));
|
||||
EditorApplication.update += EditorUpdate;
|
||||
m_skeletonData = m_skeletonDataAsset.GetSkeletonData(false);
|
||||
RepopulateWarnings();
|
||||
m_skeletonData = warnings.Count == 0 ? m_skeletonDataAsset.GetSkeletonData(false) : null;
|
||||
}
|
||||
|
||||
void OnDestroy () {
|
||||
@ -228,8 +210,9 @@ namespace Spine.Unity.Editor {
|
||||
m_previewUtility.Cleanup();
|
||||
m_previewUtility = null;
|
||||
}
|
||||
RepopulateWarnings();
|
||||
OnEnable();
|
||||
m_skeletonDataAsset.Clear();
|
||||
m_skeletonData = null;
|
||||
OnEnable(); // Should call RepopulateWarnings.
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -258,7 +241,6 @@ namespace Spine.Unity.Editor {
|
||||
using (new EditorGUI.DisabledGroupScope(skeletonJSON.objectReferenceValue == null)) {
|
||||
if (GUILayout.Button(new GUIContent("Attempt Reimport", Icons.warning))) {
|
||||
DoReimport();
|
||||
return;
|
||||
}
|
||||
}
|
||||
#else
|
||||
@ -376,15 +358,12 @@ namespace Spine.Unity.Editor {
|
||||
|
||||
void DoReimport () {
|
||||
SpineEditorUtilities.ImportSpineContent(new string[] { AssetDatabase.GetAssetPath(skeletonJSON.objectReferenceValue) }, true);
|
||||
|
||||
if (m_previewUtility != null) {
|
||||
m_previewUtility.Cleanup();
|
||||
m_previewUtility = null;
|
||||
}
|
||||
|
||||
RepopulateWarnings();
|
||||
OnEnable();
|
||||
|
||||
OnEnable(); // Should call RepopulateWarnings.
|
||||
EditorUtility.SetDirty(m_skeletonDataAsset);
|
||||
}
|
||||
|
||||
@ -535,6 +514,25 @@ namespace Spine.Unity.Editor {
|
||||
void RepopulateWarnings () {
|
||||
warnings.Clear();
|
||||
|
||||
// Clear null entries.
|
||||
{
|
||||
bool hasNulls = false;
|
||||
foreach (var a in m_skeletonDataAsset.atlasAssets) {
|
||||
if (a == null) {
|
||||
hasNulls = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasNulls) {
|
||||
var trimmedAtlasAssets = new List<AtlasAsset>();
|
||||
foreach (var a in m_skeletonDataAsset.atlasAssets) {
|
||||
if (a != null) trimmedAtlasAssets.Add(a);
|
||||
}
|
||||
m_skeletonDataAsset.atlasAssets = trimmedAtlasAssets.ToArray();
|
||||
}
|
||||
serializedObject.Update();
|
||||
}
|
||||
|
||||
if (skeletonJSON.objectReferenceValue == null) {
|
||||
warnings.Add("Missing Skeleton JSON");
|
||||
} else {
|
||||
@ -544,12 +542,13 @@ namespace Spine.Unity.Editor {
|
||||
#if !SPINE_TK2D
|
||||
bool detectedNullAtlasEntry = false;
|
||||
var atlasList = new List<Atlas>();
|
||||
for (int i = 0; i < atlasAssets.arraySize; i++) {
|
||||
if (atlasAssets.GetArrayElementAtIndex(i).objectReferenceValue == null) {
|
||||
var actualAtlasAssets = m_skeletonDataAsset.atlasAssets;
|
||||
for (int i = 0; i < actualAtlasAssets.Length; i++) {
|
||||
if (m_skeletonDataAsset.atlasAssets[i] == null) {
|
||||
detectedNullAtlasEntry = true;
|
||||
break;
|
||||
} else {
|
||||
atlasList.Add(((AtlasAsset)atlasAssets.GetArrayElementAtIndex(i).objectReferenceValue).GetAtlas());
|
||||
atlasList.Add(actualAtlasAssets[i].GetAtlas());
|
||||
}
|
||||
}
|
||||
|
||||
@ -642,26 +641,37 @@ namespace Spine.Unity.Editor {
|
||||
void CreatePreviewInstances () {
|
||||
this.DestroyPreviewInstances();
|
||||
|
||||
if (warnings.Count > 0) {
|
||||
m_skeletonDataAsset.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
var skeletonDataAsset = (SkeletonDataAsset)target;
|
||||
if (skeletonDataAsset.GetSkeletonData(false) == null)
|
||||
return;
|
||||
|
||||
if (this.m_previewInstance == null) {
|
||||
string skinName = EditorPrefs.GetString(m_skeletonDataAssetGUID + "_lastSkin", "");
|
||||
m_previewInstance = SpineEditorUtilities.InstantiateSkeletonAnimation(skeletonDataAsset, skinName).gameObject;
|
||||
|
||||
if (m_previewInstance != null) {
|
||||
m_previewInstance.hideFlags = HideFlags.HideAndDontSave;
|
||||
m_previewInstance.layer = 0x1f;
|
||||
m_skeletonAnimation = m_previewInstance.GetComponent<SkeletonAnimation>();
|
||||
m_skeletonAnimation.initialSkinName = skinName;
|
||||
m_skeletonAnimation.LateUpdate();
|
||||
m_skeletonData = m_skeletonAnimation.skeletonDataAsset.GetSkeletonData(true);
|
||||
m_previewInstance.GetComponent<Renderer>().enabled = false;
|
||||
m_initialized = true;
|
||||
try {
|
||||
m_previewInstance = SpineEditorUtilities.InstantiateSkeletonAnimation(skeletonDataAsset, skinName).gameObject;
|
||||
|
||||
if (m_previewInstance != null) {
|
||||
m_previewInstance.hideFlags = HideFlags.HideAndDontSave;
|
||||
m_previewInstance.layer = 0x1f;
|
||||
m_skeletonAnimation = m_previewInstance.GetComponent<SkeletonAnimation>();
|
||||
m_skeletonAnimation.initialSkinName = skinName;
|
||||
m_skeletonAnimation.LateUpdate();
|
||||
m_skeletonData = m_skeletonAnimation.skeletonDataAsset.GetSkeletonData(true);
|
||||
m_previewInstance.GetComponent<Renderer>().enabled = false;
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
AdjustCameraGoals(true);
|
||||
} catch {
|
||||
DestroyPreviewInstances();
|
||||
}
|
||||
|
||||
AdjustCameraGoals(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -89,14 +89,6 @@ namespace Spine.Unity {
|
||||
}
|
||||
|
||||
public SkeletonData GetSkeletonData (bool quiet) {
|
||||
if (atlasAssets == null) {
|
||||
atlasAssets = new AtlasAsset[0];
|
||||
if (!quiet)
|
||||
Debug.LogError("Atlas not set for SkeletonData asset: " + name, this);
|
||||
Clear();
|
||||
return null;
|
||||
}
|
||||
|
||||
if (skeletonJSON == null) {
|
||||
if (!quiet)
|
||||
Debug.LogError("Skeleton JSON file not set for SkeletonData asset: " + name, this);
|
||||
@ -104,17 +96,26 @@ namespace Spine.Unity {
|
||||
return null;
|
||||
}
|
||||
|
||||
#if !SPINE_TK2D
|
||||
if (atlasAssets.Length == 0) {
|
||||
Clear();
|
||||
return null;
|
||||
}
|
||||
#else
|
||||
if (atlasAssets.Length == 0 && spriteCollection == null) {
|
||||
Clear();
|
||||
return null;
|
||||
}
|
||||
#endif
|
||||
// Support attachmentless/skinless SkeletonData.
|
||||
// if (atlasAssets == null) {
|
||||
// atlasAssets = new AtlasAsset[0];
|
||||
// if (!quiet)
|
||||
// Debug.LogError("Atlas not set for SkeletonData asset: " + name, this);
|
||||
// Clear();
|
||||
// return null;
|
||||
// }
|
||||
// #if !SPINE_TK2D
|
||||
// if (atlasAssets.Length == 0) {
|
||||
// Clear();
|
||||
// return null;
|
||||
// }
|
||||
// #else
|
||||
// if (atlasAssets.Length == 0 && spriteCollection == null) {
|
||||
// Clear();
|
||||
// return null;
|
||||
// }
|
||||
// #endif
|
||||
|
||||
if (skeletonData != null)
|
||||
return skeletonData;
|
||||
|
||||
|
||||
@ -74,6 +74,13 @@ namespace Spine.Unity.Editor {
|
||||
targetBoneFollower = (BoneFollower)target;
|
||||
if (targetBoneFollower.SkeletonRenderer != null)
|
||||
targetBoneFollower.SkeletonRenderer.Initialize(false);
|
||||
|
||||
if (!targetBoneFollower.valid || needsReset) {
|
||||
targetBoneFollower.Initialize();
|
||||
targetBoneFollower.LateUpdate();
|
||||
needsReset = false;
|
||||
SceneView.RepaintAll();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSceneGUI () {
|
||||
@ -114,7 +121,7 @@ namespace Spine.Unity.Editor {
|
||||
return;
|
||||
}
|
||||
|
||||
if (needsReset) {
|
||||
if (needsReset && UnityEngine.Event.current.type == EventType.Layout) {
|
||||
targetBoneFollower.Initialize();
|
||||
targetBoneFollower.LateUpdate();
|
||||
needsReset = false;
|
||||
@ -143,11 +150,8 @@ namespace Spine.Unity.Editor {
|
||||
if (targetBoneFollower.valid) {
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUILayout.PropertyField(boneName);
|
||||
if (EditorGUI.EndChangeCheck()) {
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
needsReset = true;
|
||||
serializedObject.Update();
|
||||
}
|
||||
needsReset |= EditorGUI.EndChangeCheck();
|
||||
|
||||
EditorGUILayout.PropertyField(followBoneRotation);
|
||||
EditorGUILayout.PropertyField(followZPosition);
|
||||
EditorGUILayout.PropertyField(followLocalScale);
|
||||
@ -169,8 +173,10 @@ namespace Spine.Unity.Editor {
|
||||
|
||||
var current = UnityEngine.Event.current;
|
||||
bool wasUndo = (current.type == EventType.ValidateCommand && current.commandName == "UndoRedoPerformed");
|
||||
if (serializedObject.ApplyModifiedProperties() || wasUndo)
|
||||
if (wasUndo)
|
||||
targetBoneFollower.Initialize();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -214,8 +214,9 @@ namespace Spine.Unity.Editor {
|
||||
if (skinNameString == initialSkinName.stringValue)
|
||||
skinIndex = i;
|
||||
}
|
||||
skinIndex = EditorGUILayout.Popup("Initial Skin", skinIndex, skins);
|
||||
initialSkinName.stringValue = skins[skinIndex];
|
||||
skinIndex = EditorGUILayout.Popup("Initial Skin", skinIndex, skins);
|
||||
if (skins.Length > 0) // Support attachmentless/skinless SkeletonData.
|
||||
initialSkinName.stringValue = skins[skinIndex];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -603,7 +603,7 @@ namespace Spine.Unity.Editor {
|
||||
var localAtlases = FindAtlasesAtPath(dir);
|
||||
var requiredPaths = GetRequiredAtlasRegions(sp);
|
||||
var atlasMatch = GetMatchingAtlas(requiredPaths, localAtlases);
|
||||
if (atlasMatch != null) {
|
||||
if (atlasMatch != null || requiredPaths.Count == 0) {
|
||||
IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, atlasMatch);
|
||||
} else {
|
||||
bool resolved = false;
|
||||
@ -830,6 +830,8 @@ namespace Spine.Unity.Editor {
|
||||
StringReader reader = new StringReader(spineJson.text);
|
||||
var root = Json.Deserialize(reader) as Dictionary<string, object>;
|
||||
|
||||
if (!root.ContainsKey("skins"))
|
||||
return requiredPaths;
|
||||
|
||||
foreach (KeyValuePair<string, object> entry in (Dictionary<string, object>)root["skins"]) {
|
||||
foreach (KeyValuePair<string, object> slotEntry in (Dictionary<string, object>)entry.Value) {
|
||||
@ -1326,9 +1328,12 @@ namespace Spine.Unity.Editor {
|
||||
throw e;
|
||||
}
|
||||
|
||||
skin = skin ?? data.DefaultSkin ?? data.Skins.Items[0];
|
||||
newSkeletonAnimation.skeleton.SetSkin(skin);
|
||||
newSkeletonAnimation.initialSkinName = skin.Name;
|
||||
bool noSkins = data.DefaultSkin == null && (data.Skins == null || data.Skins.Count == 0); // Support attachmentless/skinless SkeletonData.
|
||||
skin = skin ?? data.DefaultSkin ?? (noSkins ? null : data.Skins.Items[0]);
|
||||
if (skin != null) {
|
||||
newSkeletonAnimation.initialSkinName = skin.Name;
|
||||
newSkeletonAnimation.skeleton.SetSkin(skin);
|
||||
}
|
||||
|
||||
newSkeletonAnimation.skeleton.Update(0);
|
||||
newSkeletonAnimation.state.Update(0);
|
||||
|
||||
@ -96,7 +96,7 @@ namespace Spine.Unity.MeshGeneration {
|
||||
|
||||
// Apply scale to vertices
|
||||
meshBoundsMax.x *= scale; meshBoundsMax.y *= scale;
|
||||
meshBoundsMin.x *= scale; meshBoundsMax.y *= scale;
|
||||
meshBoundsMin.x *= scale; meshBoundsMin.y *= scale;
|
||||
var vertices = this.meshVertices;
|
||||
for (int i = 0; i < totalVertexCount; i++) {
|
||||
Vector3 p = vertices[i];
|
||||
|
||||
@ -341,7 +341,7 @@ namespace Spine.Unity.Modules.AttachmentTools {
|
||||
return Sprite.Create(ar.GetMainTexture(), ar.GetUnityRect(), new Vector2(0.5f, 0.5f), pixelsPerUnit);
|
||||
}
|
||||
|
||||
internal static Texture2D ToTexture (this AtlasRegion ar, bool applyImmediately = true) {
|
||||
public static Texture2D ToTexture (this AtlasRegion ar, bool applyImmediately = true) {
|
||||
Texture2D sourceTexture = ar.GetMainTexture();
|
||||
Rect r = ar.GetUnityRect(sourceTexture.height);
|
||||
Texture2D output = new Texture2D((int)r.width, (int)r.height);
|
||||
|
||||
@ -160,25 +160,25 @@ namespace Spine.Unity {
|
||||
}
|
||||
|
||||
void DisposeColliders () {
|
||||
#if UNITY_EDITOR
|
||||
var colliders = GetComponents<PolygonCollider2D>();
|
||||
if (colliders.Length == 0) return;
|
||||
|
||||
if (Application.isPlaying) {
|
||||
foreach (var c in colliders) {
|
||||
if (c != null)
|
||||
Destroy(c);
|
||||
if (Application.isEditor) {
|
||||
if (Application.isPlaying) {
|
||||
foreach (var c in colliders) {
|
||||
if (c != null)
|
||||
Destroy(c);
|
||||
}
|
||||
} else {
|
||||
foreach (var c in colliders)
|
||||
if (c != null)
|
||||
DestroyImmediate(c);
|
||||
}
|
||||
} else {
|
||||
foreach (var c in colliders)
|
||||
if (c != null)
|
||||
DestroyImmediate(c);
|
||||
foreach (PolygonCollider2D c in colliders)
|
||||
if (c != null)
|
||||
Destroy(c);
|
||||
}
|
||||
#else
|
||||
foreach (PolygonCollider2D c in colliderTable.Values)
|
||||
if (c != null)
|
||||
Destroy(c);
|
||||
#endif
|
||||
|
||||
slot = null;
|
||||
currentAttachment = null;
|
||||
|
||||
@ -100,16 +100,19 @@ namespace Spine.Unity {
|
||||
#endregion
|
||||
|
||||
#region Bone
|
||||
/// <summary>Sets the bone's (local) X and Y according to a Vector2</summary>
|
||||
public static void SetPosition (this Bone bone, Vector2 position) {
|
||||
bone.X = position.x;
|
||||
bone.Y = position.y;
|
||||
}
|
||||
|
||||
/// <summary>Sets the bone's (local) X and Y according to a Vector3. The z component is ignored.</summary>
|
||||
public static void SetPosition (this Bone bone, Vector3 position) {
|
||||
bone.X = position.x;
|
||||
bone.Y = position.y;
|
||||
}
|
||||
|
||||
/// <summary>Gets the bone's local X and Y as a Vector2.</summary>
|
||||
public static Vector2 GetLocalPosition (this Bone bone) {
|
||||
return new Vector2(bone.x, bone.y);
|
||||
}
|
||||
@ -126,10 +129,12 @@ namespace Spine.Unity {
|
||||
return o;
|
||||
}
|
||||
|
||||
public static Vector3 GetWorldPosition (this Bone bone, UnityEngine.Transform parentTransform) {
|
||||
return parentTransform.TransformPoint(new Vector3(bone.worldX, bone.worldY));
|
||||
/// <summary>Gets the bone's Unity World position using its Spine GameObject Transform. UpdateWorldTransform needs to have been called for this to return the correct, updated value.</summary>
|
||||
public static Vector3 GetWorldPosition (this Bone bone, UnityEngine.Transform spineGameObjectTransform) {
|
||||
return spineGameObjectTransform.TransformPoint(new Vector3(bone.worldX, bone.worldY));
|
||||
}
|
||||
|
||||
/// <summary>Gets the internal bone matrix as a Unity bonespace-to-skeletonspace transformation matrix.</summary>
|
||||
public static Matrix4x4 GetMatrix4x4 (this Bone bone) {
|
||||
return new Matrix4x4 {
|
||||
m00 = bone.a, m01 = bone.b, m03 = bone.worldX,
|
||||
@ -138,7 +143,7 @@ namespace Spine.Unity {
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>Outputs a 2x2 Transformation Matrix that can convert a skeleton-space position to a bone-local position.</summary>
|
||||
/// <summary>Calculates a 2x2 Transformation Matrix that can convert a skeleton-space position to a bone-local position.</summary>
|
||||
public static void GetWorldToLocalMatrix (this Bone bone, out float ia, out float ib, out float ic, out float id) {
|
||||
float a = bone.a, b = bone.b, c = bone.c, d = bone.d;
|
||||
float invDet = 1 / (a * d - b * c);
|
||||
@ -236,6 +241,8 @@ namespace Spine.Unity {
|
||||
}
|
||||
|
||||
namespace Spine {
|
||||
using System.Collections.Generic;
|
||||
|
||||
public static class SkeletonExtensions {
|
||||
public static bool IsWeighted (this VertexAttachment va) {
|
||||
return va.bones != null && va.bones.Length > 0;
|
||||
@ -259,6 +266,85 @@ namespace Spine {
|
||||
animation.Apply(skeleton, lastTime, time, loop, events, 1f, false, false);
|
||||
}
|
||||
|
||||
internal static void SetPropertyToSetupPose (this Skeleton skeleton, int propertyID) {
|
||||
int tt = propertyID >> 24;
|
||||
var timelineType = (TimelineType)tt;
|
||||
int i = propertyID - (tt << 24);
|
||||
|
||||
Bone bone;
|
||||
IkConstraint ikc;
|
||||
PathConstraint pc;
|
||||
|
||||
switch (timelineType) {
|
||||
// Bone
|
||||
case TimelineType.Rotate:
|
||||
bone = skeleton.bones.Items[i];
|
||||
bone.rotation = bone.data.rotation;
|
||||
break;
|
||||
case TimelineType.Translate:
|
||||
bone = skeleton.bones.Items[i];
|
||||
bone.x = bone.data.x;
|
||||
bone.y = bone.data.y;
|
||||
break;
|
||||
case TimelineType.Scale:
|
||||
bone = skeleton.bones.Items[i];
|
||||
bone.scaleX = bone.data.scaleX;
|
||||
bone.scaleY = bone.data.scaleY;
|
||||
break;
|
||||
case TimelineType.Shear:
|
||||
bone = skeleton.bones.Items[i];
|
||||
bone.shearX = bone.data.shearX;
|
||||
bone.shearY = bone.data.shearY;
|
||||
break;
|
||||
|
||||
// Slot
|
||||
case TimelineType.Attachment:
|
||||
skeleton.SetSlotAttachmentToSetupPose(i);
|
||||
break;
|
||||
case TimelineType.Color:
|
||||
skeleton.slots.Items[i].SetColorToSetupPose();
|
||||
break;
|
||||
case TimelineType.Deform:
|
||||
skeleton.slots.Items[i].attachmentVertices.Clear();
|
||||
break;
|
||||
|
||||
// Skeleton
|
||||
case TimelineType.DrawOrder:
|
||||
skeleton.SetDrawOrderToSetupPose();
|
||||
break;
|
||||
|
||||
// IK Constraint
|
||||
case TimelineType.IkConstraint:
|
||||
ikc = skeleton.ikConstraints.Items[i];
|
||||
ikc.mix = ikc.data.mix;
|
||||
ikc.bendDirection = ikc.data.bendDirection;
|
||||
break;
|
||||
case TimelineType.TransformConstraint:
|
||||
var tc = skeleton.transformConstraints.Items[i];
|
||||
var tcData = tc.data;
|
||||
tc.rotateMix = tcData.rotateMix;
|
||||
tc.translateMix = tcData.translateMix;
|
||||
tc.scaleMix = tcData.scaleMix;
|
||||
tc.shearMix = tcData.shearMix;
|
||||
break;
|
||||
|
||||
// Path Constraint
|
||||
case TimelineType.PathConstraintPosition:
|
||||
pc = skeleton.pathConstraints.Items[i];
|
||||
pc.position = pc.data.position;
|
||||
break;
|
||||
case TimelineType.PathConstraintSpacing:
|
||||
pc = skeleton.pathConstraints.Items[i];
|
||||
pc.spacing = pc.data.spacing;
|
||||
break;
|
||||
case TimelineType.PathConstraintMix:
|
||||
pc = skeleton.pathConstraints.Items[i];
|
||||
pc.rotateMix = pc.data.rotateMix;
|
||||
pc.translateMix = pc.data.translateMix;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Resets the DrawOrder to the Setup Pose's draw order</summary>
|
||||
public static void SetDrawOrderToSetupPose (this Skeleton skeleton) {
|
||||
var slotsItems = skeleton.slots.Items;
|
||||
@ -315,5 +401,19 @@ namespace Spine {
|
||||
animation.Apply(skeleton, 0, 0, false, null, 0, true, true);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Skins
|
||||
/// <summary><see cref="Spine.Skin.FindNamesForSlot(int,List)"/></summary>
|
||||
public static void FindNamesForSlot (this Skin skin, string slotName, SkeletonData skeletonData, List<string> results) {
|
||||
int slotIndex = skeletonData.FindSlotIndex(slotName);
|
||||
skin.FindNamesForSlot(slotIndex, results);
|
||||
}
|
||||
|
||||
/// <summary><see cref="Spine.Skin.FindAttachmentsForSlot(int,List)"/></summary>
|
||||
public static void FindAttachmentsForSlot (this Skin skin, string slotName, SkeletonData skeletonData, List<Attachment> results) {
|
||||
int slotIndex = skeletonData.FindSlotIndex(slotName);
|
||||
skin.FindAttachmentsForSlot(slotIndex, results);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
1
spine-unity/Assets/spine-unity/version.txt
Normal file
1
spine-unity/Assets/spine-unity/version.txt
Normal file
@ -0,0 +1 @@
|
||||
This Spine-Unity runtime works with data exported from Spine Editor version: 3.5.xx
|
||||
8
spine-unity/Assets/spine-unity/version.txt.meta
Normal file
8
spine-unity/Assets/spine-unity/version.txt.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 80c06a67282e71043a4b1fad3e0c5654
|
||||
timeCreated: 1485965987
|
||||
licenseType: Free
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
x
Reference in New Issue
Block a user