Unity更换父物体后如何保持子物体NAVI的真实缩放值?
初始状态下,NAVI作为位置为(0,0,0)的父物体的子物体,其x、y、z轴缩放值为0.15。
(图片说明:展示初始状态下父物体与NAVI的层级关系)
挂载在子物体NAVI上的如下脚本,在保存游戏时会将NAVI的缩放值保存为初始的0.15:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class NaviState : MonoBehaviour, IStateQuery { public Transform parentTransform; private State m_state = new State(); private bool once = true; public System.Guid UniqueId => System.Guid.Parse("8FBA0A57-81C8-4806-9182-1D0013546288"); private class State { public bool isInteractable; public bool isChild; } public string GetState() { return JsonUtility.ToJson(m_state); } public void SetState(string jsonString) { m_state = JsonUtility.FromJson<State>(jsonString); if(m_state.isInteractable) { GetComponent<InteractableItem>().enabledInteraction = true; } else { GetComponent<InteractableItem>().enabledInteraction = false; } if(m_state.isChild) { transform.GetComponent<InteractableItem>().distance = 0; transform.parent = GameObject.Find("rig_f_middle.03.R").transform; transform.localPosition = new Vector3(0, 0, 0); transform.localRotation = Quaternion.identity; transform.localScale = new Vector3(0.15f, 0.15f, 0.15f); transform.GetComponent<Collider>().enabled = false; } } private void Update() { if (GetComponent<InteractableItem>() != null) { m_state.isInteractable = GetComponent<InteractableItem>().enabledInteraction; } if(transform.IsChildOf(parentTransform) && once) { m_state.isChild = true; once = false; } } }
加载游戏后,NAVI成为玩家手部骨骼的子物体,此时尽管NAVI的localScale仍设为0.15,却显示得异常巨大:
(图片说明:展示加载后NAVI显示过大的效果)
该父物体的位置为(0,0,0),x、y、z轴缩放值为100:
(图片说明:展示玩家手部骨骼父物体的缩放参数为100,100,100)
推测是父物体的100倍缩放导致NAVI显示过大。现咨询:如何在不修改该父物体缩放的前提下,让NAVI保持真实的0.15缩放值?
有两种可行的方法可以解决这个问题:
直接计算局部缩放抵消父物体影响
Unity中子物体的世界缩放是父物体缩放与自身局部缩放的乘积。要让NAVI的世界缩放保持0.15,需要将自身局部缩放设置为目标值除以父物体的缩放。修改SetState方法中设置缩放的代码:if(m_state.isChild) { transform.GetComponent<InteractableItem>().distance = 0; var parentTransform = GameObject.Find("rig_f_middle.03.R").transform; transform.parent = parentTransform; transform.localPosition = new Vector3(0, 0, 0); transform.localRotation = Quaternion.identity; // 计算抵消父物体缩放后的局部缩放 Vector3 targetLocalScale = new Vector3(0.15f / parentTransform.localScale.x, 0.15f / parentTransform.localScale.y, 0.15f / parentTransform.localScale.z); transform.localScale = targetLocalScale; transform.GetComponent<Collider>().enabled = false; }如果父物体缩放固定为100倍,也可以直接写死数值:
transform.localScale = new Vector3(0.0015f, 0.0015f, 0.0015f);添加中间空物体层级
创建一个空物体作为玩家手部骨骼的子物体,将空物体的局部缩放设置为Vector3.one / 100(抵消父物体的100倍缩放),然后把NAVI设为这个空物体的子物体,保持NAVI的局部缩放为0.15即可。这种方式更灵活,后续父物体缩放变化时只需调整中间空物体的缩放。
内容的提问来源于stack exchange,提问作者Daniel Lip

