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

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

总结

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

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

相关推荐
1101 110122 分钟前
STM32-笔记33-Wi-Fi遥控风扇项目
笔记
C语言扫地僧35 分钟前
Linux 多线程(理论+实践)
linux·运维·服务器·学习
半导体守望者1 小时前
AE Pinnacle 10x6 kW DeviceNet MDXL User r Manual
经验分享·笔记·功能测试·自动化·制造
egoist20231 小时前
数据结构之单链表(超详解)
c语言·开发语言·数据结构·笔记·学习·链表·gitee
不定时总结的那啥1 小时前
Unity2022接入Google广告与支付SDK、导出工程到Android Studio使用JDK17进行打包完整流程与过程中的相关错误及处理经验总结
android·unity
安冬的码畜日常2 小时前
【Vim Masterclass 笔记01】Section 1:Course Overview + Section 2:Vim Quickstart
笔记·vim
向宇it3 小时前
【从零开始入门unity游戏开发之——unity篇05】unity6基础入门——运行游戏按钮、Game游戏窗口和Project项目窗口介绍
开发语言·游戏·unity·c#·游戏引擎
虾球xz3 小时前
游戏引擎学习第72天
学习·游戏引擎
Spcarrydoinb3 小时前
python学习笔记—12—布尔类型、if语句
笔记·python·学习
go_bai3 小时前
OJ随机链表的复制题目分析
数据结构·经验分享·笔记·链表·学习方法