Files
esengine/packages/physics-rapier2d/src/components/Rigidbody2DComponent.ts

323 lines
8.3 KiB
TypeScript
Raw Normal View History

/**
* Rigidbody2D Component
* 2D
*/
import { Component, Property, Serialize, Serializable, ECSComponent } from '@esengine/ecs-framework';
import { RigidbodyType2D, CollisionDetectionMode2D } from '../types/Physics2DTypes';
import type { Vector2 } from '../types/Physics2DTypes';
/**
*
*/
export interface RigidbodyConstraints2D {
/** 冻结 X 轴位置 */
freezePositionX: boolean;
/** 冻结 Y 轴位置 */
freezePositionY: boolean;
/** 冻结旋转 */
freezeRotation: boolean;
}
/**
* 2D
*
* TransformComponent 使
*
* @example
* ```typescript
* const entity = scene.createEntity('Player');
* entity.addComponent(TransformComponent);
* const rb = entity.addComponent(Rigidbody2DComponent);
* rb.bodyType = RigidbodyType2D.Dynamic;
* rb.mass = 1;
* rb.gravityScale = 1;
* ```
*/
@ECSComponent('Rigidbody2D')
@Serializable({ version: 1, typeId: 'Rigidbody2D' })
export class Rigidbody2DComponent extends Component {
// ==================== 基础属性 ====================
/**
*
* - Dynamic: 动态刚体
* - Kinematic: 运动学刚体
* - Static: 静态刚体
*/
@Serialize()
@Property({
type: 'enum',
label: 'Body Type',
options: [
{ label: 'Dynamic', value: 0 },
{ label: 'Kinematic', value: 1 },
{ label: 'Static', value: 2 }
]
})
public bodyType: RigidbodyType2D = RigidbodyType2D.Dynamic;
/**
* kg
* Dynamic
*/
@Serialize()
@Property({ type: 'number', label: 'Mass', min: 0.001, step: 0.1 })
public mass: number = 1;
/**
*
* 0 = 1 = -1 =
*/
@Serialize()
@Property({ type: 'number', label: 'Gravity Scale', min: -10, max: 10, step: 0.1 })
public gravityScale: number = 1;
// ==================== 阻尼 ====================
/**
* 线
*
*/
@Serialize()
@Property({ type: 'number', label: 'Linear Damping', min: 0, max: 100, step: 0.1 })
public linearDamping: number = 0;
/**
*
*
*/
@Serialize()
@Property({ type: 'number', label: 'Angular Damping', min: 0, max: 100, step: 0.01 })
public angularDamping: number = 0.05;
// ==================== 约束 ====================
/**
* X
*/
@Serialize()
@Property({ type: 'boolean', label: 'Freeze Position X' })
public freezePositionX: boolean = false;
/**
* Y
*/
@Serialize()
@Property({ type: 'boolean', label: 'Freeze Position Y' })
public freezePositionY: boolean = false;
/**
*
*/
@Serialize()
@Property({ type: 'boolean', label: 'Freeze Rotation' })
public freezeRotation: boolean = false;
/**
*
* @deprecated 使 freezePositionX, freezePositionY, freezeRotation
*/
public get constraints(): RigidbodyConstraints2D {
return {
freezePositionX: this.freezePositionX,
freezePositionY: this.freezePositionY,
freezeRotation: this.freezeRotation
};
}
public set constraints(value: RigidbodyConstraints2D) {
this.freezePositionX = value.freezePositionX;
this.freezePositionY = value.freezePositionY;
this.freezeRotation = value.freezeRotation;
}
// ==================== 碰撞检测 ====================
/**
*
* - Discrete: 离散检测
* - Continuous: 连续检测穿
*/
@Serialize()
@Property({
type: 'enum',
label: 'Collision Detection',
options: [
{ label: 'Discrete', value: 0 },
{ label: 'Continuous', value: 1 }
]
})
public collisionDetection: CollisionDetectionMode2D = CollisionDetectionMode2D.Discrete;
// ==================== 休眠 ====================
/**
*
*
*/
@Serialize()
@Property({ type: 'boolean', label: 'Can Sleep' })
public canSleep: boolean = true;
/**
*
*/
@Property({ type: 'boolean', label: 'Is Awake', readOnly: true })
public isAwake: boolean = true;
// ==================== 运行时状态(不序列化)====================
/**
* 线
*/
public velocity: Vector2 = { x: 0, y: 0 };
/**
* /
*/
public angularVelocity: number = 0;
// ==================== 内部状态 ====================
/**
* Rapier
* @internal
*/
public _bodyHandle: number | null = null;
/**
* Transform
* @internal
*/
public _needsSync: boolean = true;
/**
*
* @internal
*/
public _previousPosition: Vector2 = { x: 0, y: 0 };
/**
*
* @internal
*/
public _previousRotation: number = 0;
// ==================== API 方法 ====================
/**
*
* Physics2DSystem
*/
public addForce(force: Vector2): void {
this._pendingForce.x += force.x;
this._pendingForce.y += force.y;
}
/**
*
*/
public addImpulse(impulse: Vector2): void {
this._pendingImpulse.x += impulse.x;
this._pendingImpulse.y += impulse.y;
}
/**
*
*/
public addTorque(torque: number): void {
this._pendingTorque += torque;
}
/**
*
*/
public addAngularImpulse(impulse: number): void {
this._pendingAngularImpulse += impulse;
}
/**
* 线
*/
public setVelocity(velocity: Vector2): void {
this._targetVelocity = { ...velocity };
this._hasTargetVelocity = true;
}
/**
*
*/
public setAngularVelocity(angularVelocity: number): void {
this._targetAngularVelocity = angularVelocity;
this._hasTargetAngularVelocity = true;
}
/**
*
*/
public wakeUp(): void {
this._shouldWakeUp = true;
}
/**
* 使
*/
public sleep(): void {
this._shouldSleep = true;
}
/**
* Transform
*/
public markNeedsSync(): void {
this._needsSync = true;
}
// ==================== 待处理的力和冲量 ====================
/** @internal */
public _pendingForce: Vector2 = { x: 0, y: 0 };
/** @internal */
public _pendingImpulse: Vector2 = { x: 0, y: 0 };
/** @internal */
public _pendingTorque: number = 0;
/** @internal */
public _pendingAngularImpulse: number = 0;
/** @internal */
public _targetVelocity: Vector2 = { x: 0, y: 0 };
/** @internal */
public _hasTargetVelocity: boolean = false;
/** @internal */
public _targetAngularVelocity: number = 0;
/** @internal */
public _hasTargetAngularVelocity: boolean = false;
/** @internal */
public _shouldWakeUp: boolean = false;
/** @internal */
public _shouldSleep: boolean = false;
/**
*
* @internal
*/
public _clearPendingForces(): void {
this._pendingForce.x = 0;
this._pendingForce.y = 0;
this._pendingImpulse.x = 0;
this._pendingImpulse.y = 0;
this._pendingTorque = 0;
this._pendingAngularImpulse = 0;
this._hasTargetVelocity = false;
this._hasTargetAngularVelocity = false;
this._shouldWakeUp = false;
this._shouldSleep = false;
}
public override onRemovedFromEntity(): void {
// 清理句柄,实际的物理对象清理由系统处理
this._bodyHandle = null;
this._clearPendingForces();
}
}