首页 > 其他分享 >Unity引擎2D游戏开发,敌人追击状态的转换

Unity引擎2D游戏开发,敌人追击状态的转换

时间:2023-12-28 15:35:18浏览次数:36  
标签:Enemy void 追击 2D Unity currentEnemy override public

思路:

从敌人的位置发射一道射线或者一片区域来对玩家实体进行检测,如果检测倒玩家,则进行追击进攻

利用BoxCast()即可实现

BoxCast()官方文档:https://docs.unity3d.com/cn/2022.3/ScriptReference/Physics2D.BoxCast.html

创建检测区域

由于BoxCast需要众多参数,所以在Enemy中创建相关的全局变量

[Header("检测")]
// 因为中心点在脚底,所以加一个偏移量
public Vector2 centerOffset;
// 检测大小
public Vector2 checkSize;
// 检测距离
public float checkDistance;
// 图层
public LayerMask attackLayer;

创建FoundPlayer()方法,在内部调用BaxCast()方法

public bool FoundPlayer()
{
    return Physics2D.BoxCast(transform.position + (Vector3)centerOffset, checkSize, 0, faceDirect, checkDistance, attackLayer);
}

创建OnDrawGizmosSelected()方法,用于在Unity图形界面中能够绘制出检测距离(checkDistance)的位置

private void OnDrawGizmosSelected()
{
    Gizmos.DrawWireSphere(transform.position + (Vector3)centerOffset + new Vector3(checkDistance * -transform.localScale.x, 0), 0.2f);
}

切换敌人状态

由于需要给Enemy赋予一个状态,同时也需要知道该状态的变量,再赋值给currentState。因此,在Enemy类中,编写一个切换的方法。不过,在此之前,需要创建一个枚举类(Enum),来表明当前的状态。

在Scripts下创建Utils文件夹,在文件夹内创建StateEnum C#文件
image

在内部创建三种状态

public enum NPCState
{
    Patrol, Chase, Skill
}

在Enemy中创建SwitchState()方法,形参写为刚才创建的NPCState

public void SwitchState(NPCState state)
{
}

此方法内部实现,通过传入的NPCState,转换为已经创建的三种状态变量

var newState = state switch
{
    NPCState.Patrol => patrolState,
    NPCState.Chase => chaseState,
    _ => null
};

currentState.OnExit();
currentState = newState;
currentState.OnEnter(this);

_ => null 相当于switch语句中的default。在切换状态时,需要调用OnExit()方法,关闭当前状态,再赋值新状态并调用OnEnter()

在BoarPatrolState类中,LogicUpdate()继续编写切换追击状态的代码。加一个判断,判断如果发现了玩家,则切换状态

if (currentEnemy.FoundPlayer())
{
    currentEnemy.SwitchState(NPCState.Chase);
}

编写追击代码

在Enemy文件夹下,创建BoarChaseState C#脚本,用于编写追击逻辑
image

继承BaseState,并在OnEnter()中将currentEnemy进行赋值

public class BoarChaseState : BaseState
{
    public override void OnEnter(Enemy enemy)
    {
        currentEnemy = enemy;
        Debug.Log("chase");
    }
    public override void LogicUpdate()
    {
    }

    public override void PhysicsUpdate()
    {
    }

    public override void OnExit()
    {
    }
}

与此同时,在Boar类中,添加一行代码用于初始化BoarChaseState对象

protected override void Awake()
{
    base.Awake();
    patrolState = new BoarPatrolState();
    chaseState = new BoarChaseState();
}

回到BoarChaseState类,在OnEnter()中,修改当前的速度为追击速度,并开启追击动画

public override void OnEnter(Enemy enemy)
{
    currentEnemy = enemy;
    currentEnemy.currentSpeed = currentEnemy.chaseSpeed;
    currentEnemy.animator.SetBool("run", true);
}

在LogicUpdate()方法中,使野猪追击撞墙时不进行等待立即转身

public override void LogicUpdate()
{
    // 追击时,撞墙不等待并进行转身
    if (!currentEnemy.physicsCheck.isGround || (currentEnemy.physicsCheck.touchLeftWall && currentEnemy.faceDirect.x < 0) || (currentEnemy.physicsCheck.touchRightWall && currentEnemy.faceDirect.x > 0))
    {
        currentEnemy.transform.localScale = new Vector3(currentEnemy.faceDirect.x, 1, 1);
    }
}

丢失目标后切换状态

丢失目标后,进行倒计时,在一定时间内没有发现玩家则切换回巡逻状态

在Enemy中,创建两个全局变量

// 丢失目标的时间
public float lostTime;
// 丢失目标的计时器
public float lostTimeCounter;

在TimeCounter()方法内,进行一个是否发现玩家的判断,如果没有发现则扣除倒计时

if(!FoundPlayer() && lostTimeCounter > 0)
{
    lostTimeCounter -= Time.deltaTime;
} else if (FoundPlayer())
{
    lostTimeCounter = lostTime;
}

接下来在BoarChaseState类LogicUpdate()中,加一个判断。如果丢失目标的时间计时结束,则切换回巡逻状态

public override void LogicUpdate()
{
    // 丢失目标计时结束切换回巡逻状态
    if(currentEnemy.lostTimeCounter <= 0)
    {
        currentEnemy.SwitchState(NPCState.Patrol);
    }
    // 追击时,撞墙不等待并进行转身
    if (!currentEnemy.physicsCheck.isGround || (currentEnemy.physicsCheck.touchLeftWall && currentEnemy.faceDirect.x < 0) || (currentEnemy.physicsCheck.touchRightWall && currentEnemy.faceDirect.x > 0))
    {
        currentEnemy.transform.localScale = new Vector3(currentEnemy.faceDirect.x, 1, 1);
    }
}

解决正面追击玩家时,玩家攻击不造成击退位移的问题

由于野猪追击玩家时的冲力抵消了玩家的击退位移的力,所以才会导致当前的问题

在Enemy类OnTakeDamage()方法中,添加一行代码

// 受伤时,无论x轴方向当前敌人的力有多少,都会造成击退
rb.velocity = new Vector2(0, rb.velocity.y);

标签:Enemy,void,追击,2D,Unity,currentEnemy,override,public
From: https://www.cnblogs.com/xinlindeyu/p/17932810.html

相关文章

  • Unity3D 如何提升游戏运行效率详解
    前言Unity3D是一款非常强大的游戏引擎,但是在处理复杂场景和大量资源时,游戏运行效率可能会遇到一些问题。本文将详细介绍如何提升Unity3D游戏的运行效率,包括技术详解和代码实现。对惹,这里有一个游戏开发交流小组,希望大家可以点击进来一起交流一下开发经验呀使用合适的资源压缩......
  • Unity3D Shader在GPU上是如何执行的详解
    Unity3D是一款广泛应用于游戏开发的跨平台开发引擎,它提供了丰富的功能和工具来帮助开发者创建高质量的游戏。其中一个重要的功能就是Shader,它可以用来控制对象的渲染效果。在Unity3D中,Shader是在GPU上执行的,那么它是如何工作的呢?本文将详细解释Unity3DShader在GPU上的执行过程,并......
  • Unity3D Shader Compute Shader基于GPU的并发计算详解
    在游戏开发中,计算密集型的任务通常需要耗费大量的CPU资源,这可能导致游戏性能下降,影响玩家的游戏体验。为了解决这个问题,Unity3D引入了ShaderComputeShader技术,它使用GPU进行并发计算,将一些计算密集型任务从CPU转移到GPU上执行,以提高游戏的性能和效率。本文将详细介绍Unity3DSha......
  • Unity3D 基类脚本怎么分别获取多个子类脚本的组件详解
    Unity3D是一款非常流行的游戏开发引擎,它提供了丰富的功能和工具,使得开发者可以轻松地创建高质量的游戏。在Unity3D中,脚本是游戏对象的一部分,它们通过附加到游戏对象上的组件来实现特定的功能。本文将详细介绍在Unity3D中如何分别获取多个子类脚本的组件,并提供相应的代码实现。对......
  • unity 标准资源包(过时)
    unity标准资源包Unity标准资源包(StandardAssets)是由Unity官方提供的一组可复用的资源集合,包含许多常用的游戏开发资源,如场景、材质、脚本、粒子效果、声音等。使用StandardAssets可以加速游戏开发的过程,因为它们已经预先制作好了,并且经过了官方的测试和优化,开发者可以......
  • A2DP_AVDTP
    a2dp的架构常见的音频编解码:SBC、AAC、APTX等,负责对PCMrawdata进行编解码(编码就会有压缩率,即将rawdata减少)。经过编码后的rawdata会被传送到AVDTP层,加上这层的协议数据再传送到L2CAP层,最后会传到对端的A2DPsink,然后进过解码将rawdata丢到speaker中。 A2DP定义了两个......
  • Unity知识总结系列(二):相机跟随人物的几种方式
    相机跟随人物的几种方式1、最简单,无代码,固定距离,固定视角2、代码控制,固定距离,固定视角,对1进行改进3、代码控制,固定距离,固定视角,直接移动,不会旋转4、代码控制,固定距离,固定视角,插值移动(因为Update和LateUpdate刷新率不同,会有抖动现象,不建议使用)5、代码控制,固定距离,固定视角,平滑......
  • Unity URP 风格化水
    前言笔者曾使用UE实现过一个较为完整的写实水材质系统,但是因为UE的管线是定死的,导致高光无法实现,且后来做笔试题发现关于水的交互还未实现,因此本文将实现一个完整的风格化水,考虑到水的实现部分过多,这里不再使用代码展示,而是使用ASE,原理都差不多管线设置“ShaderType”为“U......
  • unity 射线只检测某个层级
    Hithit;//参数1:射线发射的位置-参数2:射线发射的方向-参数3:射线-参数4:发射的距离-参数5:要检测的层-参数6:重写全局 Physics.queriesHitTriggers 以指定默认情况下查询(射线投射、球形投射、重叠测试等)是否命中触发器。对查询使用Ignore可忽略触发碰撞体。if(Physic......
  • Unity引擎2D游戏开发,有限状态机&抽象类多态
    状态机与抽象类观察如下代码:publicclassAttackFinish:StateMachineBehaviour{//OnStateEnteriscalledwhenatransitionstartsandthestatemachinestartstoevaluatethisstateoverridepublicvoidOnStateEnter(Animatoranimator,AnimatorStateIn......