JamesB 发表于 2022-5-27 10:18

Unity学习笔记(一):给角色换武器

勘误

本文关于骨骼(Skeleton)、关节(Joint)、骨头(Bone)这些术语的运用存在一定谬误,具体解释参见下一篇笔记。
基础知识

Unity 中,模型的骨骼(Bone)是以 Transform 的形式存在于场景中。



模型的网格(Mesh)则分为 Skeletal Mesh(已绑定骨骼)和 Static Mesh(未绑定骨骼)两种。
Skeletal Mesh 由两部分组成:固有的多边形数据 + 额外存有一份骨骼信息,导入 Unity 时会生成一个 Skinned Mesh Renderer 组件;



已绑定骨骼的 Mesh

而 Static Mesh 只有多边形数据,没有骨骼信息,对于这种模型网格,只能 translated, rotated and scaled,而无法通过骨骼 animate the vertices,所以只会生成一个 Mesh Filter + Mesh Renderer。



未绑定骨骼的 Mesh

骨骼动画的本质就是变换矩阵,应用骨骼动画就是对各个 Bone 的 Transform 坐标进行矩阵计算(显然,父骨骼上的矩阵变换会影响到子骨骼的位置坐标)。



T字姿势时的右手骨骼



模型应用跑步动作时的右手骨骼

但骨骼本身是不可见的,最后呈现出来的还是模型网格,骨骼是怎么影响到网格的呢?模型上的每个 Mesh 在建模时都有一个蒙皮(Skinning)信息,即这个 Mesh 上的顶点会受到哪些骨骼的影响以及对应的影响权重。在游戏的一帧渲染中, Mesh 上的各个顶点会根据这个 Skin Info 来计算得到变换后的顶点数据,或者说,顶点会依附于骨骼重新进行位置计算,从而完成整个渲染过程。

给空手的模型加上武器

我这里用的是 Unity Chan 模型,武器也是随便从 Asset Store 找的。
首先在导入模型时生成的 Avatar 中,找到模型的右手骨骼,


然后游戏运行时加载武器资源,实例化为场景中的 GameObject,将武器拉到右手骨骼下,调整它的 Transform 即可。
public Transform playerRightHandBone;
   
void Start ()
{
    Transform weaponTrans = Instantiate(Resources.Load<Transform>("Weapons/Sword10"));

    weaponTrans.parent = playerRightHandBone;
    weaponTrans.localPosition = new Vector3(-0.07f, 0.1f, 0.0f);
    weaponTrans.localRotation = Quaternion.Euler(168, 90, 0);
    weaponTrans.localScale = new Vector3(0.5f, 0.5f, 0.5f);
}
实现武器的切换

我想通过按手柄十字键的右键来切换武器,这里的内容可以分为几个点:

[*]将所有武器放到 Resources 目录下,然后在代码里通过 Resources.Load() 实现动态加载;
[*]监听手柄按键信息,按下指定键切换武器;
[*]切换武器的动画。
<hr/>    void SwitchWeapon()
    {
      Destroy(playerWeapon);

      weaponIndex++;
      if (weaponIndex > 10)
      {
            weaponIndex = 0;
      }
      GameObject weaponResource = Resources.Load<GameObject>("Weapons/Sword" + weaponIndex);
      if (weaponResource != null)
      {
            playerWeapon = Instantiate(weaponResource);

            playerWeapon.transform.parent = playerRightHandBone;
            playerWeapon.transform.localPosition = new Vector3(-0.07f, 0.1f, 0.0f);
            playerWeapon.transform.localRotation = Quaternion.Euler(168, 90, 0);
            playerWeapon.transform.localScale = new Vector3(0.5f, 0.5f, 0.5f);
      }
    }以上代码,先 destroy 角色当前所拿的武器,然后实例化所要切换的武器,并挂到模型身上。
<hr/>    private static bool isDPadRightPressed = false;    // D-Pad Right 键是否正被按住

    /// <summary>
    /// 手柄十字键区域右键是否按下
    /// </summary>
    /// <returns>按下那一刻返回true, 长按返回false</returns>
    public static bool GetDPadRightDown()
    {
      bool result = false;

      float right = Input.GetAxis("Weapon");
      if (right >= 0.5f)
      {
            if (!isDPadRightPressed)
            {
                result = true;
            }
            isDPadRightPressed = true;
      }
      else
      {
            isDPadRightPressed = false;
      }

      return result;
    }没想到这里踩了个坑ヽ(*`Д)ノ,本来想通过 Input.GetButtonDown() 来监听十字键右键的按下事件,没想到 D-Pad(十字键区域)的上下左右键只能作为 Axis 来接收输入,不能作为 Button 来进行监听(如果这里我理解错了还请评论告知 (_)),所以有这么一段用于判断玩家是否正长按着 D-Pad Right 键的代码。
<hr/>AnimationEvent animationEvent = new AnimationEvent();
animationEvent.functionName = "SwitchWeapon";
animationEvent.time = 0.273f;
switchWeaponClip.AddEvent(animationEvent);切换武器是有一个动画过程的,动画的前半部分收刀,后半部分拔刀,显然需要加一个动画事件,用于在动画中间的指定帧销毁旧武器,创建新武器。
然后就是根据输入播放动画了。
if (InputMgr.GetDPadRightDown())
{
    playerAnimator.SetTrigger("switchWeapon");
}
效果图



完整代码放在GitHub上的UntiyStudy项目了。

APSchmidt 发表于 2022-5-27 10:25

感谢题主,正好需要做着看看!

stonstad 发表于 2022-5-27 10:27

监听具体按键不妨尝试 GetKeyDown() 函数,形如:
Input.GetKeyDown(KeyCode.DownArrow);

c0d3n4m 发表于 2022-5-27 10:36

问一下答主,gif里的人物模型在哪里有下载┭┮﹏┭┮

franciscochonge 发表于 2022-5-27 10:40

这个是 Unity 官方出的看板娘 UnityChan,AssetStore 里免费提供的

七彩极 发表于 2022-5-27 10:48

明白了,谢谢(*°°)=3

NoiseFloor 发表于 2022-5-27 10:54

感谢题主为各位踩坑[赞]

DomDomm 发表于 2022-5-27 10:55

谢谢分享

kirin77 发表于 2022-5-27 11:03

我想幫這個角色增加一些動作, 用Blender 導入FBX後, 發現骨和皮沒有綁上, 用pose mode 移動骨時 沒有帶動皮膚, 為什麼會這樣 ?

mastertravels77 发表于 2022-5-27 11:06

解燃眉之急了算是,谢谢作者
页: [1] 2
查看完整版本: Unity学习笔记(一):给角色换武器