From 78ceafb347a4c53526bd84ba48bd1e560d413e6a Mon Sep 17 00:00:00 2001
From: CuongNV <>
Date: Wed, 15 Apr 2026 18:38:31 +0700
Subject: [PATCH] add +
---
Assets/Scripts/PlayerVisual.cs | 69 ++++++++++++++++++++++++++++++++++
1 file changed, 69 insertions(+)
diff --git a/Assets/Scripts/PlayerVisual.cs b/Assets/Scripts/PlayerVisual.cs
index e6123b63a1..f0e21fdb11 100644
--- a/Assets/Scripts/PlayerVisual.cs
+++ b/Assets/Scripts/PlayerVisual.cs
@@ -24,6 +24,7 @@ namespace BrewMonster
[SerializeField] private bool isHit;
[SerializeField] private int id;
[SerializeField] private bool isDebug;
+ [SerializeField] private bool debugNamePlateBounds;
private bool _eventBusSubscribed;
private const float FadeTime = 100;
@@ -311,5 +312,73 @@ namespace BrewMonster
BMLogger.Log($"PlayerVisual: RefreshNamedAnimancer - Successfully refreshed namedAnimancer from model: {modelRoot?.name ?? "default"}");
}
}
+
+ ///
+ /// Resolve nameplate anchor from merged bounds of all SkinnedMeshRenderers.
+ /// 从所有SkinnedMeshRenderer合并后的包围盒解析名牌锚点。
+ ///
+ public bool TryGetNamePlateAnchorWorld(out Vector3 worldPos)
+ {
+ worldPos = default;
+
+ var skinnedMeshRenderers = GetComponentsInChildren(true);
+ if (skinnedMeshRenderers == null || skinnedMeshRenderers.Length == 0)
+ {
+ return false;
+ }
+
+ Bounds combinedBounds = default;
+ bool hasAnySkinnedMesh = false;
+ for (int i = 0; i < skinnedMeshRenderers.Length; i++)
+ {
+ var renderer = skinnedMeshRenderers[i];
+ if (renderer == null || renderer.sharedMesh == null)
+ {
+ continue;
+ }
+
+ var meshBounds = renderer.sharedMesh.bounds;
+ var scale = renderer.transform.lossyScale;
+ var worldCenter = renderer.transform.TransformPoint(meshBounds.center);
+ var worldSize = new Vector3(
+ Mathf.Abs(meshBounds.size.x * scale.x),
+ Mathf.Abs(meshBounds.size.y * scale.y),
+ Mathf.Abs(meshBounds.size.z * scale.z)
+ );
+ var currentBounds = new Bounds(worldCenter, worldSize);
+ if (debugNamePlateBounds)
+ {
+ Debug.Log($"[Cuong] [PlayerVisual] smr={renderer.name} localCenter={meshBounds.center} localSize={meshBounds.size} worldCenter={worldCenter} worldSize={worldSize} worldMaxY={currentBounds.max.y}");
+ }
+
+ if (!hasAnySkinnedMesh)
+ {
+ combinedBounds = currentBounds;
+ hasAnySkinnedMesh = true;
+ }
+ else
+ {
+ combinedBounds.Encapsulate(currentBounds);
+ }
+ }
+
+ if (!hasAnySkinnedMesh)
+ {
+ if (debugNamePlateBounds)
+ {
+ Debug.LogWarning("[Cuong] [PlayerVisual] TryGetNamePlateAnchorWorld: no valid SkinnedMeshRenderer/sharedMesh.");
+ }
+ return false;
+ }
+
+ // Use merged bounds center for X/Z and merged top for Y.
+ // 使用合并包围盒中心作为X/Z,使用合并包围盒顶部作为Y。
+ worldPos = new Vector3(combinedBounds.center.x, combinedBounds.max.y, combinedBounds.center.z);
+ if (debugNamePlateBounds)
+ {
+ Debug.Log($"[Cuong] [PlayerVisual] combinedCenter={combinedBounds.center} combinedSize={combinedBounds.size} anchorWorld={worldPos}");
+ }
+ return true;
+ }
}
}
\ No newline at end of file