Unity中,将角色外观分为动画外观和物理外观,在合适的时机切换
2023-10-11 本文已影响0人
全新的饭
用途
常规情况下使用动画外观,当角色死亡时,切换为物理外观。
实现思路
角色根节点下,有2个子节点:动画外观根节点、物理外观根节点。

二者的子孙transform层级完全一致(包括名称)
动画外观根节点上挂有Animator组件。
物理外观的子孙节点中有Rigidbody(下文简称Rb)Collider、Joint等。
实现一个RoleAppearance类。
在初始化时,创建所有物理外观下Rb与动画外观下对应同名Transform的对应关系。
当切换至物理外观时:
- 隐藏动画外观
- 将动画外观中下各Transform的属性(位置、旋转、缩放)赋到对应的Rb的Transform上,将Rb的isKinematic设置为false。
- 将动画外观的Transform属性赋给物理外观的Transform。
- 显示物理外观
当切换至动画外观时:
- 隐藏物理外观
- 将各Rb的Transform的属性赋到动画外观下对应的Transform上,Rb的isKinematic设置为true。
- 将物理外观的Transform属性赋给动画外观的Transform。
- 显示动画外观
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;
}
}