* 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
212 lines
7.4 KiB
TypeScript
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);
|
|
});
|
|
});
|
|
}); |