上海网站建设的价,网站做商标在那类,网站优化具体做哪些事情,南宁seo计费管理用一个异步方法来播放一个动画#xff0c;正常情况是#xff1a;动画播放结束时#xff0c;异步方法宣告结束。那如果我提前取消这个异步任务#xff0c;那在这个异步方法里面#xff0c;我要怎么停止播放呢#xff1f;#xff01;
一、播放animation动画的异步实现
1…用一个异步方法来播放一个动画正常情况是动画播放结束时异步方法宣告结束。那如果我提前取消这个异步任务那在这个异步方法里面我要怎么停止播放呢
一、播放animation动画的异步实现
1、用play播放动画片段2、await一段时间等动画播放结束3、用stop停止动画播放
二、两种实现方式
1 、纯多任务模式的实现
实现原理 定义了两个结束的事件或者Task 1第一个是播放时长到点了 2第二个是用户取消了异步任务 3用whenAny等待 /// summary/// 等待一个动画播放完毕/// 中间如果任务被取消则停止播放动画/// /summary/// param nameAnim/param/// param namestartTime/param/// param nameendTime/param/// param namespeed/param/// param namectk任务取消标志/param/// returns/returnspublic static async UniTaskbool PlayAnim(Animation Anim, float startTime, float endTime, float speed, CancellationToken ctk){Debug.Log($当前Time.timeScale {Time.timeScale});float t (endTime - startTime) * Time.timeScale; //考虑到动画时间倍率Debug.Log($动画的时长为{t}秒);Anim[Anim.clip.name].time startTime;//跳过第几帧Anim[Anim.clip.name].speed speed;Anim.Play(Anim.clip.name); //Play()//如果时间到点结束并停止动画FuncUniTask timeFn async () { await UniTask.Delay(TimeSpan.FromSeconds(t), cancellationToken: ctk);Anim.Stop();};//用户取消任务结束并停止动画FuncUniTask cancelFn async () {Debug.Log(开始执行cancelFn的循环);while (true){Debug.Log($ctk.IsCancellationRequested {ctk.IsCancellationRequested});if (ctk.IsCancellationRequested){Debug.Log($任务取消:{ctk.IsCancellationRequested});Anim.Stop();break;};await UniTask.Yield(); //注意这里不能随意加ctk不然不能停直接跳出了//await UniTask.Yield(ctk); }Debug.Log(结束cancelFn的循环);};//等待结束var idx await UniTask.WhenAny(timeFn(), cancelFn()).AttachExternalCancellation(ctk);Debug.Log($任务结束结束方式为{idx} 备注0 动画播放结束1 用户取消任务);return true;}2 、手工启动一个循环每帧检查结束条件 /// summary/// 等待一个动画播放完毕/// 中间如果任务被取消则停止播放动画/// 改进了结束的判断方式/// /summary/// param nameAnim/param/// param namestartTime/param/// param nameendTime/param/// param namespeed/param/// param namectk任务取消标志/param/// returns/returnspublic static async UniTaskbool PlayAnim2(Animation Anim, float startTime, float endTime, float speed, CancellationToken ctk){Debug.Log($当前Time.timeScale {Time.timeScale});float t (endTime - startTime) * Time.timeScale; //考虑到动画时间倍率float elapse 0f;Debug.Log($动画的时长为{t}秒);Anim[Anim.clip.name].time startTime;//跳过第几帧Anim[Anim.clip.name].speed speed;Anim.Play(Anim.clip.name); //Play()//每帧进行结束判断while (true){elapse Time.deltaTime; //任务被取消Debug.Log($ctk.IsCancellationRequested {ctk.IsCancellationRequested});if (ctk.IsCancellationRequested){Debug.Log($任务取消:{ctk.IsCancellationRequested});//Anim.Stop();break;};//动画播放完毕if (elapse t){break;}await UniTask.Yield(); //注意这里不能随意加ctk不然不能停直接return了//await UniTask.Yield(ctk); }Anim.Stop();return true;}三、测试流程
1、启动一个“线程异步任务”——播放动画2、等待2秒后停止任务3、停止【播放动画】的“线程”
//获取animation组件
if (anim null) anim this.GetComponentAnimation();
var cti TaskSignal.CreatCts();//启动一个“线程”——播放动画
PlayAnim2(anim, 0f, 5f, 1, cti.cts.Token).Forget();//等待2秒后停止任务
await UniTask.Delay(1500);Debug.Log(停止任务......);
//停止【播放动画】的“线程”
TaskSignal.CancelTask(cti.id);四、效果
1、等待全部播放完毕 2、播放2秒后取消任务同时停止播放 五、附录测试用的代码
为了样例完整性我把三个脚本并在一个脚本里请忽略杂乱的代码组织
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using UnityEngine;
using System;
using System.Linq;public class TestPlayAnimation : MonoBehaviour
{public Animation anim;private async UniTask TestPlay(){//获取animation组件if(anim null) anim this.GetComponentAnimation();var cti TaskSignal.CreatCts();//启动一个“线程”——播放动画PlayAnim(anim, 0f, 5f, 1,cti.cts.Token).Forget();//等待2秒后停止任务await UniTask.Delay(1500);Debug.Log(停止任务......);//停止【播放动画】的“线程”TaskSignal.CancelTask(cti.id);}private async UniTask TestPlay2(){//获取animation组件if (anim null) anim this.GetComponentAnimation();var cti TaskSignal.CreatCts();//启动一个“线程”——播放动画PlayAnim2(anim, 0f, 5f, 1, cti.cts.Token).Forget();//等待2秒后停止任务await UniTask.Delay(1500);Debug.Log(停止任务......);//停止【播放动画】的“线程”TaskSignal.CancelTask(cti.id);}#if UNITY_EDITOR[ContextMenu(播放整个动画)]
#endifvoid test1(){PlayAnim2(anim, 0f, 5f, 1,this.GetCancellationTokenOnDestroy()).Forget();}#if UNITY_EDITOR[ContextMenu(停止测试)]
#endifvoid test2(){TestPlay().Forget();}#if UNITY_EDITOR[ContextMenu(停止测试2)]
#endifvoid test3(){TestPlay2().Forget();}#region 用到的异步方法 /// summary/// 等待一个动画播放完毕/// 中间如果任务被取消则停止播放动画/// /summary/// param nameAnim/param/// param namestartTime/param/// param nameendTime/param/// param namespeed/param/// param namectk任务取消标志/param/// returns/returnspublic static async UniTaskbool PlayAnim(Animation Anim, float startTime, float endTime, float speed, CancellationToken ctk){Debug.Log($当前Time.timeScale {Time.timeScale});float t (endTime - startTime) * Time.timeScale; //考虑到动画时间倍率Debug.Log($动画的时长为{t}秒);Anim[Anim.clip.name].time startTime;//跳过第几帧Anim[Anim.clip.name].speed speed;Anim.Play(Anim.clip.name); //Play()//如果时间到点结束并停止动画FuncUniTask timeFn async () {await UniTask.Delay(TimeSpan.FromSeconds(t), cancellationToken: ctk);Anim.Stop();};//用户取消任务结束并停止动画FuncUniTask cancelFn async () {Debug.Log(开始执行cancelFn的循环);while (true){//Debug.Log($ctk.IsCancellationRequested {ctk.IsCancellationRequested});if (ctk.IsCancellationRequested){Debug.Log($任务取消:{ctk.IsCancellationRequested});Anim.Stop();break;};await UniTask.Yield(); //注意这里不能随意加ctk不然不能停直接跳出了//await UniTask.Yield(ctk); }Debug.Log(结束cancelFn的循环);};//等待结束var idx await UniTask.WhenAny(timeFn(), cancelFn()).AttachExternalCancellation(ctk);Debug.Log($任务结束结束方式为{idx} 备注0 动画播放结束1 用户取消任务);return true;}/// summary/// 等待一个动画播放完毕/// 中间如果任务被取消则停止播放动画/// 改进了结束的判断方式/// /summary/// param nameAnim/param/// param namestartTime/param/// param nameendTime/param/// param namespeed/param/// param namectk任务取消标志/param/// returns/returnspublic static async UniTaskbool PlayAnim2(Animation Anim, float startTime, float endTime, float speed, CancellationToken ctk){Debug.Log($当前Time.timeScale {Time.timeScale});float t (endTime - startTime) * Time.timeScale; //考虑到动画时间倍率float elapse 0f;Debug.Log($动画的时长为{t}秒);Anim[Anim.clip.name].time startTime;//跳过第几帧Anim[Anim.clip.name].speed speed;Anim.Play(Anim.clip.name); //Play()//每帧进行结束判断while (true){elapse Time.deltaTime;//任务被取消//Debug.Log($ctk.IsCancellationRequested {ctk.IsCancellationRequested});if (ctk.IsCancellationRequested){Debug.Log($任务取消:{ctk.IsCancellationRequested});break;};//动画播放完毕if (elapse t){break;}await UniTask.Yield(); //注意这里不能随意加ctk不然不能停直接return了//await UniTask.Yield(ctk); }Anim.Stop();return true;}#endregion#region 异步任务管理脚本/// summary/// 任务管理/// /summarypublic static class TaskSignal{/// 任务信息/// summary/// /summary[Serializable]public class CtsInfo{/// summary/// 任务id/// /summary[SerializeField] public int id;/// summary/// cst实例/// /summary[SerializeField] public CancellationTokenSource cts;}/// summary/// 任务池子/// /summarypublic static ListCtsInfo ctsInfos new ListCtsInfo();/// summary/// 任务编号【自增】/// /summaryprivate static int id 0;/// summary/// 创建一个任务/// /summary/// returns/returnspublic static CtsInfo CreatCts(){var cts new CancellationTokenSource();var ci new CtsInfo { cts cts, id id };id;ctsInfos.Add(ci);return ci;}/// summary/// 取消所有的任务/// /summarypublic static void CancelAllTask(){Debug.Log($开始执行取消所有的任务CancelAllTask);ctsInfos.ForEach(ci {Debug.Log($CancelAllTask() : cts总数量为{ctsInfos.Count});try{Debug.Log($ci.id {ci.id},取消前 ci.cts {ci.cts.IsCancellationRequested});if (ci.cts.IsCancellationRequested false){Debug.Log(开始执行ci.cts.Cancel());ci.cts.Cancel();Debug.Log(执行完毕ci.cts.Cancel());}else{//Debug.Log(ci.cts已经取消了);}Debug.Log($ci.id {ci.id},取消后 ci.cts {ci.cts.IsCancellationRequested});}catch (Exception e){Debug.Log($TaskSingol.CancelAllTask()取消任务时报错{e.Message});}});Debug.Log($结束执行取消所有的任务CancelAllTask);}/// summary/// 取消所有的任务/// /summarypublic static void CancelAllTask10(){ctsInfos.ForEach(ci {if (ci.cts.Token.IsCancellationRequested false) // if (ci.cts.IsCancellationRequested false){ci.cts.Cancel();Debug.Log($取消了任务index {ci.id});}else{//Debug.Log(ci.cts已经取消了);}});}/// summary/// 取消指定的任务/// /summarypublic static void CancelTask(int id){ctsInfos.Where(ci ci.id id).ToList().ForEach(ci ci.cts.Cancel());}}#endregion
}