最佳实践
目录
09. 最佳实践
Unity游戏开发最佳实践 - 高质量代码、性能优化、架构设计
📌 本章导航
代码组织和架构
项目结构最佳实践
良好的项目结构是成功开发的基础。以下是一个推荐的Unity项目结构:
Assets/
├── Scripts/ # 脚本文件
│ ├── Core/ # 核心系统
│ │ ├── Managers/ # 管理器类
│ │ ├── Systems/ # 核心系统
│ │ └── Utilities/ # 工具类
│ ├── Game/ # 游戏逻辑
│ │ ├── Player/ # 玩家相关
│ │ ├── Enemies/ # 敌人相关
│ │ ├── Items/ # 物品相关
│ │ └── UI/ # UI逻辑
│ ├── Framework/ # 框架代码
│ └── Editor/ # 编辑器扩展
├── Prefabs/ # 预制件
│ ├── Characters/ # 角色预制件
│ ├── Environment/ # 环境预制件
│ └── UI/ # UI预制件
├── Scenes/ # 场景文件
├── Materials/ # 材质
├── Textures/ # 纹理
├── Models/ # 模型
├── Audio/ # 音频
├── Animations/ # 动画
├── Plugins/ # 插件
└── Resources/ # 资源(如果使用Resources加载)
命名约定
// ✅ 推荐的命名约定
// 类名使用PascalCase
public class PlayerController : MonoBehaviour
{
// 私有字段使用camelCase
private int playerHealth;
private float moveSpeed;
// 公共字段使用PascalCase
public int MaxHealth { get; set; }
// 常量使用PASCAL_CASE
private const float GRAVITY = -9.81f;
// 事件使用PascalCase
public event System.Action OnPlayerDeath;
// 方法使用PascalCase
public void TakeDamage(int damage)
{
playerHealth -= damage;
if (playerHealth <= 0)
{
Die();
}
}
// 私有方法使用PascalCase
private void Die()
{
// 死亡逻辑
}
}
// 枚举使用PascalCase
public enum GameState
{
MainMenu,
Playing,
Paused,
GameOver
}
// 接口使用I前缀
public interface IInteractable
{
void Interact();
}
单例模式最佳实践
using UnityEngine;
// 线程安全的单例模式
public class GameManager : MonoBehaviour
{
private static GameManager _instance;
private static readonly object _lock = new object();
private static bool _applicationIsQuitting = false;
public static GameManager Instance
{
get
{
if (_applicationIsQuitting)
{
Debug.LogWarning("单例在应用程序退出时被访问!");
return null;
}
lock (_lock)
{
if (_instance == null)
{
_instance = FindObjectOfType<GameManager>();
if (_instance == null)
{
GameObject singletonObject = new GameObject("GameManager");
_instance = singletonObject.AddComponent<GameManager>();
}
// 确保单例对象在场景切换时不被销毁
DontDestroyOnLoad(_instance);
}
return _instance;
}
}
}
void Awake()
{
if (_instance != null && _instance != this)
{
// 如果已经存在实例,销毁新的实例
Destroy(gameObject);
return;
}
_instance = this;
DontDestroyOnLoad(gameObject);
}
void OnDestroy()
{
if (_instance == this)
{
_applicationIsQuitting = true;
}
}
}
// 泛型单例基类
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static T _instance;
private static readonly object _lock = new object();
private static bool _applicationIsQuitting = false;
public static T Instance
{
get
{
if (_applicationIsQuitting)
{
Debug.LogWarning($"单例 {typeof(T)} 在应用程序退出时被访问!");
return null;
}
lock (_lock)
{
if (_instance == null)
{
_instance = FindObjectOfType<T>();
if (_instance == null)
{
GameObject singletonObject = new GameObject(typeof(T).Name);
_instance = singletonObject.AddComponent<T>();
}
if (_instance != null)
{
DontDestroyOnLoad(_instance);
}
}
return _instance;
}
}
}
protected virtual void Awake()
{
if (_instance != null && _instance != this)
{
Destroy(gameObject);
return;
}
_instance = this;
DontDestroyOnLoad(gameObject);
}
protected virtual void OnDestroy()
{
if (_instance == this)
{
_applicationIsQuitting = true;
}
}
}
组件化架构
using UnityEngine;
using System.Collections.Generic;
// 组件化架构示例
public class Entity : MonoBehaviour
{
private List<IEntityComponent> components = new List<IEntityComponent>();
void Start()
{
// 获取所有组件
IEntityComponent[] foundComponents = GetComponents<IEntityComponent>();
components.AddRange(foundComponents);
// 初始化所有组件
foreach (IEntityComponent component in components)
{
component.Initialize(this);
}
}
void Update()
{
// 更新所有组件
foreach (IEntityComponent component in components)
{
component.Update();
}
}
void FixedUpdate()
{
// 固定更新所有组件
foreach (IEntityComponent component in components)
{
component.FixedUpdate();
}
}
// 获取特定类型的组件
public T GetComponent<T>() where T : class, IEntityComponent
{
foreach (IEntityComponent component in components)
{
if (component is T specificComponent)
{
return specificComponent;
}
}
return null;
}
// 添加组件
public void AddComponent(IEntityComponent component)
{
if (!components.Contains(component))
{
components.Add(component);
component.Initialize(this);
}
}
// 移除组件
public void RemoveComponent(IEntityComponent component)
{
if (components.Contains(component))
{
component.Dispose();
components.Remove(component);
}
}
}
// 实体组件接口
public interface IEntityComponent
{
void Initialize(Entity entity);
void Update();
void FixedUpdate();
void Dispose();
}
// 移动组件示例
public class MovementComponent : MonoBehaviour, IEntityComponent
{
public float moveSpeed = 5f;
private Entity entity;
private CharacterController controller;
public void Initialize(Entity entity)
{
this.entity = entity;
controller = entity.GetComponent<CharacterController>();
}
public void Update()
{
// 处理输入和移动
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
Vector3 movement = new Vector3(horizontal, 0, vertical) * moveSpeed * Time.deltaTime;
if (controller != null)
{
controller.Move(movement);
}
}
public void FixedUpdate() { }
public void Dispose() { }
}
// 战斗组件示例
public class CombatComponent : MonoBehaviour, IEntityComponent
{
public int health = 100;
public int maxHealth = 100;
private Entity entity;
public void Initialize(Entity entity)
{
this.entity = entity;
}
public void Update() { }
public void FixedUpdate() { }
public void TakeDamage(int damage)
{
health -= damage;
if (health <= 0)
{
Die();
}
}
private void Die()
{
// 死亡逻辑
Debug.Log($"{entity.name} 死亡!");
// 通知其他系统
GameEvents.OnEntityDeath?.Invoke(entity);
}
public void Dispose() { }
}
// 事件系统
public static class GameEvents
{
public static System.Action<Entity> OnEntityDeath;
}
事件驱动架构
using UnityEngine;
using System.Collections.Generic;
// 事件系统管理器
public class EventManager : MonoBehaviour
{
private Dictionary<System.Type, System.Delegate> eventDictionary =
new Dictionary<System.Type, System.Delegate>();
private static EventManager _instance;
public static EventManager Instance
{
get
{
if (_instance == null)
{
_instance = FindObjectOfType<EventManager>();
if (_instance == null)
{
GameObject eventManagerObject = new GameObject("EventManager");
_instance = eventManagerObject.AddComponent<EventManager>();
}
}
return _instance;
}
}
void OnDisable()
{
eventDictionary.Clear();
}
// 注册事件监听器
public void Subscribe<T>(System.Action<T> listener) where T : struct
{
System.Type eventType = typeof(T);
if (eventDictionary.ContainsKey(eventType))
{
eventDictionary[eventType] = System.Delegate.Combine(eventDictionary[eventType], listener);
}
else
{
eventDictionary[eventType] = listener;
}
}
// 取消注册事件监听器
public void Unsubscribe<T>(System.Action<T> listener) where T : struct
{
System.Type eventType = typeof(T);
if (eventDictionary.ContainsKey(eventType))
{
eventDictionary[eventType] = System.Delegate.Remove(eventDictionary[eventType], listener);
if (eventDictionary[eventType] == null)
{
eventDictionary.Remove(eventType);
}
}
}
// 触发事件
public void Trigger<T>(T eventToTrigger) where T : struct
{
System.Type eventType = typeof(T);
if (eventDictionary.ContainsKey(eventType))
{
System.Delegate multicastDelegate = eventDictionary[eventType];
if (multicastDelegate != null)
{
System.Action<T> callback = multicastDelegate as System.Action<T>;
if (callback != null)
{
callback(eventToTrigger);
}
}
}
}
}
// 事件数据结构
public struct PlayerDeathEvent
{
public int playerId;
public Vector3 position;
public float time;
public PlayerDeathEvent(int id, Vector3 pos)
{
playerId = id;
position = pos;
time = Time.time;
}
}
public struct EnemySpawnEvent
{
public int enemyId;
public string enemyType;
public Vector3 position;
public EnemySpawnEvent(int id, string type, Vector3 pos)
{
enemyId = id;
enemyType = type;
position = pos;
}
}
// 使用事件系统的示例
public class PlayerDeathHandler : MonoBehaviour
{
void OnEnable()
{
EventManager.Instance.Subscribe<PlayerDeathEvent>(OnPlayerDeath);
}
void OnDisable()
{
EventManager.Instance.Unsubscribe<PlayerDeathEvent>(OnPlayerDeath);
}
void OnPlayerDeath(PlayerDeathEvent deathEvent)
{
Debug.Log($"玩家 {deathEvent.playerId} 在位置 {deathEvent.position} 死亡");
// 处理玩家死亡逻辑
HandlePlayerDeath(deathEvent);
}
void HandlePlayerDeath(PlayerDeathEvent deathEvent)
{
// 创建死亡效果
CreateDeathEffect(deathEvent.position);
// 更新UI
UpdateUIOnPlayerDeath(deathEvent.playerId);
// 检查游戏结束条件
CheckGameOverCondition();
}
void CreateDeathEffect(Vector3 position)
{
// 创建死亡特效
}
void UpdateUIOnPlayerDeath(int playerId)
{
// 更新UI显示
}
void CheckGameOverCondition()
{
// 检查是否满足游戏结束条件
}
}
性能优化策略
对象池系统
using UnityEngine;
using System.Collections.Generic;
// 通用对象池
public class ObjectPool<T> where T : Component
{
private Queue<T> pool = new Queue<T>();
private T prefab;
private Transform parent;
private int initialSize;
public ObjectPool(T prefab, int initialSize, Transform parent = null)
{
this.prefab = prefab;
this.initialSize = initialSize;
this.parent = parent;
// 预先创建对象
for (int i = 0; i < initialSize; i++)
{
T obj = CreateNewObject();
ReturnToPool(obj);
}
}
public T Get()
{
T obj;
if (pool.Count > 0)
{
obj = pool.Dequeue();
obj.gameObject.SetActive(true);
}
else
{
// 如果池空了,创建新对象(应该避免这种情况)
obj = CreateNewObject();
Debug.LogWarning($"对象池 {typeof(T)} 已空,创建新对象");
}
return obj;
}
public void ReturnToPool(T obj)
{
if (obj != null)
{
obj.gameObject.SetActive(false);
obj.transform.SetParent(parent);
pool.Enqueue(obj);
}
}
private T CreateNewObject()
{
T obj = GameObject.Instantiate(prefab);
obj.transform.SetParent(parent);
obj.gameObject.SetActive(false);
return obj;
}
public int PoolSize => pool.Count;
}
// 对象池管理器
public class ObjectPoolManager : MonoBehaviour
{
private Dictionary<string, System.Object> pools = new Dictionary<string, System.Object>();
private static ObjectPoolManager _instance;
public static ObjectPoolManager Instance
{
get
{
if (_instance == null)
{
_instance = FindObjectOfType<ObjectPoolManager>();
if (_instance == null)
{
GameObject poolManagerObject = new GameObject("ObjectPoolManager");
_instance = poolManagerObject.AddComponent<ObjectPoolManager>();
}
}
return _instance;
}
}
void Start()
{
InitializePools();
}
private void InitializePools()
{
// 初始化各种对象池
InitializePool<GameObject>("Bullet", Resources.Load<GameObject>("Prefabs/Bullet"), 20);
InitializePool<GameObject>("Explosion", Resources.Load<GameObject>("Prefabs/Explosion"), 10);
InitializePool<GameObject>("Enemy", Resources.Load<GameObject>("Prefabs/Enemy"), 5);
}
private void InitializePool<T>(string key, T prefab, int initialSize) where T : Component
{
if (prefab != null)
{
ObjectPool<T> pool = new ObjectPool<T>(prefab, initialSize, transform);
pools[key] = pool;
}
}
public T GetObject<T>(string key) where T : Component
{
if (pools.ContainsKey(key) && pools[key] is ObjectPool<T> pool)
{
return pool.Get();
}
Debug.LogError($"对象池 {key} 不存在或类型不匹配");
return null;
}
public void ReturnObject<T>(string key, T obj) where T : Component
{
if (pools.ContainsKey(key) && pools[key] is ObjectPool<T> pool)
{
pool.ReturnToPool(obj);
}
else
{
Debug.LogError($"对象池 {key} 不存在或类型不匹配");
}
}
// 获取池大小信息
public int GetPoolSize(string key)
{
if (pools.ContainsKey(key))
{
var pool = pools[key];
if (pool is ObjectPool<GameObject> goPool)
return goPool.PoolSize;
if (pool is ObjectPool<Rigidbody> rbPool)
return rbPool.PoolSize;
// 添加其他类型的检查
}
return -1;
}
}
// 使用对象池的示例
public class BulletSpawner : MonoBehaviour
{
public float spawnRate = 0.5f;
private float lastSpawnTime = 0f;
void Update()
{
if (Time.time - lastSpawnTime >= spawnRate)
{
SpawnBullet();
lastSpawnTime = Time.time;
}
}
void SpawnBullet()
{
GameObject bullet = ObjectPoolManager.Instance.GetObject<GameObject>("Bullet");
if (bullet != null)
{
bullet.transform.position = transform.position;
bullet.transform.rotation = transform.rotation;
// 设置子弹属性
Bullet bulletScript = bullet.GetComponent<Bullet>();
if (bulletScript != null)
{
bulletScript.Initialize(transform.forward, 10f);
}
}
}
void OnDisable()
{
// 返回所有子弹到池中
// 这里需要跟踪所有活跃的子弹
}
}
// 可池化组件
public class Poolable : MonoBehaviour
{
[Header("对象池设置")]
public string poolKey;
public bool returnToPoolOnDisable = true;
void OnDisable()
{
if (returnToPoolOnDisable && !string.IsNullOrEmpty(poolKey))
{
ObjectPoolManager.Instance.ReturnObject(poolKey, GetComponent<Poolable>());
}
}
public void Initialize()
{
// 初始化对象
gameObject.SetActive(true);
}
}
网格批处理优化
using UnityEngine;
using System.Collections.Generic;
// 动态批处理优化工具
public class DynamicBatchingOptimizer : MonoBehaviour
{
[Header("批处理设置")]
public bool enableDynamicBatching = true;
public int maxVerticesPerBatch = 300; // Unity的限制是300个顶点
public bool optimizeMaterials = true;
[Header("静态批处理设置")]
public bool enableStaticBatching = true;
// 优化游戏对象
public void OptimizeGameObject(GameObject go)
{
if (enableDynamicBatching)
{
OptimizeForDynamicBatching(go);
}
if (enableStaticBatching)
{
OptimizeForStaticBatching(go);
}
}
// 为动态批处理优化
private void OptimizeForDynamicBatching(GameObject go)
{
// 检查网格顶点数
MeshFilter meshFilter = go.GetComponent<MeshFilter>();
if (meshFilter != null && meshFilter.sharedMesh != null)
{
if (meshFilter.sharedMesh.vertexCount > maxVerticesPerBatch)
{
Debug.LogWarning($"游戏对象 {go.name} 的网格顶点数 ({meshFilter.sharedMesh.vertexCount}) 超过批处理限制 ({maxVerticesPerBatch})");
}
}
// 确保使用相同的材质
Renderer renderer = go.GetComponent<Renderer>();
if (renderer != null)
{
// 检查材质是否可以批处理
if (renderer.sharedMaterials.Length > 1)
{
Debug.LogWarning($"游戏对象 {go.name} 使用多个材质,无法进行批处理");
}
}
// 禁用可能阻止批处理的组件
if (go.GetComponent<Light>() != null)
{
Debug.LogWarning($"游戏对象 {go.name} 包含灯光组件,无法批处理");
}
if (go.GetComponent<ParticleSystem>() != null)
{
Debug.LogWarning($"游戏对象 {go.name} 包含粒子系统,无法批处理");
}
}
// 为静态批处理优化
private void OptimizeForStaticBatching(GameObject go)
{
go.isStatic = true; // 标记为静态
Renderer renderer = go.GetComponent<Renderer>();
if (renderer != null)
{
renderer.receiveShadows = false; // 减少阴影计算
renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; // 不投射阴影
}
}
// 批量优化场景中的对象
public void OptimizeScene()
{
GameObject[] allObjects = FindObjectsOfType<GameObject>();
foreach (GameObject go in allObjects)
{
if (go.CompareTag("Environment") || go.CompareTag("Static"))
{
OptimizeGameObject(go);
}
}
// 执行静态批处理
StaticBatchingUtility.Combine(GameObject.FindGameObjectsWithTag("Environment"));
}
}
// 材质优化器
public class MaterialOptimizer : MonoBehaviour
{
[Header("材质优化设置")]
public bool combineMaterials = true;
public bool useTextureAtlasing = true;
public bool optimizeShaders = true;
// 合并相同材质
public void CombineMaterials(GameObject parent)
{
if (!combineMaterials) return;
// 获取所有渲染器
Renderer[] renderers = parent.GetComponentsInChildren<Renderer>();
// 按材质分组
Dictionary<Material, List<Renderer>> materialGroups = new Dictionary<Material, List<Renderer>>();
foreach (Renderer renderer in renderers)
{
foreach (Material material in renderer.sharedMaterials)
{
if (!materialGroups.ContainsKey(material))
{
materialGroups[material] = new List<Renderer>();
}
materialGroups[material].Add(renderer);
}
}
// 为每个材质组创建合并网格
foreach (var group in materialGroups)
{
if (group.Value.Count > 1)
{
CombineMeshesForMaterial(group.Value, group.Key);
}
}
}
// 为特定材质合并网格
private void CombineMeshesForMaterial(List<Renderer> renderers, Material material)
{
List<CombineInstance> combineInstances = new List<CombineInstance>();
foreach (Renderer renderer in renderers)
{
MeshFilter meshFilter = renderer.GetComponent<MeshFilter>();
if (meshFilter != null && meshFilter.sharedMesh != null)
{
CombineInstance combineInstance = new CombineInstance();
combineInstance.mesh = meshFilter.sharedMesh;
combineInstance.transform = renderer.transform.localToWorldMatrix;
combineInstances.Add(combineInstance);
// 隐藏原始渲染器
renderer.enabled = false;
}
}
if (combineInstances.Count > 0)
{
// 创建合并后的网格
Mesh combinedMesh = new Mesh();
combinedMesh.CombineMeshes(combineInstances.ToArray());
// 创建新的游戏对象来承载合并的网格
GameObject combinedObject = new GameObject($"Combined_{material.name}");
combinedObject.transform.SetParent(renderers[0].transform.parent);
MeshFilter combinedMeshFilter = combinedObject.AddComponent<MeshFilter>();
combinedMeshFilter.mesh = combinedMesh;
MeshRenderer combinedRenderer = combinedObject.AddComponent<MeshRenderer>();
combinedRenderer.sharedMaterials = new Material[] { material };
}
}
}
物理优化
using UnityEngine;
using System.Collections.Generic;
// 物理优化管理器
public class PhysicsOptimizer : MonoBehaviour
{
[Header("物理优化设置")]
public int maxRigidbodyCount = 100;
public float physicsUpdateRate = 0.02f; // 50 FPS
public bool useLayerCollisionMatrix = true;
public bool optimizeTriggerCollisions = true;
[Header("物理对象池")]
public bool usePhysicsObjectPool = true;
private List<Rigidbody> activeRigidbodies = new List<Rigidbody>();
private Dictionary<Rigidbody, float> sleepTimers = new Dictionary<Rigidbody, float>();
void Start()
{
// 设置物理更新率
Time.fixedDeltaTime = physicsUpdateRate;
// 优化层碰撞矩阵
if (useLayerCollisionMatrix)
{
OptimizeLayerCollisionMatrix();
}
}
void Update()
{
// 监控刚体数量
if (activeRigidbodies.Count > maxRigidbodyCount)
{
Debug.LogWarning($"刚体数量 ({activeRigidbodies.Count}) 超过限制 ({maxRigidbodyCount})");
OptimizeRigidbodyCount();
}
// 管理休眠刚体
ManageSleepingRigidbodies();
}
// 优化层碰撞矩阵
private void OptimizeLayerCollisionMatrix()
{
// 禁用不必要的层碰撞
// 例如:UI层不应该与其他游戏对象碰撞
for (int i = 0; i < 32; i++)
{
for (int j = 0; j < 32; j++)
{
// 根据游戏需求设置碰撞矩阵
// Physics.IgnoreLayerCollision(i, j, true/false);
}
}
// 示例:禁用UI层与所有其他层的碰撞
int uiLayer = LayerMask.NameToLayer("UI");
if (uiLayer != -1)
{
for (int i = 0; i < 32; i++)
{
if (i != uiLayer)
{
Physics.IgnoreLayerCollision(uiLayer, i, true);
}
}
}
}
// 优化刚体数量
private void OptimizeRigidbodyCount()
{
// 暂停一些刚体的物理模拟
for (int i = maxRigidbodyCount; i < activeRigidbodies.Count; i++)
{
Rigidbody rb = activeRigidbodies[i];
if (rb != null)
{
rb.isKinematic = true; // 暂停物理模拟
sleepTimers[rb] = Time.time;
}
}
}
// 管理休眠刚体
private void ManageSleepingRigidbodies()
{
List<Rigidbody> toRemove = new List<Rigidbody>();
foreach (var pair in sleepTimers)
{
Rigidbody rb = pair.Key;
float sleepStartTime = pair.Value;
if (rb != null)
{
// 检查刚体是否应该唤醒
if (Time.time - sleepStartTime > 5f) // 休眠5秒后检查
{
// 检查是否有外力作用
if (rb.velocity.magnitude > 0.1f || rb.angularVelocity.magnitude > 0.1f)
{
// 有运动,唤醒刚体
rb.isKinematic = false;
toRemove.Add(rb);
}
}
}
else
{
toRemove.Add(rb);
}
}
foreach (Rigidbody rb in toRemove)
{
sleepTimers.Remove(rb);
}
}
// 注册刚体
public void RegisterRigidbody(Rigidbody rb)
{
if (!activeRigidbodies.Contains(rb))
{
activeRigidbodies.Add(rb);
}
}
// 注销刚体
public void UnregisterRigidbody(Rigidbody rb)
{
activeRigidbodies.Remove(rb);
sleepTimers.Remove(rb);
}
// 优化碰撞体
public void OptimizeCollider(Collider collider)
{
if (collider is MeshCollider meshCollider)
{
// 对于静态对象,使用凸包碰撞体
if (collider.gameObject.isStatic)
{
meshCollider.convex = true;
}
}
// 对于触发器,优化设置
if (collider.isTrigger && optimizeTriggerCollisions)
{
// 确保触发器对象没有刚体,除非需要物理响应
if (collider.GetComponent<Rigidbody>() == null)
{
// 可以添加一个简单的刚体来优化触发器性能
Rigidbody rb = collider.gameObject.AddComponent<Rigidbody>();
rb.isKinematic = true;
rb.useGravity = false;
}
}
}
// 物理对象池
public class PhysicsObjectPool<T> where T : Component
{
private Queue<T> pool = new Queue<T>();
private T prefab;
private Transform parent;
public PhysicsObjectPool(T prefab, int initialSize, Transform parent = null)
{
this.prefab = prefab;
this.parent = parent;
for (int i = 0; i < initialSize; i++)
{
T obj = CreateNewObject();
obj.GetComponent<Rigidbody>().isKinematic = true; // 初始状态为静止
ReturnToPool(obj);
}
}
public T Get()
{
T obj;
if (pool.Count > 0)
{
obj = pool.Dequeue();
obj.gameObject.SetActive(true);
obj.GetComponent<Rigidbody>().isKinematic = false; // 激活物理
}
else
{
obj = CreateNewObject();
obj.GetComponent<Rigidbody>().isKinematic = false;
}
return obj;
}
public void ReturnToPool(T obj)
{
if (obj != null)
{
obj.GetComponent<Rigidbody>().isKinematic = true; // 停止物理模拟
obj.GetComponent<Rigidbody>().velocity = Vector3.zero;
obj.GetComponent<Rigidbody>().angularVelocity = Vector3.zero;
obj.gameObject.SetActive(false);
obj.transform.SetParent(parent);
pool.Enqueue(obj);
}
}
private T CreateNewObject()
{
T obj = GameObject.Instantiate(prefab);
obj.transform.SetParent(parent);
obj.gameObject.SetActive(false);
return obj;
}
}
}
// 物理事件优化
public class OptimizedPhysicsEvents : MonoBehaviour
{
[Header("事件优化设置")]
public float eventCheckInterval = 0.1f;
public bool useCollisionFiltering = true;
private float lastEventCheckTime = 0f;
private Collider[] tempColliders = new Collider[10]; // 重用数组
void Update()
{
if (Time.time - lastEventCheckTime >= eventCheckInterval)
{
CheckPhysicsEvents();
lastEventCheckTime = Time.time;
}
}
private void CheckPhysicsEvents()
{
// 使用重用的数组进行碰撞检测
int count = Physics.OverlapSphereNonAlloc(transform.position, 5f, tempColliders);
for (int i = 0; i < count; i++)
{
if (useCollisionFiltering)
{
// 过滤不必要的碰撞事件
if (ShouldProcessCollision(tempColliders[i]))
{
ProcessCollision(tempColliders[i]);
}
}
else
{
ProcessCollision(tempColliders[i]);
}
}
}
private bool ShouldProcessCollision(Collider other)
{
// 根据标签或层过滤碰撞
return other.CompareTag("Player") || other.CompareTag("Enemy");
}
private void ProcessCollision(Collider other)
{
// 处理碰撞事件
Debug.Log($"检测到碰撞: {other.name}");
}
}
内存管理最佳实践
内存监控和分析
using UnityEngine;
using System.Collections.Generic;
using System.Text;
// 内存监控器
public class MemoryMonitor : MonoBehaviour
{
[Header("内存监控设置")]
public bool enableMemoryMonitoring = true;
public float monitorInterval = 1f;
public long memoryWarningThreshold = 500 * 1024 * 1024; // 500MB
public bool logMemoryInfo = true;
private float lastMonitorTime = 0f;
private List<long> memoryHistory = new List<long>();
private StringBuilder memoryReport = new StringBuilder();
void Update()
{
if (enableMemoryMonitoring && Time.time - lastMonitorTime >= monitorInterval)
{
MonitorMemory();
lastMonitorTime = Time.time;
}
}
private void MonitorMemory()
{
long currentMemory = System.GC.GetTotalMemory(false);
memoryHistory.Add(currentMemory);
// 保持历史记录在合理范围内
if (memoryHistory.Count > 60) // 保留最近60次记录
{
memoryHistory.RemoveAt(0);
}
// 检查内存使用是否超过阈值
if (currentMemory > memoryWarningThreshold)
{
Debug.LogWarning($"内存使用警告: {FormatBytes(currentMemory)} (阈值: {FormatBytes(memoryWarningThreshold)})");
GenerateMemoryReport();
}
if (logMemoryInfo)
{
LogMemoryInfo(currentMemory);
}
}
private void LogMemoryInfo(long currentMemory)
{
Debug.Log($"内存使用: {FormatBytes(currentMemory)}, " +
$"分配: {FormatBytes(System.GC.GetTotalMemory(false))}, " +
$"GC次数: {System.GC.CollectionCount(0)}/{System.GC.CollectionCount(1)}/{System.GC.CollectionCount(2)}");
}
// 生成内存报告
private void GenerateMemoryReport()
{
memoryReport.Length = 0; // 清空但不重新分配
memoryReport.AppendLine("=== 内存使用报告 ===");
memoryReport.AppendLine($"当前时间: {System.DateTime.Now}");
memoryReport.AppendLine($"当前内存使用: {FormatBytes(System.GC.GetTotalMemory(false))}");
memoryReport.AppendLine($"Unity报告内存: {FormatBytes(UnityEngine.Profiling.Profiler.GetTotalAllocatedMemoryLong())}");
memoryReport.AppendLine($"Unity保留内存: {FormatBytes(UnityEngine.Profiling.Profiler.GetTotalReservedMemoryLong())}");
memoryReport.AppendLine($"Unity峰值内存: {FormatBytes(UnityEngine.Profiling.Profiler.GetPeakAllocatedMemoryLong())}");
// GC统计
memoryReport.AppendLine($"GC次数 (0/1/2): {System.GC.CollectionCount(0)}/{System.GC.CollectionCount(1)}/{System.GC.CollectionCount(2)}");
// 对象统计
int totalObjects = FindObjectsOfType<Object>().Length;
memoryReport.AppendLine($"总对象数量: {totalObjects}");
// 材质统计
Material[] allMaterials = Resources.FindObjectsOfTypeAll<Material>();
memoryReport.AppendLine($"材质数量: {allMaterials.Length}");
// 纹理统计
Texture[] allTextures = Resources.FindObjectsOfTypeAll<Texture>();
memoryReport.AppendLine($"纹理数量: {allTextures.Length}");
// 音频剪辑统计
AudioClip[] allAudioClips = Resources.FindObjectsOfTypeAll<AudioClip>();
memoryReport.AppendLine($"音频剪辑数量: {allAudioClips.Length}");
Debug.Log(memoryReport.ToString());
}
// 格式化字节数
private string FormatBytes(long bytes)
{
string[] suffixes = { "B", "KB", "MB", "GB" };
int counter = 0;
decimal number = (decimal)bytes;
while (Math.Abs(number) >= 1024m && counter < suffixes.Length - 1)
{
counter++;
number /= 1024m;
}
return string.Format("{0:n1} {1}", number, suffixes[counter]);
}
// 强制垃圾回收
public void ForceGarbageCollection()
{
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
Debug.Log("强制垃圾回收完成");
}
// 获取内存使用详情
public MemoryUsageInfo GetMemoryUsageInfo()
{
return new MemoryUsageInfo
{
currentMemory = System.GC.GetTotalMemory(false),
unityAllocatedMemory = UnityEngine.Profiling.Profiler.GetTotalAllocatedMemoryLong(),
unityReservedMemory = UnityEngine.Profiling.Profiler.GetTotalReservedMemoryLong(),
unityPeakMemory = UnityEngine.Profiling.Profiler.GetPeakAllocatedMemoryLong(),
gcCountGen0 = System.GC.CollectionCount(0),
gcCountGen1 = System.GC.CollectionCount(1),
gcCountGen2 = System.GC.CollectionCount(2),
totalObjects = FindObjectsOfType<Object>().Length
};
}
}
[System.Serializable]
public class MemoryUsageInfo
{
public long currentMemory;
public long unityAllocatedMemory;
public long unityReservedMemory;
public long unityPeakMemory;
public int gcCountGen0;
public int gcCountGen1;
public int gcCountGen2;
public int totalObjects;
}
// 内存泄漏检测器
public class MemoryLeakDetector : MonoBehaviour
{
[Header("泄漏检测设置")]
public bool enableLeakDetection = true;
public float detectionInterval = 5f;
public float memoryGrowthThreshold = 0.1f; // 10%的增长阈值
private Dictionary<string, int> objectCounts = new Dictionary<string, int>();
private Dictionary<string, int> previousObjectCounts = new Dictionary<string, int>();
private float lastDetectionTime = 0f;
void Update()
{
if (enableLeakDetection && Time.time - lastDetectionTime >= detectionInterval)
{
DetectMemoryLeaks();
lastDetectionTime = Time.time;
}
}
private void DetectMemoryLeaks()
{
previousObjectCounts = new Dictionary<string, int>(objectCounts);
objectCounts.Clear();
// 统计各种对象的数量
CountObjects<Object>("Total Objects");
CountObjects<GameObject>("GameObjects");
CountObjects<Component>("Components");
CountObjects<Material>("Materials");
CountObjects<Texture>("Textures");
CountObjects<AudioClip>("AudioClips");
CountObjects<AnimationClip>("AnimationClips");
// 检查数量增长
foreach (var kvp in objectCounts)
{
if (previousObjectCounts.ContainsKey(kvp.Key))
{
int previousCount = previousObjectCounts[kvp.Key];
int currentCount = kvp.Value;
if (previousCount > 0)
{
float growthRate = (float)(currentCount - previousCount) / previousCount;
if (growthRate > memoryGrowthThreshold)
{
Debug.LogWarning($"可能的内存泄漏检测到: {kvp.Key} 数量增长 {growthRate:P2} " +
$"({previousCount} -> {currentCount})");
}
}
}
}
}
private void CountObjects<T>(string key) where T : Object
{
T[] objects = Resources.FindObjectsOfTypeAll<T>();
objectCounts[key] = objects.Length;
}
// 获取对象引用信息
public void LogObjectReferences()
{
// 记录所有对象的引用信息
Object[] allObjects = Resources.FindObjectsOfTypeAll<Object>();
Dictionary<System.Type, int> typeCounts = new Dictionary<System.Type, int>();
foreach (Object obj in allObjects)
{
System.Type type = obj.GetType();
if (typeCounts.ContainsKey(type))
{
typeCounts[type]++;
}
else
{
typeCounts[type] = 1;
}
}
Debug.Log("对象类型统计:");
foreach (var kvp in typeCounts)
{
Debug.Log($" {kvp.Key.Name}: {kvp.Value}");
}
}
}
资源管理最佳实践
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
// 资源管理器
public class ResourceManager : MonoBehaviour
{
[Header("资源管理设置")]
public bool enableAssetBundles = false;
public bool enableResourcePooling = true;
public float resourceCleanupInterval = 300f; // 5分钟
private Dictionary<string, Object> loadedAssets = new Dictionary<string, Object>();
private Dictionary<string, float> lastAccessTime = new Dictionary<string, float>();
private Dictionary<string, int> referenceCounts = new Dictionary<string, int>();
private List<string> assetsToUnload = new List<string>();
private float lastCleanupTime = 0f;
void Update()
{
if (Time.time - lastCleanupTime >= resourceCleanupInterval)
{
CleanupUnusedResources();
lastCleanupTime = Time.time;
}
}
// 异步加载资源
public Coroutine LoadAssetAsync<T>(string path, System.Action<T> callback) where T : Object
{
return StartCoroutine(LoadAssetAsyncCoroutine(path, callback));
}
private IEnumerator LoadAssetAsyncCoroutine<T>(string path, System.Action<T> callback) where T : Object
{
// 检查资源是否已加载
if (loadedAssets.ContainsKey(path))
{
referenceCounts[path]++;
lastAccessTime[path] = Time.time;
T asset = loadedAssets[path] as T;
callback?.Invoke(asset);
yield break;
}
// 异步加载资源
ResourceRequest request = Resources.LoadAsync<T>(path);
yield return request;
if (request.asset != null)
{
T asset = request.asset as T;
loadedAssets[path] = asset;
referenceCounts[path] = 1;
lastAccessTime[path] = Time.time;
callback?.Invoke(asset);
}
else
{
Debug.LogError($"无法加载资源: {path}");
callback?.Invoke(null);
}
}
// 同步加载资源
public T LoadAsset<T>(string path) where T : Object
{
// 检查是否已加载
if (loadedAssets.ContainsKey(path))
{
referenceCounts[path]++;
lastAccessTime[path] = Time.time;
return loadedAssets[path] as T;
}
// 加载资源
T asset = Resources.Load<T>(path);
if (asset != null)
{
loadedAssets[path] = asset;
referenceCounts[path] = 1;
lastAccessTime[path] = Time.time;
}
else
{
Debug.LogError($"无法加载资源: {path}");
}
return asset;
}
// 释放资源
public void UnloadAsset(string path)
{
if (referenceCounts.ContainsKey(path))
{
referenceCounts[path]--;
if (referenceCounts[path] <= 0)
{
// 标记为卸载
assetsToUnload.Add(path);
}
}
}
// 立即卸载资源
public void UnloadAssetImmediate(string path)
{
if (loadedAssets.ContainsKey(path))
{
Object asset = loadedAssets[path];
// 根据资源类型进行卸载
if (asset is GameObject || asset is Component)
{
// 对于游戏对象,使用Destroy
if (asset is GameObject go)
{
Destroy(go);
}
}
else
{
// 对于其他资源,使用Resources.UnloadAsset
Resources.UnloadAsset(asset);
}
loadedAssets.Remove(path);
referenceCounts.Remove(path);
lastAccessTime.Remove(path);
}
}
// 卸载未使用的资源
public void UnloadUnusedAssets()
{
// 使用Unity的内置方法卸载未使用的资源
Resources.UnloadUnusedAssets();
System.GC.Collect();
}
// 清理未使用的资源
private void CleanupUnusedResources()
{
// 处理标记为卸载的资源
foreach (string path in assetsToUnload)
{
UnloadAssetImmediate(path);
}
assetsToUnload.Clear();
// 卸载长时间未访问的资源
List<string> toRemove = new List<string>();
float currentTime = Time.time;
foreach (var kvp in lastAccessTime)
{
// 如果资源超过10分钟未被访问,则考虑卸载
if (currentTime - kvp.Value > 600f && referenceCounts[kvp.Key] <= 0)
{
toRemove.Add(kvp.Key);
}
}
foreach (string path in toRemove)
{
UnloadAssetImmediate(path);
}
}
// 预加载资源
public void PreloadAssets(List<string> assetPaths)
{
foreach (string path in assetPaths)
{
LoadAsset<Object>(path); // 预加载资源
}
}
// 获取资源使用统计
public ResourceUsageInfo GetResourceUsageInfo()
{
return new ResourceUsageInfo
{
loadedAssetCount = loadedAssets.Count,
totalReferenceCount = 0,
unusedAssetCount = 0
};
}
// 优化纹理内存使用
public void OptimizeTextureMemory()
{
Texture[] allTextures = Resources.FindObjectsOfTypeAll<Texture>();
foreach (Texture texture in allTextures)
{
// 对于运行时创建的纹理,确保正确释放
if (texture.name.StartsWith("Runtime_"))
{
// 这些纹理可能需要特殊处理
Debug.Log($"运行时纹理: {texture.name}, 尺寸: {texture.width}x{texture.height}");
}
}
}
void OnDestroy()
{
// 清理所有资源
foreach (string path in loadedAssets.Keys)
{
Object asset = loadedAssets[path];
if (!(asset is GameObject || asset is Component))
{
Resources.UnloadAsset(asset);
}
}
loadedAssets.Clear();
referenceCounts.Clear();
lastAccessTime.Clear();
}
}
[System.Serializable]
public class ResourceUsageInfo
{
public int loadedAssetCount;
public int totalReferenceCount;
public int unusedAssetCount;
}
// 资源加载器工具类
public static class ResourceLoader
{
// 安全加载资源,带错误处理
public static T SafeLoad<T>(string path, T defaultValue = null) where T : Object
{
try
{
T resource = Resources.Load<T>(path);
if (resource == null)
{
Debug.LogWarning($"无法加载资源: {path}, 返回默认值");
return defaultValue;
}
return resource;
}
catch (System.Exception e)
{
Debug.LogError($"加载资源时发生异常: {path}, 错误: {e.Message}");
return defaultValue;
}
}
// 异步安全加载
public static IEnumerator SafeLoadAsync<T>(string path, System.Action<T> callback, T defaultValue = null) where T : Object
{
ResourceRequest request = Resources.LoadAsync<T>(path);
yield return request;
try
{
T resource = request.asset as T;
if (resource == null)
{
Debug.LogWarning($"无法加载资源: {path}, 返回默认值");
callback?.Invoke(defaultValue);
}
else
{
callback?.Invoke(resource);
}
}
catch (System.Exception e)
{
Debug.LogError($"加载资源时发生异常: {path}, 错误: {e.Message}");
callback?.Invoke(defaultValue);
}
}
// 批量加载资源
public static IEnumerator BatchLoadAsync<T>(List<string> paths, System.Action<Dictionary<string, T>> callback) where T : Object
{
Dictionary<string, T> results = new Dictionary<string, T>();
List<Coroutine> loadOperations = new List<Coroutine>();
foreach (string path in paths)
{
yield return SafeLoadAsync(path, (T resource) =>
{
results[path] = resource;
});
}
callback?.Invoke(results);
}
}
字符串和集合优化
using UnityEngine;
using System.Collections.Generic;
using System.Text;
// 字符串优化工具
public class StringOptimization : MonoBehaviour
{
// 使用StringBuilder进行字符串拼接
private StringBuilder stringBuilder = new StringBuilder();
// 避免字符串拼接的性能问题
public string BuildStatusString(int health, int maxHealth, int level, string playerName)
{
stringBuilder.Length = 0; // 清空但不重新分配内存
stringBuilder.Append(playerName);
stringBuilder.Append(" - HP: ");
stringBuilder.Append(health);
stringBuilder.Append("/");
stringBuilder.Append(maxHealth);
stringBuilder.Append(" Lvl: ");
stringBuilder.Append(level);
return stringBuilder.ToString();
}
// 使用字符串池避免重复创建
private Dictionary<string, string> stringPool = new Dictionary<string, string>();
public string GetPooledString(string input)
{
if (stringPool.ContainsKey(input))
{
return stringPool[input];
}
string pooledString = input; // 实际上就是原字符串,但概念上是池化的
stringPool[input] = pooledString;
return pooledString;
}
// 避免装箱的数值格式化
public string FormatNumberWithoutBoxing(int number)
{
// 使用Span或直接操作字符数组来避免装箱
char[] buffer = new char[12]; // int的最大位数
int index = buffer.Length;
// 处理负数
bool isNegative = number < 0;
if (isNegative)
{
number = -number;
}
// 从后往前填充数字
do
{
buffer[--index] = (char)('0' + (number % 10));
number /= 10;
} while (number != 0);
// 添加负号
if (isNegative)
{
buffer[--index] = '-';
}
// 转换为字符串
return new string(buffer, index, buffer.Length - index);
}
// 使用缓存的字符串比较
public bool CompareCachedString(string a, string b)
{
// 对于频繁比较的字符串,可以使用引用比较(如果确定是同一实例)
// 或者使用StringComparer.OrdinalIgnoreCase等优化比较
return string.Equals(a, b, System.StringComparison.Ordinal);
}
}
// 集合优化工具
public class CollectionOptimization : MonoBehaviour
{
// 预分配集合大小
private List<int> preallocatedList = new List<int>(100); // 预分配容量
private Dictionary<int, string> preallocatedDict = new Dictionary<int, string>(50); // 预分配容量
private HashSet<string> preallocatedSet = new HashSet<string>(20); // 预分配容量
// 使用Span<T>进行高性能操作(C# 7.2+)
void ProcessArrayWithSpan(int[] array)
{
System.Span<int> span = array.AsSpan();
for (int i = 0; i < span.Length; i++)
{
span[i] *= 2; // 直接在栈上操作,无GC
}
}
// 使用Memory<T>处理数组片段
void ProcessArraySegment(int[] array, int start, int length)
{
System.Memory<int> memory = array.AsMemory(start, length);
System.Span<int> span = memory.Span;
for (int i = 0; i < span.Length; i++)
{
span[i] *= 2;
}
}
// 优化的列表操作
public void OptimizedListOperations()
{
// 预分配容量
List<GameObject> gameObjects = new List<GameObject>(100);
// 使用索引访问而不是LINQ(如果可能)
for (int i = 0; i < gameObjects.Count; i++)
{
if (gameObjects[i] != null)
{
// 处理对象
}
}
// 使用RemoveAll而不是循环Remove
gameObjects.RemoveAll(obj => obj == null);
// 使用Clear而不是创建新列表
gameObjects.Clear(); // 保持容量,只清空内容
}
// 优化的字典操作
public void OptimizedDictionaryOperations()
{
// 使用TryGetValue而不是ContainsKey + 索引
Dictionary<string, int> dict = new Dictionary<string, int>();
if (dict.TryGetValue("key", out int value))
{
// 使用value
}
// 预设容量以避免重新哈希
Dictionary<string, GameObject> objectDict = new Dictionary<string, GameObject>(100);
}
// 优化的集合查找
public void OptimizedLookups()
{
// 使用HashSet进行快速成员检查
HashSet<int> idSet = new HashSet<int> { 1, 2, 3, 4, 5 };
if (idSet.Contains(3)) // O(1)时间复杂度
{
// 快速查找
}
// 使用Dictionary进行快速键值查找
Dictionary<int, string> lookup = new Dictionary<int, string>();
if (lookup.ContainsKey(123))
{
string value = lookup[123]; // O(1)时间复杂度
}
}
// 对象池化的集合
public class PooledList<T>
{
private static Stack<List<T>> pool = new Stack<List<T>>();
private List<T> list;
public PooledList()
{
if (pool.Count > 0)
{
list = pool.Pop();
list.Clear(); // 清空内容但保持容量
}
else
{
list = new List<T>(10); // 初始容量
}
}
public void Add(T item)
{
list.Add(item);
}
public T this[int index] => list[index];
public int Count => list.Count;
public void ReturnToPool()
{
list.Clear();
pool.Push(list);
}
public List<T>.Enumerator GetEnumerator()
{
return list.GetEnumerator();
}
}
// 使用示例
void UsePooledList()
{
PooledList<GameObject> pooledList = new PooledList<GameObject>();
try
{
// 使用列表
pooledList.Add(gameObject);
// ... 其他操作
}
finally
{
// 确保返回池中
pooledList.ReturnToPool();
}
}
}
UI系统最佳实践
UI性能优化
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
// UI性能优化管理器
public class UIOptimizer : MonoBehaviour
{
[Header("UI优化设置")]
public bool enableCanvasOptimization = true;
public bool enableGraphicRaycastOptimization = true;
public bool enableLayoutOptimization = true;
public bool enableAnimationOptimization = true;
[Header("UI对象池")]
public bool useUIObjectPooling = true;
// UI对象池
private Dictionary<string, Queue<GameObject>> uiObjectPools = new Dictionary<string, Queue<GameObject>>();
// 优化Canvas
public void OptimizeCanvas(Canvas canvas)
{
if (!enableCanvasOptimization) return;
// 设置合适的渲染模式
if (canvas.renderMode == RenderMode.WorldSpace)
{
// 世界空间Canvas的优化
canvas.pixelPerfect = false; // 除非特别需要,否则关闭像素完美
}
else
{
// 屏幕空间Canvas的优化
canvas.pixelPerfect = true;
}
// 优化射线检测
if (enableGraphicRaycastOptimization)
{
GraphicRaycaster raycaster = canvas.GetComponent<GraphicRaycaster>();
if (raycaster != null)
{
raycaster.blockingObjects = GraphicRaycaster.BlockingObjects.None;
}
}
// 优化渲染顺序
canvas.sortingOrder = 0; // 根据需要调整
}
// 优化UI布局
public void OptimizeLayout(GameObject uiRoot)
{
if (!enableLayoutOptimization) return;
// 优化布局组件
LayoutGroup[] layoutGroups = uiRoot.GetComponentsInChildren<LayoutGroup>();
foreach (LayoutGroup layoutGroup in layoutGroups)
{
// 减少布局重建
if (layoutGroup is HorizontalLayoutGroup || layoutGroup is VerticalLayoutGroup)
{
// 设置固定大小以避免自动布局计算
RectTransform rectTransform = layoutGroup.GetComponent<RectTransform>();
if (rectTransform != null)
{
rectTransform.anchorMin = Vector2.zero;
rectTransform.anchorMax = Vector2.one;
}
}
}
// 优化内容大小过滤器
ContentSizeFitter[] sizeFitters = uiRoot.GetComponentsInChildren<ContentSizeFitter>();
foreach (ContentSizeFitter fitter in sizeFitters)
{
// 谨慎使用内容大小过滤器,它们会强制重新计算布局
fitter.enabled = false; // 或根据需要启用
}
}
// 优化UI动画
public void OptimizeUIAnimation(Animator animator)
{
if (!enableAnimationOptimization) return;
// 优化动画更新模式
animator.updateMode = AnimatorUpdateMode.UnscaledTime; // 根据需要选择
// 减少动画中的UI更新频率
// 在动画中避免频繁改变UI元素的属性
}
// 创建UI对象池
public void CreateUIObjectPool(string poolKey, GameObject prefab, int initialSize)
{
if (!useUIObjectPooling) return;
if (!uiObjectPools.ContainsKey(poolKey))
{
uiObjectPools[poolKey] = new Queue<GameObject>();
// 预创建对象
for (int i = 0; i < initialSize; i++)
{
GameObject obj = Instantiate(prefab);
obj.SetActive(false);
obj.transform.SetParent(transform, false);
uiObjectPools[poolKey].Enqueue(obj);
}
}
}
// 从池中获取UI对象
public GameObject GetUIObject(string poolKey)
{
if (useUIObjectPooling && uiObjectPools.ContainsKey(poolKey))
{
if (uiObjectPools[poolKey].Count > 0)
{
GameObject obj = uiObjectPools[poolKey].Dequeue();
obj.SetActive(true);
return obj;
}
else
{
Debug.LogWarning($"UI对象池 {poolKey} 已空");
}
}
return null;
}
// 返回UI对象到池中
public void ReturnUIObject(string poolKey, GameObject obj)
{
if (useUIObjectPooling && uiObjectPools.ContainsKey(poolKey))
{
obj.SetActive(false);
obj.transform.SetParent(transform, false);
uiObjectPools[poolKey].Enqueue(obj);
}
}
// 优化UI材质
public void OptimizeUIMaterials(Canvas canvas)
{
// 获取所有UI元素的材质
Graphic[] graphics = canvas.GetComponentsInChildren<Graphic>();
// 尽可能共享材质实例
Dictionary<string, Material> materialCache = new Dictionary<string, Material>();
foreach (Graphic graphic in graphics)
{
if (graphic.material != null)
{
string materialKey = graphic.material.name;
if (materialCache.ContainsKey(materialKey))
{
// 共享相同材质
graphic.material = materialCache[materialKey];
}
else
{
materialCache[materialKey] = graphic.material;
}
}
}
}
// 减少Canvas重建
public class OptimizedCanvasGroup : MonoBehaviour
{
private CanvasGroup canvasGroup;
private bool isVisible = true;
void Start()
{
canvasGroup = GetComponent<CanvasGroup>();
if (canvasGroup == null)
{
canvasGroup = gameObject.AddComponent<CanvasGroup>();
}
}
// 使用CanvasGroup而不是频繁激活/停用
public void SetVisible(bool visible)
{
if (isVisible != visible)
{
isVisible = visible;
canvasGroup.alpha = visible ? 1f : 0f;
canvasGroup.interactable = visible;
canvasGroup.blocksRaycasts = visible;
}
}
}
}
// 高效的UI更新管理器
public class UIUpdateManager : MonoBehaviour
{
[Header("更新设置")]
public float updateInterval = 0.1f; // 100ms更新一次
public bool enableBatchUpdates = true;
private List<IUIUpdatable> updatableComponents = new List<IUIUpdatable>();
private float lastUpdateTime = 0f;
void Update()
{
if (Time.time - lastUpdateTime >= updateInterval)
{
BatchUpdateUI();
lastUpdateTime = Time.time;
}
}
// 批量更新UI
private void BatchUpdateUI()
{
if (enableBatchUpdates)
{
// 批量更新所有注册的UI组件
for (int i = 0; i < updatableComponents.Count; i++)
{
updatableComponents[i]?.UpdateUI();
}
}
}
// 注册可更新的UI组件
public void RegisterUpdatable(IUIUpdatable updatable)
{
if (!updatableComponents.Contains(updatable))
{
updatableComponents.Add(updatable);
}
}
// 注销可更新的UI组件
public void UnregisterUpdatable(IUIUpdatable updatable)
{
updatableComponents.Remove(updatable);
}
}
// UI更新接口
public interface IUIUpdatable
{
void UpdateUI();
}
// 优化的文本组件
public class OptimizedText : MonoBehaviour, IUIUpdatable
{
private Text uiText;
private string currentText = "";
private int currentValue = 0;
void Start()
{
uiText = GetComponent<Text>();
if (uiText != null)
{
UIUpdateManager updateManager = FindObjectOfType<UIUpdateManager>();
if (updateManager != null)
{
updateManager.RegisterUpdatable(this);
}
}
}
// 设置文本(不立即更新)
public void SetText(string text)
{
currentText = text;
}
// 设置数值(不立即更新)
public void SetValue(int value)
{
currentValue = value;
}
// 批量更新时调用
public void UpdateUI()
{
if (uiText != null && uiText.text != currentText)
{
uiText.text = currentText;
}
}
void OnDestroy()
{
UIUpdateManager updateManager = FindObjectOfType<UIUpdateManager>();
if (updateManager != null)
{
updateManager.UnregisterUpdatable(this);
}
}
}
UI事件系统优化
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections.Generic;
// 优化的UI事件系统
public class OptimizedUIEventSystem : MonoBehaviour
{
[Header("事件优化设置")]
public bool enableEventPooling = true;
public bool enableEventThrottling = true;
public float eventThrottleInterval = 0.1f;
private Dictionary<string, float> lastEventTime = new Dictionary<string, float>();
private Queue<BaseEventData> eventPool = new Queue<BaseEventData>();
// 优化的按钮点击处理
public class OptimizedButton : Button
{
[Header("优化设置")]
public bool enableDoubleClickProtection = true;
public float doubleClickInterval = 0.3f;
private float lastClickTime = 0f;
private bool isDoubleClick = false;
public override void OnPointerClick(PointerEventData eventData)
{
if (enableDoubleClickProtection)
{
float currentTime = Time.unscaledTime;
if (currentTime - lastClickTime < doubleClickInterval)
{
isDoubleClick = true;
OnDoubleClick();
}
else
{
isDoubleClick = false;
OnSingleClick();
}
lastClickTime = currentTime;
}
else
{
OnSingleClick();
}
}
protected virtual void OnSingleClick()
{
// 单击处理
OnClick?.Invoke();
}
protected virtual void OnDoubleClick()
{
// 双击处理
OnDoubleClick?.Invoke();
}
public System.Action OnClick;
public System.Action OnDoubleClick;
}
// 优化的滑动条
public class OptimizedSlider : Slider
{
[Header("优化设置")]
public bool enableValueChangeThrottling = true;
public float valueChangeInterval = 0.1f;
private float lastValueChangeTime = 0f;
private float lastValue = 0f;
public override float value
{
get => base.value;
set
{
if (enableValueChangeThrottling)
{
float currentTime = Time.unscaledTime;
if (currentTime - lastValueChangeTime >= valueChangeInterval)
{
base.value = value;
lastValueChangeTime = currentTime;
lastValue = value;
onValueChanged.Invoke(value);
}
else if (Mathf.Abs(value - lastValue) > 0.1f) // 大幅变化仍需更新
{
base.value = value;
lastValue = value;
onValueChanged.Invoke(value);
}
}
else
{
base.value = value;
onValueChanged.Invoke(value);
}
}
}
}
// 优化的输入字段
public class OptimizedInputField : InputField
{
[Header("优化设置")]
public bool enableTextChangeThrottling = true;
public float textChangeInterval = 0.5f;
private float lastTextChangeTime = 0f;
protected override void SendOnValueChanged()
{
if (enableTextChangeThrottling)
{
float currentTime = Time.unscaledTime;
if (currentTime - lastTextChangeTime >= textChangeInterval)
{
base.SendOnValueChanged();
lastTextChangeTime = currentTime;
}
}
else
{
base.SendOnValueChanged();
}
}
}
// 事件节流检查
public bool CanProcessEvent(string eventId)
{
if (!enableEventThrottling)
{
return true;
}
float currentTime = Time.unscaledTime;
if (lastEventTime.ContainsKey(eventId))
{
if (currentTime - lastEventTime[eventId] >= eventThrottleInterval)
{
lastEventTime[eventId] = currentTime;
return true;
}
return false;
}
else
{
lastEventTime[eventId] = currentTime;
return true;
}
}
// 优化的UI动画
public class OptimizedUIAnimation : MonoBehaviour
{
[Header("动画设置")]
public AnimationCurve animationCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);
public float animationDuration = 1f;
public bool useUnscaledTime = true;
private Coroutine animationCoroutine;
private System.Action onCompleteCallback;
// 淡入动画
public void FadeIn(Graphic graphic, System.Action onComplete = null)
{
if (animationCoroutine != null)
{
StopCoroutine(animationCoroutine);
}
onCompleteCallback = onComplete;
animationCoroutine = StartCoroutine(FadeInCoroutine(graphic));
}
private System.Collections.IEnumerator FadeInCoroutine(Graphic graphic)
{
CanvasGroup canvasGroup = GetComponent<CanvasGroup>();
if (canvasGroup == null)
{
canvasGroup = gameObject.AddComponent<CanvasGroup>();
}
float startTime = useUnscaledTime ? Time.unscaledTime : Time.time;
float progress = 0f;
while (progress < 1f)
{
progress = useUnscaledTime ?
(Time.unscaledTime - startTime) / animationDuration :
(Time.time - startTime) / animationDuration;
float alpha = animationCurve.Evaluate(progress);
canvasGroup.alpha = alpha;
yield return null;
}
canvasGroup.alpha = 1f;
onCompleteCallback?.Invoke();
animationCoroutine = null;
}
// 移动动画
public void MoveTo(RectTransform rectTransform, Vector2 targetPosition, System.Action onComplete = null)
{
if (animationCoroutine != null)
{
StopCoroutine(animationCoroutine);
}
onCompleteCallback = onComplete;
animationCoroutine = StartCoroutine(MoveToCoroutine(rectTransform, targetPosition));
}
private System.Collections.IEnumerator MoveToCoroutine(RectTransform rectTransform, Vector2 targetPosition)
{
Vector2 startPosition = rectTransform.anchoredPosition;
float startTime = useUnscaledTime ? Time.unscaledTime : Time.time;
float progress = 0f;
while (progress < 1f)
{
progress = useUnscaledTime ?
(Time.unscaledTime - startTime) / animationDuration :
(Time.time - startTime) / animationDuration;
float t = animationCurve.Evaluate(progress);
rectTransform.anchoredPosition = Vector2.Lerp(startPosition, targetPosition, t);
yield return null;
}
rectTransform.anchoredPosition = targetPosition;
onCompleteCallback?.Invoke();
animationCoroutine = null;
}
void OnDisable()
{
if (animationCoroutine != null)
{
StopCoroutine(animationCoroutine);
animationCoroutine = null;
}
}
}
// UI资源管理
public class UIResourceManager : MonoBehaviour
{
private Dictionary<string, Sprite> spriteCache = new Dictionary<string, Sprite>();
private Dictionary<string, Font> fontCache = new Dictionary<string, Font>();
// 缓存精灵
public Sprite GetCachedSprite(string spritePath)
{
if (spriteCache.ContainsKey(spritePath))
{
return spriteCache[spritePath];
}
Sprite sprite = Resources.Load<Sprite>(spritePath);
if (sprite != null)
{
spriteCache[spritePath] = sprite;
}
return sprite;
}
// 缓存字体
public Font GetCachedFont(string fontPath)
{
if (fontCache.ContainsKey(fontPath))
{
return fontCache[fontPath];
}
Font font = Resources.Load<Font>(fontPath);
if (font != null)
{
fontCache[fontPath] = font;
}
return font;
}
// 清理缓存
public void ClearCache()
{
spriteCache.Clear();
fontCache.Clear();
}
}
}
音频系统最佳实践
音频管理器优化
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
// 优化的音频管理器
public class OptimizedAudioManager : MonoBehaviour
{
[Header("音频系统设置")]
public AudioMixerGroup masterMixerGroup;
public float masterVolume = 1f;
public float musicVolume = 1f;
public float sfxVolume = 1f;
public float voiceVolume = 1f;
[Header("音频源池")]
public int audioSourcePoolSize = 10;
public bool enable3DAudio = true;
public float max3DDistance = 50f;
[Header("音频剪辑")]
public List<AudioClip> musicClips = new List<AudioClip>();
public List<AudioClip> sfxClips = new List<AudioClip>();
public List<AudioClip> voiceClips = new List<AudioClip>();
// 音频源池
private Queue<AudioSource> audioSourcePool = new Queue<AudioSource>();
private List<AudioSource> activeAudioSources = new List<AudioSource>();
// 音频剪辑缓存
private Dictionary<string, AudioClip> audioClipCache = new Dictionary<string, AudioClip>();
private Dictionary<string, List<AudioClip>> audioCategoryCache = new Dictionary<string, List<AudioClip>>();
// 当前播放的音频
private Dictionary<string, AudioSource> playingAudio = new Dictionary<string, AudioSource>();
private AudioSource musicSource;
private AudioSource sfxSource;
private AudioSource voiceSource;
private static OptimizedAudioManager _instance;
public static OptimizedAudioManager Instance
{
get
{
if (_instance == null)
{
_instance = FindObjectOfType<OptimizedAudioManager>();
if (_instance == null)
{
GameObject audioManagerObject = new GameObject("OptimizedAudioManager");
_instance = audioManagerObject.AddComponent<OptimizedAudioManager>();
}
}
return _instance;
}
}
void Awake()
{
if (_instance == null)
{
_instance = this;
DontDestroyOnLoad(gameObject);
InitializeAudioSystem();
}
else if (_instance != this)
{
Destroy(gameObject);
}
}
private void InitializeAudioSystem()
{
// 初始化音频源池
InitializeAudioSourcePool();
// 构建音频剪辑缓存
BuildAudioClipCache();
}
// 初始化音频源池
private void InitializeAudioSourcePool()
{
for (int i = 0; i < audioSourcePoolSize; i++)
{
GameObject audioSourceGO = new GameObject($"AudioSource_{i}");
audioSourceGO.transform.SetParent(transform);
AudioSource audioSource = audioSourceGO.AddComponent<AudioSource>();
audioSource.playOnAwake = false;
audioSource.volume = 1f;
audioSource.pitch = 1f;
audioSource.loop = false;
audioSource.priority = 128; // 默认优先级
if (masterMixerGroup != null)
{
audioSource.outputAudioMixerGroup = masterMixerGroup;
}
audioSourcePool.Enqueue(audioSource);
}
}
// 构建音频剪辑缓存
private void BuildAudioClipCache()
{
// 缓存音乐剪辑
foreach (AudioClip clip in musicClips)
{
if (clip != null)
{
audioClipCache[$"Music_{clip.name}"] = clip;
if (!audioCategoryCache.ContainsKey("Music"))
{
audioCategoryCache["Music"] = new List<AudioClip>();
}
audioCategoryCache["Music"].Add(clip);
}
}
// 缓存音效剪辑
foreach (AudioClip clip in sfxClips)
{
if (clip != null)
{
audioClipCache[$"SFX_{clip.name}"] = clip;
if (!audioCategoryCache.ContainsKey("SFX"))
{
audioCategoryCache["SFX"] = new List<AudioClip>();
}
audioCategoryCache["SFX"].Add(clip);
}
}
// 缓存语音剪辑
foreach (AudioClip clip in voiceClips)
{
if (clip != null)
{
audioClipCache[$"Voice_{clip.name}"] = clip;
if (!audioCategoryCache.ContainsKey("Voice"))
{
audioCategoryCache["Voice"] = new List<AudioClip>();
}
audioCategoryCache["Voice"].Add(clip);
}
}
}
// 从池中获取音频源
private AudioSource GetAudioSourceFromPool()
{
AudioSource audioSource;
if (audioSourcePool.Count > 0)
{
audioSource = audioSourcePool.Dequeue();
audioSource.gameObject.SetActive(true);
}
else
{
// 如果池空了,创建新的音频源
GameObject audioSourceGO = new GameObject("AudioSource_Dynamic");
audioSourceGO.transform.SetParent(transform);
audioSource = audioSourceGO.AddComponent<AudioSource>();
if (masterMixerGroup != null)
{
audioSource.outputAudioMixerGroup = masterMixerGroup;
}
Debug.LogWarning("音频源池已空,创建动态音频源");
}
activeAudioSources.Add(audioSource);
return audioSource;
}
// 返回音频源到池中
private void ReturnAudioSourceToPool(AudioSource audioSource)
{
if (audioSource != null && activeAudioSources.Contains(audioSource))
{
audioSource.Stop();
audioSource.clip = null;
audioSource.loop = false;
audioSource.gameObject.SetActive(false);
audioSource.transform.SetParent(transform);
activeAudioSources.Remove(audioSource);
audioSourcePool.Enqueue(audioSource);
}
}
// 播放音乐
public void PlayMusic(string musicName, bool loop = true, float volume = -1f, float pitch = 1f)
{
string fullMusicName = $"Music_{musicName}";
if (audioClipCache.TryGetValue(fullMusicName, out AudioClip clip))
{
// 如果已经有音乐在播放,停止它
if (playingAudio.ContainsKey("CurrentMusic"))
{
StopAudio("CurrentMusic");
}
AudioSource audioSource = GetAudioSourceFromPool();
SetupAudioSource(audioSource, clip, loop, volume == -1f ? musicVolume : volume, pitch);
playingAudio["CurrentMusic"] = audioSource;
audioSource.Play();
}
else
{
Debug.LogWarning($"音乐剪辑 '{musicName}' 未找到");
}
}
// 播放音效
public void PlaySFX(string sfxName, Vector3? position = null, float volume = -1f, float pitch = 1f, bool use3D = true)
{
string fullSfxName = $"SFX_{sfxName}";
if (audioClipCache.TryGetValue(fullSfxName, out AudioClip clip))
{
AudioSource audioSource = GetAudioSourceFromPool();
if (position.HasValue && enable3DAudio && use3D)
{
// 3D音频设置
audioSource.spatialBlend = 1f;
audioSource.maxDistance = max3DDistance;
audioSource.rolloffMode = AudioRolloffMode.Logarithmic;
audioSource.transform.position = position.Value;
}
else
{
// 2D音频设置
audioSource.spatialBlend = 0f;
}
SetupAudioSource(audioSource, clip, false, volume == -1f ? sfxVolume : volume, pitch);
string audioKey = $"SFX_{sfxName}_{System.Guid.NewGuid()}";
playingAudio[audioKey] = audioSource;
audioSource.Play();
// 音效播放完成后自动返回池中
StartCoroutine(ReturnAudioSourceAfterPlay(audioSource, audioKey, clip.length));
}
else
{
Debug.LogWarning($"音效剪辑 '{sfxName}' 未找到");
}
}
// 播放语音
public void PlayVoice(string voiceName, float volume = -1f, float pitch = 1f)
{
string fullVoiceName = $"Voice_{voiceName}";
if (audioClipCache.TryGetValue(fullVoiceName, out AudioClip clip))
{
AudioSource audioSource = GetAudioSourceFromPool();
SetupAudioSource(audioSource, clip, false, volume == -1f ? voiceVolume : volume, pitch);
string audioKey = $"Voice_{voiceName}_{System.Guid.NewGuid()}";
playingAudio[audioKey] = audioSource;
audioSource.Play();
StartCoroutine(ReturnAudioSourceAfterPlay(audioSource, audioKey, clip.length));
}
else
{
Debug.LogWarning($"语音剪辑 '{voiceName}' 未找到");
}
}
// 设置音频源参数
private void SetupAudioSource(AudioSource audioSource, AudioClip clip, bool loop, float volume, float pitch)
{
audioSource.clip = clip;
audioSource.loop = loop;
audioSource.volume = volume * masterVolume;
audioSource.pitch = pitch;
audioSource.priority = 128;
}
// 播放完成后返回音频源到池
private IEnumerator ReturnAudioSourceAfterPlay(AudioSource audioSource, string audioKey, float clipLength)
{
yield return new WaitForSeconds(clipLength + 0.1f); // 额外等待0.1秒确保播放完成
if (playingAudio.ContainsKey(audioKey))
{
playingAudio.Remove(audioKey);
}
ReturnAudioSourceToPool(audioSource);
}
// 停止音频
public void StopAudio(string audioKey)
{
if (playingAudio.ContainsKey(audioKey))
{
AudioSource audioSource = playingAudio[audioKey];
if (audioSource != null)
{
audioSource.Stop();
// 根据音频类型决定是否返回池中
if (audioKey.StartsWith("SFX_") || audioKey.StartsWith("Voice_"))
{
ReturnAudioSourceToPool(audioSource);
}
else
{
// 音乐等持续播放的音频只停止,不返回池中
audioSource.clip = null;
}
}
playingAudio.Remove(audioKey);
}
}
// 暂停音频
public void PauseAudio(string audioKey)
{
if (playingAudio.ContainsKey(audioKey))
{
AudioSource audioSource = playingAudio[audioKey];
if (audioSource != null && audioSource.isPlaying)
{
audioSource.Pause();
}
}
}
// 恢复音频
public void ResumeAudio(string audioKey)
{
if (playingAudio.ContainsKey(audioKey))
{
AudioSource audioSource = playingAudio[audioKey];
if (audioSource != null)
{
audioSource.UnPause();
}
}
}
// 停止所有音频
public void StopAllAudio()
{
List<string> keysToStop = new List<string>(playingAudio.Keys);
foreach (string key in keysToStop)
{
StopAudio(key);
}
}
// 设置音量
public void SetMasterVolume(float volume)
{
masterVolume = Mathf.Clamp01(volume);
UpdateAllAudioVolumes();
}
public void SetMusicVolume(float volume)
{
musicVolume = Mathf.Clamp01(volume);
UpdateCategoryVolumes("Music");
}
public void SetSFXVolume(float volume)
{
sfxVolume = Mathf.Clamp01(volume);
UpdateCategoryVolumes("SFX");
}
public void SetVoiceVolume(float volume)
{
voiceVolume = Mathf.Clamp01(volume);
UpdateCategoryVolumes("Voice");
}
// 更新所有音频的音量
private void UpdateAllAudioVolumes()
{
foreach (var pair in playingAudio)
{
if (pair.Value != null)
{
if (pair.Key.StartsWith("CurrentMusic"))
{
pair.Value.volume = musicVolume * masterVolume;
}
else if (pair.Key.StartsWith("SFX_"))
{
pair.Value.volume = sfxVolume * masterVolume;
}
else if (pair.Key.StartsWith("Voice_"))
{
pair.Value.volume = voiceVolume * masterVolume;
}
}
}
}
// 更新特定类别的音量
private void UpdateCategoryVolumes(string category)
{
foreach (var pair in playingAudio)
{
if (pair.Key.Contains(category) && pair.Value != null)
{
float volume = 1f;
switch (category)
{
case "Music":
volume = musicVolume;
break;
case "SFX":
volume = sfxVolume;
break;
case "Voice":
volume = voiceVolume;
break;
}
pair.Value.volume = volume * masterVolume;
}
}
}
// 播放随机音效
public void PlayRandomSFX(string category, Vector3? position = null)
{
if (audioCategoryCache.TryGetValue(category, out List<AudioClip> clips))
{
if (clips.Count > 0)
{
AudioClip randomClip = clips[Random.Range(0, clips.Count)];
PlaySFX(randomClip.name, position);
}
}
}
// 音频池清理
void Update()
{
// 定期清理已完成的音频
List<string> completedAudio = new List<string>();
foreach (var pair in playingAudio)
{
if (pair.Value != null && !pair.Value.isPlaying)
{
completedAudio.Add(pair.Key);
}
}
foreach (string key in completedAudio)
{
if (key.StartsWith("SFX_") || key.StartsWith("Voice_"))
{
ReturnAudioSourceToPool(playingAudio[key]);
}
playingAudio.Remove(key);
}
}
void OnDestroy()
{
StopAllAudio();
}
}
音频事件系统
using UnityEngine;
// 音频事件处理器
public class AudioEventHandler : MonoBehaviour
{
[Header("音频事件设置")]
public string audioEventName;
public AudioEventType eventType = AudioEventType.SFX;
public bool playOnEnable = false;
public bool playOnStart = false;
public float delay = 0f;
void OnEnable()
{
if (playOnEnable)
{
Invoke("PlayAudioEvent", delay);
}
}
void Start()
{
if (playOnStart)
{
Invoke("PlayAudioEvent", delay);
}
}
public void PlayAudioEvent()
{
switch (eventType)
{
case AudioEventType.Music:
OptimizedAudioManager.Instance?.PlayMusic(audioEventName);
break;
case AudioEventType.SFX:
OptimizedAudioManager.Instance?.PlaySFX(audioEventName, transform.position);
break;
case AudioEventType.Voice:
OptimizedAudioManager.Instance?.PlayVoice(audioEventName);
break;
}
}
}
public enum AudioEventType
{
Music,
SFX,
Voice
}
// 音频区域触发器
public class AudioZone : MonoBehaviour
{
[Header("音频区域设置")]
public string musicName;
public float fadeDuration = 2f;
public bool loopMusic = true;
private bool playerInZone = false;
void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Player"))
{
playerInZone = true;
if (!string.IsNullOrEmpty(musicName))
{
OptimizedAudioManager.Instance?.PlayMusic(musicName, loopMusic);
}
}
}
void OnTriggerExit(Collider other)
{
if (other.CompareTag("Player"))
{
playerInZone = false;
// 可以在这里添加音乐淡出效果
}
}
}
// 音频混音器设置
public class AudioMixerController : MonoBehaviour
{
[Header("混音器设置")]
public string masterVolumeParameter = "MasterVolume";
public string musicVolumeParameter = "MusicVolume";
public string sfxVolumeParameter = "SFXVolume";
public string voiceVolumeParameter = "VoiceVolume";
private AudioMixer audioMixer;
void Start()
{
SetupAudioMixer();
}
private void SetupAudioMixer()
{
// 如果使用Unity的Audio Mixer,可以在这里设置参数
// audioMixer = Resources.Load<AudioMixer>("AudioMixer");
}
public void SetVolume(string parameter, float volume)
{
volume = Mathf.Clamp01(volume);
// 设置混音器参数
// if (audioMixer != null)
// {
// audioMixer.SetFloat(parameter, Mathf.Log10(volume) * 20);
// }
}
}
动画系统最佳实践
动画优化管理器
using UnityEngine;
using System.Collections.Generic;
// 优化的动画管理器
public class OptimizedAnimationManager : MonoBehaviour
{
[Header("动画系统设置")]
public bool enableAnimationCulling = true;
public bool enableAnimationOptimization = true;
public bool enableLODForAnimations = true;
public float animationCullDistance = 50f;
[Header("动画状态机优化")]
public bool enableStateCache = true;
public bool enableTransitionOptimization = true;
// 动画组件缓存
private Dictionary<GameObject, Animator> animatorCache = new Dictionary<GameObject, Animator>();
private Dictionary<Animator, AnimationStateCache> stateCache = new Dictionary<Animator, AnimationStateCache>();
// LOD系统
private Dictionary<Animator, AnimationLODData> lodData = new Dictionary<Animator, AnimationLODData>();
// 动画状态缓存
private class AnimationStateCache
{
public Dictionary<string, int> hashCache = new Dictionary<string, int>();
public Dictionary<int, string> nameCache = new Dictionary<int, string>();
public Dictionary<string, AnimatorStateInfo> stateInfoCache = new Dictionary<string, AnimatorStateInfo>();
}
private class AnimationLODData
{
public float distanceToCamera;
public int currentLOD;
public AnimationCullingType cullingType;
}
// 获取或创建动画器缓存
public Animator GetAnimator(GameObject go)
{
if (animatorCache.ContainsKey(go))
{
return animatorCache[go];
}
Animator animator = go.GetComponent<Animator>();
if (animator != null)
{
animatorCache[go] = animator;
if (enableStateCache)
{
stateCache[animator] = new AnimationStateCache();
}
if (enableLODForAnimations)
{
lodData[animator] = new AnimationLODData();
}
}
return animator;
}
// 优化的动画播放
public void PlayAnimation(Animator animator, string animationName, int layer = 0, float transitionDuration = 0.25f)
{
if (animator == null || string.IsNullOrEmpty(animationName)) return;
// 使用哈希值而不是字符串进行动画播放(性能更好)
int animationHash = GetAnimationHash(animator, animationName);
if (enableTransitionOptimization)
{
// 使用平滑过渡
animator.CrossFade(animationHash, transitionDuration, layer);
}
else
{
// 直接播放
animator.Play(animationHash, layer);
}
}
// 获取动画哈希值(带缓存)
private int GetAnimationHash(Animator animator, string animationName)
{
if (enableStateCache && stateCache.ContainsKey(animator))
{
AnimationStateCache cache = stateCache[animator];
if (cache.hashCache.ContainsKey(animationName))
{
return cache.hashCache[animationName];
}
else
{
int hash = Animator.StringToHash(animationName);
cache.hashCache[animationName] = hash;
cache.nameCache[hash] = animationName;
return hash;
}
}
return Animator.StringToHash(animationName);
}
// 获取动画状态信息(带缓存)
public AnimatorStateInfo GetStateInfo(Animator animator, string animationName, int layer = 0)
{
if (enableStateCache && stateCache.ContainsKey(animator))
{
AnimationStateCache cache = stateCache[animator];
string key = $"{animationName}_{layer}";
if (cache.stateInfoCache.ContainsKey(key))
{
return cache.stateInfoCache[key];
}
else
{
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(layer);
cache.stateInfoCache[key] = stateInfo;
return stateInfo;
}
}
return animator.GetCurrentAnimatorStateInfo(layer);
}
// 动画剔除系统
void Update()
{
if (enableAnimationCulling)
{
CullDistantAnimations();
}
if (enableLODForAnimations)
{
UpdateAnimationLOD();
}
// 清理状态缓存
if (enableStateCache)
{
CleanupStateCache();
}
}
// 剔除远处的动画
private void CullDistantAnimations()
{
Camera mainCamera = Camera.main;
if (mainCamera == null) return;
foreach (var pair in animatorCache)
{
Animator animator = pair.Value;
if (animator != null)
{
float distance = Vector3.Distance(mainCamera.transform.position, animator.transform.position);
if (distance > animationCullDistance)
{
// 对远处的对象使用更简单的动画更新模式
animator.updateMode = AnimatorUpdateMode.UnscaledTime; // 或其他优化模式
animator.cullingMode = AnimatorCullingMode.CullCompletely;
}
else
{
// 近处对象使用正常模式
animator.cullingMode = AnimatorCullingMode.AlwaysAnimate;
}
}
}
}
// 更新动画LOD
private void UpdateAnimationLOD()
{
Camera mainCamera = Camera.main;
if (mainCamera == null) return;
foreach (var pair in lodData)
{
Animator animator = pair.Key;
AnimationLODData lod = pair.Value;
if (animator != null)
{
lod.distanceToCamera = Vector3.Distance(mainCamera.transform.position, animator.transform.position);
// 根据距离设置LOD级别
if (lod.distanceToCamera < 10f)
{
lod.currentLOD = 2; // 高质量
lod.cullingType = AnimationCullingType.AlwaysAnimate;
}
else if (lod.distanceToCamera < 30f)
{
lod.currentLOD = 1; // 中等质量
lod.cullingType = AnimationCullingType.BasedOnRenderers;
}
else
{
lod.currentLOD = 0; // 低质量
lod.cullingType = AnimationCullingType.CullCompletely;
}
animator.cullingMode = (AnimatorCullingMode)lod.cullingType;
}
}
}
// 清理状态缓存
private void CleanupStateCache()
{
// 定期清理状态缓存以避免内存泄漏
// 这里可以实现缓存过期机制
}
// 优化的动画参数设置
public void SetAnimationParameter(Animator animator, string paramName, object value)
{
if (animator == null) return;
int paramHash = Animator.StringToHash(paramName);
if (value is bool boolValue)
{
animator.SetBool(paramHash, boolValue);
}
else if (value is int intValue)
{
animator.SetInteger(paramHash, intValue);
}
else if (value is float floatValue)
{
animator.SetFloat(paramHash, floatValue);
}
else if (value is string stringValue)
{
// 触发器参数
animator.SetTrigger(Animator.StringToHash(stringValue));
}
}
// 批量动画更新
public void BatchUpdateAnimations(List<Animator> animators, System.Action<Animator> updateAction)
{
foreach (Animator animator in animators)
{
if (animator != null && animator.isActiveAndEnabled)
{
updateAction?.Invoke(animator);
}
}
}
}
// 动画事件优化
public class OptimizedAnimationEvents : MonoBehaviour
{
[Header("事件优化设置")]
public bool enableEventPooling = true;
public bool enableEventThrottling = true;
public float eventThrottleInterval = 0.1f;
private Dictionary<string, float> lastEventTime = new Dictionary<string, float>();
private Queue<string> eventPool = new Queue<string>();
// 优化的动画事件处理器
public void OnAnimationEvent(string eventName)
{
if (enableEventThrottling)
{
if (!CanProcessEvent(eventName))
{
return; // 事件被节流
}
}
// 处理动画事件
ProcessAnimationEvent(eventName);
}
// 检查是否可以处理事件
private bool CanProcessEvent(string eventName)
{
float currentTime = Time.unscaledTime;
if (lastEventTime.ContainsKey(eventName))
{
if (currentTime - lastEventTime[eventName] >= eventThrottleInterval)
{
lastEventTime[eventName] = currentTime;
return true;
}
return false;
}
else
{
lastEventTime[eventName] = currentTime;
return true;
}
}
// 处理动画事件
private void ProcessAnimationEvent(string eventName)
{
switch (eventName)
{
case "Footstep":
PlayFootstepSound();
break;
case "Attack":
PerformAttack();
break;
case "Land":
HandleLanding();
break;
case "Jump":
HandleJump();
break;
default:
Debug.Log($"处理动画事件: {eventName}");
break;
}
}
private void PlayFootstepSound()
{
// 播放脚步声
OptimizedAudioManager.Instance?.PlaySFX("Footstep", transform.position);
}
private void PerformAttack()
{
// 执行攻击逻辑
Collider[] hitColliders = Physics.OverlapSphere(
transform.position + transform.forward * 1f,
1f
);
foreach (Collider collider in hitColliders)
{
if (collider.CompareTag("Enemy"))
{
// 对敌人造成伤害
}
}
}
private void HandleLanding()
{
// 处理着陆
OptimizedAudioManager.Instance?.PlaySFX("Land", transform.position);
}
private void HandleJump()
{
// 处理跳跃
OptimizedAudioManager.Instance?.PlaySFX("Jump", transform.position);
}
}
高级动画控制
using UnityEngine;
// 高级动画控制器
[RequireComponent(typeof(Animator))]
public class AdvancedAnimationController : MonoBehaviour
{
[Header("根运动设置")]
public bool useRootMotion = false;
public bool enableRootMotionOptimization = true;
[Header("动画层设置")]
public AnimationLayer[] animationLayers = new AnimationLayer[0];
[Header("混合树设置")]
public bool enableBlendTrees = true;
public AnimationBlendTree[] blendTrees = new AnimationBlendTree[0];
[Header("动画压缩")]
public bool enableAnimationCompression = true;
public AnimationCompressionType compressionType = AnimationCompressionType.Optimal;
private Animator animator;
private AnimationCurve speedCurve = AnimationCurve.Linear(0, 0, 1, 1);
private float currentSpeed = 0f;
private float targetSpeed = 0f;
private float speedSmoothTime = 0.1f;
private float currentDirection = 0f;
[System.Serializable]
public class AnimationLayer
{
public string layerName;
public int layerIndex;
public float weight = 1f;
public bool enableIK = false;
public float ikWeight = 1f;
}
[System.Serializable]
public class AnimationBlendTree
{
public string treeName;
public BlendTreeType treeType;
public string parameterName;
public AnimationClip[] childAnimations;
public float[] childThresholds;
}
void Start()
{
animator = GetComponent<Animator>();
if (animator != null)
{
animator.applyRootMotion = useRootMotion;
// 设置动画压缩
if (enableAnimationCompression)
{
animator.runtimeAnimatorController.animationClips[0].compression = compressionType;
}
}
}
void Update()
{
UpdateAnimationLayers();
UpdateBlendTrees();
UpdateRootMotion();
}
// 更新动画层
private void UpdateAnimationLayers()
{
if (animator == null) return;
foreach (AnimationLayer layer in animationLayers)
{
if (layer.layerIndex < animator.layerCount)
{
animator.SetLayerWeight(layer.layerIndex, layer.weight);
if (layer.enableIK)
{
animator.SetIKPositionWeight(AvatarIKGoal.LeftFoot, layer.ikWeight);
animator.SetIKPositionWeight(AvatarIKGoal.RightFoot, layer.ikWeight);
}
}
}
}
// 更新混合树
private void UpdateBlendTrees()
{
if (!enableBlendTrees || animator == null) return;
foreach (AnimationBlendTree tree in blendTrees)
{
switch (tree.treeType)
{
case BlendTreeType.Simple1D:
// 1D混合树
if (tree.childThresholds.Length > 0)
{
float normalizedSpeed = Mathf.Clamp01(currentSpeed / tree.childThresholds[tree.childThresholds.Length - 1]);
animator.SetFloat(tree.parameterName, normalizedSpeed);
}
break;
case BlendTreeType.SimpleDirectional2D:
// 2D方向混合树
animator.SetFloat("BlendX", currentDirection);
animator.SetFloat("BlendY", currentSpeed);
break;
}
}
}
// 更新根运动
private void UpdateRootMotion()
{
if (!enableRootMotionOptimization || animator == null) return;
// 优化根运动性能
if (useRootMotion)
{
// 可以在这里添加根运动的优化逻辑
// 例如:限制根运动对物理的影响
}
}
// 设置动画速度
public void SetAnimationSpeed(float speed, int layer = 0)
{
targetSpeed = speed;
currentSpeed = Mathf.SmoothDamp(currentSpeed, targetSpeed, ref speedSmoothTime, 0.1f);
if (animator != null)
{
animator.SetFloat("Speed", currentSpeed);
}
}
// 设置动画方向
public void SetAnimationDirection(float direction)
{
currentDirection = direction;
if (animator != null)
{
animator.SetFloat("Direction", currentDirection);
}
}
// 触发动画事件
public void TriggerAnimationEvent(string eventName, int layer = 0)
{
if (animator != null)
{
animator.SetTrigger(eventName);
}
}
// 设置动画参数
public void SetAnimationParameter(string paramName, float value)
{
if (animator != null)
{
animator.SetFloat(Animator.StringToHash(paramName), value);
}
}
public void SetAnimationParameter(string paramName, bool value)
{
if (animator != null)
{
animator.SetBool(Animator.StringToHash(paramName), value);
}
}
public void SetAnimationParameter(string paramName, int value)
{
if (animator != null)
{
animator.SetInteger(Animator.StringToHash(paramName), value);
}
}
// 检查动画状态
public bool IsInAnimationState(string stateName, int layer = 0)
{
if (animator == null) return false;
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(layer);
return stateInfo.IsName(stateName);
}
// 等待动画状态完成
public System.Collections.IEnumerator WaitForAnimationState(string stateName, int layer = 0)
{
while (!IsInAnimationState(stateName, layer))
{
yield return null;
}
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(layer);
while (stateInfo.normalizedTime < 1.0f)
{
yield return null;
stateInfo = animator.GetCurrentAnimatorStateInfo(layer);
}
}
// 动画中断系统
public void InterruptAnimation(string currentAnimation, string newAnimation)
{
if (animator != null)
{
// 检查当前动画是否可以被中断
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);
// 某些动画状态可能不允许中断(如攻击动画的特定阶段)
if (CanInterruptAnimation(stateInfo))
{
PlayAnimation(newAnimation);
}
}
}
private bool CanInterruptAnimation(AnimatorStateInfo stateInfo)
{
// 根据动画状态决定是否可以中断
// 例如:攻击动画的前20%可能不允许中断
return stateInfo.normalizedTime > 0.2f || stateInfo.IsTag("Interruptible");
}
private void PlayAnimation(string animationName)
{
if (animator != null)
{
animator.CrossFade(Animator.StringToHash(animationName), 0.2f);
}
}
// 动画同步
public void SyncAnimationWith(AdvancedAnimationController otherController, string parameterName)
{
if (otherController != null && animator != null)
{
float otherValue = otherController.GetAnimationParameter<float>(parameterName);
SetAnimationParameter(parameterName, otherValue);
}
}
public T GetAnimationParameter<T>(string parameterName)
{
if (animator == null) return default(T);
int paramHash = Animator.StringToHash(parameterName);
if (typeof(T) == typeof(float))
{
return (T)(object)animator.GetFloat(paramHash);
}
else if (typeof(T) == typeof(int))
{
return (T)(object)animator.GetInteger(paramHash);
}
else if (typeof(T) == typeof(bool))
{
return (T)(object)animator.GetBool(paramHash);
}
return default(T);
}
// 动画性能监控
public AnimationPerformanceData GetAnimationPerformanceData()
{
return new AnimationPerformanceData
{
isOptimized = true,
layerCount = animator != null ? animator.layerCount : 0,
currentAnimation = animator != null ?
animator.GetCurrentAnimatorStateInfo(0).IsName("Unknown") ? "Unknown" :
GetAnimationName(animator.GetCurrentAnimatorStateInfo(0).fullPathHash) : "No Animator",
updateMode = animator != null ? animator.updateMode : AnimatorUpdateMode.Normal
};
}
private string GetAnimationName(int hash)
{
// 这里需要实现哈希到动画名称的映射
// Unity不直接提供这个功能,需要自己维护映射表
return "Animation_" + hash;
}
}
[System.Serializable]
public class AnimationPerformanceData
{
public bool isOptimized;
public int layerCount;
public string currentAnimation;
public AnimatorUpdateMode updateMode;
}
public enum BlendTreeType
{
Simple1D,
SimpleDirectional2D,
FreeformDirectional2D,
FreeformCartesian2D,
Direct
}
测试和调试最佳实践
单元测试框架
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
// Unity单元测试框架
public class UnityUnitTestFramework : MonoBehaviour
{
[Header("测试设置")]
public bool runTestsOnStart = true;
public bool logTestResults = true;
public bool stopOnFirstFailure = false;
private List<TestCase> testCases = new List<TestCase>();
private int totalTests = 0;
private int passedTests = 0;
private int failedTests = 0;
private List<string> testFailures = new List<string>();
void Start()
{
if (runTestsOnStart)
{
RunAllTests();
}
}
// 定义测试用例
[System.Serializable]
public class TestCase
{
public string testName;
public System.Func<bool> testFunction;
public string expectedBehavior;
public string category = "General";
public bool enabled = true;
}
// 添加测试用例
public void AddTest(string name, System.Func<bool> testFunc, string expected = "", string category = "General")
{
TestCase testCase = new TestCase
{
testName = name,
testFunction = testFunc,
expectedBehavior = expected,
category = category,
enabled = true
};
testCases.Add(testCase);
totalTests++;
}
// 运行所有测试
public void RunAllTests()
{
Debug.Log($"开始运行 {testCases.Count} 个测试...");
foreach (TestCase testCase in testCases)
{
if (!testCase.enabled) continue;
RunSingleTest(testCase);
if (stopOnFirstFailure && failedTests > 0)
{
break;
}
}
LogTestSummary();
}
// 运行单个测试
private void RunSingleTest(TestCase testCase)
{
try
{
bool result = testCase.testFunction();
if (result)
{
passedTests++;
if (logTestResults)
{
Debug.Log($"✅ 测试通过: {testCase.testName}");
}
}
else
{
failedTests++;
string failureMessage = $"❌ 测试失败: {testCase.testName} - 期望: {testCase.expectedBehavior}";
testFailures.Add(failureMessage);
if (logTestResults)
{
Debug.LogError(failureMessage);
}
}
}
catch (System.Exception e)
{
failedTests++;
string failureMessage = $"❌ 测试异常: {testCase.testName} - 错误: {e.Message}";
testFailures.Add(failureMessage);
if (logTestResults)
{
Debug.LogError(failureMessage);
}
}
}
// 断言方法
public static bool AssertTrue(bool condition, string message = "条件应为真")
{
if (!condition)
{
Debug.LogError($"断言失败: {message}");
return false;
}
return true;
}
public static bool AssertFalse(bool condition, string message = "条件应为假")
{
if (condition)
{
Debug.LogError($"断言失败: {message}");
return false;
}
return true;
}
public static bool AssertEqual<T>(T actual, T expected, string message = "")
{
bool isEqual = EqualityComparer<T>.Default.Equals(actual, expected);
if (!isEqual)
{
Debug.LogError($"断言失败: {message} - 实际: {actual}, 期望: {expected}");
return false;
}
return true;
}
public static bool AssertNotEqual<T>(T actual, T expected, string message = "")
{
bool isNotEqual = !EqualityComparer<T>.Default.Equals(actual, expected);
if (!isNotEqual)
{
Debug.LogError($"断言失败: {message} - 实际和期望相等: {actual}");
return false;
}
return true;
}
public static bool AssertNull(object obj, string message = "对象应为null")
{
if (obj != null)
{
Debug.LogError($"断言失败: {message} - 对象不为null: {obj}");
return false;
}
return true;
}
public static bool AssertNotNull(object obj, string message = "对象不应为null")
{
if (obj == null)
{
Debug.LogError($"断言失败: {message}");
return false;
}
return true;
}
// 浮点数断言(考虑误差)
public static bool AssertFloatEqual(float actual, float expected, float tolerance = 0.001f, string message = "")
{
bool isEqual = Mathf.Abs(actual - expected) <= tolerance;
if (!isEqual)
{
Debug.LogError($"断言失败: {message} - 实际: {actual}, 期望: {expected}, 容差: {tolerance}");
return false;
}
return true;
}
// 向量断言
public static bool AssertVector3Equal(Vector3 actual, Vector3 expected, float tolerance = 0.001f, string message = "")
{
bool isEqual = Vector3.Distance(actual, expected) <= tolerance;
if (!isEqual)
{
Debug.LogError($"断言失败: {message} - 实际: {actual}, 期望: {expected}, 距离: {Vector3.Distance(actual, expected)}");
return false;
}
return true;
}
// 记录测试摘要
private void LogTestSummary()
{
string summary = $@"
=== 测试摘要 ===
总测试数: {totalTests}
通过: {passedTests}
失败: {failedTests}
成功率: {(totalTests > 0 ? (float)passedTests / totalTests * 100 : 0):F2}%
";
if (failedTests > 0)
{
summary += "\n失败详情:\n";
foreach (string failure in testFailures)
{
summary += $" {failure}\n";
}
}
Debug.Log(summary);
}
// 清理测试结果
public void ClearTestResults()
{
totalTests = 0;
passedTests = 0;
failedTests = 0;
testFailures.Clear();
testCases.Clear();
}
// 按类别运行测试
public void RunTestsByCategory(string category)
{
List<TestCase> categoryTests = testCases.FindAll(tc => tc.category == category);
Debug.Log($"运行 {category} 类别的 {categoryTests.Count} 个测试...");
foreach (TestCase testCase in categoryTests)
{
RunSingleTest(testCase);
if (stopOnFirstFailure && failedTests > 0)
{
break;
}
}
LogTestSummary();
}
// 异步测试支持
public IEnumerator RunAsyncTest(System.Func<IEnumerator> asyncTest, string testName)
{
yield return StartCoroutine(asyncTest());
// 测试完成后验证结果
// 这里可以根据需要添加验证逻辑
Debug.Log($"异步测试完成: {testName}");
}
}
// 测试示例
public class TestExample : MonoBehaviour
{
private UnityUnitTestFramework testFramework;
void Start()
{
testFramework = gameObject.AddComponent<UnityUnitTestFramework>();
// 添加测试用例
testFramework.AddTest("测试加法运算", TestAddition, "2 + 2 应该等于 4");
testFramework.AddTest("测试字符串比较", TestStringComparison, "字符串比较应该区分大小写");
testFramework.AddTest("测试向量运算", TestVectorOperations, "向量长度应该正确计算");
// 运行测试
testFramework.RunAllTests();
}
bool TestAddition()
{
int result = 2 + 2;
return UnityUnitTestFramework.AssertEqual(result, 4, "加法运算结果不正确");
}
bool TestStringComparison()
{
string str1 = "Hello";
string str2 = "hello";
return UnityUnitTestFramework.AssertNotEqual(str1, str2, "字符串比较应该区分大小写");
}
bool TestVectorOperations()
{
Vector3 v1 = new Vector3(3, 4, 0);
float magnitude = v1.magnitude;
return UnityUnitTestFramework.AssertFloatEqual(magnitude, 5f, 0.001f, "向量长度计算错误");
}
}
调试工具集
using UnityEngine;
using System.Collections.Generic;
using System.Text;
// 高级调试工具集
public class AdvancedDebugTools : MonoBehaviour
{
[Header("调试设置")]
public bool enableDebugGUI = true;
public bool enablePerformanceMonitor = true;
public bool enableSceneDebugger = true;
public bool enableMemoryProfiler = true;
[Header("调试选项")]
public KeyCode debugToggleKey = KeyCode.F1;
public KeyCode performanceToggleKey = KeyCode.F2;
public KeyCode sceneDebuggerKey = KeyCode.F3;
[Header("性能监控")]
public float monitorInterval = 1f;
public int frameSampleCount = 60;
private bool isDebugActive = false;
private bool isPerformanceMonitorActive = false;
private bool isSceneDebuggerActive = false;
private float lastMonitorTime = 0f;
private List<float> frameTimes = new List<float>();
private int frameCounter = 0;
private float totalTime = 0f;
void Update()
{
HandleDebugInput();
UpdatePerformanceMonitor();
}
// 处理调试输入
private void HandleDebugInput()
{
if (Input.GetKeyDown(debugToggleKey))
{
isDebugActive = !isDebugActive;
}
if (Input.GetKeyDown(performanceToggleKey))
{
isPerformanceMonitorActive = !isPerformanceMonitorActive;
}
if (Input.GetKeyDown(sceneDebuggerKey))
{
isSceneDebuggerActive = !isSceneDebuggerActive;
}
}
// 更新性能监控
private void UpdatePerformanceMonitor()
{
if (enablePerformanceMonitor && isPerformanceMonitorActive)
{
float frameTime = Time.unscaledDeltaTime;
frameTimes.Add(frameTime);
if (frameTimes.Count > frameSampleCount)
{
frameTimes.RemoveAt(0);
}
frameCounter++;
totalTime += frameTime;
if (Time.time - lastMonitorTime >= monitorInterval)
{
LogPerformanceData();
lastMonitorTime = Time.time;
}
}
}
// 记录性能数据
private void LogPerformanceData()
{
if (frameTimes.Count == 0) return;
float avgFrameTime = totalTime / frameCounter;
float avgFPS = 1.0f / avgFrameTime;
float minFrameTime = float.MaxValue;
float maxFrameTime = float.MinValue;
foreach (float frameTime in frameTimes)
{
if (frameTime < minFrameTime) minFrameTime = frameTime;
if (frameTime > maxFrameTime) maxFrameTime = frameTime;
}
float minFPS = 1.0f / maxFrameTime;
float maxFPS = 1.0f / minFrameTime;
string performanceData = $@"
性能数据 ({monitorInterval}秒间隔):
平均FPS: {avgFPS:F1}
最低FPS: {minFPS:F1}
最高FPS: {maxFPS:F1}
平均帧时间: {avgFrameTime * 1000:F1}ms
帧时间范围: {minFrameTime * 1000:F1}ms - {maxFrameTime * 1000:F1}ms
总帧数: {frameCounter}
";
Debug.Log(performanceData);
// 重置计数器
frameCounter = 0;
totalTime = 0f;
}
// 场景调试器
public void SceneDebug()
{
if (!enableSceneDebugger) return;
StringBuilder sceneInfo = new StringBuilder();
sceneInfo.AppendLine("=== 场景信息 ===");
// 游戏对象统计
GameObject[] allObjects = FindObjectsOfType<GameObject>();
int activeObjects = 0;
int inactiveObjects = 0;
foreach (GameObject go in allObjects)
{
if (go.activeSelf) activeObjects++;
else inactiveObjects++;
}
sceneInfo.AppendLine($"总游戏对象: {allObjects.Length}");
sceneInfo.AppendLine($"活跃对象: {activeObjects}");
sceneInfo.AppendLine($"非活跃对象: {inactiveObjects}");
// 组件统计
int totalComponents = 0;
Dictionary<string, int> componentCounts = new Dictionary<string, int>();
foreach (GameObject go in allObjects)
{
Component[] components = go.GetComponents<Component>();
totalComponents += components.Length;
foreach (Component comp in components)
{
if (comp != null)
{
string compType = comp.GetType().Name;
if (componentCounts.ContainsKey(compType))
{
componentCounts[compType]++;
}
else
{
componentCounts[compType] = 1;
}
}
}
}
sceneInfo.AppendLine($"总组件数: {totalComponents}");
sceneInfo.AppendLine("组件分布:");
foreach (var kvp in componentCounts)
{
sceneInfo.AppendLine($" {kvp.Key}: {kvp.Value}");
}
// 物理统计
int rigidbodyCount = FindObjectsOfType<Rigidbody>().Length;
int colliderCount = FindObjectsOfType<Collider>().Length;
int triggerCount = 0;
Collider[] allColliders = FindObjectsOfType<Collider>();
foreach (Collider col in allColliders)
{
if (col.isTrigger) triggerCount++;
}
sceneInfo.AppendLine($"刚体数量: {rigidbodyCount}");
sceneInfo.AppendLine($"碰撞体数量: {colliderCount}");
sceneInfo.AppendLine($"触发器数量: {triggerCount}");
Debug.Log(sceneInfo.ToString());
}
// 内存分析器
public void MemoryAnalysis()
{
if (!enableMemoryProfiler) return;
StringBuilder memoryInfo = new StringBuilder();
memoryInfo.AppendLine("=== 内存分析 ===");
// GC内存
long gcMemory = System.GC.GetTotalMemory(false);
memoryInfo.AppendLine($"GC内存使用: {FormatBytes(gcMemory)}");
// Unity内存
long unityAllocated = UnityEngine.Profiling.Profiler.GetTotalAllocatedMemoryLong();
long unityReserved = UnityEngine.Profiling.Profiler.GetTotalReservedMemoryLong();
long unityPeak = UnityEngine.Profiling.Profiler.GetPeakAllocatedMemoryLong();
memoryInfo.AppendLine($"Unity分配内存: {FormatBytes(unityAllocated)}");
memoryInfo.AppendLine($"Unity保留内存: {FormatBytes(unityReserved)}");
memoryInfo.AppendLine($"Unity峰值内存: {FormatBytes(unityPeak)}");
// GC统计
memoryInfo.AppendLine($"GC次数 (0/1/2): {System.GC.CollectionCount(0)}/{System.GC.CollectionCount(1)}/{System.GC.CollectionCount(2)}");
// 资源统计
Object[] allObjects = Resources.FindObjectsOfTypeAll<Object>();
int assetObjects = 0;
int sceneObjects = 0;
foreach (Object obj in allObjects)
{
string resourcePath = UnityEditor.AssetDatabase.GetAssetPath(obj);
if (string.IsNullOrEmpty(resourcePath))
{
sceneObjects++;
}
else
{
assetObjects++;
}
}
memoryInfo.AppendLine($"资源对象: {assetObjects}");
memoryInfo.AppendLine($"场景对象: {sceneObjects}");
memoryInfo.AppendLine($"总对象数: {allObjects.Length}");
Debug.Log(memoryInfo.ToString());
}
// 格式化字节数
private string FormatBytes(long bytes)
{
string[] suffixes = { "B", "KB", "MB", "GB", "TB" };
int counter = 0;
decimal number = (decimal)bytes;
while (Math.Abs(number) >= 1024m && counter < suffixes.Length - 1)
{
counter++;
number /= 1024m;
}
return string.Format("{0:n1} {1}", number, suffixes[counter]);
}
// 性能分析器
public class PerformanceAnalyzer
{
private Dictionary<string, List<float>> methodTimings = new Dictionary<string, List<float>>();
private Dictionary<string, float> methodTotalTime = new Dictionary<string, float>();
private Dictionary<string, int> methodCallCount = new Dictionary<string, int>();
public void StartMethodTiming(string methodName)
{
if (!methodTotalTime.ContainsKey(methodName))
{
methodTotalTime[methodName] = 0f;
methodCallCount[methodName] = 0;
}
}
public void EndMethodTiming(string methodName, float duration)
{
if (methodTimings.ContainsKey(methodName))
{
methodTimings[methodName].Add(duration);
}
else
{
methodTimings[methodName] = new List<float> { duration };
}
methodTotalTime[methodName] += duration;
methodCallCount[methodName]++;
}
public PerformanceReport GenerateReport()
{
PerformanceReport report = new PerformanceReport();
foreach (var kvp in methodTotalTime)
{
string methodName = kvp.Key;
float totalTime = kvp.Value;
int callCount = methodCallCount[methodName];
if (callCount > 0)
{
float avgTime = totalTime / callCount;
float minTime = float.MaxValue;
float maxTime = float.MinValue;
if (methodTimings.ContainsKey(methodName))
{
foreach (float time in methodTimings[methodName])
{
if (time < minTime) minTime = time;
if (time > maxTime) maxTime = time;
}
}
report.AddMethodReport(methodName, totalTime, callCount, avgTime, minTime, maxTime);
}
}
return report;
}
}
[System.Serializable]
public class PerformanceReport
{
public List<MethodPerformanceData> methodReports = new List<MethodPerformanceData>();
public void AddMethodReport(string methodName, float totalTime, int callCount, float avgTime, float minTime, float maxTime)
{
methodReports.Add(new MethodPerformanceData
{
methodName = methodName,
totalTime = totalTime,
callCount = callCount,
averageTime = avgTime,
minTime = minTime,
maxTime = maxTime
});
}
public void LogReport()
{
StringBuilder report = new StringBuilder();
report.AppendLine("=== 性能分析报告 ===");
// 按总时间排序
methodReports.Sort((a, b) => b.totalTime.CompareTo(a.totalTime));
foreach (MethodPerformanceData data in methodReports)
{
report.AppendLine($"{data.methodName}:");
report.AppendLine($" 总时间: {data.totalTime * 1000:F2}ms");
report.AppendLine($" 调用次数: {data.callCount}");
report.AppendLine($" 平均时间: {data.averageTime * 1000:F3}ms");
report.AppendLine($" 最小时间: {data.minTime * 1000:F3}ms");
report.AppendLine($" 最大时间: {data.maxTime * 1000:F3}ms");
report.AppendLine($" 每次调用平均: {(data.totalTime / data.callCount) * 1000:F3}ms");
report.AppendLine();
}
Debug.Log(report.ToString());
}
}
[System.Serializable]
public class MethodPerformanceData
{
public string methodName;
public float totalTime;
public int callCount;
public float averageTime;
public float minTime;
public float maxTime;
}
// 调试GUI
void OnGUI()
{
if (!enableDebugGUI || !isDebugActive) return;
// 创建调试窗口
GUILayout.BeginArea(new Rect(10, 10, 300, 400));
GUILayout.Box("调试工具");
if (GUILayout.Button("场景调试"))
{
SceneDebug();
}
if (GUILayout.Button("内存分析"))
{
MemoryAnalysis();
}
if (GUILayout.Button($"性能监控: {(isPerformanceMonitorActive ? "开启" : "关闭")}"))
{
isPerformanceMonitorActive = !isPerformanceMonitorActive;
}
if (GUILayout.Button($"场景调试器: {(isSceneDebuggerActive ? "开启" : "关闭")}"))
{
isSceneDebuggerActive = !isSceneDebuggerActive;
}
// 显示当前性能数据
if (frameTimes.Count > 0)
{
float currentFPS = 1.0f / Time.unscaledDeltaTime;
GUILayout.Label($"当前FPS: {currentFPS:F1}");
GUILayout.Label($"平均FPS: {(frameTimes.Count > 0 ? 1.0f / (totalTime / frameCounter) : 0):F1}");
}
GUILayout.EndArea();
}
// 对象引用分析器
public void AnalyzeObjectReferences()
{
StringBuilder analysis = new StringBuilder();
analysis.AppendLine("=== 对象引用分析 ===");
// 分析特定类型的对象
GameObject[] gameObjects = FindObjectsOfType<GameObject>();
Dictionary<string, int> tagCounts = new Dictionary<string, int>();
Dictionary<string, int> componentCounts = new Dictionary<string, int>();
foreach (GameObject go in gameObjects)
{
// 统计标签
if (tagCounts.ContainsKey(go.tag))
{
tagCounts[go.tag]++;
}
else
{
tagCounts[go.tag] = 1;
}
// 统计组件
Component[] components = go.GetComponents<Component>();
foreach (Component comp in components)
{
if (comp != null)
{
string compType = comp.GetType().Name;
if (componentCounts.ContainsKey(compType))
{
componentCounts[compType]++;
}
else
{
componentCounts[compType] = 1;
}
}
}
}
analysis.AppendLine("标签统计:");
foreach (var kvp in tagCounts)
{
analysis.AppendLine($" {kvp.Key}: {kvp.Value}");
}
analysis.AppendLine("\n组件统计 (前10):");
var sortedComponents = new List<KeyValuePair<string, int>>(componentCounts);
sortedComponents.Sort((pair1, pair2) => pair2.Value.CompareTo(pair1.Value));
int count = 0;
foreach (var kvp in sortedComponents)
{
if (count++ >= 10) break;
analysis.AppendLine($" {kvp.Key}: {kvp.Value}");
}
Debug.Log(analysis.ToString());
}
}
发布和部署最佳实践
构建优化
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
// 构建优化管理器
public class BuildOptimizationManager : MonoBehaviour
{
[Header("构建优化设置")]
public BuildTarget targetPlatform = BuildTarget.StandaloneWindows64;
public bool enableStripping = true;
public bool enableCompression = true;
public bool enableAssetBundles = true;
public bool enableAddressables = false;
[Header("代码优化")]
public bool enableScriptStripping = true;
public bool enableManagedStripping = true;
public ManagedStrippingLevel managedStrippingLevel = ManagedStrippingLevel.Medium;
[Header("图形优化")]
public bool enableStaticBatching = true;
public bool enableDynamicBatching = true;
public bool enableOcclusionCulling = true;
public bool enableLODs = true;
[Header("音频优化")]
public bool enableAudioCompression = true;
public AudioCompressionFormat audioCompressionFormat = AudioCompressionFormat.Vorbis;
public int audioSampleRateSetting = 0; // 0 = Preserve Sample Rate
[Header("纹理优化")]
public bool enableTextureCompression = true;
public TextureFormat textureFormat = TextureFormat.RGBA32;
public int maxTextureSize = 2048;
// 应用构建优化设置
[ContextMenu("应用构建优化设置")]
public void ApplyBuildOptimizations()
{
#if UNITY_EDITOR
// 应用图形设置优化
ApplyGraphicsOptimizations();
// 应用音频设置优化
ApplyAudioOptimizations();
// 应用纹理设置优化
ApplyTextureOptimizations();
// 应用Player设置优化
ApplyPlayerOptimizations();
Debug.Log("构建优化设置已应用");
#endif
}
// 应用图形优化
private void ApplyGraphicsOptimizations()
{
#if UNITY_EDITOR
PlayerSettings.batching = enableStaticBatching ?
PlayerSettings.batching | BatchMode.CombineMeshesStatic :
PlayerSettings.batching & ~BatchMode.CombineMeshesStatic;
PlayerSettings.batching = enableDynamicBatching ?
PlayerSettings.batching | BatchMode.CombineMeshesDynamic :
PlayerSettings.batching & ~BatchMode.CombineMeshesDynamic;
PlayerSettings.usePlayerLog = false; // 减少日志开销
PlayerSettings.stripUnusedMeshComponents = true; // 移除未使用的网格组件
#endif
}
// 应用音频优化
private void ApplyAudioOptimizations()
{
#if UNITY_EDITOR
PlayerSettings.audioCompressionFormat = audioCompressionFormat;
PlayerSettings.audioSampleRate = audioSampleRateSetting;
PlayerSettings.enableAudio = true;
#endif
}
// 应用纹理优化
private void ApplyTextureOptimizations()
{
#if UNITY_EDITOR
// 这些设置需要在纹理导入器中应用
string[] textureGUIDs = UnityEditor.AssetDatabase.FindAssets("t:Texture2D");
foreach (string guid in textureGUIDs)
{
string path = UnityEditor.AssetDatabase.GUIDToAssetPath(guid);
UnityEditor.TextureImporter importer =
UnityEditor.AssetImporter.GetAtPath(path) as UnityEditor.TextureImporter;
if (importer != null)
{
// 设置压缩
if (enableTextureCompression)
{
importer.compressionQuality = UnityEditor.TextureImporterCompression.High;
}
// 设置最大尺寸
importer.maxTextureSize = Mathf.Min(importer.maxTextureSize, maxTextureSize);
// 应用更改
importer.SaveAndReimport();
}
}
#endif
}
// 应用Player设置优化
private void ApplyPlayerOptimizations()
{
#if UNITY_EDITOR
PlayerSettings.stripEngineCode = enableStripping;
PlayerSettings.actionOnDotNetUnhandledException =
UnhandledExceptionPolicy.Quit;
PlayerSettings.enableInternalProfiler = false;
PlayerSettings.logObjCUncaughtExceptions = false;
PlayerSettings.enableCrashReportAPI = false;
#endif
}
// 预构建检查
public BuildCheckResult PreBuildCheck()
{
BuildCheckResult result = new BuildCheckResult();
// 检查场景设置
result.sceneCheckPassed = CheckSceneSettings();
// 检查资源优化
result.resourceCheckPassed = CheckResourceOptimization();
// 检查代码质量
result.codeCheckPassed = CheckCodeQuality();
// 检查性能设置
result.performanceCheckPassed = CheckPerformanceSettings();
// 生成检查报告
result.generateReport();
return result;
}
private bool CheckSceneSettings()
{
// 检查场景中的静态对象设置
GameObject[] allObjects = FindObjectsOfType<GameObject>();
int staticObjects = 0;
int dynamicObjects = 0;
foreach (GameObject go in allObjects)
{
if (go.isStatic)
{
staticObjects++;
}
else
{
dynamicObjects++;
}
}
Debug.Log($"场景静态对象: {staticObjects}, 动态对象: {dynamicObjects}");
// 建议静态对象数量不要过多影响构建时间
return staticObjects < 10000; // 根据项目调整阈值
}
private bool CheckResourceOptimization()
{
// 检查大纹理
Texture[] allTextures = Resources.FindObjectsOfTypeAll<Texture>();
int largeTextures = 0;
foreach (Texture texture in allTextures)
{
if (texture.width > 4096 || texture.height > 4096)
{
largeTextures++;
Debug.LogWarning($"发现大纹理: {texture.name} ({texture.width}x{texture.height})");
}
}
// 检查大音频文件
AudioClip[] allAudio = Resources.FindObjectsOfTypeAll<AudioClip>();
int largeAudio = 0;
foreach (AudioClip audio in allAudio)
{
float length = audio.length;
if (length > 60) // 超过60秒的音频
{
largeAudio++;
Debug.LogWarning($"发现长音频: {audio.name} ({length:F1}秒)");
}
}
return largeTextures == 0 && largeAudio == 0;
}
private bool CheckCodeQuality()
{
// 检查未使用的脚本
MonoBehaviour[] allBehaviours = FindObjectsOfType<MonoBehaviour>();
foreach (MonoBehaviour behaviour in allBehaviours)
{
if (behaviour == null)
{
Debug.LogWarning($"发现空脚本引用");
return false;
}
}
return true;
}
private bool CheckPerformanceSettings()
{
// 检查性能相关设置
return true; // 根据具体需求实现
}
// 构建后处理
public void PostBuildProcessing(string buildPath)
{
Debug.Log($"构建完成: {buildPath}");
// 执行构建后处理任务
PerformPostBuildTasks(buildPath);
}
private void PerformPostBuildTasks(string buildPath)
{
// 生成构建报告
GenerateBuildReport(buildPath);
// 优化构建输出
OptimizeBuildOutput(buildPath);
// 验证构建完整性
VerifyBuildIntegrity(buildPath);
}
private void GenerateBuildReport(string buildPath)
{
BuildReport report = new BuildReport();
report.buildPath = buildPath;
report.buildTime = System.DateTime.Now;
report.targetPlatform = targetPlatform.ToString();
// 收集构建信息
report.fileSize = GetDirectorySize(buildPath);
report.assetCount = GetAssetCount();
report.sceneCount = UnityEngine.SceneManagement.SceneManager.sceneCountInBuildSettings;
// 保存报告
string reportPath = System.IO.Path.Combine(buildPath, "build_report.json");
System.IO.File.WriteAllText(reportPath, JsonUtility.ToJson(report, true));
Debug.Log($"构建报告已生成: {reportPath}");
}
private long GetDirectorySize(string directoryPath)
{
if (!System.IO.Directory.Exists(directoryPath))
return 0;
long size = 0;
string[] files = System.IO.Directory.GetFiles(directoryPath, "*.*", System.IO.SearchOption.AllDirectories);
foreach (string file in files)
{
size += new System.IO.FileInfo(file).Length;
}
return size;
}
private int GetAssetCount()
{
// 简化的资源计数
int count = 0;
count += Resources.FindObjectsOfTypeAll<GameObject>().Length;
count += Resources.FindObjectsOfTypeAll<Texture>().Length;
count += Resources.FindObjectsOfTypeAll<AudioClip>().Length;
count += Resources.FindObjectsOfTypeAll<Material>().Length;
return count;
}
private void OptimizeBuildOutput(string buildPath)
{
// 移除不必要的文件
RemoveUnnecessaryFiles(buildPath);
// 压缩构建输出
CompressBuildOutput(buildPath);
}
private void RemoveUnnecessaryFiles(string buildPath)
{
// 移除调试符号等
string[] unnecessaryFiles = { "*.pdb", "*.mdb", "*.log" };
foreach (string pattern in unnecessaryFiles)
{
string[] files = System.IO.Directory.GetFiles(buildPath, pattern, System.IO.SearchOption.AllDirectories);
foreach (string file in files)
{
try
{
System.IO.File.Delete(file);
Debug.Log($"删除文件: {file}");
}
catch (System.Exception e)
{
Debug.LogWarning($"无法删除文件 {file}: {e.Message}");
}
}
}
}
private void CompressBuildOutput(string buildPath)
{
// 使用外部工具压缩构建输出
// 这里可以集成7-Zip或其他压缩工具
Debug.Log($"构建输出压缩到: {buildPath}");
}
private void VerifyBuildIntegrity(string buildPath)
{
// 验证构建文件完整性
string[] requiredFiles = {
System.IO.Path.GetFileNameWithoutExtension(PlayerSettings.productName) + GetExecutableExtension(),
"UnityPlayer.dll", // Windows平台
"Resources/unity default resources",
"Managed/"
};
bool allFilesExist = true;
foreach (string requiredFile in requiredFiles)
{
string fullPath = System.IO.Path.Combine(buildPath, requiredFile);
if (!System.IO.File.Exists(fullPath) && !System.IO.Directory.Exists(fullPath))
{
Debug.LogError($"缺少必要文件: {fullPath}");
allFilesExist = false;
}
}
if (allFilesExist)
{
Debug.Log("构建完整性验证通过");
}
else
{
Debug.LogError("构建完整性验证失败");
}
}
private string GetExecutableExtension()
{
switch (targetPlatform)
{
case BuildTarget.StandaloneWindows:
case BuildTarget.StandaloneWindows64:
return ".exe";
case BuildTarget.StandaloneOSX:
return ".app";
case BuildTarget.Android:
return ".apk";
case BuildTarget.iOS:
return ".ipa";
default:
return "";
}
}
}
[System.Serializable]
public class BuildCheckResult
{
public bool sceneCheckPassed = false;
public bool resourceCheckPassed = false;
public bool codeCheckPassed = false;
public bool performanceCheckPassed = false;
public List<string> warnings = new List<string>();
public List<string> errors = new List<string>();
public bool allChecksPassed => sceneCheckPassed && resourceCheckPassed &&
codeCheckPassed && performanceCheckPassed &&
errors.Count == 0;
public void generateReport()
{
string report = $@"
构建检查报告:
场景检查: {(sceneCheckPassed ? "通过" : "失败")}
资源检查: {(resourceCheckPassed ? "通过" : "失败")}
代码检查: {(codeCheckPassed ? "通过" : "失败")}
性能检查: {(performanceCheckPassed ? "通过" : "失败")}
总体结果: {(allChecksPassed ? "通过" : "失败")}
警告 ({warnings.Count} 个):
";
foreach (string warning in warnings)
{
report += $" ⚠️ {warning}\n";
}
report += $"\n错误 ({errors.Count} 个):\n";
foreach (string error in errors)
{
report += $" ❌ {error}\n";
}
Debug.Log(report);
}
}
[System.Serializable]
public class BuildReport
{
public string buildPath;
public System.DateTime buildTime;
public string targetPlatform;
public long fileSize;
public int assetCount;
public int sceneCount;
public string unityVersion = Application.unityVersion;
public string buildGuid = System.Guid.NewGuid().ToString();
}
部署策略
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
// 部署策略管理器
public class DeploymentStrategyManager : MonoBehaviour
{
[Header("部署配置")]
public DeploymentEnvironment currentEnvironment = DeploymentEnvironment.Development;
public string buildVersion = "1.0.0";
public string buildChannel = "default";
public bool enableAnalytics = true;
public bool enableCrashReporting = true;
[Header("更新策略")]
public UpdateStrategy updateStrategy = UpdateStrategy.HotUpdate;
public bool enableAutoUpdate = true;
public float updateCheckInterval = 3600f; // 1小时
[Header("内容分发")]
public bool enableCDN = true;
public string cdnBaseUrl = "https://cdn.example.com";
public bool enableAssetBundles = true;
private float lastUpdateCheckTime = 0f;
private bool isUpdating = false;
void Start()
{
InitializeDeployment();
}
void Update()
{
CheckForUpdates();
}
// 初始化部署
private void InitializeDeployment()
{
// 设置环境特定配置
ConfigureEnvironment();
// 初始化分析系统
if (enableAnalytics)
{
InitializeAnalytics();
}
// 初始化崩溃报告
if (enableCrashReporting)
{
InitializeCrashReporting();
}
// 检查更新
if (enableAutoUpdate)
{
StartCoroutine(CheckForUpdatesCoroutine());
}
}
// 配置环境
private void ConfigureEnvironment()
{
switch (currentEnvironment)
{
case DeploymentEnvironment.Development:
// 开发环境配置
QualitySettings.vSyncCount = 0;
Application.targetFrameRate = 60;
Debug.unityLogger.logEnabled = true;
break;
case DeploymentEnvironment.Staging:
// 预发布环境配置
QualitySettings.vSyncCount = 1;
Application.targetFrameRate = 60;
Debug.unityLogger.logEnabled = true;
break;
case DeploymentEnvironment.Production:
// 生产环境配置
QualitySettings.vSyncCount = 1;
Application.targetFrameRate = 60;
Debug.unityLogger.logEnabled = false;
break;
}
}
// 初始化分析系统
private void InitializeAnalytics()
{
// 这里集成具体的分析SDK
// 例如:Firebase Analytics, Unity Analytics等
Debug.Log("分析系统已初始化");
}
// 初始化崩溃报告
private void InitializeCrashReporting()
{
// 这里集成具体的崩溃报告SDK
// 例如:Firebase Crashlytics, Unity Cloud Diagnostics等
Debug.Log("崩溃报告系统已初始化");
}
// 检查更新
private void CheckForUpdates()
{
if (enableAutoUpdate && Time.time - lastUpdateCheckTime >= updateCheckInterval && !isUpdating)
{
StartCoroutine(CheckForUpdatesCoroutine());
lastUpdateCheckTime = Time.time;
}
}
private IEnumerator CheckForUpdatesCoroutine()
{
isUpdating = true;
// 检查是否有新版本
bool hasUpdate = CheckForNewVersion();
if (hasUpdate)
{
// 根据更新策略执行更新
switch (updateStrategy)
{
case UpdateStrategy.HotUpdate:
yield return StartCoroutine(PerformHotUpdate());
break;
case UpdateStrategy.FullUpdate:
RequestFullUpdate();
break;
case UpdateStrategy.OptionalUpdate:
ShowUpdateDialog();
break;
}
}
isUpdating = false;
}
// 检查新版本
private bool CheckForNewVersion()
{
// 实现版本检查逻辑
// 从服务器获取最新版本信息
return false; // 简化实现
}
// 执行热更新
private IEnumerator PerformHotUpdate()
{
Debug.Log("开始热更新...");
// 下载更新包
yield return StartCoroutine(DownloadUpdatePackage());
// 应用更新
ApplyHotUpdate();
Debug.Log("热更新完成");
}
private IEnumerator DownloadUpdatePackage()
{
// 实现更新包下载逻辑
yield return new WaitForSeconds(1f); // 模拟下载
}
private void ApplyHotUpdate()
{
// 实现热更新应用逻辑
// 可能包括AssetBundle加载、脚本更新等
}
// 请求完整更新
private void RequestFullUpdate()
{
Debug.Log("需要完整更新,请重新下载应用");
// 这里可以打开应用商店页面
}
// 显示更新对话框
private void ShowUpdateDialog()
{
Debug.Log("有新版本可用,是否更新?");
// 显示更新对话框给用户选择
}
// 资源加载优化
public class OptimizedResourceLoader
{
private Dictionary<string, Object> resourceCache = new Dictionary<string, Object>();
private Queue<string> lruCache = new Queue<string>();
private int maxCacheSize = 100;
public T LoadResource<T>(string path) where T : Object
{
if (resourceCache.ContainsKey(path))
{
// 移动到LRU队列末尾
lruCache.Enqueue(lruCache.Dequeue()); // 移除并重新添加到末尾
return resourceCache[path] as T;
}
T resource = Resources.Load<T>(path);
if (resource != null)
{
// 添加到缓存
resourceCache[path] = resource;
lruCache.Enqueue(path);
// 如果超过最大缓存大小,移除最久未使用的资源
if (lruCache.Count > maxCacheSize)
{
string oldestPath = lruCache.Dequeue();
resourceCache.Remove(oldestPath);
}
}
return resource;
}
public void UnloadResource(string path)
{
if (resourceCache.ContainsKey(path))
{
Resources.UnloadAsset(resourceCache[path]);
resourceCache.Remove(path);
// 从LRU队列中移除
Queue<string> newQueue = new Queue<string>();
foreach (string p in lruCache)
{
if (p != path)
{
newQueue.Enqueue(p);
}
}
lruCache = newQueue;
}
}
public void ClearCache()
{
foreach (Object resource in resourceCache.Values)
{
Resources.UnloadAsset(resource);
}
resourceCache.Clear();
lruCache.Clear();
}
}
// CDN资源加载器
public class CDNResourceLoader
{
private string baseUrl;
private OptimizedResourceLoader localLoader;
public CDNResourceLoader(string cdnUrl)
{
baseUrl = cdnUrl;
localLoader = new OptimizedResourceLoader();
}
public IEnumerator LoadFromCDN<T>(string assetPath, System.Action<T> onLoadComplete) where T : Object
{
string fullUrl = $"{baseUrl}/{assetPath}";
using (UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(fullUrl))
{
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
if (bundle != null)
{
T asset = bundle.LoadAsset<T>(System.IO.Path.GetFileName(assetPath));
onLoadComplete?.Invoke(asset);
// 卸载AssetBundle
bundle.Unload(false);
}
}
else
{
Debug.LogError($"从CDN加载资源失败: {request.error}");
// 回退到本地资源
T localAsset = localLoader.LoadResource<T>(assetPath);
onLoadComplete?.Invoke(localAsset);
}
}
}
}
// 版本管理器
public class VersionManager
{
private string currentVersion;
private string serverVersion;
private System.DateTime lastCheckTime;
public VersionManager(string currentVer)
{
currentVersion = currentVer;
}
public IEnumerator CheckServerVersion(string versionUrl, System.Action<bool> onVersionCheckComplete)
{
using (UnityWebRequest request = UnityWebRequest.Get(versionUrl))
{
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
serverVersion = request.downloadHandler.text.Trim();
lastCheckTime = System.DateTime.Now;
bool hasNewVersion = CompareVersions(serverVersion, currentVersion) > 0;
onVersionCheckComplete?.Invoke(hasNewVersion);
}
else
{
Debug.LogError($"检查版本失败: {request.error}");
onVersionCheckComplete?.Invoke(false);
}
}
}
private int CompareVersions(string version1, string version2)
{
string[] v1Parts = version1.Split('.');
string[] v2Parts = version2.Split('.');
for (int i = 0; i < Mathf.Max(v1Parts.Length, v2Parts.Length); i++)
{
int part1 = i < v1Parts.Length ? int.Parse(v1Parts[i]) : 0;
int part2 = i < v2Parts.Length ? int.Parse(v2Parts[i]) : 0;
if (part1 > part2) return 1;
if (part1 < part2) return -1;
}
return 0;
}
public string GetCurrentVersion() => currentVersion;
public string GetServerVersion() => serverVersion;
public bool IsUpdateAvailable() => CompareVersions(serverVersion, currentVersion) > 0;
}
}
public enum DeploymentEnvironment
{
Development,
Staging,
Production
}
public enum UpdateStrategy
{
HotUpdate, // 热更新
FullUpdate, // 完整更新
OptionalUpdate // 可选更新
}
实践练习
练习1: 性能监控面板
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
// 性能监控面板
public class PerformanceMonitorPanel : MonoBehaviour
{
[Header("UI引用")]
public Text fpsText;
public Text memoryText;
public Text drawCallText;
public Text batchText;
public Text objectCountText;
public Slider fpsSlider; // 用于可视化FPS变化
public Color goodPerformanceColor = Color.green;
public Color warningPerformanceColor = Color.yellow;
public Color poorPerformanceColor = Color.red;
[Header("监控设置")]
public float updateInterval = 0.5f;
public int fpsWarningThreshold = 30;
public int fpsPoorThreshold = 20;
public long memoryWarningThreshold = 500 * 1024 * 1024; // 500MB
public long memoryPoorThreshold = 800 * 1024 * 1024; // 800MB
private float lastUpdateTime = 0f;
private List<float> fpsHistory = new List<float>();
private const int fpsHistorySize = 50;
void Update()
{
if (Time.time - lastUpdateTime >= updateInterval)
{
UpdatePerformanceInfo();
lastUpdateTime = Time.time;
}
}
private void UpdatePerformanceInfo()
{
// 更新FPS
float currentFPS = 1.0f / Time.unscaledDeltaTime;
UpdateFPSInfo(currentFPS);
// 更新内存使用
UpdateMemoryInfo();
// 更新渲染统计
UpdateRenderStats();
// 更新对象计数
UpdateObjectCount();
}
private void UpdateFPSInfo(float fps)
{
if (fpsText != null)
{
fpsText.text = $"FPS: {fps:F1}";
// 根据FPS设置颜色
if (fps >= fpsWarningThreshold)
{
fpsText.color = goodPerformanceColor;
}
else if (fps >= fpsPoorThreshold)
{
fpsText.color = warningPerformanceColor;
}
else
{
fpsText.color = poorPerformanceColor;
}
}
// 更新FPS滑块
if (fpsSlider != null)
{
fpsSlider.value = Mathf.Clamp01(fps / 60f); // 假设目标是60FPS
}
// 更新FPS历史记录
fpsHistory.Add(fps);
if (fpsHistory.Count > fpsHistorySize)
{
fpsHistory.RemoveAt(0);
}
}
private void UpdateMemoryInfo()
{
if (memoryText != null)
{
long memoryUsage = System.GC.GetTotalMemory(false);
string memoryStr = FormatBytes(memoryUsage);
memoryText.text = $"Memory: {memoryStr}";
// 根据内存使用设置颜色
if (memoryUsage < memoryWarningThreshold)
{
memoryText.color = goodPerformanceColor;
}
else if (memoryUsage < memoryPoorThreshold)
{
memoryText.color = warningPerformanceColor;
}
else
{
memoryText.color = poorPerformanceColor;
}
}
}
private void UpdateRenderStats()
{
if (drawCallText != null)
{
drawCallText.text = $"Draw Calls: {UnityEngine.Rendering.RenderSettings.renderingLayerMask}";
}
if (batchText != null)
{
// 注意:Unity没有直接的API获取批处理数量,这里简化处理
batchText.text = $"Batches: N/A"; // 实际项目中需要使用profiler API
}
}
private void UpdateObjectCount()
{
if (objectCountText != null)
{
int objectCount = FindObjectsOfType<Object>().Length;
objectCountText.text = $"Objects: {objectCount}";
}
}
private string FormatBytes(long bytes)
{
string[] suffixes = { "B", "KB", "MB", "GB" };
int counter = 0;
decimal number = (decimal)bytes;
while (Math.Abs(number) >= 1024m && counter < suffixes.Length - 1)
{
counter++;
number /= 1024m;
}
return string.Format("{0:n1} {1}", number, suffixes[counter]);
}
// 获取FPS历史记录(用于图表显示)
public List<float> GetFPSHistory()
{
return new List<float>(fpsHistory);
}
// 强制垃圾回收
public void ForceGarbageCollection()
{
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
Debug.Log("强制垃圾回收完成");
}
// 卸载未使用的资源
public void UnloadUnusedAssets()
{
Resources.UnloadUnusedAssets();
Debug.Log("卸载未使用的资源");
}
// 重置监控数据
public void ResetMonitor()
{
fpsHistory.Clear();
}
}
练习2: 代码质量检查工具
using UnityEngine;
using System.Collections.Generic;
using System.Text;
using System.Linq;
// 代码质量检查工具
public class CodeQualityChecker : MonoBehaviour
{
[Header("检查设置")]
public bool checkForUnusedVariables = true;
public bool checkForDeepNesting = true;
public int maxNestingLevel = 5;
public bool checkForLongMethods = true;
public int maxMethodLength = 50;
public bool checkForGODObjects = true;
public int maxComponentCount = 10;
[Header("性能检查")]
public bool checkForExpensiveOperations = true;
public bool checkForFrequentAllocations = true;
private List<QualityIssue> issues = new List<QualityIssue>();
[System.Serializable]
public class QualityIssue
{
public string objectName;
public string componentName;
public string issueType;
public string description;
public int severity; // 1 = 低, 2 = 中, 3 = 高
public System.DateTime timestamp;
}
// 执行代码质量检查
public void RunQualityCheck()
{
issues.Clear();
Debug.Log("开始代码质量检查...");
if (checkForGODObjects)
{
CheckForGODObjects();
}
if (checkForDeepNesting)
{
CheckForDeepNestingIssues();
}
if (checkForLongMethods)
{
CheckForLongMethods();
}
if (checkForExpensiveOperations)
{
CheckForExpensiveOperations();
}
GenerateQualityReport();
}
// 检查GOD对象(组件过多的对象)
private void CheckForGODObjects()
{
GameObject[] allObjects = FindObjectsOfType<GameObject>();
foreach (GameObject go in allObjects)
{
Component[] components = go.GetComponents<Component>();
if (components.Length > maxComponentCount)
{
AddQualityIssue(go.name, "GOD Object",
$"对象有 {components.Length} 个组件,超过了建议的 {maxComponentCount} 个",
2);
}
}
}
// 检查深层嵌套
private void CheckForDeepNestingIssues()
{
MonoBehaviour[] allBehaviours = FindObjectsOfType<MonoBehaviour>();
foreach (MonoBehaviour behaviour in allBehaviours)
{
// 这里需要分析代码,实际项目中可能需要使用AST分析
// 简化版本:检查Transform层级深度
int depth = GetTransformDepth(behaviour.transform);
if (depth > maxNestingLevel)
{
AddQualityIssue(behaviour.name, "Deep Nesting",
$"Transform嵌套层级为 {depth},超过了建议的 {maxNestingLevel} 层",
2);
}
}
}
// 检查长方法
private void CheckForLongMethods()
{
MonoBehaviour[] allBehaviours = FindObjectsOfType<MonoBehaviour>();
foreach (MonoBehaviour behaviour in allBehaviours)
{
// 这需要反射或代码分析工具来检查实际方法长度
// 简化版本:检查Update方法的复杂度
System.Reflection.MethodInfo updateMethod =
behaviour.GetType().GetMethod("Update",
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.NonPublic);
if (updateMethod != null)
{
// 这里简化处理,实际需要分析方法体
AddQualityIssue(behaviour.name, "Method Length",
"Update方法可能过长,建议拆分逻辑",
1);
}
}
}
// 检查昂贵操作
private void CheckForExpensiveOperations()
{
// 检查频繁的Find操作
CheckForFrequentFindOperations();
// 检查Update中的昂贵操作
CheckForExpensiveUpdateOperations();
}
private void CheckForFrequentFindOperations()
{
GameObject[] allObjects = FindObjectsOfType<GameObject>();
foreach (GameObject go in allObjects)
{
MonoBehaviour[] behaviours = go.GetComponents<MonoBehaviour>();
foreach (MonoBehaviour behaviour in behaviours)
{
// 检查是否在Update中使用了FindObject
if (HasExpensiveFindOperation(behaviour))
{
AddQualityIssue(behaviour.name, "Expensive Operation",
"在Update中使用了FindObject操作,这很昂贵",
3);
}
}
}
}
private bool HasExpensiveFindOperation(MonoBehaviour behaviour)
{
// 简化的检查,实际需要代码分析
string scriptContent = GetScriptContent(behaviour);
return scriptContent.Contains("GameObject.Find") ||
scriptContent.Contains("FindGameObjectWithTag") ||
scriptContent.Contains("FindObjectOfType");
}
private string GetScriptContent(MonoBehaviour behaviour)
{
// 这里简化处理,实际需要读取源代码文件
return behaviour.GetType().Name;
}
private void CheckForExpensiveUpdateOperations()
{
MonoBehaviour[] allBehaviours = FindObjectsOfType<MonoBehaviour>();
foreach (MonoBehaviour behaviour in allBehaviours)
{
// 检查Update方法中是否有昂贵操作
System.Reflection.MethodInfo updateMethod =
behaviour.GetType().GetMethod("Update");
if (updateMethod != null)
{
// 检查是否调用了GetComponent等操作
AddQualityIssue(behaviour.name, "Expensive Update",
"Update方法中可能包含昂贵操作,建议缓存引用",
2);
}
}
}
// 添加质量问
private void AddQualityIssue(string objectName, string issueType, string description, int severity)
{
QualityIssue issue = new QualityIssue
{
objectName = objectName,
componentName = issueType,
issueType = issueType,
description = description,
severity = severity,
timestamp = System.DateTime.Now
};
issues.Add(issue);
}
// 生成质量报告
private void GenerateQualityReport()
{
StringBuilder report = new StringBuilder();
report.AppendLine("=== 代码质量检查报告 ===");
report.AppendLine($"检查时间: {System.DateTime.Now}");
report.AppendLine($"发现问题数量: {issues.Count}");
if (issues.Count > 0)
{
report.AppendLine("\n问题详情:");
// 按严重程度排序
var sortedIssues = issues.OrderByDescending(i => i.severity).ToList();
foreach (QualityIssue issue in sortedIssues)
{
string severityStr = issue.severity == 3 ? "高" :
issue.severity == 2 ? "中" : "低";
report.AppendLine($"[{severityStr}] {issue.objectName}.{issue.componentName}: {issue.description}");
}
}
else
{
report.AppendLine("\n✅ 未发现代码质量问题!");
}
Debug.Log(report.ToString());
}
// 获取Transform深度
private int GetTransformDepth(Transform transform)
{
int depth = 0;
Transform current = transform;
while (current.parent != null)
{
depth++;
current = current.parent;
}
return depth;
}
// 修复建议
public void GenerateFixSuggestions()
{
StringBuilder suggestions = new StringBuilder();
suggestions.AppendLine("=== 修复建议 ===");
int godObjectCount = issues.Count(i => i.issueType == "GOD Object");
int nestingIssues = issues.Count(i => i.issueType.Contains("Nesting"));
int expensiveOps = issues.Count(i => i.issueType.Contains("Expensive"));
if (godObjectCount > 0)
{
suggestions.AppendLine($"• 将 {godObjectCount} 个GOD对象拆分为多个组件");
suggestions.AppendLine(" - 使用组合模式替代继承");
suggestions.AppendLine(" - 将相关功能分组到不同的脚本中");
}
if (nestingIssues > 0)
{
suggestions.AppendLine($"• 减少 {nestingIssues} 个对象的Transform嵌套层级");
suggestions.AppendLine(" - 考虑使用对象池减少层级");
suggestions.AppendLine(" - 重新设计场景层级结构");
}
if (expensiveOps > 0)
{
suggestions.AppendLine($"• 优化 {expensiveOps} 个昂贵操作");
suggestions.AppendLine(" - 缓存GameObject.Find的结果");
suggestions.AppendLine(" - 将GetComponent调用移到Start或Awake中");
suggestions.AppendLine(" - 使用对象池替代频繁的Instantiate/Destroy");
}
Debug.Log(suggestions.ToString());
}
// 获取质量评分
public float GetQualityScore()
{
if (issues.Count == 0) return 100f;
int totalSeverity = issues.Sum(i => i.severity);
// 基于问题数量和严重程度计算分数
float score = Mathf.Clamp(100f - (issues.Count * 5 + totalSeverity * 10), 0f, 100f);
return score;
}
}
常见错误和最佳实践总结
1. 性能相关最佳实践
using UnityEngine;
using System.Collections.Generic;
// 性能最佳实践示例
public class PerformanceBestPractices : MonoBehaviour
{
// ✅ 正确:缓存组件引用
private Transform cachedTransform;
private Rigidbody cachedRigidbody;
private Renderer cachedRenderer;
private Collider cachedCollider;
void Start()
{
// 一次性获取并缓存组件引用
cachedTransform = transform;
cachedRigidbody = GetComponent<Rigidbody>();
cachedRenderer = GetComponent<Renderer>();
cachedCollider = GetComponent<Collider>();
}
void Update()
{
// 使用缓存的引用而不是每次都获取
if (cachedTransform != null)
{
cachedTransform.Translate(Vector3.forward * Time.deltaTime);
}
if (cachedRigidbody != null)
{
cachedRigidbody.velocity = new Vector3(1, 0, 0);
}
}
// ✅ 正确:使用对象池
private Queue<GameObject> objectPool = new Queue<GameObject>();
private GameObject prefab;
private GameObject GetFromPool()
{
if (objectPool.Count > 0)
{
GameObject obj = objectPool.Dequeue();
obj.SetActive(true);
return obj;
}
else
{
return Instantiate(prefab);
}
}
private void ReturnToPool(GameObject obj)
{
obj.SetActive(false);
obj.transform.SetParent(transform); // 归属到池对象下
objectPool.Enqueue(obj);
}
// ✅ 正确:避免在Update中进行昂贵操作
private float expensiveOperationInterval = 1f;
private float lastExpensiveTime = 0f;
void Update()
{
// 昂贵操作定期执行,而不是每帧执行
if (Time.time - lastExpensiveTime >= expensiveOperationInterval)
{
PerformExpensiveOperation();
lastExpensiveTime = Time.time;
}
}
private void PerformExpensiveOperation()
{
// 只在需要时执行昂贵操作
}
// ✅ 正确:使用StringBuilder进行字符串操作
private System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder();
string BuildStatusString(int health, int maxHealth, int level, string playerName)
{
stringBuilder.Length = 0; // 清空但不重新分配内存
stringBuilder.Append(playerName);
stringBuilder.Append(" - HP: ");
stringBuilder.Append(health);
stringBuilder.Append("/");
stringBuilder.Append(maxHealth);
stringBuilder.Append(" Lvl: ");
stringBuilder.Append(level);
return stringBuilder.ToString();
}
// ✅ 正确:使用预分配的集合
private List<GameObject> enemies = new List<GameObject>(100); // 预分配容量
private Dictionary<int, string> lookupTable = new Dictionary<int, string>(50); // 预分配容量
// ✅ 正确:使用Span<T>进行高性能数组操作
void ProcessArrayWithSpan(int[] array)
{
System.Span<int> span = array.AsSpan();
for (int i = 0; i < span.Length; i++)
{
span[i] *= 2; // 直接在栈上操作,无GC
}
}
// ❌ 错误:在Update中进行昂贵操作
/*
void Update()
{
// 每帧都查找对象 - 很慢!
GameObject player = GameObject.Find("Player");
// 每帧都获取组件 - 很慢!
Transform playerTransform = GameObject.FindGameObjectWithTag("Player").transform;
// 每帧都进行复杂计算 - 很慢!
List<GameObject> enemies = new List<GameObject>();
enemies.AddRange(GameObject.FindGameObjectsWithTag("Enemy"));
}
*/
// ❌ 错误:频繁创建和销毁对象
/*
void Update()
{
GameObject effect = new GameObject(); // 每帧创建新对象
Destroy(effect, 1f); // 1秒后销毁 - 造成GC压力
}
*/
// ❌ 错误:在循环中进行昂贵操作
/*
void Update()
{
for (int i = 0; i < transform.childCount; i++)
{
// 每次循环都调用GetComponent - 很慢!
var script = transform.GetChild(i).GetComponent<SomeComponent>();
}
}
*/
}
2. 内存管理最佳实践
using UnityEngine;
using System.Collections.Generic;
// 内存管理最佳实践
public class MemoryManagementBestPractices : MonoBehaviour
{
// ✅ 正确:事件系统内存管理
private System.Action<int> scoreChangedCallback;
void SubscribeToEvents()
{
// 使用具体方法而不是Lambda来避免闭包
scoreChangedCallback = OnScoreChanged;
GameEvents.OnScoreChanged += scoreChangedCallback;
}
void UnsubscribeFromEvents()
{
// 记得取消订阅以避免内存泄漏
GameEvents.OnScoreChanged -= scoreChangedCallback;
}
private void OnScoreChanged(int newScore)
{
// 处理分数改变
}
// ✅ 正确:资源管理
private List<Object> loadedAssets = new List<Object>();
void LoadAssetSafely<T>(string path) where T : Object
{
T asset = Resources.Load<T>(path);
if (asset != null)
{
loadedAssets.Add(asset);
}
}
void UnloadAllAssets()
{
foreach (Object asset in loadedAssets)
{
if (asset != null)
{
Resources.UnloadAsset(asset);
}
}
loadedAssets.Clear();
}
// ✅ 正确:使用结构体而不是类(适用于小对象)
[System.Serializable]
public struct PositionData
{
public Vector3 position;
public Quaternion rotation;
public int id;
public PositionData(Vector3 pos, Quaternion rot, int id)
{
position = pos;
rotation = rot;
this.id = id;
}
}
// ✅ 正确:避免装箱/拆箱
void AvoidBoxing()
{
// ❌ 错误:装箱
// object boxedInt = 42; // int装箱为object
// List<object> mixedList = new List<object> { 1, 2, 3, "string" }; // 发生装箱
// ✅ 正确:使用泛型
List<int> intList = new List<int> { 1, 2, 3, 4, 5 };
List<string> stringList = new List<string> { "a", "b", "c" };
}
// ✅ 正确:对象生命周期管理
private List<System.IDisposable> disposableObjects = new List<System.IDisposable>();
void RegisterDisposable(System.IDisposable disposable)
{
disposableObjects.Add(disposable);
}
void Cleanup()
{
// 清理所有可释放对象
foreach (System.IDisposable disposable in disposableObjects)
{
disposable?.Dispose();
}
disposableObjects.Clear();
}
void OnDestroy()
{
Cleanup();
UnsubscribeFromEvents();
UnloadAllAssets();
}
}
总结
本章我们学习了Unity游戏开发的最佳实践:
✅ 代码组织和架构: 项目结构、命名约定、单例模式、组件化架构、事件驱动
✅ 性能优化策略: 对象池、批处理、物理优化、LOD系统
✅ 内存管理: 监控分析、资源管理、字符串优化、集合优化
✅ UI系统: 性能优化、事件系统、动画优化
✅ 音频系统: 管理器优化、事件处理、性能监控
✅ 动画系统: 控制器优化、事件处理、性能监控
✅ 测试调试: 单元测试、调试工具、性能分析
✅ 发布部署: 构建优化、部署策略、版本管理
这些最佳实践是开发高质量Unity游戏的基础,遵循这些原则能够显著提升游戏性能和可维护性。
下一步
继续学习 10. 常见坑 →