第三人称——战斗系统
为Animator加入Combat anim
- 在Base Layer 下面新建一个Override Layer,权重设置为1
- 在Layer层新建一个Empty,Combat动画指向Empty

Player和Enemy的脚本结构

MeleeFighter将是玩家和敌人共用的近战战斗机制脚本
MeleeFighter
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class MeleeFighter : MonoBehaviour
{
    Animator animator;
    AnimationClip attackClip;
    private void Awake()
    {
        animator = GetComponent<Animator>();
        // 获取 AnimatorController 中名为 "Attack001" 的动画片段
        var clips = animator.runtimeAnimatorController.animationClips;
        attackClip = clips.FirstOrDefault(c => c.name == "Attack001");
    }
    bool inAction = false;
    public void TryToAttack(){
        if(!inAction)
        {
            StartCoroutine(Attack());
        }
    }
    /// <summary>
    /// Attack animation
    /// </summary>
    /// <returns></returns>
    IEnumerator Attack()
    {
        inAction = true;
        animator.CrossFade("Attack001", 0.2f);
        yield return null;
        float attackAnimTime = attackClip.length;
        yield return new WaitForSeconds(attackAnimTime);
        inAction = false;
    }
}
CombatController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CombatController : MonoBehaviour
{   
    MeleeFighter meleeFighter;
    private void Awake()
    {
        meleeFighter = GetComponent<MeleeFighter>();
    }
    private void Update()
    {
        if (Input.GetButtonDown("Attack"))
        {
            meleeFighter.TryToAttack();
        }
    }
}
把fire1重命名为Attack


为了后面调用inAction
这里的inAction改成属性
MeleeFighter
public bool InAction { get; private set; } = false;
修复和其他控制脚本的冲突bug
PlayerController
        //如果在动作中,不执行后面的运动逻辑并且不播放走路动画
        if (IsHanging || InAction || meleeFighter.InAtkAction)
        {
            animator.SetFloat("moveAmount", 0);
            return;
        }
CombatController
    private void Update()
    {
        if (playerController.IsHanging || !playerController.IsGrounded)
            return;
        if (Input.GetButtonDown("Attack"))
        {
            meleeFighter.TryToAttack();
        }
    }
给奎爷搞把斧子
如果遇到材质显示错误的预制体的解决方法:

斧头:

放在奎爷的RightHand的子级

新建box碰撞体,勾上Trigger


加入Enemy
玩家和敌人都unpack预制体,使其独立

加入以下组件

新建Layer

为玩家和敌人选上各自的Layer,但是其子对象不需要也选上

对武器选上对应的Layer

在 Project Settings - Physics 中设置碰撞矩阵

下面在MeleeFighter脚本中为角色编写武器部分
武器
连招系统
使用new Input
选择both

按键表配置

现在在PlayerInput可以看到SendMessage函数

下面调用这个函数就能做到按键响应
1.改造一下翻滚代码
ThirdPersonRoll
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class ThirdPersonRoll : MonoBehaviour
{
    Animator animator;
    void Awake()
    {
        animator = GetComponent<Animator>();
    }
    public void OnRoll(InputValue value)
    {
        if(value.isPressed)
            animator.SetTrigger("roll");
    }
}
功能正常
2.删去之前的攻击脚本播放攻击动画脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class ThirdPersonAttack : MonoBehaviour
{
    [Header("轻击动画列表")]
    [SerializeField] private AnimationClip[] Attack1Clips;
    [Header("重击动画列表")]
    [SerializeField] private AnimationClip[] Attack2Clips;
    PlayerController playerController;
    Animator animator;
    void Awake()
    {
        playerController = GetComponent<PlayerController>();
        animator = GetComponent<Animator>();
    }
    //攻击类输入存储值,会被新的输入值覆盖
    int inputAttackType = 0;
  
    //轻击
    void OnFire1(InputValue value)
    {
        if (value.isPressed)
        {
            inputAttackType = 1;
        }
    }
    //重击
    void OnFire2(InputValue value)
    {
        if (value.isPressed)
        {
            inputAttackType = 2;
        }
    }
    //连招数
    public int currentAttack = 0;
    //当前攻击的动画时长计时器
    float animTimer = 0;
    /// <summary>
    /// 攻击动画加载逻辑
    /// </summary>
    /// <param name="index"></param>
    /// <param name="inputAttackType"></param>
    void PlayerAttack(int index,int inputAttackType)
    {
        //攻击时取消输入
        playerController.inputEnabled = false;
        AnimationClip animationclip;
        if (inputAttackType == 1)
        {
            //轻击
            //动画载入
            animationclip = Attack1Clips[index];
            //连招数加1
            currentAttack++;
        }
        else
        {
            //重击
            //动画载入
            animationclip = Attack2Clips[index];
            //连招数归零
            currentAttack = 0;
        }
        animator.CrossFade(animationclip.name, 0.2f);
        animTimer = animationclip.length;
    }
    void Update()
    {
        if (playerController.IsHanging || !playerController.IsGrounded)
            return;
        //动画时长计时器帧自减
        animTimer -= Time.deltaTime;
        if(animTimer <= 0)
        {
            //动画播放完毕
            //恢复输入
            playerController.inputEnabled = true;
            //连招数归零
            currentAttack = 0;
        }
        //预输入逻辑
        if(inputAttackType != 0)
        {
            //如果有攻击键输入
            //在当前攻击动画播放结束前0.4s,(并且当前的连招数<攻击动画列表的长度)
            //播放对应索引的攻击动画
            if(animTimer <= 0.4f && currentAttack < Attack1Clips.Length)
            {
                PlayerAttack(currentAttack, inputAttackType);
            }
            //攻击类输入存储值归零
            inputAttackType = 0;
        }
    }
    //外部调用的属性
    public int InputAttackType => inputAttackType;
}
拖入脚本,分配轻重击动画



 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号