
核心代码实现
1. 空间哈希网格系统
public class SpatialHashGrid : MonoBehaviour
{private Dictionary<Vector2Int, HashSet<Collider2D>> grid;private float cellSize = 5f; // 根据游戏对象大小调整private int gridWidth = 200;private int gridHeight = 200;void Awake(){grid = new Dictionary<Vector2Int, HashSet<Collider2D>>();InitializeGrid();}private void InitializeGrid(){for (int x = 0; x < gridWidth; x++){for (int y = 0; y < gridHeight; y++){grid[new Vector2Int(x, y)] = new HashSet<Collider2D>();}}}public Vector2Int WorldToGrid(Vector3 worldPos){int x = Mathf.FloorToInt(worldPos.x / cellSize);int y = Mathf.FloorToInt(worldPos.y / cellSize);return new Vector2Int(Mathf.Clamp(x, 0, gridWidth - 1),Mathf.Clamp(y, 0, gridHeight - 1));}public void AddToGrid(Collider2D collider){Vector2Int gridPos = WorldToGrid(collider.transform.position);if (grid.ContainsKey(gridPos)){grid[gridPos].Add(collider);}}public void RemoveFromGrid(Collider2D collider, Vector2Int oldGridPos){if (grid.ContainsKey(oldGridPos)){grid[oldGridPos].Remove(collider);}}public HashSet<Collider2D> GetNearbyObjects(Vector3 position, int range = 1){HashSet<Collider2D> nearby = new HashSet<Collider2D>();Vector2Int centerGrid = WorldToGrid(position);for (int x = -range; x <= range; x++){for (int y = -range; y <= range; y++){Vector2Int checkGrid = new Vector2Int(centerGrid.x + x, centerGrid.y + y);if (grid.ContainsKey(checkGrid)){foreach (var obj in grid[checkGrid]){nearby.Add(obj);}}}}return nearby;}
}
2. 高效碰撞管理器
public class CollisionManager : MonoBehaviour
{[Header("性能设置")]public int maxCollisionChecksPerFrame = 100;public float maxCheckDistance = 20f;private SpatialHashGrid spatialGrid;private ObjectPoolManager poolManager;private Queue<CollisionPair> collisionQueue;private List<Bullet> activeBullets;private List<Monster> activeMonsters;// 性能统计public int CollisionChecksThisFrame { get; private set; }public int TotalCollisionsDetected { get; private set; }private struct CollisionPair{public Collider2D bullet;public Collider2D monster;public float priority; // 基于距离的优先级}void Awake(){spatialGrid = GetComponent<SpatialHashGrid>();poolManager = GetComponent<ObjectPoolManager>();collisionQueue = new Queue<CollisionPair>();activeBullets = new List<Bullet>();activeMonsters = new List<Monster>();// 设置物理层SetupPhysicsLayers();}void SetupPhysicsLayers(){// 子弹层 = 8, 怪物层 = 9Physics2D.IgnoreLayerCollision(8, 8); // 子弹间不碰撞Physics2D.IgnoreLayerCollision(9, 9); // 怪物间不碰撞// 只保留子弹-怪物碰撞}void FixedUpdate(){CollisionChecksThisFrame = 0;UpdateSpatialGrid();ProcessCollisionDetection();}private void UpdateSpatialGrid(){// 清空网格spatialGrid.ClearGrid();// 重新添加所有活跃对象foreach (var bullet in activeBullets){if (bullet.gameObject.activeInHierarchy)spatialGrid.AddToGrid(bullet.GetComponent<Collider2D>());}foreach (var monster in activeMonsters){if (monster.gameObject.activeInHierarchy)spatialGrid.AddToGrid(monster.GetComponent<Collider2D>());}}private void ProcessCollisionDetection(){// 构建碰撞候选队列BuildCollisionCandidates();// 分帧处理碰撞检测int checksThisFrame = 0;while (collisionQueue.Count > 0 && checksThisFrame < maxCollisionChecksPerFrame){var pair = collisionQueue.Dequeue();if (CheckCollision(pair)){HandleCollision(pair.bullet, pair.monster);TotalCollisionsDetected++;}checksThisFrame++;}CollisionChecksThisFrame = checksThisFrame;}private void BuildCollisionCandidates(){collisionQueue.Clear();foreach (var bullet in activeBullets){if (!bullet.gameObject.activeInHierarchy) continue;var nearbyObjects = spatialGrid.GetNearbyObjects(bullet.transform.position);foreach (var obj in nearbyObjects){if (obj.gameObject.layer == 9) // 怪物层{float distance = Vector3.Distance(bullet.transform.position, obj.transform.position);if (distance <= maxCheckDistance){collisionQueue.Enqueue(new CollisionPair{bullet = bullet.GetComponent<Collider2D>(),monster = obj,priority = 1f / (distance + 0.1f) // 距离越近优先级越高});}}}}// 按优先级排序(可选,性能消耗较大时可省略)// var sortedPairs = collisionQueue.OrderByDescending(p => p.priority);// collisionQueue = new Queue<CollisionPair>(sortedPairs);}private bool CheckCollision(CollisionPair pair){if (pair.bullet == null || pair.monster == null) return false;// 快速距离检测float sqrDistance = (pair.bullet.transform.position - pair.monster.transform.position).sqrMagnitude;float combinedRadius = GetColliderRadius(pair.bullet) + GetColliderRadius(pair.monster);return sqrDistance <= (combinedRadius * combinedRadius);}private float GetColliderRadius(Collider2D collider){if (collider is CircleCollider2D circle)return circle.radius * Mathf.Max(collider.transform.lossyScale.x, collider.transform.lossyScale.y);else if (collider is BoxCollider2D box)return Mathf.Max(box.size.x, box.size.y) * 0.5f * Mathf.Max(collider.transform.lossyScale.x, collider.transform.lossyScale.y);return 1f; // 默认半径}private void HandleCollision(Collider2D bullet, Collider2D monster){// 处理碰撞逻辑var bulletComponent = bullet.GetComponent<Bullet>();var monsterComponent = monster.GetComponent<Monster>();if (bulletComponent != null && monsterComponent != null){// 造成伤害monsterComponent.TakeDamage(bulletComponent.Damage);// 回收子弹到对象池poolManager.ReturnBullet(bulletComponent);// 播放特效var effect = poolManager.GetHitEffect();effect.transform.position = bullet.transform.position;effect.Play();}}// 注册/注销方法public void RegisterBullet(Bullet bullet){activeBullets.Add(bullet);}public void UnregisterBullet(Bullet bullet){activeBullets.Remove(bullet);}public void RegisterMonster(Monster monster){activeMonsters.Add(monster);}public void UnregisterMonster(Monster monster){activeMonsters.Remove(monster);}
}
3. 智能对象池系统
public class ObjectPoolManager : MonoBehaviour
{[System.Serializable]public class PoolSettings{public GameObject prefab;public int initialSize = 50;public int maxSize = 200;public bool allowGrowth = true;}[Header("对象池配置")]public PoolSettings bulletPool;public PoolSettings hitEffectPool;public PoolSettings damageTextPool;private Dictionary<string, Queue<GameObject>> pools;private Dictionary<string, PoolSettings> poolSettings;private Dictionary<string, int> poolCounts;void Awake(){InitializePools();}private void InitializePools(){pools = new Dictionary<string, Queue<GameObject>>();poolSettings = new Dictionary<string, PoolSettings>();poolCounts = new Dictionary<string, int>();// 初始化各个对象池CreatePool("Bullet", bulletPool);CreatePool("HitEffect", hitEffectPool);CreatePool("DamageText", damageTextPool);}private void CreatePool(string poolName, PoolSettings settings){pools[poolName] = new Queue<GameObject>();poolSettings[poolName] = settings;poolCounts[poolName] = 0;// 预创建对象for (int i = 0; i < settings.initialSize; i++){GameObject obj = Instantiate(settings.prefab, transform);obj.SetActive(false);pools[poolName].Enqueue(obj);poolCounts[poolName]++;}}public GameObject GetFromPool(string poolName){if (!pools.ContainsKey(poolName)){Debug.LogError($"Pool {poolName} does not exist!");return null;}GameObject obj = null;var pool = pools[poolName];var settings = poolSettings[poolName];// 尝试从池中获取while (pool.Count > 0){obj = pool.Dequeue();if (obj != null){obj.SetActive(true);return obj;}}// 池为空,检查是否可以扩容if (settings.allowGrowth && poolCounts[poolName] < settings.maxSize){obj = Instantiate(settings.prefab, transform);poolCounts[poolName]++;obj.SetActive(true);return obj;}Debug.LogWarning($"Pool {poolName} is exhausted!");return null;}public void ReturnToPool(string poolName, GameObject obj){if (!pools.ContainsKey(poolName)){Destroy(obj);return;}obj.SetActive(false);obj.transform.SetParent(transform);pools[poolName].Enqueue(obj);}// 便捷方法public Bullet GetBullet(){var obj = GetFromPool("Bullet");return obj?.GetComponent<Bullet>();}public void ReturnBullet(Bullet bullet){ReturnToPool("Bullet", bullet.gameObject);}public ParticleSystem GetHitEffect(){var obj = GetFromPool("HitEffect");return obj?.GetComponent<ParticleSystem>();}
}
4. 性能监控面板
public class PerformanceMonitor : MonoBehaviour
{private CollisionManager collisionManager;private ObjectPoolManager poolManager;[Header("显示设置")]public bool showDebugInfo = true;public KeyCode toggleKey = KeyCode.F1;// 性能数据private float deltaTime;private int lastFrameCollisionChecks;void Start(){collisionManager = FindObjectOfType<CollisionManager>();poolManager = FindObjectOfType<ObjectPoolManager>();}void Update(){deltaTime += (Time.unscaledDeltaTime - deltaTime) * 0.1f;if (Input.GetKeyDown(toggleKey)){showDebugInfo = !showDebugInfo;}lastFrameCollisionChecks = collisionManager.CollisionChecksThisFrame;}void OnGUI(){if (!showDebugInfo) return;GUILayout.BeginArea(new Rect(10, 10, 300, 200));GUILayout.Label($"FPS: {Mathf.Ceil(1.0f / deltaTime)}");GUILayout.Label($"碰撞检测/帧: {lastFrameCollisionChecks}");GUILayout.Label($"总碰撞数: {collisionManager.TotalCollisionsDetected}");GUILayout.Label($"活跃子弹: {FindObjectsOfType<Bullet>().Length}");GUILayout.Label($"活跃怪物: {FindObjectsOfType<Monster>().Length}");GUILayout.EndArea();}
}
配置
// 在CollisionManager中的推荐设置
[Header("性能调优")]
public int maxCollisionChecksPerFrame = 50; // 根据目标帧率调整
public float maxCheckDistance = 15f; // 根据游戏场景大小调整
public float cellSize = 3f; // 根据游戏对象平均大小调整