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

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

总结

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

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

相关推荐
陈天伟教授4 小时前
【30天学会机械制图 第15 天】项目四 学会看零件图 任务1 学习零件的基本表达方法 (1)
学习·工程制图·机械制图
从零开始的嵌入式之旅4 小时前
day31
linux·c语言·经验分享·笔记·嵌入式硬件
小张帅三代4 小时前
yolo基础学习笔记
笔记·学习·yolo
zttbee4 小时前
vue学习(白话功能版)
前端·vue.js·学习·前端框架
北风toto4 小时前
UML(统一建模语言)详细笔记
笔记·uml·软件设计师
ouynagda4 小时前
Linux 进程与线程学习笔记
linux·笔记·学习
手握风云-5 小时前
一条消息的旅程:RabbitMQ 学习与实践(四)
学习
GlueNa2SiO313 小时前
03-Flask模板引擎Jinja2详解
笔记·python·flask
Capricorn198814 小时前
解决全网抄 Karpathy 导致的 LLM Wiki 污染?基于知芽 Notebook Skill 的 raw/ 笔记法排障指南
大数据·论文阅读·人工智能·笔记·论文笔记