[unity learning] RPG Leaning(九)

[unity learning] RPG Leaning(九)

写这个文章的目的就是为了初学unity,然后更好的掌握unity中的内容【主要是代码】
学习unity的途径是Brackeys 的教程;
接上篇: unity learning RPG Leaning(八).

目的

一、把Sword和Shield的导入和调用
二、拾起Sword和Shield之后,手部动作变化
三、给人物添加攻击状态的转换
四、给人物攻击添加不同动画
在这里插入图片描述
在这里插入图片描述

一、把Sword和Shield的导入和调用

重新把player的模型导入「包含攻击的动作和Sword/Shield模型」。
由于这里的Shield是放在Armature中的,而且是一个Mesh Render的一个模型。
在这里插入图片描述
在这里插入图片描述
所以,在这里我们需要把这里Shield/Sword复制到Asset中,且隐藏Hierarchy这里的Shield/Sword(后面要用到)。Asset中的Shield和Sword需要变成Skinned Mesh Render并删除Mesh Render 和Mesh Filter。然后和之前的操作一置,把他放入到一个Item中。
在这里插入图片描述
最后修改 EquipmentManager :
加入

 public Transform Shield;
 public Transform Sword;

然后把刚刚隐藏的Shield/Sword放置到对应的位置
在这里插入图片描述
修改Equip()函数变为:

if (newItem != null && newItem.equipsolt == EquipmentSlot.Weapon)
    {
      newMesh.rootBone = Sword;
    }
    else if (newItem != null && newItem.equipsolt == EquipmentSlot.Shield)
    {
      newMesh.rootBone = Shield;
    }
    else
    {
      newMesh.transform.parent = targetMesh.transform;
      newMesh.bones = targetMesh.bones;
      newMesh.rootBone = targetMesh.rootBone;
    }

也就是把rootBone放置到对应的位置。

二、拾起Sword和Shield之后,手部动作变化

在Asset/Character 中添加两个Avatar Mask:left Mask和right Mask
在这里插入图片描述
只有右手/左手有对应的Mask,在之前创建的Player Controller的Animator/layer中加入两个layer
在这里插入图片描述
两个Layer添加刚刚的Avatar Mask
在这里插入图片描述
然后在对应的layer添加动画组建
在这里插入图片描述
创建一个PlayerAnimator类继承之前我们创建的PlayerAnimation
并修改PlayerAnimation类里面的一些函数和参数变成Protect「类内可以使用,类外不能使用,继承可以使用」和virtual,设置可重写;
在PlayerAnimator中一个武器变换的函数:

void OnEquipmentChanged(Equipment newItem, Equipment oldItem)   {
    if (newItem != null && newItem.equipsolt == EquipmentSlot.Weapon)
    {
      animator.SetLayerWeight(1, 1);
    }
    else if (newItem == null && oldItem != null && oldItem.equipsolt == EquipmentSlot.Weapon)
    {
      animator.SetLayerWeight(1, 0);
    }
    if (newItem != null && newItem.equipsolt == EquipmentSlot.Shield)
    {
      animator.SetLayerWeight(2, 1);
    }
    else if (newItem == null && oldItem != null && oldItem.equipsolt == EquipmentSlot.Shield)
    {
      animator.SetLayerWeight(2, 0);
    }   }

并把他加入到EquipmentManager的委托onEquipmentChanged中

EquipmentManager.instance.onEquipmentChanged += OnEquipmentChanged;

最后需要把控制Player动画PlayerAnimation变成PlayerAnimator;
即可实现人物手拿物体动画的感觉

在这里插入图片描述
在这里插入图片描述

三、给人物添加攻击状态的转换

就是人物如果在攻击状态的时候,会变成一个攻击状态的idle动作,也就是我们要传入一个bool的变量来判断人物是否在攻击状态;
在BaseLayer层添加动作Combat_idle:
在这里插入图片描述
在Parameter四中加入bool类型的InCombat变量
在这里插入图片描述
设置动作转换的条件
Locolmotion->Combat_idle : 这里添加了两个条件:
InCombat为true && speedPercent<0.1
注意设置这里的Has Exit Time
在这里插入图片描述
Combat_idle -> Locolmotion: 这里添加了两个条件:
InCombat为false || speedPercent>0.1
在这里插入图片描述
在这里插入图片描述
然后在CharacterCombat中添加

 public bool Incombat { get; private set; }
 const float combatCooldown = 5f;
 float lastAttackTime;
 

combatCooldown指的是当人物如果停止攻击时间超过5s的话,会把Incombat准换成false。

加入了Update()来实现这个效果

void Update()
  {
    attackCoolDown -= Time.deltaTime;
    if (Time.time - lastAttackTime > combatCooldown)
    {
      Incombat = false;
    }
  }

在人物攻击时把 Incombat =true;

public void Attack(CharacterStats targetStats)
  {
    if (attackCoolDown <= 0f)
    {
      //   targetStats.TakeDamage(myStats.damage.GetValue());
      StartCoroutine(DoDamage(targetStats, attackDelay));

      attackCoolDown = 1f / attackSpeed;
      Incombat = true;
      lastAttackTime = Time.time;
      if (OnAttack != null)
      {
        OnAttack();
      }
    }
    else
    {
      //   Debug.Log("CoolDown!");
    }
  }

被攻击物体死亡时 Incombat = false;

  IEnumerator DoDamage(CharacterStats stats, float delay)
  {
    yield return new WaitForSeconds(delay);
    stats.TakeDamage(myStats.damage.GetValue());
    if (stats.currentHealth <= 0)
    {
      Incombat = false;
    }
  }

在PlayerAnimation中传入这个Incombat;

protected CharacterCombat combat;
protected virtual void Start()
  {
    combat = GetComponent<CharacterCombat>();
  }
 protected virtual void Update()
  {
    animator.SetBool("InCombat", combat.Incombat);
  }

四、给人物攻击添加不同动画

添加Punch动画作为基础动画到组件中。
在这里插入图片描述
添加Trigger 类型的attack变量。
在这里插入图片描述
设置动作变化的触发条件是Trigger
在这里插入图片描述
退出动作设置:
在这里插入图片描述
这里我们默认的动作是Punch,但是当我们武器变换成Sword后,相应的动作也需要变换:
由于有的武器动作不止一种,所以在PlayerAnimation类中定义了AnimatorOverrideController。
Animator Override Controller是用来配合Animator Controller使用的,它让Animator Controller变得更加实用,可以让不同的使用实例的在同一状态播放不同的动作,但保留原有的结构、参数和逻辑。
unity Animator Override Controller的使用
AnimationClip是什么
简单来说AnimationClip就是一个动作动画。

  public AnimationClip replaceableAttackAnim;
  public AnimationClip[] defaultAttackAnimSet;
  protected AnimationClip[] currentAttackAnimSet;
  protected AnimatorOverrideController overrideController;
  protected virtual void Start()
  { 
    overrideController = new AnimatorOverrideController(animator.runtimeAnimatorController);
    animator.runtimeAnimatorController = overrideController;
    
    currentAttackAnimSet = defaultAttackAnimSet;
  }
  protected virtual void OnAttack()
  {
    animator.SetTrigger("attack");
    //随机播放currentAttackAnimSet组中的不同动画
    int attackIndex = Random.Range(0, currentAttackAnimSet.Length);
    overrideController[replaceableAttackAnim.name] = currentAttackAnimSet[attackIndex];
  }

Start中设置currentAttackAnimSet变为defaultAttackAnimSet;
**

  • 「这里有疑问?是不是replaceableAttackAnim设定了,就能找到对应的这个模块?之后需要好好了解AnimatorOverrideController」

**

然后在PlayerAnimator中定义一个字典来存储不同的武器对应不同的动画:
定义了WeaponAnimations结构,用来外部存储武器和动画

  [System.Serializable]
  public struct WeaponAnimations
  {
    public Equipment weapon;
    public AnimationClip[] clips;
  }
  public WeaponAnimations[] weaponAnimations;
  Dictionary<Equipment, AnimationClip[]> weaponAnimDict;
  
protected override void Start()
  {
    base.Start();
    weaponAnimDict = new Dictionary<Equipment, AnimationClip[]>();
    //外部的输入 存入字典
    foreach (WeaponAnimations a in weaponAnimations)
    {
      weaponAnimDict.Add(a.weapon, a.clips);
    }
  }
  //改写OnEquipmentChanged,改变currentAttackAnimSet
    void OnEquipmentChanged(Equipment newItem, Equipment oldItem)
  {
    if (newItem != null && newItem.equipsolt == EquipmentSlot.Weapon)
    {
      animator.SetLayerWeight(1, 1);
      if (weaponAnimDict.ContainsKey(newItem))
      {
        currentAttackAnimSet = weaponAnimDict[newItem];
      }
    }
    else if (newItem == null && oldItem != null && oldItem.equipsolt == EquipmentSlot.Weapon)
    {
      animator.SetLayerWeight(1, 0);
      currentAttackAnimSet = defaultAttackAnimSet;
    }
    ...
  }

最后需要把 combat.OnAttack += OnAttack;加入到PlayerAnimation中,也就是,当触发combat中攻击时候:需要同时调用PlayerAnimation中的OnAttack函数:

public event System.Action OnAttack;//「CharacterCombat中声明的委托」
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值