赞
踩
- using Cysharp.Threading.Tasks;
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
- using UnityEngine.Networking;
- using UnityEngine.SceneManagement;
-
- public class UniTaskTest : MonoBehaviour
- {
- private UniTaskSys uniTaskSys;
-
- public Image img_Test;
-
- //百度一张图片:右击,在新标签页中打开图像,复制url
- private string url;
-
- private bool isO_Down;
- private bool isP_Down;
-
- private void Awake()
- {
- uniTaskSys = new UniTaskSys();
- url = "https://n.sinaimg.cn/sinacn18/600/w1920h1080/20180508/2a45-haichqy4087272.jpg";
- }
-
- private void Start()
- {
- //AsyncLoadTextAsset("1");
- LoadScene("Demo");
- //AsyncWebRequestTexture(url);
-
- //uniTaskSys.DelayTest(this);
- WhenAllTest();
- WhenAnyTest();
- }
-
- private void Update()
- {
- if (Input.GetKeyDown(KeyCode.O))
- {
- isO_Down = true;
- }
- if (Input.GetKeyDown(KeyCode.P))
- {
- isP_Down = true;
- }
-
- }
-
- private async void AsyncLoadTextAsset(string path)
- {
- TextAsset textAsset = await uniTaskSys.AsyncLoad<TextAsset>(path) as TextAsset;
- Debug.Log(textAsset.text);
- }
-
- private void LoadScene(string sceneName)
- {
- uniTaskSys.AsyncLoadScene(sceneName);
- }
-
- public async void AsyncWebRequestTexture(string url)
- {
- var webRequest = UnityWebRequestTexture.GetTexture(url);
- var asyncOperation = await webRequest.SendWebRequest();
- Texture2D texture2D = ((DownloadHandlerTexture)asyncOperation.downloadHandler).texture;
- img_Test.sprite = Sprite.Create(texture2D, new Rect(0, 0, texture2D.width, texture2D.height), new Vector2(0.5f, 0.5f));
- img_Test.SetNativeSize();
- }
-
- /// <summary>
- /// 当两个条件都符合了才执行后面操作
- /// </summary>
- public async void WhenAllTest()
- {
- var firstOperation = UniTask.WaitUntil(() => isO_Down);
- var secondOperation = UniTask.WaitUntil(() => isP_Down);
- await UniTask.WhenAll(firstOperation, secondOperation);
- // 注意,whenAll可以用于平行执行多个资源的读取,非常有用!
- // var (a, b, c) = await UniTask.WhenAll(
- //LoadAsSprite("foo"),
- //LoadAsSprite("bar"),
- //LoadAsSprite("baz"));
- Debug.Log("条件01、02都符合条件了");
- }
-
- /// <summary>
- /// 当其中一个按钮点击了就执行后面操作
- /// </summary>
- private async void WhenAnyTest()
- {
- var firstOperation = UniTask.WaitUntil(() => isO_Down);
- var secondOperation = UniTask.WaitUntil(() => isP_Down);
- await UniTask.WhenAny(firstOperation, secondOperation);
- Debug.Log(isO_Down ? "O被按下" : "P被按下");
- }
-
- }
-
- public class UniTaskSys
- {
- public int count = 0;
-
- public async UniTask<Object> AsyncLoad<T>(string path) where T : Object
- {
- // 加载资源
- var asyncOperation = Resources.LoadAsync<T>(path);
- return (await asyncOperation);
- }
-
- public async void AsyncLoadScene(string sceneName)
- {
- // 加载场景
- await SceneManager.LoadSceneAsync(sceneName).ToUniTask
- (Progress.Create<float>((p) =>
- {
- Debug.Log($"加载进度为{p * 100:F2}%");
- }));
- }
-
- public async void DelayTest(MonoBehaviour mono = null)
- {
- Debug.Log(Time.realtimeSinceStartup);
- //性能最好,可以设置等待时机,PlayerLoopTiming 对应Unity中playerloop的更新时机
- //await UniTask.Yield(PlayerLoopTiming.LastUpdate);
-
- //等待1秒,类似 yield return new WaitForSeconds(1),可以设置 ignoreTimeScale
- //await UniTask.Delay(System.TimeSpan.FromSeconds(1), false);
-
- //执行在下一帧的update之后,类似 yield return null,和 UniTask.Yield() 效果一样
- //await UniTask.NextFrame();
-
- //这一帧的最后,类似 yield return new WaitForEndOfFrame(),this是一个MonoBehaviour
- //await UniTask.WaitForEndOfFrame(mono);
-
- //类似 yield return new WaitForFixedUpdate,和 await UniTask.Yield(PlayerLoopTiming.FixedUpdate)效果一样
- //await UniTask.WaitForFixedUpdate();
-
- //延迟5帧
- //await UniTask.DelayFrame(5);
-
- //类似 yield return new WaitUntil(() => count > 10),当count > 10时才执行后面逻辑
- await UniTask.WaitUntil(() => count > 10);
-
- Debug.Log(Time.realtimeSinceStartup);
- }
-
-
-
- }
- using Cysharp.Threading.Tasks;
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Threading;
- using UnityEngine;
- using UnityEngine.UI;
-
- public class UniTaskCancel : MonoBehaviour
- {
- public Transform FirstTransform;
- public Transform SecondTransform;
-
- public Button FirstRunButton;
- public Button SecondRunButton;
-
- public Button FirstCancelButton;
- public Button SecondCancelButton;
-
- //做取消时需要创建这个对象
- private CancellationTokenSource _firstCancelToken;
- private CancellationTokenSource _secondCancelToken;
- private CancellationTokenSource _linkedCancelToken;
-
- private void Start()
- {
- FirstRunButton.onClick.AddListener(OnClickFirstMove);
- SecondRunButton.onClick.AddListener(OnClickSecondMove);
-
- FirstCancelButton.onClick.AddListener(OnClickFirstCancel);
- SecondCancelButton.onClick.AddListener(OnClickSecondCancel);
-
- _firstCancelToken = new CancellationTokenSource();
- // 注意这里可以直接先行设置多久以后取消
- // _firstCancelToken = new CancellationTokenSource(TimeSpan.FromSeconds(1.5f));
- _secondCancelToken = new CancellationTokenSource();
- //用两个token创建新的linkedCancelToken,当其中一个取消后,linkedCancelToken也会取消,
- _linkedCancelToken =
- CancellationTokenSource.CreateLinkedTokenSource(_firstCancelToken.Token, _secondCancelToken.Token);
- }
-
- /// <summary>
- /// 移动first,使用try catch监听取消信号
- /// </summary>
- private async void OnClickFirstMove()
- {
- try
- {
- await MoveTransform(FirstTransform, _firstCancelToken.Token);
- }
- catch (OperationCanceledException e)
- {
- //发出取消信号,这里会抛异常
- Debug.Log("first已经被取消");
- }
- }
-
- /// <summary>
- /// 移动second,忽略异常的抛出,返回一个值元组,这种方式性能更好
- /// </summary>
- private async void OnClickSecondMove()
- {
- //第一个参数表示是否取消,第二个参数时await的返回值
- var (cancelled, _) = await MoveTransform(SecondTransform, _secondCancelToken.Token).SuppressCancellationThrow();
- // 使用LinkedToken,当first取消后,second也会取消
- // var (cancelled, _) = await MoveTransform(SecondTransform, _linkedCancelToken.Token).SuppressCancellationThrow();
- if (cancelled)
- {
- Debug.Log("second已经被取消");
- }
- }
-
- private async UniTask<int> MoveTransform(Transform tf, CancellationToken cancellationToken)
- {
- float totalTime = 10;
- float timeElapsed = 0;
- while (timeElapsed <= totalTime)
- {
- timeElapsed += Time.deltaTime;
- await UniTask.NextFrame(cancellationToken);
- tf.transform.localPosition += Vector3.right * Time.deltaTime * 3;
- }
-
- return 0;
- }
-
- /// <summary>
- /// 取消first移动,Token使用后就不能再次使用,得创建新的Token
- /// </summary>
- private void OnClickFirstCancel()
- {
- _firstCancelToken.Cancel();
- _firstCancelToken.Dispose();
- _firstCancelToken = new CancellationTokenSource();
- _linkedCancelToken =
- CancellationTokenSource.CreateLinkedTokenSource(_firstCancelToken.Token, _secondCancelToken.Token);
- }
-
- private void OnClickSecondCancel()
- {
- _secondCancelToken.Cancel();
- _secondCancelToken.Dispose();
- _secondCancelToken = new CancellationTokenSource();
- _linkedCancelToken =
- CancellationTokenSource.CreateLinkedTokenSource(_firstCancelToken.Token, _secondCancelToken.Token);
- }
-
- private void OnDestroy()
- {
- _firstCancelToken.Dispose();
- _secondCancelToken.Dispose();
- _linkedCancelToken.Dispose();
- }
- }
-
- using System;
- using System.Threading;
- using Cysharp.Threading.Tasks;
- using Cysharp.Threading.Tasks.Linq;
- using UnityEngine;
- using UnityEngine.UI;
-
- /// <summary>
- /// UI事件模板
- /// </summary>
- public class UIEventsSample : MonoBehaviour
- {
- public Transform trans_Sphere;
-
- public Button SphereButton;
- public Button DoubleClickButton;
- public Button CoolDownButton;
-
- public float DoubleClickCheckTime = 0.5f;
- public float CooldownTime = 3f;
-
- void Start()
- {
- CheckSphereClick(SphereButton.GetCancellationTokenOnDestroy()).Forget();
- CheckDoubleClickButton(DoubleClickButton, this.GetCancellationTokenOnDestroy()).Forget();
- CheckCooldownClickButton(this.GetCancellationTokenOnDestroy()).Forget();
- }
-
- /// <summary>
- /// 球体连点
- /// </summary>
- private async UniTaskVoid CheckSphereClick(CancellationToken token)
- {
- //将按钮的点击转换为异步可迭代器
- var asyncEnumerable = SphereButton.OnClickAsAsyncEnumerable();
- //ForEachAsync处理每一次点击时的操作,index表示第几次点击,Take(3)表示只处理前三次点击
- await asyncEnumerable.Take(3).ForEachAsync((_, index) =>
- {
- if (token.IsCancellationRequested) return;
- if (index == 0)
- {
- //第一次点击,放大
- SphereTweenScale(2, trans_Sphere.localScale.x, 5, token).Forget();
- }
- else if (index == 1)
- {
- //第二次点击,缩小
- SphereTweenScale(2, trans_Sphere.localScale.x, 2, token).Forget();
- }
- else if (index == 2)
- {
- //第三次点击销毁
- }
- }, token);
- GameObject.Destroy(trans_Sphere.gameObject);
- //三次点击后,await完成,可以进行后面的逻辑
- Debug.LogError("done");
- }
-
- private async UniTaskVoid SphereTweenScale(float totalTime, float from, float to, CancellationToken token)
- {
- var trans = trans_Sphere;
- float time = 0;
- while (time < totalTime)
- {
- time += Time.deltaTime;
- if (trans)
- {
- trans.localScale = (from + (time / totalTime) * (to - from)) * Vector3.one;
- }
- await UniTask.Yield(PlayerLoopTiming.Update, token);
- }
- }
-
- /// <summary>
- /// 双击按钮
- /// </summary>
- private async UniTaskVoid CheckDoubleClickButton(Button button, CancellationToken token)
- {
- while (true)
- {
- //将点击转换为异步的UniTask,然后等待第一次点击
- var clickAsync = button.OnClickAsync(token);
- await clickAsync;
- Debug.Log($"按钮被第一次点击");
-
- var secondClickAsync = button.OnClickAsync(token);
- //第二次点击和等待时间谁先到,WhenAny返回那个先执行
- int resultIndex = await UniTask.WhenAny(secondClickAsync,
- UniTask.Delay(TimeSpan.FromSeconds(DoubleClickCheckTime), cancellationToken: token));
- Debug.Log(resultIndex == 0 ? $"按钮被双击了" : $"超时,按钮算单次点击");
-
- }
- }
-
- /// <summary>
- /// 按钮冷却时间
- /// </summary>
- private async UniTaskVoid CheckCooldownClickButton(CancellationToken token)
- {
- var asyncEnumerable = CoolDownButton.OnClickAsAsyncEnumerable();
- await asyncEnumerable.ForEachAwaitAsync(async (_) =>
- {
- Debug.Log("被点击了,冷却中……");
-
- //Delay过程中不会再响应点击操作
- await UniTask.Delay(TimeSpan.FromSeconds(CooldownTime), cancellationToken: token);
- Debug.Log("冷却好了,可以点了……");
- }, cancellationToken: token);
- }
-
- }
- using Cysharp.Threading.Tasks;
- using System;
- using System.Threading;
- using UnityEngine;
- using UnityEngine.Networking;
- using UnityEngine.UI;
-
- /// <summary>
- /// 超时操作
- /// </summary>
- public class TimeoutTest : MonoBehaviour
- {
- public Button TestButton;
-
- private void Start()
- {
- //使用UniTask.UnityAction包装了OnClickTest
- TestButton.onClick.AddListener(UniTask.UnityAction(OnClickTest));
- }
-
- private async UniTaskVoid OnClickTest()
- {
- var res = await GetRequest("https://www.baidu.com/", 2f);
- //var res = await GetRequest("https://www.google.com/", 2f);
- Debug.LogError(res);
- }
-
- private async UniTask<string> GetRequest(string url, float timeout)
- {
- //这个token会在timeout之后发出取消信号
- var cts = new CancellationTokenSource();
- cts.CancelAfterSlim(TimeSpan.FromSeconds(timeout));
-
- var (failed, result) = await UnityWebRequest.Get(url).SendWebRequest().
- WithCancellation(cts.Token).SuppressCancellationThrow();
- if (!failed)
- {
- //成功了返回网页内容的开头
- return result.downloadHandler.text.Substring(0, 100);
- }
-
- return "超时";
- }
- }
-
- using Cysharp.Threading.Tasks;
- using System.Collections;
- using System.Collections.Generic;
- using System.IO;
- using UnityEngine;
- using UnityEngine.UI;
-
- /// <summary>
- /// 切换到主线程
- /// </summary>
- public class ThreadSample : MonoBehaviour
- {
- public Button btn_StandardRun;
- public Button btn_YieldRun;
-
- private void Start()
- {
- btn_StandardRun.onClick.AddListener(UniTask.UnityAction(OnClickStandardRun));
- btn_YieldRun.onClick.AddListener(UniTask.UnityAction(OnClickYieldRun));
- }
-
- public async UniTaskVoid OnClickStandardRun()
- {
- int result = 0;
-
- //切换到其他线程
- await UniTask.RunOnThreadPool(()=> { result = 1; });
- //切换到主线程
- await UniTask.SwitchToMainThread();
-
- Debug.Log($"计算结束,当前结果为:{result}");
- }
-
- /// <summary>
- /// 线程中读取文件
- /// </summary>
- private async UniTaskVoid OnClickYieldRun()
- {
- string fileName = Application.streamingAssetsPath + "/Test.txt";
- await UniTask.SwitchToThreadPool();
- string fileContent = await File.ReadAllTextAsync(fileName);
- //调用 UniTask.Yield 会自动切换会主线程
- await UniTask.Yield(PlayerLoopTiming.Update);
- Debug.LogError(fileContent);
- }
-
- }
- using Cysharp.Threading.Tasks;
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
-
- public class ForgetSample : MonoBehaviour
- {
- public Button StartButton;
- public GameObject Target;
- public const float G = 9.8f;
-
- public float FallTime = 0.5f;
-
- private void Start()
- {
- StartButton.onClick.AddListener(OnClickStart);
- }
-
- /// <summary>
- /// 同步方法中调用异步方法
- /// </summary>
- private void OnClickStart()
- {
- //不需要等待时候就调用Forget
- FallTarget(Target.transform).Forget();
- }
-
- /// <summary>
- /// 使目标掉落,async UniTaskVoid是async UniTask的轻量级版本
- /// </summary>
- private async UniTaskVoid FallTarget(Transform targetTrans)
- {
- Vector3 startPosition = targetTrans.position;
- float fallTime = 1f;
- float elapsedTime = 0;
- while (elapsedTime <= fallTime)
- {
- elapsedTime += Time.deltaTime;
- float fallY = 0.5f * G * elapsedTime * elapsedTime;
- targetTrans.position = startPosition + Vector3.down * fallY;
- //GetCancellationTokenOnDestroy 表示获取一个依赖对象生命周期的Cancel句柄,
- //当对象被销毁时,将会调用这个Cancel句柄,从而实现取消的功能
- await UniTask.Yield(this.GetCancellationTokenOnDestroy());
- }
- }
-
-
- }
-
- using Cysharp.Threading.Tasks;
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
-
- public class CallbackSample : MonoBehaviour
- {
- public Button CallbackButton;
- public GameObject Target;
- public const float G = 9.8f;
-
- public event EventHandler OneSecondHandler;
-
- private void Start()
- {
- CallbackButton.onClick.AddListener(UniTask.UnityAction(OnClickCallback));
- OneSecondHandler += CallbackSample_OneSecondHandler;
- }
-
- private void CallbackSample_OneSecondHandler(object sender, EventArgs e)
- {
- Debug.Log("1S 事件被触发");
- }
-
- private async UniTaskVoid OnClickCallback()
- {
- float time = Time.time;
- UniTaskCompletionSource source = new UniTaskCompletionSource();
- FallTarget(Target.transform, source).Forget();
- await source.Task;// UniTaskCompletionSource产生的UnitTask是可以复用的
- Debug.Log($"耗时 {Time.time - time}秒");
- }
-
- /// <summary>
- /// UniTask运行中执行回调
- /// UniTaskCompletionSource是对UniTask和CancellationToken的封装
- /// </summary>
- private async UniTask FallTarget(Transform targetTrans, UniTaskCompletionSource source)
- {
- Vector3 startPosition = targetTrans.position;
- float fallTime = 2f;
- float elapsedTime = 0;
- while (elapsedTime <= fallTime)
- {
- elapsedTime += Time.deltaTime;
- //当下落时间超过1秒时设置操作
- if (elapsedTime > 1f)
- {
- OneSecondHandler?.Invoke(this,EventArgs.Empty);
- // 表示操作完成
- source.TrySetResult();
- // 失败
- // source.TrySetException(new SystemException());
- // 取消
- // source.TrySetCanceled(someToken);
-
- // 泛型类UniTaskCompletionSource<T> SetResult是T类型,返回UniTask<T>
- }
-
- float fallY = 0.5f * G * elapsedTime * elapsedTime;
- targetTrans.position = startPosition + Vector3.down * fallY;
- await UniTask.Yield(this.GetCancellationTokenOnDestroy());
- }
- }
-
- private void OnDestroy()
- {
- OneSecondHandler -= CallbackSample_OneSecondHandler;
- }
- }
-
- using Cysharp.Threading.Tasks;
- using Cysharp.Threading.Tasks.Linq;
- using System.Collections;
- using System.Collections.Generic;
- using System.Threading;
- using UnityEngine;
- using UnityEngine.UI;
-
- public class AsyncReactivePropertySample : MonoBehaviour
- {
- public int maxHp = 100;
- public float totalChangeTime = 1f;
- public Text ShowHpText;
- public Text StateText;
- public Text ChangeText;
-
- public Slider HpSlider;
- public Image HpBarImage;
-
- public Button HealButton;
- public Button HurtButton;
-
- private AsyncReactiveProperty<string> currentHpStr;
- private AsyncReactiveProperty<int> currentHp;
- private int maxHeal = 10;
- private int maxHurt = 10;
- private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
- private CancellationTokenSource _linkedTokenSource;
-
- private void Start()
- {
- // 设置AsyncReactiveProperty
- currentHpStr = new AsyncReactiveProperty<string>($"当前血量:{maxHp}/{maxHp}");
- currentHp = new AsyncReactiveProperty<int>(maxHp);
- HpSlider.maxValue = maxHp;
- HpSlider.value = maxHp;
-
- currentHp.Subscribe(OnHpChange);
- CheckHpChange(currentHp).Forget();
- CheckFirstLowHp(currentHp).Forget();
-
- currentHpStr.BindTo(ShowHpText);
-
- HealButton.onClick.AddListener(OnClickHeal);
- HurtButton.onClick.AddListener(OnClickHurt);
-
- _linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_cancellationTokenSource.Token,
- this.GetCancellationTokenOnDestroy());
-
- }
-
- private void OnClickHeal()
- {
- ChangeHp(Random.Range(0, maxHeal));
- }
-
- private void OnClickHurt()
- {
- ChangeHp(-Random.Range(0, maxHurt));
- }
-
- private void ChangeHp(int deltaHp)
- {
- currentHp.Value = Mathf.Clamp(currentHp.Value + deltaHp, 0, maxHp);
- currentHpStr.Value = $"当前血量:{currentHp.Value}/{maxHp}";
- }
-
- /// <summary>
- /// currentHp变化时修改提示信息
- /// </summary>
- private async UniTaskVoid CheckHpChange(AsyncReactiveProperty<int> hp)
- {
- int hpValue = hp.Value;
- // WithoutCurrent 忽略初始值
- await hp.WithoutCurrent().ForEachAsync((_, index) =>
- {
- ChangeText.text = $"血量发生变化 第{index}次 变化{hp.Value - hpValue}";
- hpValue = hp.Value;
- }, this.GetCancellationTokenOnDestroy());
- }
-
- /// <summary>
- /// currentHp低于临界值,显示提示信息
- /// </summary>
- private async UniTaskVoid CheckFirstLowHp(AsyncReactiveProperty<int> hp)
- {
- await hp.FirstAsync((value) => value < maxHp * 0.4f, this.GetCancellationTokenOnDestroy());
- StateText.text = "首次血量低于界限,请注意!";
- }
-
- private async UniTaskVoid OnHpChange(int hp)
- {
- _cancellationTokenSource.Cancel();
- _cancellationTokenSource = new CancellationTokenSource();
- _linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_cancellationTokenSource.Token,
- this.GetCancellationTokenOnDestroy());
- await SyncSlider(hp, _linkedTokenSource.Token);
- }
-
- /// <summary>
- /// 同步血条
- /// </summary>
- private async UniTask SyncSlider(int hp, CancellationToken token)
- {
- var sliderValue = HpSlider.value;
- float needTime = Mathf.Abs((sliderValue - hp) / maxHp * totalChangeTime);
- float useTime = 0;
- while (useTime < needTime)
- {
- useTime += Time.deltaTime;
- bool result = await UniTask.Yield(PlayerLoopTiming.Update, token)
- .SuppressCancellationThrow();
- if (result)
- {
- return;
- }
-
- var newValue = (sliderValue + (hp - sliderValue) * (useTime / needTime));
- SetNewValue(newValue);
- }
- }
-
- private void SetNewValue(float newValue)
- {
- if (!HpSlider) return;
- HpSlider.value = newValue;
- HpBarImage.color = HpSlider.value / maxHp < 0.4f ? Color.red : Color.white;
- }
- }
-
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。