Unity笔记——Unity 封装方法指南

在 Unity 开发中,良好的封装可以提高代码的可维护性、可读性和复用性。以下是几种常见的封装方法:

1. 方法封装

cs 复制代码
// 基础方法封装
public class PlayerController : MonoBehaviour
{
    private float speed = 5f;
    
    // 封装移动逻辑
    private void MovePlayer()
    {
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");
        Vector3 movement = new Vector3(horizontal, 0, vertical) * speed * Time.deltaTime;
        transform.Translate(movement);
    }
    
    void Update()
    {
        MovePlayer();
    }
}

2. 属性封装

cs 复制代码
// 使用属性进行封装
public class PlayerStats : MonoBehaviour
{
    private int _health = 100;
    
    // 封装健康值属性
    public int Health
    {
        get => _health;
        set
        {
            _health = Mathf.Clamp(value, 0, 100);
            Debug.Log($"Health changed to: {_health}");
        }
    }
    
    public void TakeDamage(int damage)
    {
        Health -= damage;
    }
}

3. 组件封装

cs 复制代码
// 封装常用组件访问
public class PlayerMovement : MonoBehaviour
{
    private Rigidbody _rb;
    private Animator _animator;
    
    private void Awake()
    {
        _rb = GetComponent<Rigidbody>();
        _animator = GetComponent<Animator>();
    }
    
    public void Move(Vector3 direction, float speed)
    {
        _rb.velocity = direction * speed;
        _animator.SetBool("IsMoving", direction. Magnitude > 0);
    }
}

4. 单例模式封装

cs 复制代码
// 单例模式封装
public class GameManager : MonoBehaviour
{
    private static GameManager _instance;
    
    public static GameManager Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = FindObjectOfType<GameManager>();
                if (_instance == null)
                {
                    GameObject obj = new GameObject();
                    obj.name = typeof(GameManager).Name;
                    _instance = obj.AddComponent<GameManager>();
                    DontDestroyOnLoad(obj);
                }
            }
            return _instance;
        }
    }
    
    private void Awake()
    {
        if (_instance == null)
        {
            _instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }
    
    // 其他游戏管理方法...
}

单例模式其实是很常见的模式,写法有很多种,这里更好的封装应该是将单例抽出来,做成基类,把让需要使用单例的类继承这个基类。

cs 复制代码
// 利用泛型给不同的子类创建单例模式
public class Singleton<T> : MonoBehaviour where T : Singleton<T>
{
    private static T instance;
    public static T Instance
    {
        get
        {
            if (instance == null)
            {
                instance = FindObjectOfType<T>();
                if (instance == null)
                {
                    GameObject obj = new GameObject(typeof(T).Name);
                    instance = obj.AddComponent<T>();
                    DontDestroyOnLoad(obj); // 按需持久化
                }
            }
            return instance;
        }
    }

    protected virtual void Awake()
    {
        if (instance != null)
        {
            GameObject.Destroy(gameObject);
        }
        else
        {
            instance = this as T;
            // 按需持久化,不要在场景切换时销毁
            DontDestroyOnLoad(gameObject);
        }
    }
}

// 在其他需要使用单例的情况下就可以继承该基类,而不用重写一个新的单例模式
public class GameManager : SingletonMono<GameManager>
{
    protected override void Awake()
    {
        base. Awake();
    }
}

5. 事件系统封装

cs 复制代码
// 事件系统封装
public class EventManager : MonoBehaviour
{
    public delegate void PlayerDeathHandler();
    public static event PlayerDeathHandler OnPlayerDeath;
    
    public static void TriggerPlayerDeath()
    {
        OnPlayerDeath?.Invoke();
    }
}

// 使用示例
public class Player : MonoBehaviour
{
    private void Die()
    {
        // 玩家死亡逻辑...
        EventManager.TriggerPlayerDeath();
    }
}

public class UIManager : MonoBehaviour
{
    private void OnEnable()
    {
        EventManager.OnPlayerDeath += ShowGameOverScreen;
    }
    
    private void OnDisable()
    {
        EventManager.OnPlayerDeath -= ShowGameOverScreen;
    }
    
    private void ShowGameOverScreen()
    {
        // 显示游戏结束UI
    }
}

6. 脚本间通信封装(接口)

cs 复制代码
// 使用接口进行封装
public interface IDamageable
{
    void TakeDamage(int amount);
}

public class Enemy : MonoBehaviour, IDamageable
{
    public void TakeDamage(int amount)
    {
        // 敌人受伤逻辑
    }
}

public class PlayerCombat : MonoBehaviour
{
    private void Attack(IDamageable target)
    {
        target.TakeDamage(10);
    }
}

7. 协程封装

cs 复制代码
// 协程方法封装
public class CoroutineUtils : MonoBehaviour
{
    public static IEnumerator FadeOut(Renderer renderer, float duration)
    {
        Color originalColor = renderer.material.color;
        float elapsed = 0f;
        
        while (elapsed < duration)
        {
            float alpha = Mathf.Lerp(1f, 0f, elapsed / duration);
            renderer.material.color = new Color(originalColor.r, originalColor.g, originalColor.b, alpha);
            elapsed += Time.deltaTime;
            yield return null;
        }
    }
}

// 使用示例
StartCoroutine(CoroutineUtils.FadeOut(GetComponent<Renderer>(), 2f));

实践建议

  1. 单一职责原则:每个方法/类只做一件事

  2. 适当的访问修饰符:使用 private/protected/public 控制访问级别

  3. 参数验证:在公共方法中添加参数检查

  4. 添加注释:使用 /// <summary>注释 或者 // 注释说明方法用途和参数

  5. 避免过度封装:保持简单,只在必要时封装,当同一方法或者类似逻辑的实现出现第二次时就可以考虑封装该方法、将其抽象为抽象类方法 或者 考虑接口实现

良好的封装可以使你的 Unity 项目更易于维护和扩展,特别是在团队协作中。

相关推荐
我爱挣钱我也要早睡!9 小时前
Java 复习笔记
java·开发语言·笔记
汇能感知13 小时前
摄像头模块在运动相机中的特殊应用
经验分享·笔记·科技
阿巴Jun14 小时前
【数学】线性代数知识点总结
笔记·线性代数·矩阵
茯苓gao14 小时前
STM32G4 速度环开环,电流环闭环 IF模式建模
笔记·stm32·单片机·嵌入式硬件·学习
是誰萆微了承諾14 小时前
【golang学习笔记 gin 】1.2 redis 的使用
笔记·学习·golang
DKPT15 小时前
Java内存区域与内存溢出
java·开发语言·jvm·笔记·学习
ST.J15 小时前
前端笔记2025
前端·javascript·css·vue.js·笔记
Suckerbin15 小时前
LAMPSecurity: CTF5靶场渗透
笔记·安全·web安全·网络安全
小憩-16 小时前
【机器学习】吴恩达机器学习笔记
人工智能·笔记·机器学习
UQI-LIUWJ17 小时前
unsloth笔记:运行&微调 gemma
人工智能·笔记·深度学习