13.碰撞和点击
13.1 知识点
UniTask 在 Unity 中的碰撞与点击事件处理
在 Unity 开发中,处理异步事件(如碰撞和鼠标点击)通常需要编写复杂的协程或回调函数。UniTask 提供了一种更简洁高效的方式来处理这些异步事件。本文将通过具体示例,介绍如何使用 UniTask 监听游戏对象的碰撞和点击事件,以及实例化预制体并对其进行异步操作。
/*
* 此脚本演示了UniTask在Unity中的使用:
* 1. 对场景中指定的测试物体(testBall)进行碰撞和鼠标点击事件监听。
* 2. 通过预制体(redBallPrefab)实例化小球,在生成点(bornPoint)生成,并对其进行异步移动和碰撞事件监听。
*
* 注意:确保项目中已导入Cysharp.Threading.Tasks相关插件,并在需要的物体上挂载Collider组件以触发碰撞事件。
*/
using Cysharp.Threading.Tasks;
using Cysharp.Threading.Tasks.Triggers;
using System.Threading;
using Cysharp.Threading.Tasks.Linq;
using UnityEngine;
public class Lesson13_碰撞和点击 : MonoBehaviour
{
// 用于检测碰撞和点击事件的测试物体(需要在场景中挂载,并具备Collider组件)
public GameObject testBall;
// 用于实例化小球的预制体以及生成位置
public GameObject redBallPrefab;
public Transform bornPoint;
//是否碰撞
private bool _isCollision;
// 移动速度(用于在Update中让testBall持续运动)
[SerializeField] private float speed = 1f;
// 脚本启动时同时开启所有测试
void Start()
{
// 同时监听testBall的碰撞和鼠标点击事件
TestCollision().Forget();
TestClick().Forget();
// 实例化小球并开始对其实例的异步移动与碰撞事件监听
TestUniTaskInstantiationRedBall().Forget();
}
// 每帧调用,使testBall沿X轴持续移动
void Update()
{
if (testBall != null && !_isCollision)
testBall.transform.Translate(new Vector3(speed, 0, 0) * Time.deltaTime);
}
// 异步等待testBall发生碰撞事件,并输出碰撞对象的信息
async UniTaskVoid TestCollision()
{
var collisionTrigger = testBall.GetAsyncCollisionEnterTrigger();
// 捕获返回的碰撞信息
Collision collision = await collisionTrigger.OnCollisionEnterAsync();
// 输出碰撞对象的名称
Debug.Log("testBall发生碰撞,碰撞对象是:" + collision.gameObject.name);
_isCollision = true;
}
// 异步等待testBall接收到鼠标点击事件,并在点击后输出日志
async UniTaskVoid TestClick()
{
var clickTrigger = testBall.GetAsyncMouseDownTrigger();
await clickTrigger.OnMouseDownAsync();
Debug.Log("testBall被点击!");
}
// 实例化预制体小球,并启动异步移动与碰撞监听
private async UniTaskVoid TestUniTaskInstantiationRedBall()
{
// 在指定位置生成红色小球
var redBall = Instantiate(redBallPrefab, bornPoint.position, Quaternion.identity);
// 获取当小球被销毁时的取消标记
var token = redBall.GetCancellationTokenOnDestroy();
// 异步移动生成的小球
Move(redBall.transform, token).Forget();
// 使用异步流监听生成小球的碰撞事件,并在碰撞时输出碰撞物体的名称
redBall.GetAsyncCollisionEnterTrigger()
.ForEachAsync(
collision =>
{
Debug.Log("生成的红色小球碰撞到:" + collision.gameObject.name);
_isCollision = true;
},
cancellationToken: token
)
.Forget();
}
// 异步移动指定物体的Transform,沿X轴移动,持续5秒,碰撞了也不移动
async UniTaskVoid Move(Transform tf, CancellationToken token)
{
float totalTime = 5f;
float elapsedTime = 0f;
while (elapsedTime < totalTime && !_isCollision)
{
elapsedTime += Time.deltaTime;
tf.position -= new Vector3(speed, 0, 0) * Time.deltaTime;
await UniTask.NextFrame(token);
}
}
}
监听游戏对象的碰撞事件
在 Unity 中,检测游戏对象的碰撞通常需要在 OnCollisionEnter
等方法中处理。使用 UniTask,可以更优雅地监听碰撞事件。
using Cysharp.Threading.Tasks;
using UnityEngine;
public class CollisionExample : MonoBehaviour
{
public GameObject testBall;
private bool isCollision = false;
void Start()
{
TestCollision().Forget();
}
async UniTaskVoid TestCollision()
{
var collisionTrigger = testBall.GetAsyncCollisionEnterTrigger();
Collision collision = await collisionTrigger.OnCollisionEnterAsync();
Debug.Log($"[Collision] testBall 发生碰撞,碰撞对象是:{collision.gameObject.name}");
isCollision = true;
}
}
在上述示例中:
GetAsyncCollisionEnterTrigger()
用于获取testBall
的碰撞触发器。OnCollisionEnterAsync()
异步等待碰撞事件的发生,并返回碰撞信息。- 当
testBall
发生碰撞时,输出碰撞对象的名称,并将isCollision
标志设为true
。
监听游戏对象的鼠标点击事件
除了碰撞事件,UniTask 也可以用于监听游戏对象的鼠标点击事件。
using Cysharp.Threading.Tasks;
using UnityEngine;
public class ClickExample : MonoBehaviour
{
public GameObject testBall;
void Start()
{
TestClick().Forget();
}
async UniTaskVoid TestClick()
{
var clickTrigger = testBall.GetAsyncMouseDownTrigger();
await clickTrigger.OnMouseDownAsync();
Debug.Log("[Click] testBall 被点击!");
}
}
在上述示例中:
GetAsyncMouseDownTrigger()
获取testBall
的鼠标点击触发器。OnMouseDownAsync()
异步等待鼠标点击事件的发生。- 当
testBall
被点击时,输出相应的日志信息。
实例化预制体并进行异步移动与碰撞监听
在游戏开发中,常需要实例化预制体(Prefab)并对其进行操作。UniTask 可以方便地实现对实例化对象的异步移动和事件监听。
using Cysharp.Threading.Tasks;
using UnityEngine;
using System.Threading;
public class InstantiateAndMoveExample : MonoBehaviour
{
public GameObject redBallPrefab;
public Transform bornPoint;
private bool isCollision = false;
[SerializeField] private float speed = 1f;
void Start()
{
TestUniTaskInstantiationRedBall().Forget();
}
private async UniTaskVoid TestUniTaskInstantiationRedBall()
{
var redBall = Instantiate(redBallPrefab, bornPoint.position, Quaternion.identity);
var token = redBall.GetCancellationTokenOnDestroy();
Move(redBall.transform, token).Forget();
redBall.GetAsyncCollisionEnterTrigger()
.ForEachAsync(
collision =>
{
Debug.Log($"[Collision] 生成的红色小球碰撞到:{collision.gameObject.name}");
isCollision = true;
},
cancellationToken: token
)
.Forget();
}
async UniTaskVoid Move(Transform tf, CancellationToken token)
{
float totalTime = 5f;
float elapsedTime = 0f;
while (elapsedTime < totalTime && !isCollision)
{
elapsedTime += Time.deltaTime;
tf.position -= new Vector3(speed, 0, 0) * Time.deltaTime;
await UniTask.NextFrame(token);
}
}
}
在上述示例中:
- 在
bornPoint
位置实例化redBallPrefab
。 - 获取实例化对象的销毁取消标记
token
,用于在对象销毁时取消异步操作。 Move
方法异步地沿 X 轴移动实例化的小球,持续 5 秒或直到发生碰撞。- 使用
GetAsyncCollisionEnterTrigger().ForEachAsync()
监听小球的碰撞事件,并在发生碰撞时输出日志信息。
总结
UniTask 提供了强大的异步事件处理能力,使得在 Unity 中监听碰撞、鼠标点击等事件变得更加简洁和高效。通过 UniTask,可以避免传统回调和协程带来的复杂性,提高代码的可读性和维护性。
13.2 知识点代码
Lesson13_碰撞和点击
/*
* 此脚本演示了UniTask在Unity中的使用:
* 1. 对场景中指定的测试物体(testBall)进行碰撞和鼠标点击事件监听。
* 2. 通过预制体(redBallPrefab)实例化小球,在生成点(bornPoint)生成,并对其进行异步移动和碰撞事件监听。
*
* 注意:确保项目中已导入Cysharp.Threading.Tasks相关插件,并在需要的物体上挂载Collider组件以触发碰撞事件。
*/
using Cysharp.Threading.Tasks;
using Cysharp.Threading.Tasks.Triggers;
using System.Threading;
using Cysharp.Threading.Tasks.Linq;
using UnityEngine;
public class Lesson13_碰撞和点击 : MonoBehaviour
{
// 用于检测碰撞和点击事件的测试物体(需要在场景中挂载,并具备Collider组件)
public GameObject testBall;
// 用于实例化小球的预制体以及生成位置
public GameObject redBallPrefab;
public Transform bornPoint;
//是否碰撞
private bool _isCollision;
// 移动速度(用于在Update中让testBall持续运动)
[SerializeField] private float speed = 1f;
// 脚本启动时同时开启所有测试
void Start()
{
// 同时监听testBall的碰撞和鼠标点击事件
TestCollision().Forget();
TestClick().Forget();
// 实例化小球并开始对其实例的异步移动与碰撞事件监听
TestUniTaskInstantiationRedBall().Forget();
}
// 每帧调用,使testBall沿X轴持续移动
void Update()
{
if (testBall != null && !_isCollision)
testBall.transform.Translate(new Vector3(speed, 0, 0) * Time.deltaTime);
}
// 异步等待testBall发生碰撞事件,并输出碰撞对象的信息
async UniTaskVoid TestCollision()
{
var collisionTrigger = testBall.GetAsyncCollisionEnterTrigger();
// 捕获返回的碰撞信息
Collision collision = await collisionTrigger.OnCollisionEnterAsync();
// 输出碰撞对象的名称
Debug.Log("testBall发生碰撞,碰撞对象是:" + collision.gameObject.name);
_isCollision = true;
}
// 异步等待testBall接收到鼠标点击事件,并在点击后输出日志
async UniTaskVoid TestClick()
{
var clickTrigger = testBall.GetAsyncMouseDownTrigger();
await clickTrigger.OnMouseDownAsync();
Debug.Log("testBall被点击!");
}
// 实例化预制体小球,并启动异步移动与碰撞监听
private async UniTaskVoid TestUniTaskInstantiationRedBall()
{
// 在指定位置生成红色小球
var redBall = Instantiate(redBallPrefab, bornPoint.position, Quaternion.identity);
// 获取当小球被销毁时的取消标记
var token = redBall.GetCancellationTokenOnDestroy();
// 异步移动生成的小球
Move(redBall.transform, token).Forget();
// 使用异步流监听生成小球的碰撞事件,并在碰撞时输出碰撞物体的名称
redBall.GetAsyncCollisionEnterTrigger()
.ForEachAsync(
collision =>
{
Debug.Log("生成的红色小球碰撞到:" + collision.gameObject.name);
_isCollision = true;
},
cancellationToken: token
)
.Forget();
}
// 异步移动指定物体的Transform,沿X轴移动,持续5秒,碰撞了也不移动
async UniTaskVoid Move(Transform tf, CancellationToken token)
{
float totalTime = 5f;
float elapsedTime = 0f;
while (elapsedTime < totalTime && !_isCollision)
{
elapsedTime += Time.deltaTime;
tf.position -= new Vector3(speed, 0, 0) * Time.deltaTime;
await UniTask.NextFrame(token);
}
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com