原练习挑战是: Unity小练习 0003,有奖代码逻辑趣味小练习
在解题之前我们需要了解异步和协程是什么?他们的区别是什么?
在Unity中,异步操作和协程都是用于处理耗时任务或需要分步执行的任务的技术,但它们有一些区别。
异步操作:
- 异步操作通常是基于C#的
async
和await
关键字实现的,在Unity中也可以使用这些关键字进行异步编程。
- 异步操作更加符合传统的多线程编程思想,它可以在后台线程执行耗时操作,并通过
await
关键字等待操作完成。
- 异步操作更适合于处理IO密集型的任务,比如文件读写、网络请求等,可以避免阻塞主线程而提高程序的响应性。
协程:
- 协程是Unity引擎提供的一种特殊的迭代器(Iterator),通过使用
yield return
语句来实现挂起和恢复执行的功能。
- 协程更适合处理需要分步执行的任务,比如动画播放、延时操作、复杂的游戏逻辑等。
- 协程在Unity中被广泛应用于处理游戏对象行为、状态机逻辑、动画控制等,它能够简化代码逻辑,使得复杂任务的实现更加清晰和可控。
区别:
- 异步操作是C#语言层面的特性,而协程是Unity引擎提供的一种特殊机制。
- 异步操作更加通用,可以处理各种类型的任务,而协程更适合处理游戏开发中的特定场景和需求。
- 在使用上,异步操作需要借助于
Task
等类进行管理,而协程则直接使用Unity的StartCoroutine
等方法启动和管理。
总的来说,异步操作更加通用和灵活,适用于各种情况下的异步任务处理,而协程则更专注于游戏开发领域,提供了一种便捷的方式来处理游戏中的复杂逻辑和任务。
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
using System.Threading.Tasks;
public class PatrolCube : MonoBehaviour
{
public Transform center; // 圆心
public float radius = 10f; // 半径
public float moveSpeed = 5f; // 移动速度
public List<Vector3> patrolPoints; // 巡逻点
public int currentPatrolIndex = 0; // 当前巡逻点索引
private CancellationTokenSource cancellationTokenSource; // 令牌
private bool isDestroyed = false; // 判断物体是否已销毁
public int patrolPointCount = 0; // 巡逻点数量
async void Start()
{
cancellationTokenSource = new CancellationTokenSource();
// 生成巡逻点
await GeneratePatrolPoints(cancellationTokenSource.Token);
// 执行巡逻
await Patrol(cancellationTokenSource.Token);
}
// 生成巡逻点
async Task GeneratePatrolPoints(CancellationToken cancellationToken)
{
var tempPatrolPoints = new List<Vector3>();
for (int i = 0; i < 4; i++)
{
// 检查是否已取消或对象是否已销毁
if (cancellationToken.IsCancellationRequested || isDestroyed)
return;
float angle = i \* Mathf.PI \* 0.5f;
float x = center.position.x + Mathf.Cos(angle) \* radius;
float z = center.position.z + Mathf.Sin(angle) \* radius;
tempPatrolPoints.Add(new Vector3(x, center.position.y, z));
}
patrolPoints = new List<Vector3>(tempPatrolPoints);
patrolPointCount = patrolPoints.Count;
}
// 执行巡逻
async Task Patrol(CancellationToken cancellationToken)
{
while (true)
{
// 检查是否已取消或对象是否已销毁
if (cancellationToken.IsCancellationRequested || isDestroyed)
return;
Vector3 targetPosition = patrolPoints\[currentPatrolIndex\];
while (Vector3.Distance(transform.position, targetPosition) > 0.1f)
{
// 移动向目标位置
transform.position = Vector3.MoveTowards(transform.position, targetPosition, moveSpeed \* Time.deltaTime);
// 调整朝向目标位置
Vector3 direction = (targetPosition - transform.position).normalized;
Quaternion lookRotation = Quaternion.LookRotation(direction);
transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Time.deltaTime \* 5f);
// 等待一定时间
await Task.Delay(10);
// 检查是否已取消或对象是否已销毁
if (cancellationToken.IsCancellationRequested || isDestroyed)
return;
}
// 切换至下一个巡逻点
currentPatrolIndex = (currentPatrolIndex + 1) % patrolPointCount;
targetPosition = patrolPoints\[currentPatrolIndex\];
// 等待一定时间
await Task.Delay(10);
// 检查是否已取消或对象是否已销毁
if (cancellationToken.IsCancellationRequested || isDestroyed)
return;
}
}
// 在对象销毁时执行
void OnDestroy()
{
// 在对象销毁时取消异步操作
if (cancellationTokenSource ≠ null)
{
cancellationTokenSource.Cancel(); // 取消异步操作
cancellationTokenSource.Dispose(); // 释放资源
}
isDestroyed = true; // 设置对象已销毁标志
}
}