Unity中,将角色外观分为动画外观和物理外观,在合适的时机切换

2023-10-11  本文已影响0人  全新的饭

用途

常规情况下使用动画外观,当角色死亡时,切换为物理外观。

实现思路

角色根节点下,有2个子节点:动画外观根节点、物理外观根节点。


角色层级说明

二者的子孙transform层级完全一致(包括名称)
动画外观根节点上挂有Animator组件。
物理外观的子孙节点中有Rigidbody(下文简称Rb)Collider、Joint等。

实现一个RoleAppearance类。
在初始化时,创建所有物理外观下Rb与动画外观下对应同名Transform的对应关系。

当切换至物理外观时:

  1. 隐藏动画外观
  2. 将动画外观中下各Transform的属性(位置、旋转、缩放)赋到对应的Rb的Transform上,将Rb的isKinematic设置为false。
  3. 将动画外观的Transform属性赋给物理外观的Transform。
  4. 显示物理外观

当切换至动画外观时:

  1. 隐藏物理外观
  2. 将各Rb的Transform的属性赋到动画外观下对应的Transform上,Rb的isKinematic设置为true。
  3. 将物理外观的Transform属性赋给动画外观的Transform。
  4. 显示动画外观

RoleAppearance.cs

using System.Transactions;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RoleAppearance : MonoBehaviour
{
    [SerializeField]
    private GameObject _animAppearance;
    [SerializeField]
    private GameObject _phyAppearance;

    // 物理外观下的Rb-动画外观下的同名Trans
    private Dictionary<Rigidbody, Transform> _rbTransDict;

    private void Start()
    {
        Init();
    }

    private void OnDestroy()
    {
        MyDestroy();
    }

    private void Init()
    {
        InitRbTransDict();
        ShowAnimAppearance();

        void InitRbTransDict()
        {
            _rbTransDict = new Dictionary<Rigidbody, Transform>();
            var rbs = _phyAppearance.GetComponentsInChildren<Rigidbody>();
            var animAppearanceChildren = _animAppearance.GetComponentsInChildren<Transform>();
            var animAppearanceChildrenDict = new Dictionary<string, Transform>();
            foreach (var c in animAppearanceChildren)
            {
                animAppearanceChildrenDict.Add(c.name, c);
            }

            foreach (var rb in rbs)
            {
                _rbTransDict.Add(rb, animAppearanceChildrenDict[rb.name]);
            }
        }
    }
    private void MyDestroy()
    {
        DestroyRbTransDict();

        void DestroyRbTransDict()
        {
            _rbTransDict.Clear();
            _rbTransDict = null;
        }
    }

    public void ShowAnimAppearance()
    {
        _phyAppearance.SetActive(false);
        SetRbTransInfo(false);
        _animAppearance.SetActive(true);
    }
    public void ShowPhyAppearance()
    {
        _animAppearance.SetActive(false);
        SetRbTransInfo(true);
        _phyAppearance.SetActive(true);
    }

    // 若是false,则将物理外观下的目标trans的信息赋予动画外观下的对应trans
    private void SetRbTransInfo(bool isAnimToPhy)
    {
        foreach (var rb in _rbTransDict.Keys)
        {
            if (isAnimToPhy)
            {
                CopyTransformInfo(_rbTransDict[rb], rb.transform);
                rb.isKinematic = false;
            }
            else
            {
                CopyTransformInfo(rb.transform, _rbTransDict[rb]);
                rb.isKinematic = true;
            }
        }

        if (isAnimToPhy)
        {
            CopyTransformInfo(_animAppearance.transform, _phyAppearance.transform);
        }
        else
        {
            CopyTransformInfo(_phyAppearance.transform, _animAppearance.transform);
        }
    }

    private void CopyTransformInfo(Transform from, Transform to)
    {
        to.position = from.position;
        to.rotation = from.rotation;
        to.localScale = from.localScale;
    }
}
上一篇 下一篇

猜你喜欢

热点阅读