122 lines
4.5 KiB
C#
122 lines
4.5 KiB
C#
using UnityEngine;
|
|
using OctoberStudio.VAT;
|
|
|
|
namespace OctoberStudio
|
|
{
|
|
/// <summary>
|
|
/// 把 VAT prefab 挂到原 EnemyBehavior 上,作为视觉替换层。
|
|
/// - 隐藏原 SpriteRenderer / Animator(留 Shadow)
|
|
/// - Spawn VAT view 作为子物体
|
|
/// - 朝向: 把 EnemyBehavior.ExternalFacingOverride 设 true,EnemyBehavior 不再写 transform.localScale.x,
|
|
/// sign 通过 OnFacingSignChanged event 推给本组件 → 调 VATAnimationController.SetFacing。
|
|
/// 一律走 Y 旋转,完全不依赖 localScale。
|
|
/// </summary>
|
|
[DisallowMultipleComponent]
|
|
public class EnemyVATAttachment : MonoBehaviour
|
|
{
|
|
[Header("VAT Source")]
|
|
[Tooltip("烤好的 VAT prefab (e.g. mon1001_VAT.prefab)")]
|
|
[SerializeField] private GameObject vatPrefab;
|
|
|
|
[Header("View Transform")]
|
|
[SerializeField] private Vector3 localOffset = new Vector3(0f, 0.3f, 0f);
|
|
[SerializeField] private Vector3 localScale = new Vector3(0.5f, 0.5f, 0.5f);
|
|
|
|
[Header("Hide Originals")]
|
|
[Tooltip("不禁用名字含此关键字的 SpriteRenderer (默认 Shadow 阴影保留)")]
|
|
[SerializeField] private string keepNameContains = "Shadow";
|
|
|
|
private GameObject _spawnedView;
|
|
private VATAnimationController _vatCtrl;
|
|
private EnemyBehavior _enemy;
|
|
|
|
private void Awake()
|
|
{
|
|
_enemy = GetComponent<EnemyBehavior>();
|
|
HideOriginalSprites();
|
|
SpawnVATView();
|
|
if (_spawnedView != null)
|
|
{
|
|
_vatCtrl = _spawnedView.GetComponent<VATAnimationController>();
|
|
}
|
|
|
|
// 接管 EnemyBehavior 朝向:不再写 transform.localScale.x,sign 走 event
|
|
if (_enemy != null)
|
|
{
|
|
_enemy.ExternalFacingOverride = true;
|
|
_enemy.OnFacingSignChanged += HandleEnemyFacingChanged;
|
|
}
|
|
|
|
// 出生时同步一次初始朝向(VATAnimationController.OnEnable 默认 SetFacing(+1) 已先跑过,
|
|
// 这里覆盖一次以应对对象池复用或 prefab 上 root.scale.x 非常规情况)
|
|
if (_vatCtrl != null) _vatCtrl.SetFacing(1);
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
if (_enemy != null) _enemy.OnFacingSignChanged -= HandleEnemyFacingChanged;
|
|
}
|
|
|
|
private void HandleEnemyFacingChanged(int sign)
|
|
{
|
|
if (_vatCtrl != null) _vatCtrl.SetFacing(sign);
|
|
}
|
|
|
|
private void HideOriginalSprites()
|
|
{
|
|
var all = GetComponentsInChildren<SpriteRenderer>(true);
|
|
foreach (var sr in all)
|
|
{
|
|
if (!string.IsNullOrEmpty(keepNameContains) &&
|
|
sr.gameObject.name.IndexOf(keepNameContains, System.StringComparison.OrdinalIgnoreCase) >= 0)
|
|
continue;
|
|
sr.enabled = false;
|
|
}
|
|
|
|
// 子物体上的 Animator 也禁用(主 Sprite 那个,Animator 切 Sprite 已无用,省 CPU)
|
|
var animators = GetComponentsInChildren<Animator>(true);
|
|
foreach (var an in animators)
|
|
{
|
|
if (!string.IsNullOrEmpty(keepNameContains) &&
|
|
an.gameObject.name.IndexOf(keepNameContains, System.StringComparison.OrdinalIgnoreCase) >= 0)
|
|
continue;
|
|
an.enabled = false;
|
|
}
|
|
}
|
|
|
|
private void SpawnVATView()
|
|
{
|
|
if (vatPrefab == null) return;
|
|
_spawnedView = Instantiate(vatPrefab, transform);
|
|
_spawnedView.name = "_VAT_View";
|
|
_spawnedView.transform.localPosition = localOffset;
|
|
_spawnedView.transform.localScale = localScale;
|
|
// 注意: 不在这里写 localRotation = identity!
|
|
// VATAnimationController.OnEnable 已在 Instantiate 中调过 SetFacing(),把 Y 设成了 ±facing 值,
|
|
// 这里 reset 会把它抹成 0,导致 LateUpdate 第一次跑之前 view 朝向是错的。
|
|
// VAT prefab 的 root rotation 本身就是 identity,无需重置。
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
// 仅给 Editor 工具读
|
|
public GameObject VATPrefab
|
|
{
|
|
get => vatPrefab;
|
|
set => vatPrefab = value;
|
|
}
|
|
|
|
public Vector3 LocalScale
|
|
{
|
|
get => localScale;
|
|
set => localScale = value;
|
|
}
|
|
|
|
public Vector3 LocalOffset
|
|
{
|
|
get => localOffset;
|
|
set => localOffset = value;
|
|
}
|
|
#endif
|
|
}
|
|
}
|