using System.Collections; using System.Collections.Generic; using UnityEngine; public struct ColliderDescriptor { public ColliderInfo colliderInfo; public UnitCollider unitCollider; } public struct Box { public Vector3 center; public Vector3 size; } public struct CollisionInfo { public ColliderDescriptor collider; // 主动 public ColliderDescriptor collidee; // 从动 public Box intersection; public bool isCollision; } public class CollisionSystem : SingletonMB { public delegate void StageHandle(); public StageHandle onSolveHit; [SerializeField] private int m_UnitColliderCount; ColliderRegistry registry { get { return ColliderRegistry.Instance; } } private void Start() { } void Update() { m_UnitColliderCount = registry.colliders != null ? registry.colliders.Count : 0; SolveHit(); SolveProjectile(); } // hitbox <-> hurtbox void SolveHit() { // collect all hit box List hitboxes = ListPool.Get(); foreach (var collider in registry.colliders) { ColliderInfo[] boxes = collider.GetCurrentBoxesInfoByType(ColliderBox.EColliderType.HitBox); if (boxes == null || boxes.Length == 0) continue; for(int i = 0; i < boxes.Length; ++i) { ColliderDescriptor descriptor = new ColliderDescriptor(); descriptor.colliderInfo = boxes[i]; descriptor.unitCollider = collider; hitboxes.Add(descriptor); } } // collect all hurt box List hurtboxes = ListPool.Get(); foreach (var collider in registry.colliders) { ColliderInfo[] boxes = collider.GetCurrentBoxesInfoByType(ColliderBox.EColliderType.HurtBox); if (boxes == null || boxes.Length == 0) continue; for (int i = 0; i < boxes.Length; ++i) { ColliderDescriptor descriptor = new ColliderDescriptor(); descriptor.colliderInfo = boxes[i]; descriptor.unitCollider = collider; hurtboxes.Add(descriptor); } } // solve for(int i = 0; i < hitboxes.Count; ++ i) { ColliderDescriptor hitbox = hitboxes[i]; for (int j = 0; j < hurtboxes.Count; ++j) { ColliderDescriptor hurtbox = hurtboxes[j]; if (hitbox.unitCollider == hurtbox.unitCollider) continue; if (hitbox.unitCollider.owner.type == hurtbox.unitCollider.owner.type) continue; CollisionInfo collision = ColliderUtility.GetCollision(hitbox, hurtbox); if (!collision.isCollision) continue; if (!hitbox.unitCollider.CanCollide(hitbox.colliderInfo.colliderHash, hurtbox.unitCollider.owner.GetHashCode())) continue; hitbox.unitCollider.RecordCollision(hitbox.colliderInfo.colliderHash, hurtbox.unitCollider.owner.GetHashCode()); hitbox.unitCollider.owner.OnHit(collision); hurtbox.unitCollider.owner.OnGetHit(collision); } } ListPool.Release(hitboxes); ListPool.Release(hurtboxes); } void SolveProjectile() { } // throwbox <-> hurtbox void SolveThrow() { } // defendbox <-> hurtbox void SolveDefend() { } // blockbox <-> hitbox void SolveBlock() { } private void OnDrawGizmos() { } } public static class ColliderUtility { public static CollisionInfo GetCollision(ColliderDescriptor collider, ColliderDescriptor collidee) { CollisionInfo collision = new CollisionInfo(); collision.collider = collider; collision.collidee = collidee; Box colliderBox = GetColliderInWorldSpace(collider); Box collideeBox = GetColliderInWorldSpace(collidee); Box intersection = GetIntersection(colliderBox, collideeBox); collision.intersection = intersection; collision.isCollision = intersection.size.magnitude != 0; return collision; } public static Box GetColliderInWorldSpace(ColliderDescriptor collider) { Box box = new Box(); Vector3 fac = new Vector3(1, 1, collider.unitCollider.owner.transform.forward.normalized == Vector3.forward ? 1 : -1); Vector3 unitPos = collider.unitCollider.owner.transform.position; Vector3 pos = Vector3.zero; // gizmo位置 Vector3 localPos = collider.colliderInfo.position; Vector3 localSize = collider.colliderInfo.size; var pivot = collider.colliderInfo.pivot; switch (pivot) { case ColliderBox.Pivot.MiddleBottom: localPos.y += localSize.y / 2; break; } pos = unitPos + Vector3.Scale(localPos, fac); box.center = pos; box.size = localSize; return box; } public static Box GetIntersection(Box b1, Box b2) { bool isIntersection = true; float l1 = b1.center.x - b1.size.x / 2; float r1 = b1.center.x + b1.size.x / 2; float l2 = b2.center.x - b2.size.x / 2; float r2 = b2.center.x + b2.size.x / 2; isIntersection &= r1 >= l2 && l1 <= r2; float o1 = b1.center.y - b1.size.y / 2; float t1 = b1.center.y + b1.size.y / 2; float o2 = b2.center.y - b2.size.y / 2; float t2 = b2.center.y + b2.size.y / 2; isIntersection &= t1 >= o2 && o1 <= t2; float c1 = b1.center.z - b1.size.z / 2; float f1 = b1.center.z + b1.size.z / 2; float c2 = b2.center.z - b2.size.z / 2; float f2 = b2.center.z + b2.size.z / 2; isIntersection &= f1 >= c2 && c1 <= f2; if(!isIntersection) { return new Box(); } Box box = new Box(); float l = Mathf.Max(l1, l2); float r = Mathf.Min(r1, r2); float b = Mathf.Max(o1, o2); float t = Mathf.Min(t1, t2); float c = Mathf.Max(c1, c2); float f = Mathf.Max(f1, f2); box.center = new Vector3((l + r) / 2, (b + t) / 2, (c + f) / 2 ); box.size = new Vector3(r - l, t - b, f - c); return box; } }