using UnityEngine; namespace OctoberStudio.Rendering { /// /// 渲染器模式:Sprite (2D) 或 Mesh (3D) /// public enum RendererMode { Sprite = 0, Mesh = 1, } /// /// 统一渲染适配器。 /// 让 OctoberStudio 的业务逻辑无需关心使用 还是 。 /// 在 Prefab 上挂载此组件,选择 Mode,勾选 Auto Fetch 即可让组件自动绑定子级 Renderer。 /// /// 典型用法: /// 2D Prefab → Mode=Sprite,自动找 SpriteRenderer,行为与原版完全一致 /// 3D Prefab → Mode=Mesh,自动找 MeshRenderer,所有 Color/Flip/Sorting 操作映射到 Mesh 上 /// /// 业务代码统一通过适配器属性 (Color/FlipX/SortingOrder/...) 操作, /// 切换 2D/3D 时无需重写逻辑层。 /// [DisallowMultipleComponent] [ExecuteAlways] [AddComponentMenu("OctoberStudio/Rendering/Renderer Adapter")] public class RendererAdapter : MonoBehaviour { [Tooltip("渲染模式:Sprite=2D 模式 (默认), Mesh=3D 模式")] [SerializeField] private RendererMode mode = RendererMode.Sprite; [Tooltip("启用后会在 OnValidate / Reset 自动查找并绑定子级 Renderer 组件")] [SerializeField] private bool autoFetch = true; [Tooltip("自动查找时的搜索根 (留空 = 自己)")] [SerializeField] private Transform fetchRoot; [Tooltip("是否在 mode 切换时自动启用/禁用对应的 Renderer (推荐勾选避免两个同时显示)")] [SerializeField] private bool applyEnabledOnModeChange = true; [Header("Bound Renderers (可手动指定,否则自动 fetch)")] [SerializeField] private SpriteRenderer spriteRenderer; [SerializeField] private MeshRenderer meshRenderer; #region Public Read-only public RendererMode Mode => mode; public bool IsSpriteMode => mode == RendererMode.Sprite; public bool IsMeshMode => mode == RendererMode.Mesh; public SpriteRenderer Sprite => spriteRenderer; public MeshRenderer Mesh => meshRenderer; /// /// 当前激活的 Renderer (Sprite 模式返回 SpriteRenderer,Mesh 模式返回 MeshRenderer) /// public Renderer Active => mode == RendererMode.Sprite ? (Renderer)spriteRenderer : meshRenderer; #endregion #region Unified API public bool IsVisible => Active != null && Active.isVisible; public Bounds Bounds => Active != null ? Active.bounds : new Bounds(transform.position, Vector3.zero); public bool Enabled { get => Active != null && Active.enabled; set { if (Active != null) Active.enabled = value; } } public Color Color { get { if (mode == RendererMode.Sprite) return spriteRenderer != null ? spriteRenderer.color : Color.white; return meshRenderer != null && meshRenderer.sharedMaterial != null && meshRenderer.sharedMaterial.HasProperty(MainColorPropID) ? meshRenderer.material.GetColor(MainColorPropID) : Color.white; } set { if (mode == RendererMode.Sprite) { if (spriteRenderer != null) spriteRenderer.color = value; } else { if (meshRenderer != null && meshRenderer.material != null && meshRenderer.material.HasProperty(MainColorPropID)) meshRenderer.material.SetColor(MainColorPropID, value); } } } public float Alpha { get => Color.a; set { var c = Color; c.a = value; Color = c; } } /// /// 水平翻转。 /// Sprite 模式:spriteRenderer.flipX /// Mesh 模式:transform.localScale.x 符号 /// public bool FlipX { get { if (mode == RendererMode.Sprite) return spriteRenderer != null && spriteRenderer.flipX; return transform.localScale.x < 0; } set { if (mode == RendererMode.Sprite) { if (spriteRenderer != null) spriteRenderer.flipX = value; } else { var s = transform.localScale; s.x = Mathf.Abs(s.x) * (value ? -1f : 1f); transform.localScale = s; } } } public bool FlipY { get { if (mode == RendererMode.Sprite) return spriteRenderer != null && spriteRenderer.flipY; return transform.localScale.y < 0; } set { if (mode == RendererMode.Sprite) { if (spriteRenderer != null) spriteRenderer.flipY = value; } else { var s = transform.localScale; s.y = Mathf.Abs(s.y) * (value ? -1f : 1f); transform.localScale = s; } } } public int SortingOrder { get => Active != null ? Active.sortingOrder : 0; set { if (Active != null) Active.sortingOrder = value; } } public string SortingLayerName { get => Active != null ? Active.sortingLayerName : "Default"; set { if (Active != null) Active.sortingLayerName = value; } } public int SortingLayerID { get => Active != null ? Active.sortingLayerID : 0; set { if (Active != null) Active.sortingLayerID = value; } } public Material Material { get => Active != null ? Active.material : null; set { if (Active != null) Active.material = value; } } public Material SharedMaterial { get => Active != null ? Active.sharedMaterial : null; set { if (Active != null) Active.sharedMaterial = value; } } #endregion #region Lifecycle private static readonly int MainColorPropID = Shader.PropertyToID("_Color"); private void Reset() { FetchComponents(); ApplyMode(); } private void OnValidate() { if (autoFetch) FetchComponents(); if (applyEnabledOnModeChange) ApplyMode(); } private void Awake() { if (autoFetch) FetchComponents(); if (applyEnabledOnModeChange) ApplyMode(); } #endregion #region Public Operations /// /// 在子级中查找并绑定对应类型的 Renderer (优先用根节点上的,再退到子级)。 /// [ContextMenu("Fetch Renderer Components")] public void FetchComponents() { var root = fetchRoot != null ? fetchRoot : transform; if (spriteRenderer == null) { spriteRenderer = root.GetComponent(); if (spriteRenderer == null) spriteRenderer = root.GetComponentInChildren(true); } if (meshRenderer == null) { meshRenderer = root.GetComponent(); if (meshRenderer == null) meshRenderer = root.GetComponentInChildren(true); } } /// /// 根据当前 mode 启用/禁用对应 Renderer (避免两个同时显示)。 /// [ContextMenu("Apply Mode")] public void ApplyMode() { if (spriteRenderer != null) spriteRenderer.enabled = (mode == RendererMode.Sprite); if (meshRenderer != null) meshRenderer.enabled = (mode == RendererMode.Mesh); } /// /// 运行时切换 mode (推荐通过这个方法切换,避免直接改 Inspector 字段不生效)。 /// public void SetMode(RendererMode newMode) { if (mode == newMode) return; mode = newMode; if (applyEnabledOnModeChange) ApplyMode(); } #endregion } }