Files
esengine/packages/framework/math/tests/CollisionDetector.test.ts
YHH 155411e743 refactor: reorganize package structure and decouple framework packages (#338)
* refactor: reorganize package structure and decouple framework packages

## Package Structure Reorganization
- Reorganized 55 packages into categorized subdirectories:
  - packages/framework/ - Generic framework (Laya/Cocos compatible)
  - packages/engine/ - ESEngine core modules
  - packages/rendering/ - Rendering modules (WASM dependent)
  - packages/physics/ - Physics modules
  - packages/streaming/ - World streaming
  - packages/network-ext/ - Network extensions
  - packages/editor/ - Editor framework and plugins
  - packages/rust/ - Rust WASM engine
  - packages/tools/ - Build tools and SDK

## Framework Package Decoupling
- Decoupled behavior-tree and blueprint packages from ESEngine dependencies
- Created abstracted interfaces (IBTAssetManager, IBehaviorTreeAssetContent)
- ESEngine-specific code moved to esengine/ subpath exports
- Framework packages now usable with Cocos/Laya without ESEngine

## CI Configuration
- Updated CI to only type-check and lint framework packages
- Added type-check:framework and lint:framework scripts

## Breaking Changes
- Package import paths changed due to directory reorganization
- ESEngine integrations now use subpath imports (e.g., '@esengine/behavior-tree/esengine')

* fix: update es-engine file path after directory reorganization

* docs: update README to focus on framework over engine

* ci: only build framework packages, remove Rust/WASM dependencies

* fix: remove esengine subpath from behavior-tree and blueprint builds

ESEngine integration code will only be available in full engine builds.
Framework packages are now purely engine-agnostic.

* fix: move network-protocols to framework, build both in CI

* fix: update workflow paths from packages/core to packages/framework/core

* fix: exclude esengine folder from type-check in behavior-tree and blueprint

* fix: update network tsconfig references to new paths

* fix: add test:ci:framework to only test framework packages in CI

* fix: only build core and math npm packages in CI

* fix: exclude test files from CodeQL and fix string escaping security issue
2025-12-26 14:50:35 +08:00

212 lines
7.4 KiB
TypeScript

import { CollisionDetector } from '../src/Collision/CollisionDetector';
import { Vector2 } from '../src/Vector2';
import { Rectangle } from '../src/Rectangle';
import { Circle } from '../src/Circle';
declare global {
var expectFloatsEqual: (actual: number, expected: number, epsilon?: number) => void;
}
describe('CollisionDetector', () => {
describe('点与几何体碰撞', () => {
test('点与圆形碰撞检测', () => {
const circle = new Circle(0, 0, 5);
const pointInside = new Vector2(3, 0);
const pointOutside = new Vector2(10, 0);
const pointOnBoundary = new Vector2(5, 0);
const collision1 = CollisionDetector.pointCircle(pointInside, circle);
expect(collision1.collided).toBe(true);
expect(collision1.penetration).toBe(2);
const collision2 = CollisionDetector.pointCircle(pointOutside, circle);
expect(collision2.collided).toBe(false);
const collision3 = CollisionDetector.pointCircle(pointOnBoundary, circle);
expect(collision3.collided).toBe(true);
expectFloatsEqual(collision3.penetration!, 0, 1e-10);
});
test('点与矩形碰撞检测', () => {
const rect = new Rectangle(10, 10, 20, 20);
const pointInside = new Vector2(15, 15);
const pointOutside = new Vector2(5, 5);
const collision1 = CollisionDetector.pointRect(pointInside, rect);
expect(collision1.collided).toBe(true);
expect(collision1.normal).toBeDefined();
const collision2 = CollisionDetector.pointRect(pointOutside, rect);
expect(collision2.collided).toBe(false);
});
});
describe('圆形碰撞检测', () => {
test('圆形与圆形碰撞检测', () => {
const circle1 = new Circle(0, 0, 5);
const circle2 = new Circle(8, 0, 5); // 相交
const circle3 = new Circle(15, 0, 5); // 不相交
const circle4 = new Circle(10, 0, 5); // 边界接触
const collision1 = CollisionDetector.circleCircle(circle1, circle2);
expect(collision1.collided).toBe(true);
expect(collision1.penetration).toBe(2);
const collision2 = CollisionDetector.circleCircle(circle1, circle3);
expect(collision2.collided).toBe(false);
const collision3 = CollisionDetector.circleCircle(circle1, circle4);
expect(collision3.collided).toBe(true);
expectFloatsEqual(collision3.penetration!, 0, 1e-10);
});
test('圆形与矩形碰撞检测', () => {
const circle = new Circle(15, 15, 5);
const rect1 = new Rectangle(10, 10, 20, 20); // 相交
const rect2 = new Rectangle(30, 30, 10, 10); // 不相交
const collision1 = CollisionDetector.circleRect(circle, rect1);
expect(collision1.collided).toBe(true);
const collision2 = CollisionDetector.circleRect(circle, rect2);
expect(collision2.collided).toBe(false);
});
});
describe('矩形碰撞检测', () => {
test('矩形与矩形碰撞检测', () => {
const rect1 = new Rectangle(10, 10, 20, 20);
const rect2 = new Rectangle(15, 15, 20, 20); // 相交
const rect3 = new Rectangle(40, 40, 10, 10); // 不相交
const collision1 = CollisionDetector.rectRect(rect1, rect2);
expect(collision1.collided).toBe(true);
expect(collision1.penetration).toBeGreaterThan(0);
expect(collision1.normal).toBeDefined();
const collision2 = CollisionDetector.rectRect(rect1, rect3);
expect(collision2.collided).toBe(false);
});
});
describe('射线投射', () => {
test('射线与圆形相交', () => {
const rayOrigin = new Vector2(-10, 0);
const rayDirection = new Vector2(1, 0);
const circle = new Circle(0, 0, 5);
const collision = CollisionDetector.rayCircle(rayOrigin, rayDirection, circle);
expect(collision.collided).toBe(true);
expect(collision.distance).toBe(5);
expect(collision.contactPoint!.x).toBe(-5);
expect(collision.contactPoint!.y).toBe(0);
});
test('射线与圆形不相交', () => {
const rayOrigin = new Vector2(-10, 10);
const rayDirection = new Vector2(1, 0);
const circle = new Circle(0, 0, 5);
const collision = CollisionDetector.rayCircle(rayOrigin, rayDirection, circle);
expect(collision.collided).toBe(false);
});
test('射线与矩形相交', () => {
const rayOrigin = new Vector2(-5, 15);
const rayDirection = new Vector2(1, 0);
const rect = new Rectangle(10, 10, 20, 20);
const collision = CollisionDetector.rayRect(rayOrigin, rayDirection, rect);
expect(collision.collided).toBe(true);
expect(collision.distance).toBe(15);
});
test('射线距离限制', () => {
const rayOrigin = new Vector2(-10, 0);
const rayDirection = new Vector2(1, 0);
const circle = new Circle(0, 0, 5);
const collision = CollisionDetector.rayCircle(rayOrigin, rayDirection, circle, 3);
expect(collision.collided).toBe(false);
});
});
describe('线段相交', () => {
test('线段与线段相交', () => {
const p1 = new Vector2(0, 0);
const p2 = new Vector2(10, 10);
const p3 = new Vector2(0, 10);
const p4 = new Vector2(10, 0);
const collision = CollisionDetector.lineSegmentLineSegment(p1, p2, p3, p4);
expect(collision.collided).toBe(true);
expect(collision.contactPoint!.x).toBe(5);
expect(collision.contactPoint!.y).toBe(5);
});
test('线段与线段不相交', () => {
const p1 = new Vector2(0, 0);
const p2 = new Vector2(5, 5);
const p3 = new Vector2(10, 0);
const p4 = new Vector2(15, 5);
const collision = CollisionDetector.lineSegmentLineSegment(p1, p2, p3, p4);
expect(collision.collided).toBe(false);
});
test('线段与圆形相交', () => {
const lineStart = new Vector2(-10, 0);
const lineEnd = new Vector2(10, 0);
const circle = new Circle(0, 0, 5);
const collision = CollisionDetector.lineSegmentCircle(lineStart, lineEnd, circle);
expect(collision.collided).toBe(true);
});
});
describe('快速排斥测试', () => {
test('AABB包围盒测试', () => {
const bounds1 = new Rectangle(10, 10, 20, 20);
const bounds2 = new Rectangle(15, 15, 20, 20);
const bounds3 = new Rectangle(40, 40, 10, 10);
expect(CollisionDetector.aabbTest(bounds1, bounds2)).toBe(true);
expect(CollisionDetector.aabbTest(bounds1, bounds3)).toBe(false);
});
test('圆形包围盒测试', () => {
const center1 = new Vector2(0, 0);
const center2 = new Vector2(8, 0);
const center3 = new Vector2(15, 0);
expect(CollisionDetector.circleTest(center1, 5, center2, 5)).toBe(true);
expect(CollisionDetector.circleTest(center1, 5, center3, 5)).toBe(false);
});
});
describe('边界情况', () => {
test('零半径圆形', () => {
const point = new Vector2(0, 0);
const circle = new Circle(0, 0, 0);
const collision = CollisionDetector.pointCircle(point, circle);
expect(collision.collided).toBe(true);
});
test('零面积矩形', () => {
const point = new Vector2(10, 10);
const rect = new Rectangle(10, 10, 0, 0);
const collision = CollisionDetector.pointRect(point, rect);
expect(collision.collided).toBe(true);
});
test('同心圆形', () => {
const circle1 = new Circle(0, 0, 5);
const circle2 = new Circle(0, 0, 3);
const collision = CollisionDetector.circleCircle(circle1, circle2);
expect(collision.collided).toBe(true);
});
});
});