Unity学习笔记(四)如何实现角色攻击、组合攻击

前言

本文为Udemy课程The Ultimate Guide to Creating an RPG Game in Unity学习笔记

实现动画

首先实现角色移动的动画,动画的实现过程在第二篇,这里仅展示效果

attack1

触发攻击动画

实现脚本

接下来我们通过 Animator 编辑动画之间的过渡,以及检测是否移动(isAttacking)

可以攻击的条件:

  • 在地面上
  • 攻击有间隔时间
  • 攻击时不能移动

实现攻击:

  • 通过鼠标点击触发攻击
  • 判断是非为攻击状态
  • 设置攻击动画,攻击动画结束时通过事件触发

脚本新增内容 player2 ,删除了除了本功能以外的代码

SQL 复制代码
public class Player2 : MonoBehaviour
{
    
    [Header("Attack info")]
    [SerializeField] private float comboTime = .3f;
    private bool isAttacking;
    private float comboTimeWindow;

    private float xInput;
    
    void Update()
    {
        ...
        comboTimeWindow -= Time.deltaTime;

        AnimatorContronllers();
        ...
    }

    private void CheckInput()
    {
        if (Input.GetKeyDown(KeyCode.Mouse0))
        {
            ShartAttackEvent();
        }
        ...
    }

    private void ShartAttackEvent()
    {
        if (!isGrounded)
            return;

        isAttacking = true;
        comboTimeWindow = comboTime;
    }

    public void AttackOver()
    {
        isAttacking = false;
    }
    
    private void Movement()
    {
        xInput = Input.GetAxisRaw("Horizontal");
        // 不能边打边走
        if (isAttacking)
        {
            rb.velocity = new Vector2(0, 0);
        }
        else if (dashTime > 0)
        {
            rb.velocity = new Vector2(facingDir * dashSpeed, 0);
        }
        else
        {
            rb.velocity = new Vector2(xInput * moveSpeed, rb.velocity.y);
        }
    }
    
    private void AnimatorContronllers()
    {
        ...
        anim.SetBool("isAttacking", isAttacking);
    }
}

动画结束事件脚本

SQL 复制代码
public class Player2AnimEvent : MonoBehaviour
{
    private Player2 player;

    void Start()
    {
        player = GetComponentInParent<Player2>();
    }

    private void AnimationTrigger()
    {
        player.AttackOver();
    }
}

动画添加事件

将事件脚本加到 Animator 这里


注意这里不能过度到自己

这里要有退出时间,使用attacking = false进行过度太突兀了。使用动画的退出时间比较平滑

最终效果

实现组合攻击

attack2

attack3

组合攻击条件

  • 处于攻击状态
  • 在一定时间内连续攻击
  • 组合攻击完之后我们可以循环进行组合攻击

实现条件

  • 我们需求当前是第几次攻击
  • 我们需要知道第二次攻击间隔时间

我们要设置 Animator 的参数

记得要在 attack 2 和 attack3 设置动画结束事件

代码变化

SQL 复制代码
public class Player2 : MonoBehaviour
{
    
    [Header("Attack info")]
    [SerializeField] private float comboTime = .3f;
    private bool isAttacking;
    private float comboTimeWindow;
    public int comboCounter;
    private float xInput;
    
    void Update()
    {
        ...
        comboTimeWindow -= Time.deltaTime;

        AnimatorContronllers();
        ...
    }

    private void CheckInput()
    {
        if (Input.GetKeyDown(KeyCode.Mouse0))
        {
            ShartAttackEvent();
        }
        ...
    }

    private void ShartAttackEvent()
    {
        if (!isGrounded)
            return;
        if (comboTimeWindow < 0)
            comboCounter = 0;
    
        isAttacking = true;
        comboTimeWindow = comboTime;
    }

    public void AttackOver()
    {
        comboCounter++;
        isAttacking = false;
        if (comboCounter > 2)
            comboCounter = 0;
    }
    
    private void AnimatorContronllers()
    {
        ...
        anim.SetBool("isAttacking", isAttacking);
        anim.SetInteger("comboCounter", comboCounter);
    }
}

最终效果

扩展

我们可以使用混合树来实现组合攻击吗?(混合树(Blend Tree)和子状态机(Sub-State Machine)的区别)

在Unity动画系统中,混合树(Blend Tree **)** 和 子状态机(Sub-State Machine) 是Animator Controller中两种不同的功能,它们用于组织和管理动画的播放,但它们的使用场景和目的不同。以下是两者的区别:

  1. 混合树(Blend Tree**)**

概念

  • 混合树是一种用于基于输入参数动态混合多个动画的结构。
  • 它的主要功能是通过一个或多个输入参数(如速度、角度等)来实时混合动画,从而实现平滑的动画过渡。

主要特点

  • 动态混合动画:允许根据输入参数的变化动态调整多个动画的权重,生成过渡自然的效果。
  • 主要用于运动动画:常用于需要连续平滑过渡的动画,如角色移动(行走、奔跑、慢跑)或视角调整。
  • 单个动画状态:混合树属于Animator中的单个状态,且其内部不支持条件判断或过渡关系。

使用场景

  1. 运动动画:例如,根据"速度"参数在站立、行走、跑步之间动态过渡。
  2. 方向调整:例如,结合"前后"和"左右"输入参数混合8个方向的动画(如8方向移动)。
  3. 平滑控制:任何需要基于输入参数动态调整动画权重的场景。

优点

  • 提供平滑的动画过渡。
  • 通过参数驱动,节省了状态之间过渡的复杂性。
  • 使用简单,易于可视化调整。
  1. 子状态机(Sub-State Machine)

概念

  • 子状态机是一种用于将动画状态组织成逻辑组的工具。
  • 它的主要功能是提高复杂状态机的可读性和可维护性,通过将多个动画状态归类到子状态机中。

主要特点

  • 逻辑分组:可以将多个相关的动画状态封装在一个子状态机中,便于管理。
  • 支持状态切换:子状态机内部的状态可以彼此过渡,且子状态机与外部状态之间也可以进行切换。
  • 条件驱动:通过参数和条件来控制动画状态的切换。

使用场景

  1. 复杂动画状态机:当Animator有太多的动画状态时,可以用子状态机来简化结构。例如,将"站立状态"、"战斗状态"、"跳跃状态"分别封装到子状态机中。
  2. 分层管理动画:将动画状态逻辑分层以提高可维护性和可扩展性。
  3. 模块化设计:当不同模块(如战斗、移动)有独立逻辑时,可以分别用子状态机实现。

优点

  • 简化复杂的状态机结构。
  • 增强可读性和逻辑清晰度。
  • 易于扩展,适合有大量状态的项目。
混合树 VS 子状态机

特性混合树(Blend Tree)子状态机(Sub-State Machine)功能动态混合多个动画,生成平滑的动画过渡逻辑分组多个动画状态,简化状态机管理主要用途用于基于输入参数动态调整动画(如移动速度、方向)用于管理和组织复杂的动画状态动画过渡内部动画通过参数动态混合,无需显式设置过渡状态之间通过过渡条件切换层次结构属于单个动画状态包含多个动画状态典型场景行走、跑步、转向等连续变化的动画各种独立的动画状态(如战斗、移动、跳跃等逻辑)灵活性专注于参数驱动的动态效果适合逻辑复杂的动画状态机

如何选择?
  • 选择混合树
    • 如果需要通过参数动态调整动画,例如在不同速度、角度下生成平滑过渡的运动动画。
    • 如果关注的是动画的平滑效果,而不是状态逻辑的复杂性。
  • 选择子状态机
    • 如果需要组织大量动画状态,或需要逻辑分组来简化复杂状态机的设计。
    • 如果动画状态之间的切换需要明确的条件和逻辑判断。

总结

  • 混合树专注于动画平滑过渡,解决的是"一个状态内的动画动态混合问题"。
  • 子状态机专注于状态管理和逻辑组织,解决的是"动画状态机结构复杂性的问题"。

根据具体需求决定使用哪种工具,或者在复杂项目中结合使用两者,可以达到最佳效果。

相关推荐
刘阿去1 小时前
tcc编译器教程6 进一步学习编译gmake源代码
c语言·学习
LuckyLay2 小时前
Golang学习笔记_49——解释器模式
笔记·学习·设计模式·golang·解释器模式
sauTCc2 小时前
DataWhale-三月学习任务-大语言模型初探(一、二、五章学习)
人工智能·学习·语言模型
RichardK.3 小时前
CCF-CSP第27次认证第1题 --《如此编码》
c++·学习
weixin_502539853 小时前
rust学习笔记13-18. 四数之和
笔记·学习·rust
宇希啊3 小时前
2025/03/06(嵌入式学习开始第二天)
嵌入式硬件·学习
种豆走天下3 小时前
Zookeeper学习
分布式·学习·zookeeper
~Yogi4 小时前
每日学习Java之一万个为什么
java·开发语言·学习
程序员正茂4 小时前
Unity安卓Android从StreamingAssets加载AssetBundle
android·unity·assetbundle·streamingassets
郭涤生6 小时前
在线程间共享数据_第三章_《C++并发编程》笔记
c++·笔记·算法