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
This commit is contained in:
YHH
2025-12-26 14:50:35 +08:00
committed by GitHub
parent a84ff902e4
commit 155411e743
1936 changed files with 4147 additions and 11578 deletions

View File

@@ -0,0 +1,594 @@
import { Vector2 } from './Vector2';
import { Rectangle } from './Rectangle';
/**
* 2D圆形类
*
* 表示一个圆形,提供圆形相关的几何运算功能:
* - 圆形创建和属性获取
* - 包含检测(点、圆形)
* - 相交检测和计算
* - 变换和操作
*/
export class Circle {
/** 圆心X坐标 */
public x: number;
/** 圆心Y坐标 */
public y: number;
/** 半径 */
public radius: number;
/**
* 创建圆形
* @param x 圆心X坐标默认为0
* @param y 圆心Y坐标默认为0
* @param radius 半径默认为0
*/
constructor(x: number = 0, y: number = 0, radius: number = 0) {
this.x = x;
this.y = y;
this.radius = radius;
}
// 静态常量
/** 空圆形 */
static readonly EMPTY = new Circle(0, 0, 0);
/** 单位圆 */
static readonly UNIT = new Circle(0, 0, 1);
// 属性获取
/** 获取圆心坐标 */
get center(): Vector2 {
return new Vector2(this.x, this.y);
}
/** 设置圆心坐标 */
set center(value: Vector2) {
this.x = value.x;
this.y = value.y;
}
/** 获取直径 */
get diameter(): number {
return this.radius * 2;
}
/** 设置直径 */
set diameter(value: number) {
this.radius = value * 0.5;
}
/** 获取面积 */
get area(): number {
return Math.PI * this.radius * this.radius;
}
/** 获取周长 */
get circumference(): number {
return 2 * Math.PI * this.radius;
}
/** 获取包围矩形 */
get bounds(): Rectangle {
return new Rectangle(
this.x - this.radius,
this.y - this.radius,
this.diameter,
this.diameter
);
}
/** 检查是否为空圆形 */
get isEmpty(): boolean {
return this.radius <= 0;
}
// 基础操作
/**
* 设置圆形属性
* @param x 圆心X坐标
* @param y 圆心Y坐标
* @param radius 半径
* @returns 当前圆形实例(链式调用)
*/
set(x: number, y: number, radius: number): this {
this.x = x;
this.y = y;
this.radius = radius;
return this;
}
/**
* 复制另一个圆形的值
* @param other 源圆形
* @returns 当前圆形实例(链式调用)
*/
copy(other: Circle): this {
this.x = other.x;
this.y = other.y;
this.radius = other.radius;
return this;
}
/**
* 克隆当前圆形
* @returns 新的圆形实例
*/
clone(): Circle {
return new Circle(this.x, this.y, this.radius);
}
/**
* 设置圆心位置
* @param x 新的X坐标
* @param y 新的Y坐标
* @returns 当前圆形实例(链式调用)
*/
setPosition(x: number, y: number): this {
this.x = x;
this.y = y;
return this;
}
/**
* 设置圆心位置(使用向量)
* @param center 新的圆心位置
* @returns 当前圆形实例(链式调用)
*/
setCenter(center: Vector2): this {
this.x = center.x;
this.y = center.y;
return this;
}
/**
* 设置半径
* @param radius 新的半径
* @returns 当前圆形实例(链式调用)
*/
setRadius(radius: number): this {
this.radius = radius;
return this;
}
// 变换操作
/**
* 平移圆形
* @param dx X方向偏移
* @param dy Y方向偏移
* @returns 当前圆形实例(链式调用)
*/
translate(dx: number, dy: number): this {
this.x += dx;
this.y += dy;
return this;
}
/**
* 平移圆形(使用向量)
* @param offset 偏移向量
* @returns 当前圆形实例(链式调用)
*/
translateBy(offset: Vector2): this {
this.x += offset.x;
this.y += offset.y;
return this;
}
/**
* 缩放圆形
* @param scale 缩放因子
* @returns 当前圆形实例(链式调用)
*/
scale(scale: number): this {
this.radius *= scale;
return this;
}
/**
* 扩展圆形
* @param amount 扩展量(正值扩大半径,负值缩小半径)
* @returns 当前圆形实例(链式调用)
*/
inflate(amount: number): this {
this.radius += amount;
return this;
}
// 包含检测
/**
* 检查是否包含指定点
* @param point 点
* @returns 是否包含
*/
containsPoint(point: Vector2): boolean {
const dx = point.x - this.x;
const dy = point.y - this.y;
return dx * dx + dy * dy <= this.radius * this.radius;
}
/**
* 检查是否包含指定坐标
* @param x X坐标
* @param y Y坐标
* @returns 是否包含
*/
contains(x: number, y: number): boolean {
const dx = x - this.x;
const dy = y - this.y;
return dx * dx + dy * dy <= this.radius * this.radius;
}
/**
* 检查是否完全包含另一个圆形
* @param other 另一个圆形
* @returns 是否完全包含
*/
containsCircle(other: Circle): boolean {
const distance = this.distanceToCircle(other);
return distance + other.radius <= this.radius;
}
/**
* 检查点是否在圆的边界上
* @param point 点
* @param epsilon 容差默认为Number.EPSILON
* @returns 是否在边界上
*/
pointOnBoundary(point: Vector2, epsilon: number = Number.EPSILON): boolean {
const distance = this.distanceToPoint(point);
return Math.abs(distance - this.radius) < epsilon;
}
// 相交检测
/**
* 检查是否与另一个圆形相交
* @param other 另一个圆形
* @returns 是否相交
*/
intersects(other: Circle): boolean {
const dx = this.x - other.x;
const dy = this.y - other.y;
const distanceSquared = dx * dx + dy * dy;
const radiusSum = this.radius + other.radius;
return distanceSquared <= radiusSum * radiusSum;
}
/**
* 检查是否与矩形相交
* @param rect 矩形
* @returns 是否相交
*/
intersectsRect(rect: Rectangle): boolean {
// 找到矩形上离圆心最近的点
const closestX = Math.max(rect.x, Math.min(this.x, rect.right));
const closestY = Math.max(rect.y, Math.min(this.y, rect.bottom));
// 计算圆心到最近点的距离
const dx = this.x - closestX;
const dy = this.y - closestY;
return dx * dx + dy * dy <= this.radius * this.radius;
}
/**
* 计算与另一个圆形的相交面积
* @param other 另一个圆形
* @returns 相交面积
*/
intersectionArea(other: Circle): number {
const d = this.distanceToCircle(other);
// 不相交
if (d >= this.radius + other.radius) {
return 0;
}
// 一个圆完全包含另一个圆
if (d <= Math.abs(this.radius - other.radius)) {
const smallerRadius = Math.min(this.radius, other.radius);
return Math.PI * smallerRadius * smallerRadius;
}
// 部分相交
const r1 = this.radius;
const r2 = other.radius;
const part1 = r1 * r1 * Math.acos((d * d + r1 * r1 - r2 * r2) / (2 * d * r1));
const part2 = r2 * r2 * Math.acos((d * d + r2 * r2 - r1 * r1) / (2 * d * r2));
const part3 = 0.5 * Math.sqrt((-d + r1 + r2) * (d + r1 - r2) * (d - r1 + r2) * (d + r1 + r2));
return part1 + part2 - part3;
}
// 距离计算
/**
* 计算圆心到点的距离
* @param point 点
* @returns 距离
*/
distanceToPoint(point: Vector2): number {
const dx = point.x - this.x;
const dy = point.y - this.y;
return Math.sqrt(dx * dx + dy * dy);
}
/**
* 计算圆形边界到点的最短距离
* @param point 点
* @returns 最短距离(点在圆内时为负值)
*/
distanceToPointFromBoundary(point: Vector2): number {
return this.distanceToPoint(point) - this.radius;
}
/**
* 计算两个圆心之间的距离
* @param other 另一个圆形
* @returns 圆心距离
*/
distanceToCircle(other: Circle): number {
const dx = this.x - other.x;
const dy = this.y - other.y;
return Math.sqrt(dx * dx + dy * dy);
}
/**
* 计算两个圆形边界之间的最短距离
* @param other 另一个圆形
* @returns 最短距离(相交时为负值)
*/
distanceToCircleFromBoundary(other: Circle): number {
return this.distanceToCircle(other) - this.radius - other.radius;
}
/**
* 计算圆形到矩形的最短距离
* @param rect 矩形
* @returns 最短距离
*/
distanceToRect(rect: Rectangle): number {
return Math.max(0, rect.distanceToPoint(this.center) - this.radius);
}
/**
* 获取圆形上距离指定点最近的点
* @param point 指定点
* @returns 最近点
*/
closestPointTo(point: Vector2): Vector2 {
const direction = Vector2.subtract(point, this.center);
if (direction.isZero) {
// 点在圆心,返回圆上任意点
return new Vector2(this.x + this.radius, this.y);
}
return this.center.clone().add(direction.normalized().multiply(this.radius));
}
/**
* 获取圆形上距离指定点最远的点
* @param point 指定点
* @returns 最远点
*/
farthestPointFrom(point: Vector2): Vector2 {
const direction = Vector2.subtract(point, this.center);
if (direction.isZero) {
// 点在圆心,返回圆上任意点
return new Vector2(this.x - this.radius, this.y);
}
return this.center.clone().subtract(direction.normalized().multiply(this.radius));
}
// 几何运算
/**
* 获取指定角度上的圆周点
* @param angle 角度(弧度)
* @returns 圆周点
*/
getPointAtAngle(angle: number): Vector2 {
return new Vector2(
this.x + this.radius * Math.cos(angle),
this.y + this.radius * Math.sin(angle)
);
}
/**
* 获取点相对于圆心的角度
* @param point 点
* @returns 角度(弧度)
*/
getAngleToPoint(point: Vector2): number {
return Math.atan2(point.y - this.y, point.x - this.x);
}
/**
* 获取圆形与直线的交点
* @param lineStart 直线起点
* @param lineEnd 直线终点
* @returns 交点数组0-2个点
*/
getLineIntersections(lineStart: Vector2, lineEnd: Vector2): Vector2[] {
const dx = lineEnd.x - lineStart.x;
const dy = lineEnd.y - lineStart.y;
const fx = lineStart.x - this.x;
const fy = lineStart.y - this.y;
const a = dx * dx + dy * dy;
const b = 2 * (fx * dx + fy * dy);
const c = fx * fx + fy * fy - this.radius * this.radius;
const discriminant = b * b - 4 * a * c;
if (discriminant < 0) {
return []; // 无交点
}
if (discriminant === 0) {
// 一个交点(切线)
const t = -b / (2 * a);
return [new Vector2(lineStart.x + t * dx, lineStart.y + t * dy)];
}
// 两个交点
const sqrt = Math.sqrt(discriminant);
const t1 = (-b - sqrt) / (2 * a);
const t2 = (-b + sqrt) / (2 * a);
return [
new Vector2(lineStart.x + t1 * dx, lineStart.y + t1 * dy),
new Vector2(lineStart.x + t2 * dx, lineStart.y + t2 * dy)
];
}
// 比较操作
/**
* 检查两个圆形是否相等
* @param other 另一个圆形
* @param epsilon 容差默认为Number.EPSILON
* @returns 是否相等
*/
equals(other: Circle, epsilon: number = Number.EPSILON): boolean {
return Math.abs(this.x - other.x) < epsilon &&
Math.abs(this.y - other.y) < epsilon &&
Math.abs(this.radius - other.radius) < epsilon;
}
/**
* 检查两个圆形是否完全相等
* @param other 另一个圆形
* @returns 是否完全相等
*/
exactEquals(other: Circle): boolean {
return this.x === other.x && this.y === other.y && this.radius === other.radius;
}
// 静态方法
/**
* 从直径创建圆形
* @param x 圆心X坐标
* @param y 圆心Y坐标
* @param diameter 直径
* @returns 新的圆形实例
*/
static fromDiameter(x: number, y: number, diameter: number): Circle {
return new Circle(x, y, diameter * 0.5);
}
/**
* 从三个点创建外接圆
* @param p1 第一个点
* @param p2 第二个点
* @param p3 第三个点
* @returns 外接圆如果三点共线返回null
*/
static fromThreePoints(p1: Vector2, p2: Vector2, p3: Vector2): Circle | null {
const ax = p1.x; const ay = p1.y;
const bx = p2.x; const by = p2.y;
const cx = p3.x; const cy = p3.y;
const d = 2 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by));
if (Math.abs(d) < Number.EPSILON) {
return null; // 三点共线
}
const ux = ((ax * ax + ay * ay) * (by - cy) + (bx * bx + by * by) * (cy - ay) + (cx * cx + cy * cy) * (ay - by)) / d;
const uy = ((ax * ax + ay * ay) * (cx - bx) + (bx * bx + by * by) * (ax - cx) + (cx * cx + cy * cy) * (bx - ax)) / d;
const radius = Math.sqrt((ax - ux) * (ax - ux) + (ay - uy) * (ay - uy));
return new Circle(ux, uy, radius);
}
/**
* 从点数组创建最小包围圆
* @param points 点数组
* @returns 最小包围圆
*/
static fromPointArray(points: Vector2[]): Circle {
if (points.length === 0) {
return Circle.EMPTY.clone();
}
if (points.length === 1) {
return new Circle(points[0].x, points[0].y, 0);
}
// 使用Welzl算法的简化版本
// 这里使用更简单的方法:找到包围所有点的圆
let minX = points[0].x, minY = points[0].y;
let maxX = points[0].x, maxY = points[0].y;
for (const point of points) {
minX = Math.min(minX, point.x);
minY = Math.min(minY, point.y);
maxX = Math.max(maxX, point.x);
maxY = Math.max(maxY, point.y);
}
const centerX = (minX + maxX) * 0.5;
const centerY = (minY + maxY) * 0.5;
const center = new Vector2(centerX, centerY);
let maxDistance = 0;
for (const point of points) {
const distance = Vector2.distance(center, point);
maxDistance = Math.max(maxDistance, distance);
}
return new Circle(centerX, centerY, maxDistance);
}
/**
* 线性插值两个圆形
* @param a 起始圆形
* @param b 目标圆形
* @param t 插值参数0到1
* @returns 新的插值结果圆形
*/
static lerp(a: Circle, b: Circle, t: number): Circle {
return new Circle(
a.x + (b.x - a.x) * t,
a.y + (b.y - a.y) * t,
a.radius + (b.radius - a.radius) * t
);
}
// 字符串转换
/**
* 转换为字符串
* @returns 字符串表示
*/
toString(): string {
return `Circle(${this.x.toFixed(2)}, ${this.y.toFixed(2)}, r=${this.radius.toFixed(2)})`;
}
/**
* 转换为数组
* @returns [x, y, radius] 数组
*/
toArray(): [number, number, number] {
return [this.x, this.y, this.radius];
}
/**
* 转换为普通对象
* @returns {x, y, radius} 对象
*/
toObject(): { x: number; y: number; radius: number } {
return { x: this.x, y: this.y, radius: this.radius };
}
}