需求
实现怪物有一定范围的侦测能力,当目标进入侦测范围内后,自动追踪目标[使用unity navmash实现],当子弹进入时,销毁子弹,播放怪物死亡动画以及其他事件。
实现方案
实现怪物在主角靠近一定范围内时发动攻击的功能,主要涉及到游戏AI和碰撞检测方面的知识。下面我将介绍几种成熟的方案,这些方案可以根据你的具体需求和使用的游戏开发框架进行选择和调整:
1. 碰撞检测触发(Collision Detection)
- 基础原理:在游戏世界中为怪物设置一个不可见的碰撞体(如圆形、矩形或多边形区域),当主角的碰撞体进入这个区域时,触发攻击行为。
- 优点:简单直观,适用于大多数2D游戏。
- 缺点:对于复杂形状的碰撞检测可能需要更高的计算成本。
2. 距离检测(Distance Checking)
- 基础原理:通过计算怪物和主角之间的距离,当距离小于某个设定值时,触发攻击。
- 优点:实现简单,计算成本较低。
- 缺点:不考虑障碍物阻挡,可能导致怪物通过墙体攻击主角。
3. 视野检测(Field of View Checking)
- 基础原理:除了检测距离,还需要检测主角是否在怪物的视野内(例如通过射线检测或扇形区域检测)。
- 优点:更加真实,可以模拟怪物的视线被障碍物阻挡的情况。
- 缺点:实现复杂度和计算成本较高。
4. 导航网格和路径寻找(NavMesh and Pathfinding)
- 基础原理:利用导航网格确定游戏中可行走的区域,并使用路径寻找算法(如A*算法)计算怪物到主角的路径。如果路径存在且长度小于某个阈值,则触发攻击。
- 优点:可以实现复杂的追踪和规避行为,适用于需要复杂AI行为的游戏。
- 缺点:实现难度较高,对于简单游戏可能过于复杂。
5. 状态机(State Machine)
- 基础原理:结合上述方法,使用状态机管理怪物的行为状态(如巡逻、追踪、攻击等)。当主角满足攻击触发条件时,怪物状态转换为攻击状态。
- 优点:提高了AI行为的可控性和复杂性。
- 缺点:需要较为复杂的逻辑设计。
选择建议
- 对于简单的游戏,可以考虑使用碰撞检测触发或距离检测方案。
- 如果游戏场景中存在很多障碍物,视野检测或导航网格和路径寻找将是更好的选择。
- 为了实现更加复杂和智能的怪物行为,建议使用状态机结合上述某种或多种检测方法。
方案1和方案3优劣对比
比较碰撞检测触发(方案1)和视野检测(方案3)的优缺点可以帮助你根据游戏的具体需求和设计目标选择更合适的怪物行为触发机制。下面是两种方法的优缺点比较:
碰撞检测触发(Collision Detection)
优点:
- 简单易实现:基于碰撞检测的逻辑相对简单,大多数游戏引擎都提供了碰撞检测的内置支持,容易实现和集成。
- 计算效率高:相对于复杂的算法,碰撞检测通常只需要较少的计算资源,适合快速开发和运行在性能受限的平台上。
- 直观:对于玩家来说,这种触发机制很直观。当他们看到角色进入了怪物的"领域",自然能预期到接下来可能会发生什么。
缺点:
- 不考虑视线:碰撞检测不考虑怪物的视野和障碍物遮挡,可能导致不够真实的情况发生,例如怪物能够通过墙壁"看到"玩家并触发攻击。
- 形状限制:如果游戏中的角色或怪物具有复杂的形状,简单的碰撞体(如圆形或矩形)可能无法精确表示实际的物理空间,需要更复杂的碰撞体设计。
视野检测(Field of View Checking)
优点:
- 更加真实:视野检测能够模拟怪物的视线和视野范围,包括视野被障碍物阻挡的情况,这为游戏增添了更多的真实感和策略性。
- 灵活性:可以根据需要调整视野的角度和距离,为不同的怪物设计不同的感知能力,增加游戏的多样性和复杂性。
- 适合复杂环境:在复杂的游戏环境中(如多障碍物、复杂地形等),视野检测可以更准确地反映怪物的行为和玩家的潜行机会。
缺点:
- 实现复杂度高:相比于简单的碰撞检测,视野检测需要更复杂的数学计算和逻辑判断,可能涉及射线投射、扇形区域检测等技术,增加了开发的难度。
- 计算成本高:尤其是在场景中有大量动态对象和复杂地形时,视野检测可能需要较多的计算资源,对性能有一定影响。
结论
- 如果你的游戏需要简单、直观的敌人行为触发,并且对计算资源有限制,碰撞检测触发是一个好的选择。
- 如果游戏设计强调真实感、策略性和环境交互,尤其是在复杂的游戏环境中,视野检测提供了更多的灵活性和真实性,但需要权衡实现的复杂度和性能影响。
选择方案1实现
这里我们实现怪物检测范围为圆形,给怪物prefab挂载Circle Collider 2D,当目标进入或者在触发器内部时追逐目标,(注意把触发器 istrigger 勾选上)
给怪物同时挂上box collider 2D,当子弹和怪物主体发生碰撞时,使用回调OnCollisionEnter2D,实现子弹击中逻辑(注意不要勾选istrigger)
,
// 假设这是你的怪物脚本
public class Monster : MonoBehaviour
{
private CircleCollider2D detectCollider;
void Start()
{
// 初始化圆形碰撞器,并设置初试半径
detectCollider = gameObject.AddComponent<CircleCollider2D>();
detectCollider.radius = 1.0f; // 初始半径,可根据需求调整
detectCollider.isTrigger = true; // 设置为触发器,用于检测进入碰撞区域的对象而不是进行物理碰撞
}
// 动态调整检测范围半径的方法
public void SetDetectionRadius(float radius)
{
if(detectCollider != null)
{
detectCollider.radius = radius;
}
}
}
设置进入/待在/离开怪物的回调函数
using UnityEngine;
public class Monster : MonoBehaviour
{
// 当玩家角色进入触发器范围时调用
void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
Debug.Log("玩家进入怪物的检测范围");
// 在这里添加怪物开始攻击玩家的代码
}
}
// 当玩家角色在触发器范围内时调用
void OnTriggerStay2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
Debug.Log("玩家仍在怪物的检测范围内");
// 可以添加例如持续伤害等效果的代码
}
}
// 当玩家角色离开触发器范围时调用
void OnTriggerExit2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
Debug.Log("玩家离开怪物的检测范围");
// 在这里添加怪物停止攻击的代码
}
}
}