Skip to content

Commit

Permalink
feat: physics fix-time update (#700)
Browse files Browse the repository at this point in the history
* feat: fix-time physics update

* feat: add physicsUpdate in Script
  • Loading branch information
yangfengzzz authored Mar 22, 2022
1 parent 6f3e202 commit 37e4b14
Show file tree
Hide file tree
Showing 13 changed files with 106 additions and 48 deletions.
24 changes: 23 additions & 1 deletion packages/core/src/ComponentsManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Script } from "./Script";
import { ShaderMacroCollection } from "./shader/ShaderMacroCollection";
import { RenderContext } from "./RenderPipeline/RenderContext";
import { Vector3 } from "@oasis-engine/math";
import { Collider } from "./physics/Collider";
import { Collider } from "./physics";

/**
* The manager of the components.
Expand All @@ -19,6 +19,7 @@ export class ComponentsManager {
private _onStartScripts: DisorderedArray<Script> = new DisorderedArray();
private _onUpdateScripts: DisorderedArray<Script> = new DisorderedArray();
private _onLateUpdateScripts: DisorderedArray<Script> = new DisorderedArray();
private _onPhysicsUpdateScripts: DisorderedArray<Script> = new DisorderedArray();
private _destroyComponents: Script[] = [];

// Animation
Expand Down Expand Up @@ -89,6 +90,17 @@ export class ComponentsManager {
script._onLateUpdateIndex = -1;
}

addOnPhysicsUpdateScript(script: Script): void {
script._onPhysicsUpdateIndex = this._onPhysicsUpdateScripts.length;
this._onPhysicsUpdateScripts.add(script);
}

removeOnPhysicsUpdateScript(script: Script): void {
const replaced = this._onPhysicsUpdateScripts.deleteByIndex(script._onPhysicsUpdateIndex);
replaced && (replaced._onPhysicsUpdateIndex = script._onPhysicsUpdateIndex);
script._onPhysicsUpdateIndex = -1;
}

addOnUpdateAnimations(animation: Component): void {
//@ts-ignore
animation._onUpdateIndex = this._onUpdateAnimations.length;
Expand Down Expand Up @@ -154,6 +166,16 @@ export class ComponentsManager {
}
}

callScriptOnPhysicsUpdate(): void {
const elements = this._onPhysicsUpdateScripts._elements;
for (let i = this._onPhysicsUpdateScripts.length - 1; i >= 0; --i) {
const element = elements[i];
if (element._started) {
element.onPhysicsUpdate();
}
}
}

callAnimationUpdate(deltaTime): void {
const elements = this._onUpdateAnimations._elements;
for (let i = this._onUpdateAnimations.length - 1; i >= 0; --i) {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/Engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ export class Engine extends EventDispatcher {
this._hardwareRenderer.init(canvas);
if (physics) {
PhysicsManager._nativePhysics = physics;
this.physicsManager = new PhysicsManager();
this.physicsManager = new PhysicsManager(this);
}
this._canvas = canvas;
// @todo delete
Expand Down
26 changes: 20 additions & 6 deletions packages/core/src/Script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ export class Script extends Component {
_onLateUpdateIndex: number = -1;
/** @internal */
@ignoreClone
_onPhysicsUpdateIndex: number = -1;
/** @internal */
@ignoreClone
_onPreRenderIndex: number = -1;
/** @internal */
@ignoreClone
Expand Down Expand Up @@ -67,41 +70,46 @@ export class Script extends Component {
*/
onEndRender(camera: Camera): void {}

/**
* Called before physics calculations, the number of times is related to the physical update frequency.
*/
onPhysicsUpdate(): void {}

/**
* Called when the collision enter.
* @param other ColliderShape
* @param other - ColliderShape
*/
onTriggerEnter(other: ColliderShape): void {}

/**
* Called when the collision stay.
* @remarks onTriggerStay is called every frame while the collision stay.
* @param other ColliderShape
* @param other - ColliderShape
*/
onTriggerExit(other: ColliderShape): void {}

/**
* Called when the collision exit.
* @param other ColliderShape
* @param other - ColliderShape
*/
onTriggerStay(other: ColliderShape): void {}

/**
* Called when the collision enter.
* @param other ColliderShape
* @param other - ColliderShape
*/
onCollisionEnter(other: ColliderShape): void {}

/**
* Called when the collision stay.
* @remarks onTriggerStay is called every frame while the collision stay.
* @param other ColliderShape
* @param other - ColliderShape
*/
onCollisionExit(other: ColliderShape): void {}

/**
* Called when the collision exit.
* @param other ColliderShape
* @param other - ColliderShape
*/
onCollisionStay(other: ColliderShape): void {}

Expand Down Expand Up @@ -172,6 +180,9 @@ export class Script extends Component {
if (this.onLateUpdate !== prototype.onLateUpdate) {
componentsManager.addOnLateUpdateScript(this);
}
if (this.onPhysicsUpdate !== prototype.onPhysicsUpdate) {
componentsManager.addOnPhysicsUpdateScript(this);
}
this._entity._addScript(this);
this.onEnable();
}
Expand All @@ -194,6 +205,9 @@ export class Script extends Component {
if (this._onLateUpdateIndex !== -1) {
componentsManager.removeOnLateUpdateScript(this);
}
if (this._onPhysicsUpdateIndex !== -1) {
componentsManager.removeOnPhysicsUpdateScript(this);
}
if (this._entityCacheIndex !== -1) {
this._entity._removeScript(this);
}
Expand Down
9 changes: 4 additions & 5 deletions packages/core/src/physics/DynamicCollider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ export class DynamicCollider extends Collider {
private _sleepThreshold: number = 0;
private _solverIterations: number = 0;
private _isKinematic: boolean = false;
private _freezeRotation: boolean = false;
private _constraints: DynamicColliderConstraints = 0;
private _collisionDetectionMode: CollisionDetectionMode = CollisionDetectionMode.Discrete;

Expand Down Expand Up @@ -227,20 +226,20 @@ export class DynamicCollider extends Collider {

/**
* Moves kinematically controlled dynamic actors through the game world.
* @param position The desired position for the kinematic actor
* @param position - The desired position for the kinematic actor
*/
move(position: Vector3): void;

/**
* Moves kinematically controlled dynamic actors through the game world.
* @param rotation The desired rotation for the kinematic actor
* @param rotation - The desired rotation for the kinematic actor
*/
move(rotation: Quaternion): void;

/**
* Moves kinematically controlled dynamic actors through the game world.
* @param position The desired position for the kinematic actor
* @param rotation The desired rotation for the kinematic actor
* @param position - The desired position for the kinematic actor
* @param rotation - The desired rotation for the kinematic actor
*/
move(position: Vector3, rotation: Quaternion): void;

Expand Down
24 changes: 22 additions & 2 deletions packages/core/src/physics/PhysicsManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { IPhysics, IPhysicsManager } from "@oasis-engine/design";
import { Collider } from "./Collider";
import { Layer } from "../Layer";
import { ColliderShape } from "./shape/ColliderShape";
import { Engine } from "../Engine";

/**
* A physics manager is a collection of bodies and constraints which can interact.
Expand All @@ -12,6 +13,9 @@ export class PhysicsManager {
/** @internal */
static _nativePhysics: IPhysics;

private _engine: Engine;
private _restTime: number = 0;

private _gravity: Vector3 = new Vector3();
private _nativePhysicsManager: IPhysicsManager;
private _physicalObjectsMap: Record<number, ColliderShape> = {};
Expand Down Expand Up @@ -102,6 +106,12 @@ export class PhysicsManager {
}
};

/** The fixed time step in seconds at which physics are performed. */
fixedTimeStep: number = 1 / 60;

/** The max sum of time step in seconds one frame. */
maxSumTimeStep: number = 1 / 3;

get gravity(): Vector3 {
return this._gravity;
}
Expand All @@ -114,7 +124,8 @@ export class PhysicsManager {
this._nativePhysicsManager.setGravity(gravity);
}

constructor() {
constructor(engine: Engine) {
this._engine = engine;
this._nativePhysicsManager = PhysicsManager._nativePhysics.createPhysicsManager(
this._onContactEnter,
this._onContactExit,
Expand Down Expand Up @@ -232,7 +243,16 @@ export class PhysicsManager {
* @internal
*/
_update(deltaTime: number): void {
this._nativePhysicsManager.update(deltaTime);
const { fixedTimeStep: fixedTimeStep, _nativePhysicsManager: nativePhysicsManager } = this;
const componentManager = this._engine._componentsManager;

const simulateTime = deltaTime + this._restTime;
const step = Math.floor(Math.min(this.maxSumTimeStep, simulateTime) / fixedTimeStep);
this._restTime = simulateTime - step * fixedTimeStep;
for (let i = 0; i < step; i++) {
componentManager.callScriptOnPhysicsUpdate();
nativePhysicsManager.update(fixedTimeStep);
}
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/physics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ export { CapsuleColliderShape } from "./shape/CapsuleColliderShape";

export { Collider } from "./Collider";
export { StaticCollider } from "./StaticCollider";
export { DynamicCollider } from "./DynamicCollider";
export { DynamicCollider, CollisionDetectionMode, DynamicColliderConstraints } from "./DynamicCollider";
32 changes: 16 additions & 16 deletions packages/design/src/physics/IDynamicCollider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,85 +7,85 @@ import { ICollider } from "./ICollider";
export interface IDynamicCollider extends ICollider {
/**
* Sets the linear damping coefficient.
* @param value Linear damping coefficient.
* @param value - Linear damping coefficient.
*/
setLinearDamping(value: number): void;

/**
* Sets the angular damping coefficient.
* @param value Angular damping coefficient.
* @param value - Angular damping coefficient.
*/
setAngularDamping(value: number): void;

/**
* Sets the linear velocity of the actor.
* @param value New linear velocity of actor.
* @param value - New linear velocity of actor.
*/
setLinearVelocity(value: Vector3): void;

/**
* Sets the angular velocity of the actor.
* @param value New angular velocity of actor.
* @param value - New angular velocity of actor.
*/
setAngularVelocity(value: Vector3): void;

/**
* Sets the mass of a dynamic actor.
* @param value New mass value for the actor.
* @param value - New mass value for the actor.
*/
setMass(value: number): void;

/**
* Sets the pose of the center of mass relative to the actor.
* @param value Mass frame offset transform relative to the actor frame.
* @param value - Mass frame offset transform relative to the actor frame.
*/
setCenterOfMass(value: Vector3): void;

/**
* Sets the inertia tensor, using a parameter specified in mass space coordinates.
* @param value New mass space inertia tensor for the actor.
* @param value - New mass space inertia tensor for the actor.
*/
setInertiaTensor(value: Vector3): void;

/**
* Set the maximum angular velocity permitted for this actor.
* @param value Max allowable angular velocity for actor.
* @param value - Max allowable angular velocity for actor.
*/
setMaxAngularVelocity(value: number): void;

/**
* Sets the maximum depenetration velocity permitted to be introduced by the solver.
* @param value The maximum velocity to de-penetrate
* @param value - The maximum velocity to de-penetrate
*/
setMaxDepenetrationVelocity(value: number): void;

/**
* Sets the mass-normalized kinetic energy threshold below which an actor may go to sleep.
* @param value Energy below which an actor may go to sleep.
* @param value - Energy below which an actor may go to sleep.
*/
setSleepThreshold(value: number): void;

/**
* Sets the solver iteration counts for the body.
* @param value Number of position iterations the solver should perform for this body.
* @param value - Number of position iterations the solver should perform for this body.
*/
setSolverIterations(value: number): void;

/**
* Sets the colliders' collision detection mode.
* @param value rigid body flag
* @param value - rigid body flag
*/
setCollisionDetectionMode(value: number): void;

/**
* Controls whether physics affects the dynamic collider.
* @param value is or not
* @param value - is or not
*/
setIsKinematic(value: boolean): void;

/**
* Raises or clears a particular rigid dynamic lock flag.
* @param flags the flag to raise(set) or clear.
* @param flags - the flag to raise(set) or clear.
*/
setConstraints(flags: number): void;

Expand All @@ -103,8 +103,8 @@ export interface IDynamicCollider extends ICollider {

/**
* Moves kinematically controlled dynamic actors through the game world.
* @param positionOrRotation The desired position or rotation for the kinematic actor
* @param rotation The desired rotation for the kinematic actor
* @param positionOrRotation - The desired position or rotation for the kinematic actor
* @param rotation - The desired rotation for the kinematic actor
*/
move(positionOrRotation: Vector3 | Quaternion, rotation?: Quaternion): void;

Expand Down
2 changes: 1 addition & 1 deletion packages/physics-lite/src/LitePhysicsManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ export class LitePhysicsManager implements IPhysicsManager {

private _fireEvent(): void {
const { _eventPool: eventPool, _currentEvents: currentEvents } = this;
for (let i = 0, n = currentEvents.length; i < n;) {
for (let i = 0, n = currentEvents.length; i < n; ) {
const event = currentEvents.get(i);
if (!event.needUpdate) {
if (event.state == TriggerEventState.Enter) {
Expand Down
6 changes: 3 additions & 3 deletions packages/physics-physx/src/shape/PhysXBoxColliderShape.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class PhysXBoxColliderShape extends PhysXColliderShape implements IBoxCol
this._halfSize.z * this._scale.z
);
this._allocShape(material);
this._setLocalPose(this._scale);
this._setLocalPose();
this.setUniqueID(uniqueID);
}

Expand All @@ -46,9 +46,9 @@ export class PhysXBoxColliderShape extends PhysXColliderShape implements IBoxCol
* {@inheritDoc IColliderShape.setWorldScale }
*/
setWorldScale(scale: Vector3): void {
this._setLocalPose(this._scale);

scale.cloneTo(this._scale);
this._setLocalPose();

Vector3.multiply(this._halfSize, this._scale, PhysXBoxColliderShape._tempHalfExtents);
this._pxGeometry.halfExtents = PhysXBoxColliderShape._tempHalfExtents;
this._pxShape.setGeometry(this._pxGeometry);
Expand Down
Loading

0 comments on commit 37e4b14

Please sign in to comment.