You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity+C#实现明暗模式:无需多精灵的最优方案咨询

实现Unity明暗模式切换(无需多套精灵)

完全可以实现你想要的方案,核心思路是用ScriptableObject作为颜色配置资产(对应你说的"color prefab"),配合全局主题管理器和组件订阅机制,只需要切换配置实例就能完成全量模式切换,无需替换精灵。下面是具体实现步骤:

1. 创建颜色配置资产(ScriptableObject)

先定义一个存储颜色方案的ScriptableObject,你可以根据项目需求扩展颜色类型:

using UnityEngine;

[CreateAssetMenu(fileName = "NewColorScheme", menuName = "UI/Color Scheme")]
public class ColorScheme : ScriptableObject
{
    // 按业务场景定义颜色,比如:
    public Color backgroundColor;
    public Color textColor;
    public Color primaryButtonColor;
    public Color secondaryButtonColor;
    public Color iconTintColor; // 用于给精灵染色的色调
}

在Unity编辑器右键 → UI/Color Scheme,分别创建LightScheme和DarkScheme两个实例,然后在Inspector里设置对应模式的颜色值。

2. 全局主题管理器

做一个单例管理器,负责管理当前使用的颜色方案,以及通知所有需要变色的组件更新:

using UnityEngine;
using System.Collections.Generic;

public class ThemeManager : MonoBehaviour
{
    public static ThemeManager Instance { get; private set; }

    [Header("颜色方案引用")]
    public ColorScheme lightScheme;
    public ColorScheme darkScheme;

    private ColorScheme _currentScheme;
    private List<IThemeReceiver> _themeReceivers = new List<IThemeReceiver>();

    private void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject);
            return;
        }
        Instance = this;
        DontDestroyOnLoad(gameObject);

        // 默认启用浅色模式
        _currentScheme = lightScheme;
    }

    // 切换到浅色模式
    public void SwitchToLightMode()
    {
        _currentScheme = lightScheme;
        RefreshAllThemes();
    }

    // 切换到深色模式
    public void SwitchToDarkMode()
    {
        _currentScheme = darkScheme;
        RefreshAllThemes();
    }

    // 注册需要监听主题变化的组件
    public void RegisterReceiver(IThemeReceiver receiver)
    {
        if (!_themeReceivers.Contains(receiver))
        {
            _themeReceivers.Add(receiver);
            receiver.UpdateTheme(_currentScheme); // 注册后立即同步当前主题
        }
    }

    // 取消注册
    public void UnregisterReceiver(IThemeReceiver receiver)
    {
        _themeReceivers.Remove(receiver);
    }

    // 通知所有组件更新主题
    private void RefreshAllThemes()
    {
        foreach (var receiver in _themeReceivers)
        {
            receiver.UpdateTheme(_currentScheme);
        }
    }
}

// 定义主题更新接口,所有需要变色的组件都要实现它
public interface IThemeReceiver
{
    void UpdateTheme(ColorScheme currentScheme);
}

把这个管理器挂载到一个全局GameObject(比如GameManager)上,然后在Inspector里把之前创建的LightScheme和DarkScheme拖入对应字段。

3. 给UI/精灵添加主题适配组件

针对不同类型的元素(Image、Text、SpriteRenderer等),创建对应的适配组件,实现IThemeReceiver接口:

示例1:适配UI Image(包括精灵按钮)

using UnityEngine;
using UnityEngine.UI;

public class ThemedImage : MonoBehaviour, IThemeReceiver
{
    public enum ColorUsage { Background, PrimaryButton, SecondaryButton, IconTint }
    public ColorUsage targetColor;

    private Image _image;

    private void Awake()
    {
        _image = GetComponent<Image>();
        ThemeManager.Instance.RegisterReceiver(this);
    }

    private void OnDestroy()
    {
        ThemeManager.Instance.UnregisterReceiver(this);
    }

    public void UpdateTheme(ColorScheme currentScheme)
    {
        switch (targetColor)
        {
            case ColorUsage.Background:
                _image.color = currentScheme.backgroundColor;
                break;
            case ColorUsage.PrimaryButton:
                _image.color = currentScheme.primaryButtonColor;
                break;
            case ColorUsage.SecondaryButton:
                _image.color = currentScheme.secondaryButtonColor;
                break;
            case ColorUsage.IconTint:
                _image.color = currentScheme.iconTintColor;
                break;
        }
    }
}

示例2:适配UI Text

using UnityEngine;
using UnityEngine.UI;

public class ThemedText : MonoBehaviour, IThemeReceiver
{
    private Text _text;

    private void Awake()
    {
        _text = GetComponent<Text>();
        ThemeManager.Instance.RegisterReceiver(this);
    }

    private void OnDestroy()
    {
        ThemeManager.Instance.UnregisterReceiver(this);
    }

    public void UpdateTheme(ColorScheme currentScheme)
    {
        _text.color = currentScheme.textColor;
    }
}

示例3:适配2D精灵(SpriteRenderer)

using UnityEngine;

public class ThemedSprite : MonoBehaviour, IThemeReceiver
{
    private SpriteRenderer _spriteRenderer;

    private void Awake()
    {
        _spriteRenderer = GetComponent<SpriteRenderer>();
        ThemeManager.Instance.RegisterReceiver(this);
    }

    private void OnDestroy()
    {
        ThemeManager.Instance.UnregisterReceiver(this);
    }

    public void UpdateTheme(ColorScheme currentScheme)
    {
        // 用色调给精灵染色,保留原纹理的透明度和灰度
        _spriteRenderer.color = currentScheme.iconTintColor;
    }
}

4. 模式切换调用

在你的切换按钮逻辑里,直接调用管理器的切换方法即可:

// 比如按钮点击事件里的代码
public void OnToggleDarkMode(bool isDark)
{
    if (isDark)
    {
        ThemeManager.Instance.SwitchToDarkMode();
    }
    else
    {
        ThemeManager.Instance.SwitchToLightMode();
    }
}

扩展提示

  • 如果需要保存用户的模式偏好,可以在ThemeManager里加入PlayerPrefs存储逻辑,启动时读取并设置对应模式。
  • 对于复杂材质(比如带多个颜色属性的3D材质),可以扩展ThemedMaterial组件,指定要修改的材质属性名。

内容的提问来源于stack exchange,提问作者unitydevelopmentquestions

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 13:20:28