当前位置: 首页 > news >正文

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

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

1. 方法封装

// 基础方法封装
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. 属性封装

// 使用属性进行封装
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. 组件封装

// 封装常用组件访问
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. 单例模式封装

// 单例模式封装
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);}}// 其他游戏管理方法...
}

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

// 利用泛型给不同的子类创建单例模式
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. 事件系统封装

// 事件系统封装
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. 脚本间通信封装(接口)

// 使用接口进行封装
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. 协程封装

// 协程方法封装
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 项目更易于维护和扩展,特别是在团队协作中。

http://www.xdnf.cn/news/1154863.html

相关文章:

  • OpenCV 入门知识:图片展示、摄像头捕获、控制鼠标及其 Trackbar(滑动条)生成!
  • QT无边框窗口
  • 2025 年科技革命时刻表:四大关键节点将如何重塑未来?
  • 详解Mysql Order by排序底层原理
  • RK3588 编译 Android 13 镜像方法
  • 用C语言实现控制台应用的按键方向控制
  • Qt的安装和环境配置
  • 【愚公系列】《MIoT.VC》002-构建基本仿真工作站(布局一个基本工作站)
  • OPC UA, CAN, PROFINET, SOCKET, MODBUS, HTTP, S7七种物联网常用协议解释
  • 金融工程、金融与经济学知识点
  • Claude 3模型深度剖析:架构创新与性能突破
  • JAVA面试宝典 -《容灾设计:异地多活架构实践》
  • 从零搭建智能搜索代理:LangGraph + 实时搜索 + PDF导出完整项目实战
  • 从TPACK到TPACK - AI:人工智能时代教师知识框架的重构与验证
  • Kubernetes中为ELK组件配置持久化存储
  • nginx定期清理日志
  • 线程池的状态
  • AI开发 | 基于FastAPI+React的流式对话
  • sqli-labs通关笔记-第09关 GET时间盲注(单引号闭合 手工注入+脚本注入两种方法)
  • Docker Desktop 入门教程(Windows macOS)
  • Elasticsearch 简化指南:GCP Google Compute Engine
  • 相似度计算
  • COGNEX康耐视IS5403-01智能相机加Navitar 18R00 LR1010WM52镜头
  • IP协议介绍
  • GPT-4o mini TTS:领先的文本转语音技术
  • VTM 是“H.266/VVC 标准的官方参考软件”视频分析,入门教程,它存在的唯一目的就是“让学术界和工业界在同一把尺子上做实验
  • Docker 在 Ubuntu 系统中的详细操作指南
  • 事务的传播行为,分别在spring和mysql中讲解
  • CentOS 服务器docker pull 拉取失败
  • 相机模型和对极几何