本文分享Unity中的AI算法和实现1-Waypoint
在Unity中, 我们有一些有趣且常见的AI算法可以研究和使用, 其中最常见的就是怪物的简单AI, 比如在RPG游戏里, 怪物在某些点定点巡逻, 当玩家进入检测区域时, 怪物会主动追击玩家, 追击到玩家后对玩家进行伤害, 或者在超过最大距离后脱离追击状态, 由恢复到巡逻状态.
我们接下来几篇文章会简单的实现一个基于有限状态机的怪物AI, 这篇文章是最基础的部分, 介绍Waypoint.
Waypoint顾名思义, 是用来描述点的一个抽象概念, 简单点说就是一个一个位置, 我们的怪物向这些预先设定的位置定点巡逻.
这个算法本身非常简单:
- 我们有一个Waypoint列表, 有一个怪物.
- 怪物根据顺序(可以另外定义顺序算法), 向目标点转向, 位移, 到达目标点后, 继续向下一个目标点转向和位移(也可以在这个点等待一会, 观望一番后才向下一个点前进).
- 到达最后一个目标点(数组最后一个元素), 切换到第一个目标点, 继续前进.
下面开始我们的示例.
创建场景
新建工程后, 往场景中拖一个Plane, 充当地面, 再拖一个Capsule充当怪物, 并给怪物创建一个眼睛, 用来表示方向, 最后调整一下整个场景的颜色(可选).
然后创建一个空的GameObject充当Waypoint容器, 然后创建空的子GameObject充当Waypoint, 我们可以给Waypoint节点增加Icon方便观察:
然后多创建几个Waypoint节点并摆好位置:
对应的Hierarchy如下:
最后创建控制脚本: MonsterContoller_Wp.cs并挂载到Monster身上.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Debug = UnityEngine.Debug;
public class MonsterContoller_Wp : MonoBehaviour
{
[SerializeField] private Transform[] m_Waypoints;
[SerializeField] private float m_MoveSpeed = 10f;
[SerializeField] private float m_RotateSpeed = 10f;
[SerializeField] private float m_MinTargetDistance = 0.5f;
/// <summary>
/// 当前wp索引
/// </summary>
private int m_CurrentWpIndex = 0;
/// <summary>
/// 缓存Transform, 避免每帧使用属性获取
/// </summary>
private Transform m_SelfTrans;
private void Start()
{
m_SelfTrans = transform;
Application.targetFrameRate = 60;
}
private void Update()
{
var target = m_Waypoints[m_CurrentWpIndex];
if (Vector3.Distance(target.position, m_SelfTrans.position) < m_MinTargetDistance)
{ // 已经靠近, 切换到下一个点
m_CurrentWpIndex++;
m_CurrentWpIndex %= m_Waypoints.Length; // 越界后从头开始
target = m_Waypoints[m_CurrentWpIndex];
}
var targetDir = (target.position - m_SelfTrans.position).normalized;
// 移动和转向
m_SelfTrans.Translate(targetDir * Time.deltaTime * m_MoveSpeed, Space.World); // 匀速向forward移动Time.deltaTime * m_MoveSpeed长度的距离
m_SelfTrans.rotation = Quaternion.Lerp(m_SelfTrans.rotation, Quaternion.LookRotation(targetDir), Time.deltaTime * m_RotateSpeed);
}
}
代码很简单, 也有对应的注释, 这里不再赘述, 下面是效果:
好了, 今天的内容就是这些, 希望对大家有所帮助.