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
}
}