spine-3.8-例子-1:AtlasRegionAttacher

功能说明:

        键盘AD按键控制场景中spine对象(士兵),左右移动

        鼠标左键点击屏幕,士兵攻击

        士兵隔一段时间会眨一眨眼

制作流程:

hierarchy中 新建 SkeletonAnimation

建好后将其命名为 FootSoldier

将资源  FootSoldier_SkeletonData.asset 拖到 FootSoldier 的SkeletonAnimation组件中

FootSoldier 的SkeletonAnimation组件中的 skin 调成White

这时能看到屏幕上有个spine对象了,此时是没有剑的,运行后也没有剑

增加手中的剑

将脚本  AtlasRegionAttacher 挂到FootSoldier上

将spineAtlasAsset   Equipment_Atlas 挂在 AtlasRegionAttacher 上

增加 AtlasRegionAttacher 上的Attachment 如图

这时,运行后手中是有剑的了

代码:这里展示的是 从资源库里找到新的资源放到某个地方


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

namespace Spine.Unity.Examples {
	/// <summary>
	/// Example code for a component that replaces the default attachment of a slot with an image from a Spine atlas.</summary>
	public class AtlasRegionAttacher : MonoBehaviour {

		[System.Serializable]
		public class SlotRegionPair {
			[SpineSlot] public string slot;
			[SpineAtlasRegion] public string region;
		}

		[SerializeField] protected SpineAtlasAsset atlasAsset;
		[SerializeField] protected bool inheritProperties = true;
		[SerializeField] protected List<SlotRegionPair> attachments = new List<SlotRegionPair>();
        
        Atlas atlas;

		void Awake () {
			var skeletonRenderer = GetComponent<SkeletonRenderer>();
			skeletonRenderer.OnRebuild += Apply;   //这句不写不行,出不来武器
			if (skeletonRenderer.valid) Apply(skeletonRenderer);  //这句不写可以,正常出现武器,valid 字面意思有效的
			
		}

		void Apply (SkeletonRenderer skeletonRenderer) {
			if (!this.enabled) return;

			//检查atlas资源怎么样,有没有。把SkeletonRenderer的Scale找到。
			atlas = atlasAsset.GetAtlas();
			if (atlas == null) return;
			float scale = skeletonRenderer.skeletonDataAsset.scale;

            // attachments:插槽名+资源名 数组
            foreach (var entry in attachments) {
				Slot slot = skeletonRenderer.Skeleton.FindSlot(entry.slot); //插槽
				Attachment originalAttachment = slot.Attachment;//插槽下面的附件
				AtlasRegion region = atlas.FindRegion(entry.region);//资源


				//检查后  插槽的附件替换成某资源:比如说 插槽的附件换成 Equipment/sword1 

				//检查:先看看 资源有没有
				if (region == null) {
					slot.Attachment = null;
				}
				//检查:有资源+让换 且 插槽下面附件不为空(插槽有附件)
				//操作:原来的附件更新一下,替换成新资源
				else if (inheritProperties && originalAttachment != null) {
					slot.Attachment = originalAttachment.GetRemappedClone(region, true, true, scale);
				}
                //检查:有资源+其它情况
                //情况1: 让换 且 附件空
                //情况2: 不让换 且 附件不为空
                //情况3: 不让换 且 附件空
				//操作: 资源格式化,赋给附件
                else
                {
					var newRegionAttachment = region.ToRegionAttachment(region.name, scale);
					slot.Attachment = newRegionAttachment;
				}
			}
		}
	}
}

控制

脚本 FootSoldierExample 挂在 FootSoldier上

调整如下

/******************************************************************************
 * Spine Runtimes License Agreement
 * Last updated January 1, 2020. Replaces all prior versions.
 *
 * Copyright (c) 2013-2020, Esoteric Software LLC
 *
 * Integration of the Spine Runtimes into software or otherwise creating
 * derivative works of the Spine Runtimes is permitted under the terms and
 * conditions of Section 2 of the Spine Editor License Agreement:
 * http://esotericsoftware.com/spine-editor-license
 *
 * Otherwise, it is permitted to integrate the Spine Runtimes into software
 * or otherwise create derivative works of the Spine Runtimes (collectively,
 * "Products"), provided that each user of the Products must obtain their own
 * Spine Editor license and redistribution of the Products in any form must
 * include this license and copyright notice.
 *
 * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
 * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *****************************************************************************/

// Contributed by: Mitch Thompson

using UnityEngine;
using System.Collections;
using Spine.Unity;

namespace Spine.Unity.Examples {
	public class FootSoldierExample : MonoBehaviour {
		[SpineAnimation("Idle")]
		public string idleAnimation;

		[SpineAnimation]
		public string attackAnimation;

		[SpineAnimation]
		public string moveAnimation;

		[SpineSlot]
		public string eyesSlot;

		[SpineAttachment(currentSkinOnly: true, slotField: "eyesSlot")]
		public string eyesOpenAttachment;

		[SpineAttachment(currentSkinOnly: true, slotField: "eyesSlot")]
		public string blinkAttachment;

		[Range(0, 0.2f)]
		public float blinkDuration = 0.05f;

		public KeyCode attackKey = KeyCode.Mouse0;
		public KeyCode rightKey = KeyCode.D;
		public KeyCode leftKey = KeyCode.A;

		public float moveSpeed = 3;

		SkeletonAnimation skeletonAnimation; 

		void Awake () {
			skeletonAnimation = GetComponent<SkeletonAnimation>();
			skeletonAnimation.OnRebuild += Apply; //委托:在骨架成功初始化后,开始有节奏的眨眼睛
        }

		//骨架初始化成功后 调用的函数
		void Apply (SkeletonRenderer skeletonRenderer) {
            //调用协程函数,协程函数就是眨眼睛
            StartCoroutine(Blink());
		}

		//update中主要 用来控制移动
		void Update () {
			//鼠标左键 播放打击动画
			if (Input.GetKey(attackKey)) {
				skeletonAnimation.AnimationName = attackAnimation;  
			} else {
				//如果 键盘按键 D 就面向右向右走
				if (Input.GetKey(rightKey)) {
					skeletonAnimation.AnimationName = moveAnimation;
					skeletonAnimation.Skeleton.ScaleX = 1;
					transform.Translate(moveSpeed * Time.deltaTime, 0, 0);

                    
                }
                //如果 键盘按键 A 就面向左向左走
                else if (Input.GetKey(leftKey)) {
					skeletonAnimation.AnimationName = moveAnimation;
					skeletonAnimation.Skeleton.ScaleX = -1;
					transform.Translate(-moveSpeed * Time.deltaTime, 0, 0);
				}
				
				//如果没有以上的操作,就播放idle动画
				else {
					skeletonAnimation.AnimationName = idleAnimation;
				}
			}
		}

		//眨眼睛
		IEnumerator Blink() {
			while (true) {
				yield return new WaitForSeconds(Random.Range(0.25f, 3f));
				skeletonAnimation.Skeleton.SetAttachment(eyesSlot, blinkAttachment);
				yield return new WaitForSeconds(blinkDuration);
				skeletonAnimation.Skeleton.SetAttachment(eyesSlot, eyesOpenAttachment);
			}
		}
	}
}

总结和疑问

替换插槽上的图片:或隐或现

这里的情况是:插槽原来就有两张图,只不过一显一隐

skeletonAnimation.Skeleton.SetAttachment(插槽名, 图片名);

增加手里的剑:无中生有

在资源库里找到新的资源,放到某个位置,这里指原来可能没有

首先要有一个SpineAtlasAsset

将下面这俩武器的资源文件放进某文件夹中自动生成SpineAtlasAsset

Equipment.png

Equipment.atlas.txt

播放动画,这俩种方式在使用上效果的区别

skeletonAnimation.AnimationName = “idle”;

skeletonAnimation..AnimationState.SetAnimation(0, "idle", false);

需要注意的是,例子里动画的loop是勾选的

LOOP勾选

第一种API:AnimationName = “idle”;

         点击按钮就会不断播放的挥砍(攻击动画),再点击或者憋着也不会受影响

第二种API:AnimationState.SetAnimation(0, "idle", false);

        点击可以正常播放

        憋着按钮,动画会卡主住 ,松开后会继续播放完,再点击继续播放一次

LOOP取消

第一种API,播放一次后,不管怎么按都不播了

第二种API:AnimationState.SetAnimation(0, "idle", false);    和之前一样

        点击可以正常播放

        憋着按钮,动画会卡主住 ,松开后会继续播放完,再点击继续播放一次

所以,这个例子里的控制设计为,如果没有其它操作(挥砍或移动),就切回idle动画

初始化

初始化就调用,每隔一段时间执行一次效果

//委托:在骨架成功初始化后,开始有节奏的眨眼睛
skeletonAnimation.OnRebuild += Apply; 

//骨架初始化成功后 调用的函数
void Apply (SkeletonRenderer skeletonRenderer) {
            
     StartCoroutine(Blink());
}

//调用协程函数,协程函数就是眨眼睛
IEnumerator Blink() {
    while (true) {
	    yield return new WaitForSeconds(Random.Range(0.25f, 3f));
	    skeletonAnimation.Skeleton.SetAttachment(eyesSlot, blinkAttachment);
	    yield return new WaitForSeconds(blinkDuration);
	    skeletonAnimation.Skeleton.SetAttachment(eyesSlot, eyesOpenAttachment);
	    }
}

skeletonAnimation.OnRebuild += Apply; //委托:在骨架成功初始化后,开始有节奏的眨眼睛

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值