第7章 2D游戏开发的数学原理与高级实现

7.1 Sprite的数学基础与渲染优化

7.1.1 2D摄像机投影矩阵与坐标变换

在2D游戏开发中,摄像机的作用至关重要。与3D摄像机不同,2D摄像机通常使用正交投影(Orthographic Projection),其投影矩阵的数学原理直接影响着游戏的可视范围和坐标系统。

正交投影矩阵公式:

投影矩阵 = [
    [2/(right-left), 0, 0, -(right+left)/(right-left)],
    [0, 2/(top-bottom), 0, -(top+bottom)/(top-bottom)],
    [0, 0, -2/(far-near), -(far+near)/(far-near)],
    [0, 0, 0, 1]
]

在商业级2D游戏中,我们通常需要更复杂的摄像机系统。以下是一个高级2D摄像机控制器的实现:

using UnityEngine;
using System.Collections.Generic;

namespace CommercialProject.Graphics2D
{
    /// <summary>
    /// 高级2D摄像机控制器
    /// 支持多种分辨率自适应策略和动态缩放
    /// </summary>
    public class AdvancedCamera2D : MonoBehaviour
    {
        [SerializeField]
        private Camera targetCamera;
        
        [SerializeField]
        private Vector2 referenceResolution = new Vector2(1920, 1080);
        
        [SerializeField]
        private float pixelsPerUnit = 100f;
        
        [SerializeField]
        private CameraMode cameraMode = CameraMode.Orthographic;
        
        [SerializeField]
        private bool enableDynamicZoom = true;
        
        [SerializeField]
        private float minOrthographicSize = 2f;
        
        [SerializeField]
        private float maxOrthographicSize = 10f;
        
        // 追踪目标
        private List<Transform> trackingTargets;
        private Vector2 weightedPosition;
        private Vector2 cameraVelocity;
        
        // 边界限制
        private Rect cameraBounds;
        private bool useBounds = false;
        
        // 屏幕震动
        private float shakeIntensity;
        private float shakeDuration;
        private Vector3 originalPosition;
        
        /// <summary>
        /// 摄像机模式
        /// </summary>
        public enum CameraMode
        {
            Orthographic,
            Perspective2D,
            Parallax
        }
        
        /// <summary>
        /// 摄像机状态
        /// </summary>
        public struct CameraState
        {
            public Vector3 Position;
            public float OrthographicSize;
            public float Rotation;
            public Vector4 ViewportRect;
        }
        
        private void Awake()
        {
            InitializeCamera();
            trackingTargets = new List<Transform>();
        }
        
        private void Start()
        {
            CalculateOptimalOrthographicSize();
            SetupCameraListeners();
        }
        
        private void LateUpdate()
        {
            UpdateCameraPosition();
            HandleScreenShake();
            ApplyCameraEffects();
        }
        
        /// <summary>
        /// 初始化摄像机设置
        /// </summary>
        private void InitializeCamera()
        {
            if (targetCamera == null)
            {
                targetCamera = GetComponent<Camera>();
            }
            
            // 确保是正交摄像机
            targetCamera.orthographic = cameraMode == CameraMode.Orthographic;
            
            // 设置投影矩阵
            SetupProjectionMatrix();
            
            // 计算初始位置
            originalPosition = transform.position;
        }
        
        /// <summary>
        /// 设置投影矩阵
        /// 基于分辨率和像素精度
        /// </summary>
        private void SetupProjectionMatrix()
        {
            // 计算正交投影大小
            float orthographicSize = CalculateOrthographicSize();
            targetCamera.orthographicSize = orthographicSize;
            
            // 如果需要透视2D效果
            if (cameraMode == CameraMode.Perspective2D)
            {
                SetupPerspective2D();
            }
            
            // 应用投影矩阵自定义
            ApplyCustomProjection();
        }
        
        /// <summary>
        /// 计算正交投影大小
        /// 基于像素精度和屏幕分辨率
        /// </summary>
        private float CalculateOrthographicSize()
        {
            // 基本公式: orthographicSize = (screenHeight / pixelsPerUnit) / 2
            
            float screenHeight = Screen.height;
            float baseSize = (screenHeight / pixelsPerUnit) / 2f;
            
            // 考虑参考分辨率
            float aspectRatio = (float)Screen.width / Screen.height;
            float referenceAspect = referenceResolution.x / referenceResolution.y;
            
            if (Mathf.Abs(aspectRatio - referenceAspect) > 0.01f)
            {
                // 宽高比不同,需要调整
                baseSize *= referenceAspect / aspectRatio;
            }
            
            return Mathf.Clamp(baseSize, minOrthographicSize, maxOrthographicSize);
        }
        
        /// <summary>
        /// 设置透视2D效果
        /// 模拟2.5D视觉效果
        /// </summary>
        private void SetupPerspective2D()
        {
            // 使用透视投影但限制在2D平面
            targetCamera.orthographic = false;
            
            // 设置视野角以匹配正交效果
            float fov = Mathf.Atan2(targetCamera.orthographicSize, 10f) * 2f * Mathf.Rad2Deg;
            targetCamera.fieldOfView = fov;
            
            // 调整远裁剪平面
            targetCamera.farClipPlane = 100f;
            targetCamera.nearClipPlane = 0.1f;
        }
        
        /// <summary>
        /// 应用自定义投影矩阵
        /// 用于特殊效果如鱼眼、倾斜等
        /// </summary>
        private void ApplyCustomProjection()
        {
            // 获取标准投影矩阵
            Matrix4x4 standardMatrix = targetCamera.projectionMatrix;
            
            // 可以根据需要修改矩阵
            // 例如:倾斜效果
            if (Application.isEditor)
            {
                // 在编辑器中添加轻微倾斜以测试效果
                ApplyTiltEffect(ref standardMatrix, 0.05f);
            }
            
            targetCamera.projectionMatrix = standardMatrix;
        }
        
        /// <summary>
        /// 应用倾斜效果
        /// </summary>
        private void ApplyTiltEffect(ref Matrix4x4 matrix, float tiltAmount)
        {
            // 修改投影矩阵的倾斜分量
            matrix[0, 1] = tiltAmount;
            matrix[1, 0] = tiltAmount * 0.5f;
        }
        
        /// <summary>
        /// 计算最佳正交大小
        /// 考虑所有追踪目标
        /// </summary>
        private void CalculateOptimalOrthographicSize()
        {
            if (!enableDynamicZoom || trackingTargets.Count == 0)
                return;
            
            // 计算包围所有目标的边界框
            Bounds combinedBounds = CalculateTargetBounds();
            
            // 计算需要的摄像机大小
            float requiredWidth = combinedBounds.size.x / targetCamera.aspect;
            float requiredHeight = combinedBounds.size.y;
            
            float requiredSize = Mathf.Max(requiredWidth, requiredHeight) / 2f;
            
            // 添加边距
            requiredSize *= 1.2f;
            
            // 平滑过渡
            float currentSize = targetCamera.orthographicSize;
            float newSize = Mathf.Lerp(currentSize, requiredSize, Time.deltaTime * 2f);
            
            targetCamera.orthographicSize = Mathf.Clamp(newSize, minOrthographicSize, maxOrthographicSize);
        }
        
        /// <summary>
        /// 计算目标边界框
        /// </summary>
        private Bounds CalculateTargetBounds()
        {
            if (trackingTargets.Count == 0)
                return new Bounds(transform.position, Vector3.zero);
            
            Bounds bounds = new Bounds(trackingTargets[0].position, Vector3.zero);
            
            foreach (Transform target in trackingTargets)
            {
                if (target != null)
                {
                    bounds.Encapsulate(target.position);
                    
                    // 考虑目标的边界框
                    Renderer renderer = target.GetComponent<Renderer>();
                    if (renderer != null)
                    {
                        bounds.Encapsulate(renderer.bounds);
                    }
                }
            }
            
            return bounds;
        }
        
        /// <summary>
        /// 更新摄像机位置
        /// 平滑追踪多个目标
        /// </summary>
        private void UpdateCameraPosition()
        {
            if (trackingTargets.Count == 0)
                return;
            
            // 计算加权中心
            Vector3 newPosition = CalculateWeightedCenter();
            
            // 应用边界限制
            if (useBounds)
            {
                newPosition = ClampToBounds(newPosition);
            }
            
            // 平滑移动
            transform.position = Vector3.SmoothDamp(
                transform.position, 
                newPosition, 
                ref cameraVelocity, 
                0.3f
            );
            
            // 更新正交大小(如果需要)
            if (enableDynamicZoom)
            {
                CalculateOptimalOrthographicSize();
            }
        }
        
        /// <summary>
        /// 计算加权中心
        /// 不同的目标可以有不同权重
        /// </summary>
        private Vector3 CalculateWeightedCenter()
        {
            if (trackingTargets.Count == 0)
                return transform.position;
            
            Vector3 center = Vector3.zero;
            float totalWeight = 0f;
            
            foreach (Transform target in trackingTargets)
            {
                if (target != null)
                {
                    // 可以根据目标类型设置不同权重
                    float weight = GetTargetWeight(target);
                    center += target.position * weight;
                    totalWeight += weight;
                }
            }
            
            if (totalWeight > 0)
            {
                center /= totalWeight;
            }
            
            // 保持Z轴不变
            center.z = transform.position.z;
            
            return center;
        }
        
        /// <summary>
        /// 获取目标权重
        /// </summary>
        private float GetTargetWeight(Transform target)
        {
            // 默认权重为1
            float weight = 1f;
            
            // 可以根据标签、层或其他属性调整权重
            if (target.CompareTag("Player"))
            {
                weight = 2f; // 玩家权重更高
            }
            else if (target.CompareTag("Boss"))
            {
                weight = 1.5f; // Boss中等权重
            }
            
            return weight;
        }
        
        /// <summary>
        /// 限制在边界内
        /// </summary>
        private Vector3 ClampToBounds(Vector3 position)
        {
            // 考虑摄像机大小
            float cameraHeight = targetCamera.orthographicSize * 2f;
            float cameraWidth = cameraHeight * targetCamera.aspect;
            
            float minX = cameraBounds.xMin + cameraWidth / 2f;
            float maxX = cameraBounds.xMax - cameraWidth / 2f;
            float minY = cameraBounds.yMin + cameraHeight / 2f;
            float maxY = cameraBounds.yMax - cameraHeight / 2f;
            
            position.x = Mathf.Clamp(position.x, minX, maxX);
            position.y = Mathf.Clamp(position.y, minY, maxY);
            
            return position;
        }
        
        /// <summary>
        /// 添加追踪目标
        /// </summary>
        public void AddTrackingTarget(Transform target, float initialWeight = 1f)
        {
            if (!trackingTargets.Contains(target))
            {
                trackingTargets.Add(target);
                
                // 可以在这里设置初始权重
                if (initialWeight != 1f)
                {
                    // 存储自定义权重
                    // 实际项目中可以用字典存储
                }
            }
        }
        
        /// <summary>
        /// 移除追踪目标
        /// </summary>
        public void RemoveTrackingTarget(Transform target)
        {
            trackingTargets.Remove(target);
        }
        
        /// <summary>
        /// 设置摄像机边界
        /// </summary>
        public void SetCameraBounds(Rect bounds)
        {
            cameraBounds = bounds;
            useBounds = true;
        }
        
        /// <summary>
        /// 触发屏幕震动
        /// </summary>
        public void ShakeScreen(float intensity, float duration)
        {
            shakeIntensity = intensity;
            shakeDuration = duration;
            originalPosition = transform.position;
        }
        
        /// <summary>
        /// 处理屏幕震动
        /// </summary>
        private void HandleScreenShake()
        {
            if (shakeDuration > 0)
            {
                // 随机偏移
                Vector3 shakeOffset = Random.insideUnitCircle * shakeIntensity;
                transform.position = originalPosition + shakeOffset;
                
                shakeDuration -= Time.deltaTime;
                
                if (shakeDuration <= 0)
                {
                    // 恢复原位置
                    transform.position = originalPosition;
                }
            }
        }
        
        /// <summary>
        /// 应用摄像机效果
        /// </summary>
        private void ApplyCameraEffects()
        {
            // 这里可以添加各种后期效果
            // 例如:动态模糊、颜色分级等
        }
        
        /// <summary>
        /// 设置摄像机监听
        /// </summary>
        private void SetupCameraListeners()
        {
            // 监听分辨率变化
            StartCoroutine(MonitorResolutionChanges());
            
            // 监听屏幕旋转
            StartCoroutine(MonitorOrientationChanges());
        }
        
        /// <summary>
        /// 分辨率变化监控协程
        /// </summary>
        private System.Collections.IEnumerator MonitorResolutionChanges()
        {
            Vector2Int lastResolution = new Vector2Int(Screen.width, Screen.height);
            
            while (true)
            {
                yield return new WaitForSeconds(0.5f);
                
                Vector2Int currentResolution = new Vector2Int(Screen.width, Screen.height);
                
                if (currentResolution != lastResolution)
                {
                    lastResolution = currentResolution;
                    OnResolutionChanged(currentResolution);
                }
            }
        }
        
        /// <summary>
        /// 分辨率变化处理
        /// </summary>
        private void OnResolutionChanged(Vector2Int newResolution)
        {
            // 重新计算正交大小
            float newSize = CalculateOrthographicSize();
            targetCamera.orthographicSize = newSize;
            
            // 通知其他系统
            BroadcastMessage("OnCameraResolutionChanged", newResolution, 
                           SendMessageOptions.DontRequireReceiver);
        }
        
        /// <summary>
        /// 保存摄像机状态
        /// </summary>
        public CameraState SaveState()
        {
            CameraState state = new CameraState
            {
                Position = transform.position,
                OrthographicSize = targetCamera.orthographicSize,
                Rotation = transform.eulerAngles.z,
                ViewportRect = targetCamera.rect
            };
            
            return state;
        }
        
        /// <summary>
        /// 恢复摄像机状态
        /// </summary>
        public void RestoreState(CameraState state)
        {
            transform.position = state.Position;
            targetCamera.orthographicSize = state.OrthographicSize;
            transform.rotation = Quaternion.Euler(0, 0, state.Rotation);
            targetCamera.rect = state.ViewportRect;
        }
    }
}

7.1.2 Sprite渲染器的排序算法与优化

在2D游戏中,Sprite的正确排序对于视觉呈现至关重要。Unity使用Sorting Layer和Order in Layer来管理渲染顺序,但在商业项目中,我们需要更精细的控制和优化。

排序算法原理:

  1. 深度排序:基于Z轴或自定义深度值
  2. 层级排序:Sorting Layer的优先级
  3. 批次排序:相同材质的Sprite连续渲染

以下是一个高级Sprite排序管理器的实现:

using UnityEngine;
using System.Collections.Generic;
using System.Linq;

namespace CommercialProject.Graphics2D
{
    /// <summary>
    /// 高级Sprite排序管理器
    /// 支持动态深度计算和批量优化
    /// </summary>
    public class AdvancedSpriteSorter : MonoBehaviour
    {
        [SerializeField]
        private SortingMethod sortingMethod = SortingMethod.YAxis;
        
        [SerializeField]
        private bool enableDynamicSorting = true;
        
        [SerializeField]
        private float sortingUpdateInterval = 0.1f;
        
        [SerializeField]
        private bool useCustomDepthCalculation = false;
        
        // 自定义排序规则
        public delegate int CustomSortRule(SpriteRenderer a, SpriteRenderer b);
        private CustomSortRule customSortRule;
        
        // 排序组管理
        private Dictionary<string, List<SpriteRenderer>> sortingGroups;
        
        /// <summary>
        /// 排序方法枚举
        /// </summary>
        public enum SortingMethod
        {
            YAxis,           // Y轴排序(越往下越在前)
            ZAxis,           // Z轴排序
            CustomRule,      // 自定义规则
            Manual           // 手动控制
        }
        
        /// <summary>
        /// Sprite深度信息
        /// </summary>
        public class SpriteDepthInfo
        {
            public SpriteRenderer Renderer;
            public float CalculatedDepth;
            public int OriginalOrder;
            public string GroupId;
            
            public SpriteDepthInfo(SpriteRenderer renderer, float depth, string groupId)
            {
                Renderer = renderer;
                CalculatedDepth = depth;
                OriginalOrder = renderer.sortingOrder;
                GroupId = groupId;
            }
        }
        
        private void Start()
        {
            InitializeSortingSystem();
            StartCoroutine(DynamicSortingUpdate());
        }
        
        /// <summary>
        /// 初始化排序系统
        /// </summary>
        private void InitializeSortingSystem()
        {
            sortingGroups = new Dictionary<string, List<SpriteRenderer>>();
            
            // 扫描场景中的所有SpriteRenderer
            ScanSceneSprites();
            
            // 设置默认排序规则
            if (sortingMethod == SortingMethod.YAxis)
            {
                SetYAxisSortingRule();
            }
            else if (sortingMethod == SortingMethod.CustomRule && customSortRule == null)
            {
                SetDefaultCustomRule();
            }
        }
        
        /// <summary>
        /// 扫描场景Sprite
        /// </summary>
        private void ScanSceneSprites()
        {
            SpriteRenderer[] allSprites = FindObjectsOfType<SpriteRenderer>();
            
            foreach (SpriteRenderer sprite in allSprites)
            {
                // 检查是否属于某个排序组
                string groupId = GetSpriteGroup(sprite);
                
                if (!sortingGroups.ContainsKey(groupId))
                {
                    sortingGroups[groupId] = new List<SpriteRenderer>();
                }
                
                sortingGroups[groupId].Add(sprite);
                
                // 如果使用自定义深度计算,计算初始深度
                if (useCustomDepthCalculation)
                {
                    CalculateCustomDepth(sprite);
                }
            }
        }
        
        /// <summary>
        /// 获取Sprite所属分组
        /// </summary>
        private string GetSpriteGroup(SpriteRenderer sprite)
        {
            // 默认使用Sorting Layer作为分组
            return sprite.sortingLayerName;
        }
        
        /// <summary>
        /// 设置Y轴排序规则
        /// </summary>
        private void SetYAxisSortingRule()
        {
            customSortRule = (a, b) =>
            {
                // Y值越小(越靠下)的渲染顺序越靠前
                float depthA = CalculateYAxisDepth(a.transform.position.y, a.bounds.size.y);
                float depthB = CalculateYAxisDepth(b.transform.position.y, b.bounds.size.y);
                
                return depthB.CompareTo(depthA); // 降序排列
            };
        }
        
        /// <summary>
        /// 计算Y轴深度
        /// </summary>
        private float CalculateYAxisDepth(float yPosition, float height)
        {
            // 基础深度基于Y坐标
            float baseDepth = -yPosition; // Y越小(越往下)深度值越大
            
            // 考虑Sprite高度,高的物体应该覆盖更多区域
            baseDepth += height * 0.1f;
            
            return baseDepth;
        }
        
        /// <summary>
        /// 设置默认自定义规则
        /// </summary>
        private void SetDefaultCustomRule()
        {
            customSortRule = (a, b) =>
            {
                // 综合多种因素的排序规则
                float scoreA = CalculateSpriteScore(a);
                float scoreB = CalculateSpriteScore(b);
                
                return scoreB.CompareTo(scoreA);
            };
        }
        
        /// <summary>
        /// 计算Sprite综合评分
        /// </summary>
        private float CalculateSpriteScore(SpriteRenderer sprite)
        {
            float score = 0f;
            
            // 1. Y轴位置权重(50%)
            score += (-sprite.transform.position.y) * 0.5f;
            
            // 2. Z轴位置权重(30%)
            score += sprite.transform.position.z * 0.3f;
            
            // 3. 尺寸权重(20%)
            score += sprite.bounds.size.magnitude * 0.2f;
            
            return score;
        }
        
        /// <summary>
        /// 计算自定义深度
        /// </summary>
        private void CalculateCustomDepth(SpriteRenderer sprite)
        {
            if (sprite == null)
                return;
            
            // 基于多种因素计算深度
            float depth = 0f;
            
            // 位置因素
            depth += sprite.transform.position.y * -100f; // Y轴主要影响
            depth += sprite.transform.position.z * 10f;    // Z轴次要影响
            
            // 尺寸因素
            depth += sprite.bounds.size.y * 5f;
            
            // 材质因素(如果有)
            if (sprite.material != null)
            {
                // 可以根据材质属性调整深度
                depth += sprite.material.GetInstanceID() % 1000 * 0.001f;
            }
            
            // 存储计算出的深度
            sprite.sortingOrder = Mathf.RoundToInt(depth);
        }
        
        /// <summary>
        /// 动态排序更新协程
        /// </summary>
        private System.Collections.IEnumerator DynamicSortingUpdate()
        {
            while (enableDynamicSorting)
            {
                yield return new WaitForSeconds(sortingUpdateInterval);
                
                UpdateAllSpriteSorting();
            }
        }
        
        /// <summary>
        /// 更新所有Sprite排序
        /// </summary>
        private void UpdateAllSpriteSorting()
        {
            foreach (var group in sortingGroups)
            {
                UpdateGroupSorting(group.Key, group.Value);
            }
        }
        
        /// <summary>
        /// 更新分组排序
        /// </summary>
        private void UpdateGroupSorting(string groupId, List<SpriteRenderer> sprites)
        {
            if (sprites.Count <= 1)
                return;
            
            // 收集深度信息
            List<SpriteDepthInfo> depthInfos = new List<SpriteDepthInfo>();
            
            foreach (SpriteRenderer sprite in sprites)
            {
                if (sprite != null && sprite.isVisible)
                {
                    float depth = CalculateDepthForSorting(sprite);
                    depthInfos.Add(new SpriteDepthInfo(sprite, depth, groupId));
                }
            }
            
            // 根据选择的排序方法排序
            switch (sortingMethod)
            {
                case SortingMethod.YAxis:
                    SortByYAxis(depthInfos);
                    break;
                    
                case SortingMethod.ZAxis:
                    SortByZAxis(depthInfos);
                    break;
                    
                case SortingMethod.CustomRule:
                    SortByCustomRule(depthInfos);
                    break;
            }
            
            // 应用排序结果
            ApplySortingOrders(depthInfos);
            
            // 优化渲染批次
            OptimizeRenderBatches(depthInfos);
        }
        
        /// <summary>
        /// 计算排序深度
        /// </summary>
        private float CalculateDepthForSorting(SpriteRenderer sprite)
        {
            switch (sortingMethod)
            {
                case SortingMethod.YAxis:
                    return sprite.transform.position.y;
                    
                case SortingMethod.ZAxis:
                    return sprite.transform.position.z;
                    
                case SortingMethod.CustomRule:
                    return CalculateSpriteScore(sprite);
                    
                default:
                    return sprite.sortingOrder;
            }
        }
        
        /// <summary>
        /// Y轴排序
        /// </summary>
        private void SortByYAxis(List<SpriteDepthInfo> depthInfos)
        {
            depthInfos.Sort((a, b) =>
            {
                // 考虑Sprite高度
                float depthA = a.Renderer.transform.position.y - a.Renderer.bounds.extents.y;
                float depthB = b.Renderer.transform.position.y - b.Renderer.bounds.extents.y;
                
                return depthA.CompareTo(depthB); // 升序:Y值小的在前
            });
        }
        
        /// <summary>
        /// Z轴排序
        /// </summary>
        private void SortByZAxis(List<SpriteDepthInfo> depthInfos)
        {
            depthInfos.Sort((a, b) =>
            {
                return a.Renderer.transform.position.z.CompareTo(b.Renderer.transform.position.z);
            });
        }
        
        /// <summary>
        /// 自定义规则排序
        /// </summary>
        private void SortByCustomRule(List<SpriteDepthInfo> depthInfos)
        {
            if (customSortRule != null)
            {
                depthInfos.Sort((a, b) =>
                {
                    return customSortRule(a.Renderer, b.Renderer);
                });
            }
        }
        
        /// <summary>
        /// 应用排序顺序
        /// </summary>
        private void ApplySortingOrders(List<SpriteDepthInfo> depthInfos)
        {
            for (int i = 0; i < depthInfos.Count; i++)
            {
                depthInfos[i].Renderer.sortingOrder = i;
            }
        }
        
        /// <summary>
        /// 优化渲染批次
        /// 相同材质的Sprite连续渲染
        /// </summary>
        private void OptimizeRenderBatches(List<SpriteDepthInfo> depthInfos)
        {
            // 按材质分组
            var materialGroups = depthInfos
                .GroupBy(info => info.Renderer.sharedMaterial)
                .OrderBy(group => group.Key.GetInstanceID());
            
            int currentOrder = 0;
            
            foreach (var materialGroup in materialGroups)
            {
                // 对同一材质的Sprite按深度排序
                var sortedInGroup = materialGroup
                    .OrderBy(info => info.CalculatedDepth)
                    .ToList();
                
                // 分配连续的顺序
                foreach (var info in sortedInGroup)
                {
                    info.Renderer.sortingOrder = currentOrder++;
                }
            }
        }
        
        /// <summary>
        /// 手动排序Sprite
        /// 用于特定场景或性能敏感区域
        /// </summary>
        public void ManualSortSprite(SpriteRenderer sprite, int manualOrder)
        {
            if (sprite == null)
                return;
            
            // 暂时禁用动态排序
            bool wasDynamic = enableDynamicSorting;
            enableDynamicSorting = false;
            
            // 应用手动顺序
            sprite.sortingOrder = manualOrder;
            
            // 恢复原状态
            StartCoroutine(RestoreDynamicSorting(wasDynamic, 1f));
        }
        
        /// <summary>
        /// 恢复动态排序协程
        /// </summary>
        private System.Collections.IEnumerator RestoreDynamicSorting(bool shouldEnable, float delay)
        {
            yield return new WaitForSeconds(delay);
            enableDynamicSorting = shouldEnable;
        }
        
        /// <summary>
        /// 注册Sprite到排序系统
        /// </summary>
        public void RegisterSprite(SpriteRenderer sprite, string groupId = "Default")
        {
            if (sprite == null)
                return;
            
            if (!sortingGroups.ContainsKey(groupId))
            {
                sortingGroups[groupId] = new List<SpriteRenderer>();
            }
            
            if (!sortingGroups[groupId].Contains(sprite))
            {
                sortingGroups[groupId].Add(sprite);
                
                // 立即计算一次深度
                if (useCustomDepthCalculation)
                {
                    CalculateCustomDepth(sprite);
                }
            }
        }
        
        /// <summary>
        /// 取消注册Sprite
        /// </summary>
        public void UnregisterSprite(SpriteRenderer sprite)
        {
            foreach (var group in sortingGroups)
            {
                group.Value.Remove(sprite);
            }
        }
        
        /// <summary>
        /// 设置自定义排序规则
        /// </summary>
        public void SetCustomSortRule(CustomSortRule rule)
        {
            customSortRule = rule;
            sortingMethod = SortingMethod.CustomRule;
        }
        
        /// <summary>
        /// 强制立即更新排序
        /// </summary>
        public void ForceSortingUpdate()
        {
            UpdateAllSpriteSorting();
        }
        
        /// <summary>
        /// 获取Sprite的当前深度信息
        /// </summary>
        public SpriteDepthInfo GetSpriteDepthInfo(SpriteRenderer sprite)
        {
            foreach (var group in sortingGroups)
            {
                foreach (var s in group.Value)
                {
                    if (s == sprite)
                    {
                        float depth = CalculateDepthForSorting(sprite);
                        return new SpriteDepthInfo(sprite, depth, group.Key);
                    }
                }
            }
            
            return null;
        }
    }
}

7.1.3 Sprite裁切的几何算法与优化

Sprite裁切(Cropping)是2D游戏开发中常见的需求,特别是在实现血条、进度条、遮罩效果时。裁切涉及到纹理坐标的计算和几何变换。

纹理裁切数学原理:

裁切UV = 原始UV × 裁切比例 + 裁切偏移
裁切比例 = 目标尺寸 / 原始尺寸
裁切偏移 = 裁切起始位置 / 原始尺寸

以下是一个高级Sprite裁切系统的实现:

using UnityEngine;
using System.Collections.Generic;

namespace CommercialProject.Graphics2D
{
    /// <summary>
    /// 高级Sprite裁切系统
    /// 支持多种裁切模式和动态效果
    /// </summary>
    public class AdvancedSpriteCropper : MonoBehaviour
    {
        [SerializeField]
        private SpriteRenderer targetRenderer;
        
        [SerializeField]
        private CropMode cropMode = CropMode.Horizontal;
        
        [SerializeField]
        [Range(0, 1)]
        private float cropAmount = 1f;
        
        [SerializeField]
        private bool useWorldSpace = false;
        
        [SerializeField]
        private bool enableAnimation = false;
        
        [SerializeField]
        private float animationSpeed = 1f;
        
        // 材质属性ID缓存
        private static readonly int CropAmountId = Shader.PropertyToID("_CropAmount");
        private static readonly int CropDirectionId = Shader.PropertyToID("_CropDirection");
        private static readonly int CropCenterId = Shader.PropertyToID("_CropCenter");
        
        // 动画状态
        private float targetCropAmount;
        private float animationVelocity;
        
        // 自定义裁切区域
        private Rect customCropRect = new Rect(0, 0, 1, 1);
        
        /// <summary>
        /// 裁切模式枚举
        /// </summary>
        public enum CropMode
        {
            Horizontal,     // 水平裁切
            Vertical,       // 垂直裁切
            Radial,         // 径向裁切
            Custom,         // 自定义矩形
            Mask            // 遮罩裁切
        }
        
        /// <summary>
        /// 裁切动画曲线
        /// </summary>
        public AnimationCurve cropAnimationCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);
        
        private void Start()
        {
            InitializeCropSystem();
            
            if (enableAnimation)
            {
                targetCropAmount = cropAmount;
                StartCoroutine(AnimateCrop());
            }
        }
        
        private void Update()
        {
            if (enableAnimation)
            {
                UpdateCropAnimation();
            }
        }
        
        /// <summary>
        /// 初始化裁切系统
        /// </summary>
        private void InitializeCropSystem()
        {
            if (targetRenderer == null)
            {
                targetRenderer = GetComponent<SpriteRenderer>();
            }
            
            // 确保有材质实例
            if (targetRenderer != null)
            {
                targetRenderer.material = new Material(targetRenderer.material);
                
                // 设置初始裁切参数
                ApplyCropParameters();
            }
        }
        
        /// <summary>
        /// 应用裁切参数
        /// </summary>
        private void ApplyCropParameters()
        {
            if (targetRenderer == null || targetRenderer.material == null)
                return;
            
            Material material = targetRenderer.material;
            
            // 设置基本参数
            material.SetFloat(CropAmountId, cropAmount);
            
            // 根据模式设置方向
            Vector2 direction = Vector2.zero;
            Vector2 center = Vector2.zero;
            
            switch (cropMode)
            {
                case CropMode.Horizontal:
                    direction = Vector2.right;
                    center = new Vector2(0.5f, 0.5f);
                    break;
                    
                case CropMode.Vertical:
                    direction = Vector2.up;
                    center = new Vector2(0.5f, 0.5f);
                    break;
                    
                case CropMode.Radial:
                    direction = Vector2.one.normalized;
                    center = new Vector2(0.5f, 0.5f);
                    break;
                    
                case CropMode.Custom:
                    // 自定义矩形裁切
                    ApplyCustomCrop(material);
                    return;
                    
                case CropMode.Mask:
                    // 遮罩裁切需要额外的设置
                    ApplyMaskCrop(material);
                    return;
            }
            
            material.SetVector(CropDirectionId, direction);
            material.SetVector(CropCenterId, center);
        }
        
        /// <summary>
        /// 应用自定义裁切
        /// </summary>
        private void ApplyCustomCrop(Material material)
        {
            // 自定义矩形裁切使用四个参数
            material.SetVector("_CropRect", new Vector4(
                customCropRect.x,
                customCropRect.y,
                customCropRect.width,
                customCropRect.height
            ));
        }
        
        /// <summary>
        /// 应用遮罩裁切
        /// </summary>
        private void ApplyMaskCrop(Material material)
        {
            // 遮罩裁切需要遮罩纹理
            if (material.HasProperty("_MaskTex"))
            {
                // 可以在这里设置遮罩纹理
                // material.SetTexture("_MaskTex", maskTexture);
            }
        }
        
        /// <summary>
        /// 设置裁切比例
        /// </summary>
        public void SetCropAmount(float amount)
        {
            cropAmount = Mathf.Clamp01(amount);
            
            if (enableAnimation)
            {
                targetCropAmount = cropAmount;
            }
            else
            {
                ApplyCropParameters();
            }
        }
        
        /// <summary>
        /// 设置裁切模式
        /// </summary>
        public void SetCropMode(CropMode mode)
        {
            cropMode = mode;
            ApplyCropParameters();
        }
        
        /// <summary>
        /// 设置自定义裁切区域
        /// </summary>
        public void SetCustomCropRect(Rect rect)
        {
            customCropRect = rect;
            cropMode = CropMode.Custom;
            ApplyCropParameters();
        }
        
        /// <summary>
        /// 更新裁切动画
        /// </summary>
        private void UpdateCropAnimation()
        {
            if (Mathf.Abs(cropAmount - targetCropAmount) > 0.001f)
            {
                cropAmount = Mathf.SmoothDamp(
                    cropAmount, 
                    targetCropAmount, 
                    ref animationVelocity, 
                    0.3f / animationSpeed
                );
                
                ApplyCropParameters();
            }
        }
        
        /// <summary>
        /// 裁切动画协程
        /// </summary>
        private System.Collections.IEnumerator AnimateCrop()
        {
            while (true)
            {
                // 这里可以添加周期性动画效果
                yield return null;
            }
        }
        
        /// <summary>
        /// 基于世界坐标的裁切
        /// 例如:根据其他物体的位置进行裁切
        /// </summary>
        public void SetWorldSpaceCrop(Vector3 worldPosition, float influenceRadius)
        {
            if (!useWorldSpace)
                return;
            
            // 计算世界位置到本地位置的转换
            Vector3 localPosition = transform.InverseTransformPoint(worldPosition);
            
            // 计算裁切参数
            float distance = localPosition.magnitude;
            float cropValue = Mathf.Clamp01(distance / influenceRadius);
            
            SetCropAmount(cropValue);
        }
        
        /// <summary>
        /// 创建进度条裁切效果
        /// </summary>
        public void CreateProgressBarCrop(float progress, ProgressDirection direction = ProgressDirection.RightToLeft)
        {
            cropMode = CropMode.Horizontal;
            
            // 根据方向调整裁切
            switch (direction)
            {
                case ProgressDirection.LeftToRight:
                    SetCropAmount(progress);
                    break;
                    
                case ProgressDirection.RightToLeft:
                    SetCropAmount(1 - progress);
                    break;
                    
                case ProgressDirection.TopToBottom:
                    cropMode = CropMode.Vertical;
                    SetCropAmount(1 - progress);
                    break;
                    
                case ProgressDirection.BottomToTop:
                    cropMode = CropMode.Vertical;
                    SetCropAmount(progress);
                    break;
                    
                case ProgressDirection.RadialCW:
                    cropMode = CropMode.Radial;
                    SetCropAmount(progress);
                    // 需要设置旋转方向
                    break;
                    
                case ProgressDirection.RadialCCW:
                    cropMode = CropMode.Radial;
                    SetCropAmount(progress);
                    // 需要设置旋转方向
                    break;
            }
            
            ApplyCropParameters();
        }
        
        public enum ProgressDirection
        {
            LeftToRight,
            RightToLeft,
            TopToBottom,
            BottomToTop,
            RadialCW,
            RadialCCW
        }
        
        /// <summary>
        /// 创建遮罩裁切效果
        /// </summary>
        public void CreateMaskCrop(Texture2D maskTexture, bool invertMask = false)
        {
            if (targetRenderer == null || targetRenderer.material == null)
                return;
            
            cropMode = CropMode.Mask;
            
            Material material = targetRenderer.material;
            
            // 设置遮罩纹理
            if (material.HasProperty("_MaskTex"))
            {
                material.SetTexture("_MaskTex", maskTexture);
                material.SetFloat("_InvertMask", invertMask ? 1 : 0);
            }
            
            ApplyCropParameters();
        }
        
        /// <summary>
        /// 像素精确裁切
        /// 确保裁切边缘在像素边界上
        /// </summary>
        public void SetPixelPerfectCrop(float amount, int textureWidth)
        {
            // 计算最接近的像素边界
            int pixelCrop = Mathf.RoundToInt(amount * textureWidth);
            float perfectAmount = pixelCrop / (float)textureWidth;
            
            SetCropAmount(perfectAmount);
        }
        
        /// <summary>
        /// 批量裁切多个Sprite
        /// </summary>
        public static void BatchCropSprites(SpriteRenderer[] sprites, float amount, CropMode mode)
        {
            foreach (SpriteRenderer sprite in sprites)
            {
                var cropper = sprite.GetComponent<AdvancedSpriteCropper>();
                if (cropper == null)
                {
                    cropper = sprite.gameObject.AddComponent<AdvancedSpriteCropper>();
                }
                
                cropper.SetCropMode(mode);
                cropper.SetCropAmount(amount);
            }
        }
        
        /// <summary>
        /// 保存裁切状态
        /// </summary>
        public CropState SaveCropState()
        {
            return new CropState
            {
                CropAmount = cropAmount,
                Mode = cropMode,
                CustomRect = customCropRect,
                UseWorldSpace = useWorldSpace
            };
        }
        
        /// <summary>
        /// 恢复裁切状态
        /// </summary>
        public void RestoreCropState(CropState state)
        {
            cropAmount = state.CropAmount;
            cropMode = state.Mode;
            customCropRect = state.CustomRect;
            useWorldSpace = state.UseWorldSpace;
            
            ApplyCropParameters();
        }
        
        /// <summary>
        /// 裁切状态结构
        /// </summary>
        [System.Serializable]
        public struct CropState
        {
            public float CropAmount;
            public CropMode Mode;
            public Rect CustomRect;
            public bool UseWorldSpace;
        }
    }
}

7.2 Sprite动画的数学插值与控制

7.2.1 2D动画的创建与关键帧插值算法

2D动画的核心是帧插值(Interpolation)。在商业级2D游戏中,我们不仅需要基本的帧动画,还需要复杂的插值算法来实现平滑的动画效果。

插值算法分类:

  1. 线性插值(Lerp):最简单的插值方式
  2. 样条插值(Spline):使用贝塞尔曲线或Catmull-Rom曲线
  3. 球形插值(Slerp):用于旋转插值
  4. 缓动函数(Easing):各种数学缓动曲线

以下是一个高级2D动画系统的实现:

using UnityEngine;
using System.Collections.Generic;

namespace CommercialProject.Animation2D
{
    /// <summary>
    /// 高级2D动画系统
    /// 支持多种插值算法和动画混合
    /// </summary>
    public class AdvancedSpriteAnimator : MonoBehaviour
    {
        [SerializeField]
        private SpriteRenderer targetRenderer;
        
        [SerializeField]
        private List<AnimationClip2D> animationClips;
        
        [SerializeField]
        private bool playOnStart = true;
        
        [SerializeField]
        private string defaultClipName = "Idle";
        
        // 动画状态
        private AnimationClip2D currentClip;
        private float currentTime;
        private bool isPlaying;
        private float playbackSpeed = 1f;
        
        // 插值算法
        private InterpolationMethod interpolationMethod = InterpolationMethod.Linear;
        
        // 动画事件
        public event System.Action<string> OnAnimationEvent;
        public event System.Action OnAnimationComplete;
        
        /// <summary>
        /// 2D动画剪辑
        /// </summary>
        [System.Serializable]
        public class AnimationClip2D
        {
            public string ClipName;
            public Sprite[] Frames;
            public float FrameRate = 12f;
            public bool Loop = true;
            public AnimationEvent2D[] Events;
            
            // 计算属性
            public float FrameDuration => 1f / FrameRate;
            public float TotalDuration => Frames.Length * FrameDuration;
            
            /// <summary>
            /// 获取指定时间的Sprite
            /// </summary>
            public Sprite GetSpriteAtTime(float time)
            {
                if (Frames == null || Frames.Length == 0)
                    return null;
                
                if (Loop)
                {
                    time %= TotalDuration;
                }
                else
                {
                    time = Mathf.Clamp(time, 0, TotalDuration);
                }
                
                float frameFloat = time / FrameDuration;
                int frameIndex = Mathf.FloorToInt(frameFloat);
                
                if (frameIndex >= Frames.Length)
                {
                    frameIndex = Frames.Length - 1;
                }
                
                return Frames[frameIndex];
            }
        }
        
        /// <summary>
        /// 动画事件
        /// </summary>
        [System.Serializable]
        public class AnimationEvent2D
        {
            public string EventName;
            public float TriggerTime;
            public bool HasTriggered;
        }
        
        /// <summary>
        /// 插值方法枚举
        /// </summary>
        public enum InterpolationMethod
        {
            Linear,
            EaseInOut,
            Spring,
            Bounce,
            CustomCurve
        }
        
        private void Start()
        {
            InitializeAnimator();
            
            if (playOnStart && !string.IsNullOrEmpty(defaultClipName))
            {
                Play(defaultClipName);
            }
        }
        
        private void Update()
        {
            if (isPlaying && currentClip != null)
            {
                UpdateAnimation(Time.deltaTime);
            }
        }
        
        /// <summary>
        /// 初始化动画器
        /// </summary>
        private void InitializeAnimator()
        {
            if (targetRenderer == null)
            {
                targetRenderer = GetComponent<SpriteRenderer>();
            }
            
            // 验证动画剪辑
            ValidateAnimationClips();
        }
        
        /// <summary>
        /// 验证动画剪辑
        /// </summary>
        private void ValidateAnimationClips()
        {
            foreach (var clip in animationClips)
            {
                if (clip.Frames == null || clip.Frames.Length == 0)
                {
                    Debug.LogWarning($"Animation clip '{clip.ClipName}' has no frames!");
                }
            }
        }
        
        /// <summary>
        /// 播放动画
        /// </summary>
        public void Play(string clipName, float speed = 1f)
        {
            AnimationClip2D clip = FindClipByName(clipName);
            if (clip == null)
            {
                Debug.LogWarning($"Animation clip '{clipName}' not found!");
                return;
            }
            
            currentClip = clip;
            currentTime = 0f;
            playbackSpeed = speed;
            isPlaying = true;
            
            // 重置事件触发状态
            ResetEventStates();
            
            // 立即更新第一帧
            UpdateSprite();
        }
        
        /// <summary>
        /// 通过名称查找剪辑
        /// </summary>
        private AnimationClip2D FindClipByName(string name)
        {
            foreach (var clip in animationClips)
            {
                if (clip.ClipName == name)
                {
                    return clip;
                }
            }
            return null;
        }
        
        /// <summary>
        /// 重置事件状态
        /// </summary>
        private void ResetEventStates()
        {
            if (currentClip?.Events != null)
            {
                foreach (var evt in currentClip.Events)
                {
                    evt.HasTriggered = false;
                }
            }
        }
        
        /// <summary>
        /// 更新动画
        /// </summary>
        private void UpdateAnimation(float deltaTime)
        {
            // 应用播放速度
            float scaledDeltaTime = deltaTime * playbackSpeed;
            
            // 更新动画时间
            float previousTime = currentTime;
            currentTime += scaledDeltaTime;
            
            // 检查动画事件
            CheckAnimationEvents(previousTime, currentTime);
            
            // 更新Sprite
            UpdateSprite();
            
            // 检查动画是否完成
            if (!currentClip.Loop && currentTime >= currentClip.TotalDuration)
            {
                OnAnimationComplete?.Invoke();
                
                // 可以在这里触发下一个动画或停止
                if (animationClips.Count > 0)
                {
                    // 自动切换到默认动画
                    Play(defaultClipName);
                }
                else
                {
                    isPlaying = false;
                }
            }
        }
        
        /// <summary>
        /// 检查动画事件
        /// </summary>
        private void CheckAnimationEvents(float previousTime, float currentTime)
        {
            if (currentClip?.Events == null)
                return;
            
            foreach (var evt in currentClip.Events)
            {
                if (!evt.HasTriggered && 
                    currentTime >= evt.TriggerTime && 
                    previousTime < evt.TriggerTime)
                {
                    evt.HasTriggered = true;
                    OnAnimationEvent?.Invoke(evt.EventName);
                }
            }
        }
        
        /// <summary>
        /// 更新Sprite
        /// 应用插值算法
        /// </summary>
        private void UpdateSprite()
        {
            if (currentClip == null || targetRenderer == null)
                return;
            
            Sprite currentSprite = currentClip.GetSpriteAtTime(currentTime);
            
            if (currentSprite != null)
            {
                targetRenderer.sprite = currentSprite;
            }
        }
        
        /// <summary>
        /// 停止动画
        /// </summary>
        public void Stop()
        {
            isPlaying = false;
            currentTime = 0f;
        }
        
        /// <summary>
        /// 暂停动画
        /// </summary>
        public void Pause()
        {
            isPlaying = false;
        }
        
        /// <summary>
        /// 恢复动画
        /// </summary>
        public void Resume()
        {
            if (currentClip != null)
            {
                isPlaying = true;
            }
        }
        
        /// <summary>
        /// 设置播放速度
        /// </summary>
        public void SetPlaybackSpeed(float speed)
        {
            playbackSpeed = speed;
        }
        
        /// <summary>
        /// 跳转到指定时间
        /// </summary>
        public void Seek(float time)
        {
            if (currentClip != null)
            {
                currentTime = Mathf.Clamp(time, 0, currentClip.TotalDuration);
                UpdateSprite();
            }
        }
        
        /// <summary>
        /// 跳转到指定帧
        /// </summary>
        public void SeekFrame(int frameIndex)
        {
            if (currentClip != null && currentClip.Frames != null)
            {
                frameIndex = Mathf.Clamp(frameIndex, 0, currentClip.Frames.Length - 1);
                currentTime = frameIndex * currentClip.FrameDuration;
                UpdateSprite();
            }
        }
        
        /// <summary>
        /// 获取当前动画进度(0-1)
        /// </summary>
        public float GetNormalizedTime()
        {
            if (currentClip == null)
                return 0f;
            
            return currentTime / currentClip.TotalDuration;
        }
        
        /// <summary>
        /// 添加动画剪辑
        /// </summary>
        public void AddAnimationClip(AnimationClip2D clip)
        {
            if (FindClipByName(clip.ClipName) == null)
            {
                animationClips.Add(clip);
            }
            else
            {
                Debug.LogWarning($"Animation clip '{clip.ClipName}' already exists!");
            }
        }
        
        /// <summary>
        /// 移除动画剪辑
        /// </summary>
        public void RemoveAnimationClip(string clipName)
        {
            AnimationClip2D clip = FindClipByName(clipName);
            if (clip != null)
            {
                animationClips.Remove(clip);
                
                if (currentClip == clip)
                {
                    currentClip = null;
                    isPlaying = false;
                }
            }
        }
        
        /// <summary>
        /// 创建动画事件
        /// </summary>
        public void AddAnimationEvent(string clipName, string eventName, float triggerTime)
        {
            AnimationClip2D clip = FindClipByName(clipName);
            if (clip != null)
            {
                if (clip.Events == null)
                {
                    clip.Events = new AnimationEvent2D[0];
                }
                
                var newEvent = new AnimationEvent2D
                {
                    EventName = eventName,
                    TriggerTime = triggerTime,
                    HasTriggered = false
                };
                
                var eventList = new List<AnimationEvent2D>(clip.Events);
                eventList.Add(newEvent);
                clip.Events = eventList.ToArray();
            }
        }
        
        /// <summary>
        /// 交叉淡入淡出动画
        /// </summary>
        public void CrossFade(string toClipName, float fadeDuration)
        {
            if (!isPlaying || currentClip == null)
            {
                Play(toClipName);
                return;
            }
            
            StartCoroutine(CrossFadeCoroutine(toClipName, fadeDuration));
        }
        
        /// <summary>
        /// 交叉淡入淡出协程
        /// </summary>
        private System.Collections.IEnumerator CrossFadeCoroutine(string toClipName, float fadeDuration)
        {
            AnimationClip2D fromClip = currentClip;
            AnimationClip2D toClip = FindClipByName(toClipName);
            
            if (toClip == null)
                yield break;
            
            // 创建临时SpriteRenderer用于混合
            GameObject tempObject = new GameObject("TempSprite");
            tempObject.transform.SetParent(transform);
            tempObject.transform.localPosition = Vector3.zero;
            
            SpriteRenderer tempRenderer = tempObject.AddComponent<SpriteRenderer>();
            tempRenderer.sprite = targetRenderer.sprite;
            tempRenderer.sortingOrder = targetRenderer.sortingOrder - 1;
            
            // 播放新动画
            Play(toClipName);
            
            // 淡出旧动画
            float elapsedTime = 0f;
            while (elapsedTime < fadeDuration)
            {
                elapsedTime += Time.deltaTime;
                float t = elapsedTime / fadeDuration;
                
                // 更新透明度
                Color color = tempRenderer.color;
                color.a = 1f - t;
                tempRenderer.color = color;
                
                yield return null;
            }
            
            // 清理临时对象
            Destroy(tempObject);
        }
        
        /// <summary>
        /// 获取当前动画信息
        /// </summary>
        public AnimationInfo GetCurrentAnimationInfo()
        {
            return new AnimationInfo
            {
                ClipName = currentClip?.ClipName,
                IsPlaying = isPlaying,
                CurrentTime = currentTime,
                NormalizedTime = GetNormalizedTime(),
                FrameIndex = GetCurrentFrameIndex()
            };
        }
        
        /// <summary>
        /// 获取当前帧索引
        /// </summary>
        private int GetCurrentFrameIndex()
        {
            if (currentClip == null)
                return -1;
            
            return Mathf.FloorToInt(currentTime / currentClip.FrameDuration);
        }
        
        /// <summary>
        /// 动画信息结构
        /// </summary>
        public struct AnimationInfo
        {
            public string ClipName;
            public bool IsPlaying;
            public float CurrentTime;
            public float NormalizedTime;
            public int FrameIndex;
        }
    }
}

7.2.2 2D动画控制器的状态机与混合树

在商业级2D游戏中,复杂的角色动画需要状态机(State Machine)和动画混合(Animation Blending)系统。这些系统基于图论和插值数学。

动画混合原理:

  • 线性混合result = animation1 * weight1 + animation2 * weight2
  • 加法混合result = base + additive
  • 同步混合:确保动画时间同步

以下是一个高级2D动画控制器的实现:

using UnityEngine;
using System.Collections.Generic;

namespace CommercialProject.Animation2D
{
    /// <summary>
    /// 高级2D动画控制器
    /// 支持状态机、混合树和图层系统
    /// </summary>
    public class AdvancedAnimationController2D : MonoBehaviour
    {
        [SerializeField]
        private SpriteRenderer targetRenderer;
        
        [SerializeField]
        private AnimationStateMachine stateMachine;
        
        [SerializeField]
        private List<AnimationLayer> animationLayers;
        
        [SerializeField]
        private bool updateRootMotion = false;
        
        // 当前状态
        private AnimationState currentState;
        private float stateTransitionTime;
        private float stateTransitionDuration;
        
        // 混合树
        private BlendTree2D currentBlendTree;
        private Vector2 blendParameters;
        
        /// <summary>
        /// 动画状态机
        /// </summary>
        [System.Serializable]
        public class AnimationStateMachine
        {
            public List<AnimationState> States;
            public List<AnimationTransition> Transitions;
            public string DefaultStateName;
            
            /// <summary>
            /// 查找状态
            /// </summary>
            public AnimationState FindState(string stateName)
            {
                foreach (var state in States)
                {
                    if (state.StateName == stateName)
                    {
                        return state;
                    }
                }
                return null;
            }
            
            /// <summary>
            /// 获取状态转换
            /// </summary>
            public AnimationTransition[] GetTransitionsFromState(string fromState)
            {
                List<AnimationTransition> result = new List<AnimationTransition>();
                
                foreach (var transition in Transitions)
                {
                    if (transition.FromState == fromState)
                    {
                        result.Add(transition);
                    }
                }
                
                return result.ToArray();
            }
        }
        
        /// <summary>
        /// 动画状态
        /// </summary>
        [System.Serializable]
        public class AnimationState
        {
            public string StateName;
            public AdvancedSpriteAnimator.AnimationClip2D AnimationClip;
            public float Speed = 1f;
            public bool Loop = true;
            public AnimationBlendMode BlendMode = AnimationBlendMode.Override;
            public float TransitionDuration = 0.2f;
            
            // 根运动数据
            public Vector2 RootMotionDelta;
            public bool HasRootMotion;
        }
        
        /// <summary>
        /// 动画转换
        /// </summary>
        [System.Serializable]
        public class AnimationTransition
        {
            public string FromState;
            public string ToState;
            public TransitionCondition[] Conditions;
            public float TransitionDuration = 0.2f;
            public bool HasExitTime;
            public float ExitTime = 0.8f;
            
            /// <summary>
            /// 检查条件是否满足
            /// </summary>
            public bool CheckConditions(AnimationParameters parameters)
            {
                foreach (var condition in Conditions)
                {
                    if (!condition.IsMet(parameters))
                    {
                        return false;
                    }
                }
                return true;
            }
        }
        
        /// <summary>
        /// 转换条件
        /// </summary>
        [System.Serializable]
        public class TransitionCondition
        {
            public string ParameterName;
            public ConditionType Type;
            public float FloatValue;
            public bool BoolValue;
            public int IntValue;
            
            public enum ConditionType
            {
                FloatGreater,
                FloatLess,
                BoolEquals,
                IntGreater,
                IntLess
            }
            
            public bool IsMet(AnimationParameters parameters)
            {
                AnimationParameter parameter = parameters.GetParameter(ParameterName);
                if (parameter == null)
                    return false;
                
                switch (Type)
                {
                    case ConditionType.FloatGreater:
                        return parameter.FloatValue > FloatValue;
                        
                    case ConditionType.FloatLess:
                        return parameter.FloatValue < FloatValue;
                        
                    case ConditionType.BoolEquals:
                        return parameter.BoolValue == BoolValue;
                        
                    case ConditionType.IntGreater:
                        return parameter.IntValue > IntValue;
                        
                    case ConditionType.IntLess:
                        return parameter.IntValue < IntValue;
                        
                    default:
                        return false;
                }
            }
        }
        
        /// <summary>
        /// 动画参数
        /// </summary>
        [System.Serializable]
        public class AnimationParameters
        {
            private Dictionary<string, AnimationParameter> parameters;
            
            public AnimationParameters()
            {
                parameters = new Dictionary<string, AnimationParameter>();
            }
            
            public void SetFloat(string name, float value)
            {
                if (!parameters.ContainsKey(name))
                {
                    parameters[name] = new AnimationParameter(name);
                }
                parameters[name].FloatValue = value;
            }
            
            public void SetBool(string name, bool value)
            {
                if (!parameters.ContainsKey(name))
                {
                    parameters[name] = new AnimationParameter(name);
                }
                parameters[name].BoolValue = value;
            }
            
            public void SetInt(string name, int value)
            {
                if (!parameters.ContainsKey(name))
                {
                    parameters[name] = new AnimationParameter(name);
                }
                parameters[name].IntValue = value;
            }
            
            public AnimationParameter GetParameter(string name)
            {
                if (parameters.ContainsKey(name))
                {
                    return parameters[name];
                }
                return null;
            }
        }
        
        /// <summary>
        /// 动画参数类
        /// </summary>
        [System.Serializable]
        public class AnimationParameter
        {
            public string Name;
            public float FloatValue;
            public bool BoolValue;
            public int IntValue;
            
            public AnimationParameter(string name)
            {
                Name = name;
            }
        }
        
        /// <summary>
        /// 动画混合模式
        /// </summary>
        public enum AnimationBlendMode
        {
            Override,
            Additive,
            Multiply
        }
        
        /// <summary>
        /// 动画图层
        /// </summary>
        [System.Serializable]
        public class AnimationLayer
        {
            public string LayerName;
            public float Weight = 1f;
            public AnimationBlendMode BlendMode = AnimationBlendMode.Override;
            public AvatarMask Mask;
            public AnimationState CurrentState;
            
            // 用于混合
            public AnimationState PreviousState;
            public float TransitionProgress;
        }
        
        /// <summary>
        /// 2D混合树
        /// </summary>
        [System.Serializable]
        public class BlendTree2D
        {
            public string TreeName;
            public BlendTreeMotion[] Motions;
            public Vector2 ParameterRange = new Vector2(-1, 1);
            
            /// <summary>
            /// 获取混合后的动画
            /// </summary>
            public AdvancedSpriteAnimator.AnimationClip2D GetBlendedClip(Vector2 parameters)
            {
                if (Motions == null || Motions.Length == 0)
                    return null;
                
                if (Motions.Length == 1)
                    return Motions[0].Clip;
                
                // 计算每个Motion的权重
                float[] weights = new float[Motions.Length];
                float totalWeight = 0f;
                
                for (int i = 0; i < Motions.Length; i++)
                {
                    float distance = Vector2.Distance(parameters, Motions[i].Position);
                    float weight = 1f / (distance + 0.001f); // 防止除零
                    weights[i] = weight;
                    totalWeight += weight;
                }
                
                // 归一化权重
                for (int i = 0; i < weights.Length; i++)
                {
                    weights[i] /= totalWeight;
                }
                
                // 创建混合后的剪辑(简化实现)
                // 实际项目中需要更复杂的混合算法
                return Motions[0].Clip; // 简化返回第一个
            }
        }
        
        /// <summary>
        /// 混合树Motion
        /// </summary>
        [System.Serializable]
        public class BlendTreeMotion
        {
            public AdvancedSpriteAnimator.AnimationClip2D Clip;
            public Vector2 Position;
            public float Threshold = 0.1f;
        }
        
        // 动画参数实例
        private AnimationParameters animationParameters;
        
        private void Start()
        {
            InitializeController();
            
            // 进入默认状态
            if (!string.IsNullOrEmpty(stateMachine.DefaultStateName))
            {
                TransitionToState(stateMachine.DefaultStateName, 0f);
            }
        }
        
        private void Update()
        {
            UpdateStateMachine();
            UpdateAnimationLayers();
            ApplyRootMotion();
        }
        
        /// <summary>
        /// 初始化控制器
        /// </summary>
        private void InitializeController()
        {
            if (targetRenderer == null)
            {
                targetRenderer = GetComponent<SpriteRenderer>();
            }
            
            animationParameters = new AnimationParameters();
            
            // 初始化图层
            if (animationLayers == null)
            {
                animationLayers = new List<AnimationLayer>();
                
                // 创建基础层
                AnimationLayer baseLayer = new AnimationLayer
                {
                    LayerName = "Base Layer",
                    Weight = 1f
                };
                animationLayers.Add(baseLayer);
            }
        }
        
        /// <summary>
        /// 更新状态机
        /// </summary>
        private void UpdateStateMachine()
        {
            if (currentState == null)
                return;
            
            // 检查状态转换
            CheckStateTransitions();
            
            // 更新状态过渡
            UpdateStateTransition();
        }
        
        /// <summary>
        /// 检查状态转换
        /// </summary>
        private void CheckStateTransitions()
        {
            if (stateTransitionTime < stateTransitionDuration)
                return; // 正在过渡中
            
            AnimationTransition[] transitions = stateMachine.GetTransitionsFromState(currentState.StateName);
            
            foreach (var transition in transitions)
            {
                // 检查退出时间
                if (transition.HasExitTime)
                {
                    // 需要获取动画的标准化时间
                    // 这里简化处理
                }
                
                // 检查条件
                if (transition.CheckConditions(animationParameters))
                {
                    TransitionToState(transition.ToState, transition.TransitionDuration);
                    break;
                }
            }
        }
        
        /// <summary>
        /// 转换到状态
        /// </summary>
        public void TransitionToState(string stateName, float transitionDuration)
        {
            AnimationState newState = stateMachine.FindState(stateName);
            if (newState == null)
            {
                Debug.LogWarning($"State '{stateName}' not found!");
                return;
            }
            
            // 设置过渡
            if (currentState != null)
            {
                stateTransitionTime = 0f;
                stateTransitionDuration = transitionDuration;
            }
            
            // 更新当前状态
            currentState = newState;
            
            // 更新基础层
            if (animationLayers.Count > 0)
            {
                animationLayers[0].PreviousState = animationLayers[0].CurrentState;
                animationLayers[0].CurrentState = newState;
                animationLayers[0].TransitionProgress = 0f;
            }
        }
        
        /// <summary>
        /// 更新状态过渡
        /// </summary>
        private void UpdateStateTransition()
        {
            if (stateTransitionTime < stateTransitionDuration)
            {
                stateTransitionTime += Time.deltaTime;
                
                // 更新基础层过渡进度
                if (animationLayers.Count > 0)
                {
                    animationLayers[0].TransitionProgress = 
                        Mathf.Clamp01(stateTransitionTime / stateTransitionDuration);
                }
            }
        }
        
        /// <summary>
        /// 更新动画图层
        /// </summary>
        private void UpdateAnimationLayers()
        {
            // 基础层始终存在
            if (animationLayers.Count == 0)
                return;
            
            // 更新基础层
            UpdateLayer(animationLayers[0]);
            
            // 如果有更多图层,混合它们
            for (int i = 1; i < animationLayers.Count; i++)
            {
                UpdateLayer(animationLayers[i]);
                BlendLayerWithBase(animationLayers[i]);
            }
        }
        
        /// <summary>
        /// 更新图层
        /// </summary>
        private void UpdateLayer(AnimationLayer layer)
        {
            if (layer.CurrentState == null)
                return;
            
            // 更新过渡进度
            if (layer.TransitionProgress < 1f)
            {
                layer.TransitionProgress += Time.deltaTime / layer.CurrentState.TransitionDuration;
                layer.TransitionProgress = Mathf.Clamp01(layer.TransitionProgress);
            }
        }
        
        /// <summary>
        /// 图层与基础层混合
        /// </summary>
        private void BlendLayerWithBase(AnimationLayer layer)
        {
            if (layer.CurrentState == null || layer.Weight <= 0f)
                return;
            
            // 根据混合模式混合动画
            switch (layer.BlendMode)
            {
                case AnimationBlendMode.Additive:
                    // 加法混合:基础层 + 当前层
                    ApplyAdditiveBlend(layer);
                    break;
                    
                case AnimationBlendMode.Multiply:
                    // 乘法混合:基础层 × 当前层
                    ApplyMultiplicativeBlend(layer);
                    break;
                    
                case AnimationBlendMode.Override:
                    // 覆盖混合:使用当前层覆盖基础层
                    ApplyOverrideBlend(layer);
                    break;
            }
        }
        
        /// <summary>
        /// 应用加法混合
        /// </summary>
        private void ApplyAdditiveBlend(AnimationLayer layer)
        {
            // 在实际项目中,这里需要实现动画的加法混合
            // 这通常涉及对Sprite的变换进行加法操作
        }
        
        /// <summary>
        /// 设置动画参数
        /// </summary>
        public void SetFloat(string name, float value)
        {
            animationParameters.SetFloat(name, value);
            
            // 如果使用混合树,更新混合参数
            if (currentBlendTree != null)
            {
                // 根据参数更新混合
                UpdateBlendTreeParameters();
            }
        }
        
        public void SetBool(string name, bool value)
        {
            animationParameters.SetBool(name, value);
        }
        
        public void SetInt(string name, int value)
        {
            animationParameters.SetInt(name, value);
        }
        
        /// <summary>
        /// 设置混合参数
        /// </summary>
        public void SetBlendParameters(Vector2 parameters)
        {
            blendParameters = parameters;
            
            if (currentBlendTree != null)
            {
                // 更新混合树
                UpdateBlendTree();
            }
        }
        
        /// <summary>
        /// 更新混合树
        /// </summary>
        private void UpdateBlendTree()
        {
            if (currentBlendTree == null)
                return;
            
            // 获取混合后的动画剪辑
            var blendedClip = currentBlendTree.GetBlendedClip(blendParameters);
            
            if (blendedClip != null)
            {
                // 创建临时状态用于混合树
                AnimationState blendState = new AnimationState
                {
                    StateName = "BlendTree",
                    AnimationClip = blendedClip,
                    Speed = 1f,
                    Loop = true
                };
                
                // 设置到基础层
                if (animationLayers.Count > 0)
                {
                    animationLayers[0].CurrentState = blendState;
                }
            }
        }
        
        /// <summary>
        /// 应用根运动
        /// </summary>
        private void ApplyRootMotion()
        {
            if (!updateRootMotion || currentState == null || !currentState.HasRootMotion)
                return;
            
            // 计算根运动位移
            Vector2 motionDelta = currentState.RootMotionDelta * Time.deltaTime;
            
            // 应用到Transform
            transform.Translate(motionDelta, Space.World);
        }
        
        /// <summary>
        /// 添加动画图层
        /// </summary>
        public void AddAnimationLayer(string layerName, float weight = 1f, AvatarMask mask = null)
        {
            AnimationLayer newLayer = new AnimationLayer
            {
                LayerName = layerName,
                Weight = weight,
                Mask = mask
            };
            
            animationLayers.Add(newLayer);
        }
        
        /// <summary>
        /// 移除动画图层
        /// </summary>
        public void RemoveAnimationLayer(string layerName)
        {
            for (int i = animationLayers.Count - 1; i >= 0; i--)
            {
                if (animationLayers[i].LayerName == layerName)
                {
                    animationLayers.RemoveAt(i);
                    break;
                }
            }
        }
        
        /// <summary>
        /// 设置图层权重
        /// </summary>
        public void SetLayerWeight(string layerName, float weight)
        {
            foreach (var layer in animationLayers)
            {
                if (layer.LayerName == layerName)
                {
                    layer.Weight = Mathf.Clamp01(weight);
                    break;
                }
            }
        }
        
        /// <summary>
        /// 获取当前状态信息
        /// </summary>
        public StateInfo GetCurrentStateInfo()
        {
            return new StateInfo
            {
                StateName = currentState?.StateName,
                IsTransitioning = stateTransitionTime < stateTransitionDuration,
                TransitionProgress = stateTransitionTime / stateTransitionDuration
            };
        }
        
        /// <summary>
        /// 状态信息结构
        /// </summary>
        public struct StateInfo
        {
            public string StateName;
            public bool IsTransitioning;
            public float TransitionProgress;
        }
    }
}

7.3 Tile地图的数学算法与高级编辑

7.3.1 Tile的创建与自动拼接算法

Tile地图系统的核心是自动拼接算法(Auto-Tiling)。商业级2D游戏需要复杂的拼接规则和高效的生成算法。

自动拼接算法原理:

  1. 位掩码算法:使用4位或8位表示相邻Tile
  2. Marching Squares:用于生成平滑边界
  3. Wang Tiles:使用预先设计的Tile集合

以下是一个高级Tile系统的实现:

using UnityEngine;
using UnityEngine.Tilemaps;
using System.Collections.Generic;

namespace CommercialProject.TilemapSystem
{
    /// <summary>
    /// 高级Tile系统
    /// 支持自动拼接、动态生成和优化
    /// </summary>
    public class AdvancedTileSystem : MonoBehaviour
    {
        [SerializeField]
        private Tilemap targetTilemap;
        
        [SerializeField]
        private AdvancedRuleTile ruleTile;
        
        [SerializeField]
        private bool enableAutoUpdate = true;
        
        [SerializeField]
        private OptimizationLevel optimizationLevel = OptimizationLevel.Medium;
        
        // Tile数据缓存
        private Dictionary<Vector3Int, TileData> tileDataCache;
        private Dictionary<Vector3Int, TileNeighbors> neighborCache;
        
        /// <summary>
        /// Tile数据
        /// </summary>
        public class TileData
        {
            public Vector3Int Position;
            public TileBase Tile;
            public int TileId;
            public int VariantIndex;
            public TileFlags Flags;
            public Color Color;
        }
        
        /// <summary>
        /// 邻居信息
        /// </summary>
        public struct TileNeighbors
        {
            public TileBase Up;
            public TileBase Down;
            public TileBase Left;
            public TileBase Right;
            public TileBase UpLeft;
            public TileBase UpRight;
            public TileBase DownLeft;
            public TileBase DownRight;
            
            /// <summary>
            /// 计算位掩码
            /// </summary>
            public int CalculateBitmask(TileBase self)
            {
                int mask = 0;
                
                // 4位方向
                if (Up == self) mask |= 1 << 0;     // 上
                if (Right == self) mask |= 1 << 1;   // 右
                if (Down == self) mask |= 1 << 2;    // 下
                if (Left == self) mask |= 1 << 3;    // 左
                
                // 8位方向(如果需要)
                // if (UpLeft == self) mask |= 1 << 4;
                // if (UpRight == self) mask |= 1 << 5;
                // if (DownLeft == self) mask |= 1 << 6;
                // if (DownRight == self) mask |= 1 << 7;
                
                return mask;
            }
        }
        
        /// <summary>
        /// 优化级别
        /// </summary>
        public enum OptimizationLevel
        {
            None,
            Low,
            Medium,
            High
        }
        
        /// <summary>
        /// 高级规则Tile
        /// </summary>
        [CreateAssetMenu(fileName = "AdvancedRuleTile", menuName = "2D/Tiles/Advanced Rule Tile")]
        public class AdvancedRuleTile : RuleTile
        {
            // 扩展规则Tile以支持更多功能
            
            [System.Serializable]
            public class ExtendedRule : RuleTile.TilingRule
            {
                public int Priority = 0;
                public bool UseRandomVariant = false;
                public TileBase[] RandomVariants;
                public AnimationCurve VariantDistribution;
            }
            
            public ExtendedRule[] extendedRules;
            
            public override bool RuleMatch(int neighbor, TileBase other)
            {
                // 扩展匹配规则
                if (neighbor == RuleTile.TilingRule.Neighbor.NotEmpty && other != null)
                    return true;
                
                if (neighbor == RuleTile.TilingRule.Neighbor.Empty && other == null)
                    return true;
                
                return base.RuleMatch(neighbor, other);
            }
            
            /// <summary>
            /// 获取匹配的规则
            /// </summary>
            public ExtendedRule GetMatchingRule(TileNeighbors neighbors, TileBase self)
            {
                if (extendedRules == null)
                    return null;
                
                // 按优先级排序
                List<ExtendedRule> sortedRules = new List<ExtendedRule>(extendedRules);
                sortedRules.Sort((a, b) => b.Priority.CompareTo(a.Priority));
                
                foreach (var rule in sortedRules)
                {
                    if (CheckRuleMatch(rule, neighbors, self))
                    {
                        return rule;
                    }
                }
                
                return null;
            }
            
            /// <summary>
            /// 检查规则匹配
            /// </summary>
            private bool CheckRuleMatch(ExtendedRule rule, TileNeighbors neighbors, TileBase self)
            {
                // 检查每个方向的匹配
                if (!CheckDirectionMatch(rule.m_Neighbors[0], neighbors.Up, self))
                    return false;
                if (!CheckDirectionMatch(rule.m_Neighbors[1], neighbors.Right, self))
                    return false;
                if (!CheckDirectionMatch(rule.m_Neighbors[2], neighbors.Down, self))
                    return false;
                if (!CheckDirectionMatch(rule.m_Neighbors[3], neighbors.Left, self))
                    return false;
                
                return true;
            }
            
            private bool CheckDirectionMatch(int ruleNeighbor, TileBase actualTile, TileBase self)
            {
                if (ruleNeighbor == TilingRule.Neighbor.This)
                    return actualTile == self;
                if (ruleNeighbor == TilingRule.Neighbor.NotThis)
                    return actualTile != self && actualTile != null;
                if (ruleNeighbor == TilingRule.Neighbor.Any)
                    return true;
                if (ruleNeighbor == TilingRule.Neighbor.Empty)
                    return actualTile == null;
                
                return base.RuleMatch(ruleNeighbor, actualTile);
            }
        }
        
        private void Awake()
        {
            InitializeTileSystem();
        }
        
        private void Start()
        {
            BuildTileCache();
            
            if (enableAutoUpdate)
            {
                StartCoroutine(AutoUpdateTiles());
            }
        }
        
        /// <summary>
        /// 初始化Tile系统
        /// </summary>
        private void InitializeTileSystem()
        {
            if (targetTilemap == null)
            {
                targetTilemap = GetComponent<Tilemap>();
            }
            
            tileDataCache = new Dictionary<Vector3Int, TileData>();
            neighborCache = new Dictionary<Vector3Int, TileNeighbors>();
        }
        
        /// <summary>
        /// 构建Tile缓存
        /// </summary>
        private void BuildTileCache()
        {
            tileDataCache.Clear();
            neighborCache.Clear();
            
            // 获取Tilemap边界
            targetTilemap.CompressBounds();
            BoundsInt bounds = targetTilemap.cellBounds;
            
            // 遍历所有Tile
            for (int x = bounds.xMin; x < bounds.xMax; x++)
            {
                for (int y = bounds.yMin; y < bounds.yMax; y++)
                {
                    Vector3Int position = new Vector3Int(x, y, 0);
                    TileBase tile = targetTilemap.GetTile(position);
                    
                    if (tile != null)
                    {
                        // 存储Tile数据
                        TileData data = new TileData
                        {
                            Position = position,
                            Tile = tile,
                            TileId = tile.GetInstanceID(),
                            Color = targetTilemap.GetColor(position)
                        };
                        
                        tileDataCache[position] = data;
                        
                        // 计算并存储邻居信息
                        TileNeighbors neighbors = CalculateNeighbors(position);
                        neighborCache[position] = neighbors;
                    }
                }
            }
        }
        
        /// <summary>
        /// 计算邻居信息
        /// </summary>
        private TileNeighbors CalculateNeighbors(Vector3Int position)
        {
            TileNeighbors neighbors = new TileNeighbors();
            
            // 4方向邻居
            neighbors.Up = targetTilemap.GetTile(position + Vector3Int.up);
            neighbors.Down = targetTilemap.GetTile(position + Vector3Int.down);
            neighbors.Left = targetTilemap.GetTile(position + Vector3Int.left);
            neighbors.Right = targetTilemap.GetTile(position + Vector3Int.right);
            
            // 8方向邻居(对角线)
            neighbors.UpLeft = targetTilemap.GetTile(position + Vector3Int.up + Vector3Int.left);
            neighbors.UpRight = targetTilemap.GetTile(position + Vector3Int.up + Vector3Int.right);
            neighbors.DownLeft = targetTilemap.GetTile(position + Vector3Int.down + Vector3Int.left);
            neighbors.DownRight = targetTilemap.GetTile(position + Vector3Int.down + Vector3Int.right);
            
            return neighbors;
        }
        
        /// <summary>
        /// 自动更新Tile协程
        /// </summary>
        private System.Collections.IEnumerator AutoUpdateTiles()
        {
            while (enableAutoUpdate)
            {
                yield return new WaitForSeconds(0.1f);
                
                // 检查需要更新的Tile
                UpdateDirtyTiles();
            }
        }
        
        /// <summary>
        /// 更新需要刷新的Tile
        /// </summary>
        private void UpdateDirtyTiles()
        {
            List<Vector3Int> dirtyPositions = FindDirtyTiles();
            
            foreach (Vector3Int position in dirtyPositions)
            {
                UpdateTileAtPosition(position);
            }
        }
        
        /// <summary>
        /// 查找需要更新的Tile
        /// </summary>
        private List<Vector3Int> FindDirtyTiles()
        {
            List<Vector3Int> dirtyPositions = new List<Vector3Int>();
            
            // 检查所有缓存的Tile
            foreach (var kvp in tileDataCache)
            {
                Vector3Int position = kvp.Key;
                TileData data = kvp.Value;
                
                // 获取当前Tile
                TileBase currentTile = targetTilemap.GetTile(position);
                
                // 如果Tile发生变化
                if (currentTile != data.Tile)
                {
                    dirtyPositions.Add(position);
                }
            }
            
            return dirtyPositions;
        }
        
        /// <summary>
        /// 更新指定位置的Tile
        /// </summary>
        public void UpdateTileAtPosition(Vector3Int position)
        {
            if (ruleTile == null)
                return;
            
            // 获取当前Tile
            TileBase currentTile = targetTilemap.GetTile(position);
            
            // 获取邻居信息
            TileNeighbors neighbors = CalculateNeighbors(position);
            
            // 应用规则Tile
            if (ruleTile is AdvancedRuleTile advancedRuleTile)
            {
                var matchingRule = advancedRuleTile.GetMatchingRule(neighbors, currentTile);
                
                if (matchingRule != null)
                {
                    // 应用规则
                    ApplyRuleTile(position, matchingRule, neighbors);
                }
            }
            else
            {
                // 使用基础RuleTile
                ruleTile.RefreshTile(position, targetTilemap);
            }
            
            // 更新缓存
            UpdateTileCache(position);
            
            // 更新邻居Tile(如果需要)
            UpdateNeighborTiles(position);
        }
        
        /// <summary>
        /// 应用规则Tile
        /// </summary>
        private void ApplyRuleTile(Vector3Int position, AdvancedRuleTile.ExtendedRule rule, TileNeighbors neighbors)
        {
            TileBase tileToSet = rule.m_Sprites.Length > 0 ? ruleTile : null;
            
            if (tileToSet != null)
            {
                // 设置Tile
                targetTilemap.SetTile(position, tileToSet);
                
                // 设置变换矩阵
                Matrix4x4 transformMatrix = Matrix4x4.TRS(
                    rule.m_PerlinScale > 0 ? GetPerlinOffset(position, rule) : Vector3.zero,
                    Quaternion.Euler(0, 0, rule.m_Rotation),
                    Vector3.one
                );
                
                targetTilemap.SetTransformMatrix(position, transformMatrix);
                
                // 设置颜色
                if (rule.m_RandomColor)
                {
                    Color randomColor = new Color(
                        Random.value,
                        Random.value,
                        Random.value,
                        1f
                    );
                    targetTilemap.SetColor(position, randomColor);
                }
                
                // 处理随机变体
                if (rule.UseRandomVariant && rule.RandomVariants != null && rule.RandomVariants.Length > 0)
                {
                    int variantIndex = SelectRandomVariant(rule);
                    if (variantIndex >= 0 && variantIndex < rule.RandomVariants.Length)
                    {
                        targetTilemap.SetTile(position, rule.RandomVariants[variantIndex]);
                    }
                }
            }
        }
        
        /// <summary>
        /// 获取柏林噪声偏移
        /// </summary>
        private Vector3 GetPerlinOffset(Vector3Int position, AdvancedRuleTile.ExtendedRule rule)
        {
            float perlinX = Mathf.PerlinNoise(position.x * rule.m_PerlinScale, position.y * rule.m_PerlinScale);
            float perlinY = Mathf.PerlinNoise((position.x + 100) * rule.m_PerlinScale, (position.y + 100) * rule.m_PerlinScale);
            
            return new Vector3(
                (perlinX - 0.5f) * rule.m_PerlinScale,
                (perlinY - 0.5f) * rule.m_PerlinScale,
                0
            );
        }
        
        /// <summary>
        /// 选择随机变体
        /// </summary>
        private int SelectRandomVariant(AdvancedRuleTile.ExtendedRule rule)
        {
            if (rule.VariantDistribution != null && rule.VariantDistribution.keys.Length > 0)
            {
                // 使用分布曲线
                float randomValue = Random.value;
                float curveValue = rule.VariantDistribution.Evaluate(randomValue);
                
                return Mathf.FloorToInt(curveValue * rule.RandomVariants.Length);
            }
            else
            {
                // 均匀随机
                return Random.Range(0, rule.RandomVariants.Length);
            }
        }
        
        /// <summary>
        /// 更新Tile缓存
        /// </summary>
        private void UpdateTileCache(Vector3Int position)
        {
            TileBase tile = targetTilemap.GetTile(position);
            
            if (tile != null)
            {
                TileData data = new TileData
                {
                    Position = position,
                    Tile = tile,
                    TileId = tile.GetInstanceID(),
                    Color = targetTilemap.GetColor(position)
                };
                
                tileDataCache[position] = data;
                
                // 更新邻居信息
                TileNeighbors neighbors = CalculateNeighbors(position);
                neighborCache[position] = neighbors;
            }
            else
            {
                // 移除缓存
                tileDataCache.Remove(position);
                neighborCache.Remove(position);
            }
        }
        
        /// <summary>
        /// 更新邻居Tile
        /// </summary>
        private void UpdateNeighborTiles(Vector3Int centerPosition)
        {
            // 更新直接邻居
            Vector3Int[] neighborOffsets = new Vector3Int[]
            {
                Vector3Int.up,
                Vector3Int.down,
                Vector3Int.left,
                Vector3Int.right,
                Vector3Int.up + Vector3Int.left,
                Vector3Int.up + Vector3Int.right,
                Vector3Int.down + Vector3Int.left,
                Vector3Int.down + Vector3Int.right
            };
            
            foreach (Vector3Int offset in neighborOffsets)
            {
                Vector3Int neighborPos = centerPosition + offset;
                UpdateTileAtPosition(neighborPos);
            }
        }
        
        /// <summary>
        /// 批量设置Tile
        /// </summary>
        public void SetTiles(Vector3Int[] positions, TileBase tile)
        {
            targetTilemap.SetTiles(positions, new TileBase[positions.Length]);
            
            // 更新缓存
            foreach (Vector3Int position in positions)
            {
                UpdateTileCache(position);
                UpdateNeighborTiles(position);
            }
        }
        
        /// <summary>
        /// 填充区域
        /// </summary>
        public void FillArea(Vector3Int start, Vector3Int end, TileBase tile)
        {
            List<Vector3Int> positions = new List<Vector3Int>();
            
            int minX = Mathf.Min(start.x, end.x);
            int maxX = Mathf.Max(start.x, end.x);
            int minY = Mathf.Min(start.y, end.y);
            int maxY = Mathf.Max(start.y, end.y);
            
            for (int x = minX; x <= maxX; x++)
            {
                for (int y = minY; y <= maxY; y++)
                {
                    positions.Add(new Vector3Int(x, y, 0));
                }
            }
            
            SetTiles(positions.ToArray(), tile);
        }
        
        /// <summary>
        /// 优化Tilemap
        /// </summary>
        public void OptimizeTilemap()
        {
            switch (optimizationLevel)
            {
                case OptimizationLevel.Low:
                    OptimizeLow();
                    break;
                    
                case OptimizationLevel.Medium:
                    OptimizeMedium();
                    break;
                    
                case OptimizationLevel.High:
                    OptimizeHigh();
                    break;
            }
        }
        
        /// <summary>
        /// 低级别优化
        /// </summary>
        private void OptimizeLow()
        {
            // 压缩边界
            targetTilemap.CompressBounds();
        }
        
        /// <summary>
        /// 中级别优化
        /// </summary>
        private void OptimizeMedium()
        {
            OptimizeLow();
            
            // 合并相同Tile的连续块
            MergeTileChunks();
        }
        
        /// <summary>
        /// 高级别优化
        /// </summary>
        private void OptimizeHigh()
        {
            OptimizeMedium();
            
            // 移除不可见Tile
            RemoveInvisibleTiles();
            
            // 优化碰撞体
            OptimizeColliders();
        }
        
        /// <summary>
        /// 合并Tile块
        /// </summary>
        private void MergeTileChunks()
        {
            // 检测连续的相同Tile并合并
            // 实际实现需要更复杂的算法
        }
        
        /// <summary>
        /// 获取Tile信息
        /// </summary>
        public TileData GetTileData(Vector3Int position)
        {
            if (tileDataCache.ContainsKey(position))
            {
                return tileDataCache[position];
            }
            return null;
        }
        
        /// <summary>
        /// 获取区域内的所有Tile
        /// </summary>
        public List<TileData> GetTilesInArea(BoundsInt area)
        {
            List<TileData> tiles = new List<TileData>();
            
            for (int x = area.xMin; x < area.xMax; x++)
            {
                for (int y = area.yMin; y < area.yMax; y++)
                {
                    Vector3Int position = new Vector3Int(x, y, 0);
                    TileData data = GetTileData(position);
                    if (data != null)
                    {
                        tiles.Add(data);
                    }
                }
            }
            
            return tiles;
        }
    }
}

7.4 2D碰撞检测的数学原理与优化

7.4.1 Collider 2D的几何形状与相交检测

2D碰撞检测的核心是几何形状的相交检测。不同的碰撞体形状需要不同的数学算法。

常见形状相交检测算法:

  1. AABB(Axis-Aligned Bounding Box):矩形相交检测
  2. 圆形相交:距离检测 distance <= r1 + r2
  3. 凸多边形相交:分离轴定理(SAT)
  4. 线段相交:参数方程求解

以下是一个高级2D碰撞检测系统的实现:

using UnityEngine;
using System.Collections.Generic;

namespace CommercialProject.Physics2D
{
    /// <summary>
    /// 高级2D碰撞检测系统
    /// 支持多种几何形状和优化算法
    /// </summary>
    public class AdvancedCollisionSystem2D : MonoBehaviour
    {
        [SerializeField]
        private bool enableBroadPhase = true;
        
        [SerializeField]
        private BroadPhaseMethod broadPhaseMethod = BroadPhaseMethod.SpatialHash;
        
        [SerializeField]
        private float gridCellSize = 1f;
        
        // 碰撞体注册
        private List<Collider2D> registeredColliders;
        private Dictionary<Collider2D, ColliderData> colliderData;
        
        // 空间分区
        private SpatialHashGrid spatialGrid;
        private QuadTree quadTree;
        
        /// <summary>
        /// 碰撞体数据
        /// </summary>
        public class ColliderData
        {
            public Collider2D Collider;
            public Bounds WorldBounds;
            public Vector2 Velocity;
            public int LayerMask;
            public bool IsTrigger;
            public object UserData;
        }
        
        /// <summary>
        /// 碰撞结果
        /// </summary>
        public struct CollisionResult
        {
            public bool HasCollision;
            public Vector2 Point;
            public Vector2 Normal;
            public float Depth;
            public Collider2D OtherCollider;
            public Rigidbody2D OtherRigidbody;
        }
        
        /// <summary>
        /// 碰撞信息
        /// </summary>
        public struct CollisionInfo
        {
            public Collider2D Collider;
            public Collider2D OtherCollider;
            public Vector2 ContactPoint;
            public Vector2 RelativeVelocity;
            public float Impulse;
        }
        
        /// <summary>
        /// 宽相位方法
        /// </summary>
        public enum BroadPhaseMethod
        {
            None,
            SpatialHash,
            QuadTree,
            SweepAndPrune
        }
        
        private void Awake()
        {
            InitializeCollisionSystem();
        }
        
        private void FixedUpdate()
        {
            UpdateCollisionSystem();
        }
        
        /// <summary>
        /// 初始化碰撞系统
        /// </summary>
        private void InitializeCollisionSystem()
        {
            registeredColliders = new List<Collider2D>();
            colliderData = new Dictionary<Collider2D, ColliderData>();
            
            if (enableBroadPhase)
            {
                InitializeBroadPhase();
            }
        }
        
        /// <summary>
        /// 初始化宽相位
        /// </summary>
        private void InitializeBroadPhase()
        {
            switch (broadPhaseMethod)
            {
                case BroadPhaseMethod.SpatialHash:
                    spatialGrid = new SpatialHashGrid(gridCellSize);
                    break;
                    
                case BroadPhaseMethod.QuadTree:
                    quadTree = new QuadTree(new Rect(-100, -100, 200, 200), 4);
                    break;
            }
        }
        
        /// <summary>
        /// 更新碰撞系统
        /// </summary>
        private void UpdateCollisionSystem()
        {
            // 更新所有碰撞体数据
            UpdateColliderData();
            
            // 执行宽相位检测
            List<ColliderPair> potentialPairs = PerformBroadPhase();
            
            // 执行窄相位检测
            PerformNarrowPhase(potentialPairs);
            
            // 更新空间分区(如果需要)
            UpdateSpatialPartition();
        }
        
        /// <summary>
        /// 更新碰撞体数据
        /// </summary>
        private void UpdateColliderData()
        {
            foreach (var collider in registeredColliders)
            {
                if (collider != null)
                {
                    UpdateColliderBounds(collider);
                    
                    // 更新速度信息
                    Rigidbody2D rb = collider.attachedRigidbody;
                    if (rb != null)
                    {
                        colliderData[collider].Velocity = rb.velocity;
                    }
                }
            }
        }
        
        /// <summary>
        /// 更新碰撞体边界
        /// </summary>
        private void UpdateColliderBounds(Collider2D collider)
        {
            if (colliderData.ContainsKey(collider))
            {
                colliderData[collider].WorldBounds = collider.bounds;
            }
        }
        
        /// <summary>
        /// 执行宽相位检测
        /// </summary>
        private List<ColliderPair> PerformBroadPhase()
        {
            if (!enableBroadPhase)
            {
                // 没有宽相位,检查所有可能的组合
                return GetAllPossiblePairs();
            }
            
            switch (broadPhaseMethod)
            {
                case BroadPhaseMethod.SpatialHash:
                    return spatialGrid.GetPotentialPairs();
                    
                case BroadPhaseMethod.QuadTree:
                    return quadTree.GetPotentialPairs();
                    
                case BroadPhaseMethod.SweepAndPrune:
                    return PerformSweepAndPrune();
                    
                default:
                    return new List<ColliderPair>();
            }
        }
        
        /// <summary>
        /// 获取所有可能碰撞对
        /// </summary>
        private List<ColliderPair> GetAllPossiblePairs()
        {
            List<ColliderPair> pairs = new List<ColliderPair>();
            
            for (int i = 0; i < registeredColliders.Count; i++)
            {
                for (int j = i + 1; j < registeredColliders.Count; j++)
                {
                    pairs.Add(new ColliderPair(registeredColliders[i], registeredColliders[j]));
                }
            }
            
            return pairs;
        }
        
        /// <summary>
        /// 执行窄相位检测
        /// </summary>
        private void PerformNarrowPhase(List<ColliderPair> potentialPairs)
        {
            foreach (var pair in potentialPairs)
            {
                if (ShouldCheckCollision(pair.A, pair.B))
                {
                    CollisionResult result = CheckCollision(pair.A, pair.B);
                    
                    if (result.HasCollision)
                    {
                        HandleCollision(pair.A, pair.B, result);
                    }
                }
            }
        }
        
        /// <summary>
        /// 检查是否应该检测碰撞
        /// </summary>
        private bool ShouldCheckCollision(Collider2D a, Collider2D b)
        {
            if (a == null || b == null)
                return false;
            
            // 检查层级
            if (!Physics2D.GetIgnoreLayerCollision(a.gameObject.layer, b.gameObject.layer))
                return false;
            
            // 检查是否为触发器
            if (a.isTrigger || b.isTrigger)
            {
                // 触发器需要特殊处理
                return true;
            }
            
            // 检查边界框相交(快速拒绝)
            Bounds boundsA = colliderData[a].WorldBounds;
            Bounds boundsB = colliderData[b].WorldBounds;
            
            return boundsA.Intersects(boundsB);
        }
        
        /// <summary>
        /// 检查碰撞
        /// </summary>
        public CollisionResult CheckCollision(Collider2D a, Collider2D b)
        {
            CollisionResult result = new CollisionResult
            {
                HasCollision = false
            };
            
            // 根据碰撞体类型选择不同的检测算法
            if (a is BoxCollider2D && b is BoxCollider2D)
            {
                result = CheckBoxBoxCollision((BoxCollider2D)a, (BoxCollider2D)b);
            }
            else if (a is CircleCollider2D && b is CircleCollider2D)
            {
                result = CheckCircleCircleCollision((CircleCollider2D)a, (CircleCollider2D)b);
            }
            else if (a is PolygonCollider2D && b is PolygonCollider2D)
            {
                result = CheckPolygonPolygonCollision((PolygonCollider2D)a, (PolygonCollider2D)b);
            }
            else if (a is BoxCollider2D && b is CircleCollider2D)
            {
                result = CheckBoxCircleCollision((BoxCollider2D)a, (CircleCollider2D)b);
            }
            else if (a is CircleCollider2D && b is BoxCollider2D)
            {
                result = CheckBoxCircleCollision((BoxCollider2D)b, (CircleCollider2D)a);
                // 反转法线
                if (result.HasCollision)
                {
                    result.Normal = -result.Normal;
                }
            }
            
            return result;
        }
        
        /// <summary>
        /// 检查盒子与盒子碰撞
        /// </summary>
        private CollisionResult CheckBoxBoxCollision(BoxCollider2D a, BoxCollider2D b)
        {
            CollisionResult result = new CollisionResult();
            
            // 获取世界空间的边界
            Bounds boundsA = a.bounds;
            Bounds boundsB = b.bounds;
            
            // 检查是否相交
            if (!boundsA.Intersects(boundsB))
            {
                result.HasCollision = false;
                return result;
            }
            
            // 计算相交区域
            float overlapX = Mathf.Min(
                boundsA.max.x - boundsB.min.x,
                boundsB.max.x - boundsA.min.x
            );
            
            float overlapY = Mathf.Min(
                boundsA.max.y - boundsB.min.y,
                boundsB.max.y - boundsA.min.y
            );
            
            // 选择最小的重叠方向
            if (overlapX < overlapY)
            {
                result.Depth = overlapX;
                result.Normal = boundsA.center.x < boundsB.center.x ? 
                    Vector2.right : Vector2.left;
            }
            else
            {
                result.Depth = overlapY;
                result.Normal = boundsA.center.y < boundsB.center.y ? 
                    Vector2.up : Vector2.down;
            }
            
            // 计算接触点(简化:使用中心点)
            result.Point = (boundsA.center + boundsB.center) * 0.5f;
            result.HasCollision = true;
            result.OtherCollider = b;
            
            return result;
        }
        
        /// <summary>
        /// 检查圆形与圆形碰撞
        /// </summary>
        private CollisionResult CheckCircleCircleCollision(CircleCollider2D a, CircleCollider2D b)
        {
            CollisionResult result = new CollisionResult();
            
            Vector2 centerA = a.bounds.center;
            Vector2 centerB = b.bounds.center;
            
            float radiusA = a.radius * Mathf.Max(a.transform.lossyScale.x, a.transform.lossyScale.y);
            float radiusB = b.radius * Mathf.Max(b.transform.lossyScale.x, b.transform.lossyScale.y);
            
            Vector2 delta = centerB - centerA;
            float distance = delta.magnitude;
            float totalRadius = radiusA + radiusB;
            
            if (distance < totalRadius)
            {
                result.HasCollision = true;
                result.Depth = totalRadius - distance;
                result.Normal = delta.normalized;
                result.Point = centerA + result.Normal * radiusA;
                result.OtherCollider = b;
            }
            else
            {
                result.HasCollision = false;
            }
            
            return result;
        }
        
        /// <summary>
        /// 检查多边形与多边形碰撞(使用分离轴定理)
        /// </summary>
        private CollisionResult CheckPolygonPolygonCollision(PolygonCollider2D a, PolygonCollider2D b)
        {
            CollisionResult result = new CollisionResult();
            
            // 获取顶点(世界坐标)
            Vector2[] verticesA = GetWorldVertices(a);
            Vector2[] verticesB = GetWorldVertices(b);
            
            // 使用分离轴定理
            float minOverlap = float.MaxValue;
            Vector2 minAxis = Vector2.zero;
            
            // 检查A的边
            for (int i = 0; i < verticesA.Length; i++)
            {
                Vector2 edge = verticesA[(i + 1) % verticesA.Length] - verticesA[i];
                Vector2 axis = new Vector2(-edge.y, edge.x).normalized;
                
                float overlap = CalculateOverlapOnAxis(verticesA, verticesB, axis);
                
                if (overlap <= 0)
                {
                    // 分离轴存在,没有碰撞
                    result.HasCollision = false;
                    return result;
                }
                
                if (overlap < minOverlap)
                {
                    minOverlap = overlap;
                    minAxis = axis;
                }
            }
            
            // 检查B的边
            for (int i = 0; i < verticesB.Length; i++)
            {
                Vector2 edge = verticesB[(i + 1) % verticesB.Length] - verticesB[i];
                Vector2 axis = new Vector2(-edge.y, edge.x).normalized;
                
                float overlap = CalculateOverlapOnAxis(verticesA, verticesB, axis);
                
                if (overlap <= 0)
                {
                    result.HasCollision = false;
                    return result;
                }
                
                if (overlap < minOverlap)
                {
                    minOverlap = overlap;
                    minAxis = axis;
                }
            }
            
            // 所有轴都有重叠,存在碰撞
            result.HasCollision = true;
            result.Depth = minOverlap;
            result.Normal = minAxis;
            
            // 确保法线指向A到B
            Vector2 centerA = CalculateCentroid(verticesA);
            Vector2 centerB = CalculateCentroid(verticesB);
            
            if (Vector2.Dot(centerB - centerA, minAxis) < 0)
            {
                result.Normal = -minAxis;
            }
            
            // 计算接触点(简化)
            result.Point = centerA;
            result.OtherCollider = b;
            
            return result;
        }
        
        /// <summary>
        /// 检查盒子与圆形碰撞
        /// </summary>
        private CollisionResult CheckBoxCircleCollision(BoxCollider2D box, CircleCollider2D circle)
        {
            CollisionResult result = new CollisionResult();
            
            // 将圆形中心转换到盒子局部空间
            Vector2 circleCenter = circle.bounds.center;
            Vector2 boxCenter = box.bounds.center;
            Vector2 boxSize = box.size * 0.5f;
            
            // 计算盒子局部坐标
            Vector2 localCirclePos = circleCenter - boxCenter;
            
            // 旋转处理(如果需要)
            float boxRotation = box.transform.eulerAngles.z * Mathf.Deg2Rad;
            if (Mathf.Abs(boxRotation) > 0.001f)
            {
                float cos = Mathf.Cos(-boxRotation);
                float sin = Mathf.Sin(-boxRotation);
                localCirclePos = new Vector2(
                    localCirclePos.x * cos - localCirclePos.y * sin,
                    localCirclePos.x * sin + localCirclePos.y * cos
                );
            }
            
            // 找到最近的点
            Vector2 closestPoint = new Vector2(
                Mathf.Clamp(localCirclePos.x, -boxSize.x, boxSize.x),
                Mathf.Clamp(localCirclePos.y, -boxSize.y, boxSize.y)
            );
            
            // 计算距离
            Vector2 delta = localCirclePos - closestPoint;
            float distance = delta.magnitude;
            float circleRadius = circle.radius * Mathf.Max(
                circle.transform.lossyScale.x, 
                circle.transform.lossyScale.y
            );
            
            if (distance < circleRadius)
            {
                result.HasCollision = true;
                result.Depth = circleRadius - distance;
                
                // 转换回世界空间
                if (Mathf.Abs(boxRotation) > 0.001f)
                {
                    float cos = Mathf.Cos(boxRotation);
                    float sin = Mathf.Sin(boxRotation);
                    delta = new Vector2(
                        delta.x * cos - delta.y * sin,
                        delta.x * sin + delta.y * cos
                    );
                }
                
                result.Normal = delta.normalized;
                result.Point = boxCenter + closestPoint;
                result.OtherCollider = circle;
            }
            else
            {
                result.HasCollision = false;
            }
            
            return result;
        }
        
        /// <summary>
        /// 获取世界坐标顶点
        /// </summary>
        private Vector2[] GetWorldVertices(PolygonCollider2D collider)
        {
            Vector2[] localVertices = collider.points;
            Vector2[] worldVertices = new Vector2[localVertices.Length];
            
            Transform transform = collider.transform;
            
            for (int i = 0; i < localVertices.Length; i++)
            {
                worldVertices[i] = transform.TransformPoint(localVertices[i]);
            }
            
            return worldVertices;
        }
        
        /// <summary>
        /// 计算在轴上的重叠
        /// </summary>
        private float CalculateOverlapOnAxis(Vector2[] verticesA, Vector2[] verticesB, Vector2 axis)
        {
            float minA, maxA, minB, maxB;
            ProjectVertices(verticesA, axis, out minA, out maxA);
            ProjectVertices(verticesB, axis, out minB, out maxB);
            
            if (minA > maxB || minB > maxA)
            {
                return 0; // 没有重叠
            }
            
            return Mathf.Min(maxA, maxB) - Mathf.Max(minA, minB);
        }
        
        /// <summary>
        /// 投影顶点到轴
        /// </summary>
        private void ProjectVertices(Vector2[] vertices, Vector2 axis, out float min, out float max)
        {
            min = float.MaxValue;
            max = float.MinValue;
            
            foreach (Vector2 vertex in vertices)
            {
                float projection = Vector2.Dot(vertex, axis);
                min = Mathf.Min(min, projection);
                max = Mathf.Max(max, projection);
            }
        }
        
        /// <summary>
        /// 计算多边形质心
        /// </summary>
        private Vector2 CalculateCentroid(Vector2[] vertices)
        {
            Vector2 centroid = Vector2.zero;
            float area = 0f;
            
            for (int i = 0; i < vertices.Length; i++)
            {
                Vector2 current = vertices[i];
                Vector2 next = vertices[(i + 1) % vertices.Length];
                
                float cross = current.x * next.y - next.x * current.y;
                area += cross;
                
                centroid.x += (current.x + next.x) * cross;
                centroid.y += (current.y + next.y) * cross;
            }
            
            area *= 0.5f;
            centroid /= (6f * area);
            
            return centroid;
        }
        
        /// <summary>
        /// 处理碰撞
        /// </summary>
        private void HandleCollision(Collider2D a, Collider2D b, CollisionResult result)
        {
            // 发送碰撞消息
            SendCollisionMessages(a, b, result);
            
            // 物理响应
            ApplyCollisionResponse(a, b, result);
            
            // 触发器处理
            if (a.isTrigger || b.isTrigger)
            {
                HandleTriggerCollision(a, b, result);
            }
        }
        
        /// <summary>
        /// 发送碰撞消息
        /// </summary>
        private void SendCollisionMessages(Collider2D a, Collider2D b, CollisionResult result)
        {
            // 发送给碰撞体A
            a.SendMessage("OnCustomCollisionEnter2D", 
                new CollisionInfo
                {
                    Collider = a,
                    OtherCollider = b,
                    ContactPoint = result.Point,
                    RelativeVelocity = CalculateRelativeVelocity(a, b),
                    Impulse = CalculateCollisionImpulse(a, b, result)
                }, 
                SendMessageOptions.DontRequireReceiver);
            
            // 发送给碰撞体B
            b.SendMessage("OnCustomCollisionEnter2D",
                new CollisionInfo
                {
                    Collider = b,
                    OtherCollider = a,
                    ContactPoint = result.Point,
                    RelativeVelocity = CalculateRelativeVelocity(b, a),
                    Impulse = CalculateCollisionImpulse(b, a, result)
                },
                SendMessageOptions.DontRequireReceiver);
        }
        
        /// <summary>
        /// 应用碰撞响应
        /// </summary>
        private void ApplyCollisionResponse(Collider2D a, Collider2D b, CollisionResult result)
        {
            Rigidbody2D rbA = a.attachedRigidbody;
            Rigidbody2D rbB = b.attachedRigidbody;
            
            // 如果两个都有刚体,应用物理响应
            if (rbA != null && rbB != null && !a.isTrigger && !b.isTrigger)
            {
                // 计算冲量
                Vector2 impulse = CalculateImpulse(rbA, rbB, result);
                
                // 应用冲量
                rbA.AddForceAtPosition(-impulse, result.Point, ForceMode2D.Impulse);
                rbB.AddForceAtPosition(impulse, result.Point, ForceMode2D.Impulse);
                
                // 处理摩擦
                ApplyFriction(rbA, rbB, result);
            }
            else if (rbA != null && !a.isTrigger)
            {
                // 只有A有刚体,推开A
                Vector2 push = result.Normal * result.Depth * 0.5f;
                rbA.MovePosition(rbA.position + push);
            }
            else if (rbB != null && !b.isTrigger)
            {
                // 只有B有刚体,推开B
                Vector2 push = -result.Normal * result.Depth * 0.5f;
                rbB.MovePosition(rbB.position + push);
            }
        }
        
        /// <summary>
        /// 计算相对速度
        /// </summary>
        private Vector2 CalculateRelativeVelocity(Collider2D a, Collider2D b)
        {
            Rigidbody2D rbA = a.attachedRigidbody;
            Rigidbody2D rbB = b.attachedRigidbody;
            
            Vector2 velA = rbA != null ? rbA.velocity : Vector2.zero;
            Vector2 velB = rbB != null ? rbB.velocity : Vector2.zero;
            
            return velB - velA;
        }
        
        /// <summary>
        /// 计算碰撞冲量
        /// </summary>
        private float CalculateCollisionImpulse(Collider2D a, Collider2D b, CollisionResult result)
        {
            // 简化计算
            Rigidbody2D rbA = a.attachedRigidbody;
            Rigidbody2D rbB = b.attachedRigidbody;
            
            if (rbA == null || rbB == null)
                return 0f;
            
            Vector2 relativeVel = CalculateRelativeVelocity(a, b);
            float normalVel = Vector2.Dot(relativeVel, result.Normal);
            
            // 如果物体正在分离,冲量为0
            if (normalVel > 0)
                return 0f;
            
            float restitution = Mathf.Min(rbA.sharedMaterial?.bounciness ?? 0, 
                                          rbB.sharedMaterial?.bounciness ?? 0);
            
            float impulseMagnitude = -(1 + restitution) * normalVel;
            
            // 考虑质量
            float invMassA = rbA.mass > 0 ? 1f / rbA.mass : 0f;
            float invMassB = rbB.mass > 0 ? 1f / rbB.mass : 0f;
            
            impulseMagnitude /= (invMassA + invMassB);
            
            return impulseMagnitude;
        }
        
        /// <summary>
        /// 计算冲量
        /// </summary>
        private Vector2 CalculateImpulse(Rigidbody2D rbA, Rigidbody2D rbB, CollisionResult result)
        {
            float impulseMagnitude = CalculateCollisionImpulse(rbA.GetComponent<Collider2D>(), 
                                                              rbB.GetComponent<Collider2D>(), 
                                                              result);
            
            return result.Normal * impulseMagnitude;
        }
        
        /// <summary>
        /// 应用摩擦力
        /// </summary>
        private void ApplyFriction(Rigidbody2D rbA, Rigidbody2D rbB, CollisionResult result)
        {
            // 计算切向速度
            Vector2 relativeVel = CalculateRelativeVelocity(rbA.GetComponent<Collider2D>(), 
                                                           rbB.GetComponent<Collider2D>());
            
            Vector2 tangent = relativeVel - result.Normal * Vector2.Dot(relativeVel, result.Normal);
            tangent.Normalize();
            
            // 计算切向冲量
            float tangentVel = Vector2.Dot(relativeVel, tangent);
            float friction = Mathf.Min(rbA.sharedMaterial?.friction ?? 0, 
                                      rbB.sharedMaterial?.friction ?? 0);
            
            float frictionImpulse = -tangentVel * friction;
            
            // 应用摩擦力冲量
            Vector2 frictionForce = tangent * frictionImpulse;
            rbA.AddForceAtPosition(-frictionForce, result.Point, ForceMode2D.Impulse);
            rbB.AddForceAtPosition(frictionForce, result.Point, ForceMode2D.Impulse);
        }
        
        /// <summary>
        /// 处理触发器碰撞
        /// </summary>
        private void HandleTriggerCollision(Collider2D a, Collider2D b, CollisionResult result)
        {
            // 发送触发器消息
            if (a.isTrigger)
            {
                a.SendMessage("OnCustomTriggerEnter2D", b, SendMessageOptions.DontRequireReceiver);
            }
            
            if (b.isTrigger)
            {
                b.SendMessage("OnCustomTriggerEnter2D", a, SendMessageOptions.DontRequireReceiver);
            }
        }
        
        /// <summary>
        /// 注册碰撞体
        /// </summary>
        public void RegisterCollider(Collider2D collider, object userData = null)
        {
            if (!registeredColliders.Contains(collider))
            {
                registeredColliders.Add(collider);
                
                ColliderData data = new ColliderData
                {
                    Collider = collider,
                    WorldBounds = collider.bounds,
                    LayerMask = 1 << collider.gameObject.layer,
                    IsTrigger = collider.isTrigger,
                    UserData = userData
                };
                
                colliderData[collider] = data;
                
                // 添加到宽相位系统
                if (enableBroadPhase)
                {
                    AddToBroadPhase(collider, data.WorldBounds);
                }
            }
        }
        
        /// <summary>
        /// 注销碰撞体
        /// </summary>
        public void UnregisterCollider(Collider2D collider)
        {
            if (registeredColliders.Contains(collider))
            {
                registeredColliders.Remove(collider);
                colliderData.Remove(collider);
                
                // 从宽相位系统移除
                if (enableBroadPhase)
                {
                    RemoveFromBroadPhase(collider);
                }
            }
        }
        
        /// <summary>
        /// 添加到宽相位
        /// </summary>
        private void AddToBroadPhase(Collider2D collider, Bounds bounds)
        {
            switch (broadPhaseMethod)
            {
                case BroadPhaseMethod.SpatialHash:
                    spatialGrid.Add(collider, bounds);
                    break;
                    
                case BroadPhaseMethod.QuadTree:
                    quadTree.Insert(collider, bounds);
                    break;
            }
        }
        
        /// <summary>
        /// 从宽相位移除
        /// </summary>
        private void RemoveFromBroadPhase(Collider2D collider)
        {
            switch (broadPhaseMethod)
            {
                case BroadPhaseMethod.SpatialHash:
                    spatialGrid.Remove(collider);
                    break;
                    
                case BroadPhaseMethod.QuadTree:
                    quadTree.Remove(collider);
                    break;
            }
        }
        
        /// <summary>
        /// 更新空间分区
        /// </summary>
        private void UpdateSpatialPartition()
        {
            if (!enableBroadPhase)
                return;
            
            switch (broadPhaseMethod)
            {
                case BroadPhaseMethod.SpatialHash:
                    spatialGrid.Clear();
                    foreach (var collider in registeredColliders)
                    {
                        if (collider != null)
                        {
                            spatialGrid.Add(collider, collider.bounds);
                        }
                    }
                    break;
                    
                case BroadPhaseMethod.QuadTree:
                    quadTree.Clear();
                    foreach (var collider in registeredColliders)
                    {
                        if (collider != null)
                        {
                            quadTree.Insert(collider, collider.bounds);
                        }
                    }
                    break;
            }
        }
        
        /// <summary>
        /// 执行扫描和裁剪算法
        /// </summary>
        private List<ColliderPair> PerformSweepAndPrune()
        {
            List<ColliderPair> pairs = new List<ColliderPair>();
            
            // 按X轴排序
            registeredColliders.Sort((a, b) =>
            {
                float minXA = colliderData[a].WorldBounds.min.x;
                float minXB = colliderData[b].WorldBounds.min.x;
                return minXA.CompareTo(minXB);
            });
            
            // 扫描活动列表
            List<Collider2D> activeList = new List<Collider2D>();
            
            foreach (Collider2D collider in registeredColliders)
            {
                ColliderData data = colliderData[collider];
                float currentMinX = data.WorldBounds.min.x;
                
                // 移除不再重叠的碰撞体
                for (int i = activeList.Count - 1; i >= 0; i--)
                {
                    Collider2D active = activeList[i];
                    if (colliderData[active].WorldBounds.max.x < currentMinX)
                    {
                        activeList.RemoveAt(i);
                    }
                }
                
                // 检查与活动列表中所有碰撞体的重叠
                foreach (Collider2D active in activeList)
                {
                    // 检查Y轴重叠
                    Bounds boundsA = data.WorldBounds;
                    Bounds boundsB = colliderData[active].WorldBounds;
                    
                    if (boundsA.min.y <= boundsB.max.y && boundsA.max.y >= boundsB.min.y)
                    {
                        pairs.Add(new ColliderPair(collider, active));
                    }
                }
                
                // 添加到活动列表
                activeList.Add(collider);
            }
            
            return pairs;
        }
        
        /// <summary>
        /// 射线检测
        /// </summary>
        public RaycastResult2D Raycast(Vector2 origin, Vector2 direction, float distance, int layerMask)
        {
            RaycastResult2D result = new RaycastResult2D();
            float closestDistance = distance;
            
            foreach (var collider in registeredColliders)
            {
                if (collider == null)
                    continue;
                
                // 检查层级
                if ((layerMask & (1 << collider.gameObject.layer)) == 0)
                    continue;
                
                // 快速边界框检查
                Bounds bounds = colliderData[collider].WorldBounds;
                if (!bounds.IntersectRay(new Ray(origin, direction)))
                    continue;
                
                // 精确检测(简化)
                float hitDistance = CheckRayCollider(origin, direction, collider);
                
                if (hitDistance > 0 && hitDistance < closestDistance)
                {
                    closestDistance = hitDistance;
                    result.Hit = true;
                    result.Distance = hitDistance;
                    result.Point = origin + direction * hitDistance;
                    result.Normal = CalculateRaycastNormal(origin, direction, collider, hitDistance);
                    result.Collider = collider;
                }
            }
            
            return result;
        }
        
        /// <summary>
        /// 检查射线与碰撞体相交
        /// </summary>
        private float CheckRayCollider(Vector2 origin, Vector2 direction, Collider2D collider)
        {
            // 简化实现,实际项目中需要根据碰撞体类型实现
            if (collider is BoxCollider2D box)
            {
                return RayBoxIntersection(origin, direction, box);
            }
            else if (collider is CircleCollider2D circle)
            {
                return RayCircleIntersection(origin, direction, circle);
            }
            
            return -1f;
        }
        
        /// <summary>
        /// 射线与盒子相交检测
        /// </summary>
        private float RayBoxIntersection(Vector2 origin, Vector2 direction, BoxCollider2D box)
        {
            Bounds bounds = box.bounds;
            Vector2 min = bounds.min;
            Vector2 max = bounds.max;
            
            float tMin = (min.x - origin.x) / direction.x;
            float tMax = (max.x - origin.x) / direction.x;
            
            if (tMin > tMax) Swap(ref tMin, ref tMax);
            
            float tyMin = (min.y - origin.y) / direction.y;
            float tyMax = (max.y - origin.y) / direction.y;
            
            if (tyMin > tyMax) Swap(ref tyMin, ref tyMax);
            
            if (tMin > tyMax || tyMin > tMax)
                return -1f;
            
            if (tyMin > tMin) tMin = tyMin;
            if (tyMax < tMax) tMax = tyMax;
            
            if (tMax < 0)
                return -1f;
            
            return tMin >= 0 ? tMin : tMax;
        }
        
        /// <summary>
        /// 射线与圆形相交检测
        /// </summary>
        private float RayCircleIntersection(Vector2 origin, Vector2 direction, CircleCollider2D circle)
        {
            Vector2 center = circle.bounds.center;
            float radius = circle.radius * Mathf.Max(
                circle.transform.lossyScale.x, 
                circle.transform.lossyScale.y
            );
            
            Vector2 toCircle = center - origin;
            float tca = Vector2.Dot(toCircle, direction);
            
            if (tca < 0)
                return -1f;
            
            float d2 = Vector2.Dot(toCircle, toCircle) - tca * tca;
            float radius2 = radius * radius;
            
            if (d2 > radius2)
                return -1f;
            
            float thc = Mathf.Sqrt(radius2 - d2);
            float t0 = tca - thc;
            float t1 = tca + thc;
            
            if (t0 > t1) Swap(ref t0, ref t1);
            
            if (t0 < 0)
            {
                t0 = t1;
                if (t0 < 0)
                    return -1f;
            }
            
            return t0;
        }
        
        /// <summary>
        /// 计算射线投射法线
        /// </summary>
        private Vector2 CalculateRaycastNormal(Vector2 origin, Vector2 direction, Collider2D collider, float distance)
        {
            Vector2 hitPoint = origin + direction * distance;
            
            if (collider is CircleCollider2D circle)
            {
                Vector2 center = circle.bounds.center;
                return (hitPoint - center).normalized;
            }
            else if (collider is BoxCollider2D box)
            {
                Bounds bounds = box.bounds;
                Vector2 localPoint = hitPoint - (Vector2)bounds.center;
                
                // 找到最近的面
                float minDist = Mathf.Min(
                    Mathf.Abs(bounds.max.x - hitPoint.x),
                    Mathf.Abs(hitPoint.x - bounds.min.x),
                    Mathf.Abs(bounds.max.y - hitPoint.y),
                    Mathf.Abs(hitPoint.y - bounds.min.y)
                );
                
                if (Mathf.Abs(bounds.max.x - hitPoint.x) == minDist)
                    return Vector2.right;
                else if (Mathf.Abs(hitPoint.x - bounds.min.x) == minDist)
                    return Vector2.left;
                else if (Mathf.Abs(bounds.max.y - hitPoint.y) == minDist)
                    return Vector2.up;
                else
                    return Vector2.down;
            }
            
            return -direction;
        }
        
        private void Swap(ref float a, ref float b)
        {
            float temp = a;
            a = b;
            b = temp;
        }
        
        /// <summary>
        /// 重叠检测
        /// </summary>
        public OverlapResult2D OverlapArea(Vector2 point, Vector2 size, int layerMask)
        {
            OverlapResult2D result = new OverlapResult2D();
            result.Colliders = new List<Collider2D>();
            
            Bounds areaBounds = new Bounds(point, size);
            
            foreach (var collider in registeredColliders)
            {
                if (collider == null)
                    continue;
                
                // 检查层级
                if ((layerMask & (1 << collider.gameObject.layer)) == 0)
                    continue;
                
                // 检查重叠
                if (areaBounds.Intersects(colliderData[collider].WorldBounds))
                {
                    result.Colliders.Add(collider);
                    result.HasOverlap = true;
                }
            }
            
            return result;
        }
        
        /// <summary>
        /// 获取碰撞体数据
        /// </summary>
        public ColliderData GetColliderData(Collider2D collider)
        {
            if (colliderData.ContainsKey(collider))
            {
                return colliderData[collider];
            }
            return null;
        }
    }
    
    /// <summary>
    /// 碰撞体对
    /// </summary>
    public struct ColliderPair
    {
        public Collider2D A;
        public Collider2D B;
        
        public ColliderPair(Collider2D a, Collider2D b)
        {
            A = a;
            B = b;
        }
    }
    
    /// <summary>
    /// 射线检测结果
    /// </summary>
    public struct RaycastResult2D
    {
        public bool Hit;
        public float Distance;
        public Vector2 Point;
        public Vector2 Normal;
        public Collider2D Collider;
    }
    
    /// <summary>
    /// 重叠检测结果
    /// </summary>
    public struct OverlapResult2D
    {
        public bool HasOverlap;
        public List<Collider2D> Colliders;
    }
    
    /// <summary>
    /// 空间哈希网格
    /// </summary>
    public class SpatialHashGrid
    {
        private Dictionary<Vector2Int, List<Collider2D>> grid;
        private float cellSize;
        
        public SpatialHashGrid(float cellSize)
        {
            this.cellSize = cellSize;
            grid = new Dictionary<Vector2Int, List<Collider2D>>();
        }
        
        public void Add(Collider2D collider, Bounds bounds)
        {
            Vector2Int minCell = GetCellCoordinate(bounds.min);
            Vector2Int maxCell = GetCellCoordinate(bounds.max);
            
            for (int x = minCell.x; x <= maxCell.x; x++)
            {
                for (int y = minCell.y; y <= maxCell.y; y++)
                {
                    Vector2Int cell = new Vector2Int(x, y);
                    
                    if (!grid.ContainsKey(cell))
                    {
                        grid[cell] = new List<Collider2D>();
                    }
                    
                    if (!grid[cell].Contains(collider))
                    {
                        grid[cell].Add(collider);
                    }
                }
            }
        }
        
        public void Remove(Collider2D collider)
        {
            foreach (var cell in grid)
            {
                cell.Value.Remove(collider);
            }
        }
        
        public void Clear()
        {
            grid.Clear();
        }
        
        public List<ColliderPair> GetPotentialPairs()
        {
            List<ColliderPair> pairs = new List<ColliderPair>();
            HashSet<string> pairSet = new HashSet<string>();
            
            foreach (var cell in grid.Values)
            {
                if (cell.Count < 2)
                    continue;
                
                for (int i = 0; i < cell.Count; i++)
                {
                    for (int j = i + 1; j < cell.Count; j++)
                    {
                        string pairId = GetPairId(cell[i], cell[j]);
                        
                        if (!pairSet.Contains(pairId))
                        {
                            pairSet.Add(pairId);
                            pairs.Add(new ColliderPair(cell[i], cell[j]));
                        }
                    }
                }
            }
            
            return pairs;
        }
        
        private Vector2Int GetCellCoordinate(Vector2 point)
        {
            return new Vector2Int(
                Mathf.FloorToInt(point.x / cellSize),
                Mathf.FloorToInt(point.y / cellSize)
            );
        }
        
        private string GetPairId(Collider2D a, Collider2D b)
        {
            int idA = a.GetInstanceID();
            int idB = b.GetInstanceID();
            
            if (idA < idB)
            {
                return $"{idA}_{idB}";
            }
            else
            {
                return $"{idB}_{idA}";
            }
        }
    }
    
    /// <summary>
    /// 四叉树
    /// </summary>
    public class QuadTree
    {
        private class QuadTreeNode
        {
            public Rect Bounds;
            public int Capacity;
            public List<Collider2D> Colliders;
            public QuadTreeNode[] Children;
            public bool IsDivided;
            
            public QuadTreeNode(Rect bounds, int capacity)
            {
                Bounds = bounds;
                Capacity = capacity;
                Colliders = new List<Collider2D>();
                Children = new QuadTreeNode[4];
                IsDivided = false;
            }
            
            public bool Insert(Collider2D collider, Bounds bounds)
            {
                if (!Bounds.Overlaps(new Rect(bounds.min, bounds.size)))
                    return false;
                
                if (Colliders.Count < Capacity)
                {
                    Colliders.Add(collider);
                    return true;
                }
                
                if (!IsDivided)
                {
                    Subdivide();
                }
                
                for (int i = 0; i < 4; i++)
                {
                    if (Children[i].Insert(collider, bounds))
                    {
                        return true;
                    }
                }
                
                // 如果无法插入到子节点,留在当前节点
                Colliders.Add(collider);
                return true;
            }
            
            private void Subdivide()
            {
                float halfWidth = Bounds.width * 0.5f;
                float halfHeight = Bounds.height * 0.5f;
                
                Children[0] = new QuadTreeNode(
                    new Rect(Bounds.x, Bounds.y + halfHeight, halfWidth, halfHeight),
                    Capacity
                );
                
                Children[1] = new QuadTreeNode(
                    new Rect(Bounds.x + halfWidth, Bounds.y + halfHeight, halfWidth, halfHeight),
                    Capacity
                );
                
                Children[2] = new QuadTreeNode(
                    new Rect(Bounds.x, Bounds.y, halfWidth, halfHeight),
                    Capacity
                );
                
                Children[3] = new QuadTreeNode(
                    new Rect(Bounds.x + halfWidth, Bounds.y, halfWidth, halfHeight),
                    Capacity
                );
                
                IsDivided = true;
            }
            
            public void Query(Bounds bounds, List<Collider2D> result)
            {
                if (!Bounds.Overlaps(new Rect(bounds.min, bounds.size)))
                    return;
                
                foreach (var collider in Colliders)
                {
                    result.Add(collider);
                }
                
                if (IsDivided)
                {
                    for (int i = 0; i < 4; i++)
                    {
                        Children[i].Query(bounds, result);
                    }
                }
            }
            
            public void Clear()
            {
                Colliders.Clear();
                
                if (IsDivided)
                {
                    for (int i = 0; i < 4; i++)
                    {
                        Children[i].Clear();
                    }
                    IsDivided = false;
                }
            }
        }
        
        private QuadTreeNode root;
        
        public QuadTree(Rect bounds, int capacity)
        {
            root = new QuadTreeNode(bounds, capacity);
        }
        
        public void Insert(Collider2D collider, Bounds bounds)
        {
            root.Insert(collider, bounds);
        }
        
        public void Remove(Collider2D collider)
        {
            // 四叉树通常不清除单个元素
            // 实际项目中需要更复杂的实现
        }
        
        public void Clear()
        {
            root.Clear();
        }
        
        public List<ColliderPair> GetPotentialPairs()
        {
            List<ColliderPair> pairs = new List<ColliderPair>();
            HashSet<string> pairSet = new HashSet<string>();
            
            // 查询每个碰撞体附近的碰撞体
            foreach (var collider in GetAllColliders())
            {
                List<Collider2D> nearby = Query(collider.bounds);
                
                foreach (var other in nearby)
                {
                    if (other == collider)
                        continue;
                    
                    string pairId = GetPairId(collider, other);
                    
                    if (!pairSet.Contains(pairId))
                    {
                        pairSet.Add(pairId);
                        pairs.Add(new ColliderPair(collider, other));
                    }
                }
            }
            
            return pairs;
        }
        
        private List<Collider2D> GetAllColliders()
        {
            List<Collider2D> allColliders = new List<Collider2D>();
            CollectColliders(root, allColliders);
            return allColliders;
        }
        
        private void CollectColliders(QuadTreeNode node, List<Collider2D> result)
        {
            result.AddRange(node.Colliders);
            
            if (node.IsDivided)
            {
                for (int i = 0; i < 4; i++)
                {
                    CollectColliders(node.Children[i], result);
                }
            }
        }
        
        private List<Collider2D> Query(Bounds bounds)
        {
            List<Collider2D> result = new List<Collider2D>();
            root.Query(bounds, result);
            return result;
        }
        
        private string GetPairId(Collider2D a, Collider2D b)
        {
            int idA = a.GetInstanceID();
            int idB = b.GetInstanceID();
            
            if (idA < idB)
            {
                return $"{idA}_{idB}";
            }
            else
            {
                return $"{idB}_{idA}";
            }
        }
    }
}

7.5 小结

本章深入探讨了2D游戏开发中的数学原理和高级实现技术。我们从2D摄像机的投影矩阵和坐标变换开始,详细讲解了Sprite渲染的排序算法和裁切技术。这些基础数学概念是构建高质量2D游戏的关键。

在Sprite动画部分,我们探讨了关键帧插值算法和动画控制系统的实现。通过状态机和混合树,我们可以创建复杂的角色动画系统,这在商业级2D游戏中是必不可少的。

Tile地图系统部分展示了自动拼接算法和高级编辑功能的数学实现。通过规则Tile和自定义算法,我们可以创建复杂而美观的游戏地图。

2D碰撞检测部分深入研究了各种几何形状的相交检测算法,包括分离轴定理、空间分区优化等技术。这些算法不仅影响游戏的物理真实性,也直接关系到游戏的性能。

通过本章的学习,读者应该能够:

  1. 深入理解2D游戏开发中的核心数学原理
  2. 掌握商业级2D游戏系统的实现技术
  3. 能够根据项目需求定制和优化2D游戏组件
  4. 理解性能优化背后的数学和算法基础

在商业2D游戏开发中,数学不仅仅是理论,它是实现高效、美观、流畅游戏体验的实践工具。从精确的碰撞检测到平滑的动画插值,从智能的Tile拼接到优化的渲染排序,数学算法贯穿了整个开发过程。

掌握这些技术不仅能够解决当前的开发挑战,也为未来应对更复杂的2D游戏需求奠定了坚实的基础。无论是独立开发者还是大型游戏公司,这些知识和技能都是宝贵的资产。

Logo

这里是一个专注于游戏开发的社区,我们致力于为广大游戏爱好者提供一个良好的学习和交流平台。我们的专区包含了各大流行引擎的技术博文,涵盖了从入门到进阶的各个阶段,无论你是初学者还是资深开发者,都能在这里找到适合自己的内容。除此之外,我们还会不定期举办游戏开发相关的活动,让大家更好地交流互动。加入我们,一起探索游戏开发的奥秘吧!

更多推荐