@cyclonium/physics-2d 0.0.104 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/character-controller-2d.js +1 -2
- package/lib/collider-2d.d.ts +0 -25
- package/lib/physics-2d-settings.d.ts +1 -0
- package/lib/physics-2d-settings.js +7 -2
- package/lib/physics-world-2d-scene-component.d.ts +4 -1
- package/lib/physics-world-2d-scene-component.js +37 -8
- package/lib/physics-world-2d.d.ts +2 -1
- package/lib/physics-world-2d.js +22 -1
- package/lib/rigid-body-2d.d.ts +7 -0
- package/lib/rigid-body-2d.js +44 -2
- package/package.json +3 -3
|
@@ -156,8 +156,7 @@ let KinematicCharacterController2D = class KinematicCharacterController2D extend
|
|
|
156
156
|
else {
|
|
157
157
|
const currentPosition = fromPx2ImplVec2(rigidBody.impl.nextTranslation());
|
|
158
158
|
const newPosition = fromPx2ImplVec2(currentPosition).add(movement);
|
|
159
|
-
|
|
160
|
-
rigidBody.impl.setNextKinematicTranslation(toPx2ImplVec2(newPosition));
|
|
159
|
+
rigidBody.setNextKinematicPosition(newPosition);
|
|
161
160
|
}
|
|
162
161
|
this._emitCharacterCollisionEvents(impl, world);
|
|
163
162
|
}
|
package/lib/collider-2d.d.ts
CHANGED
|
@@ -12,37 +12,12 @@ export declare abstract class Collider2D extends PhysicsComponent2DBase {
|
|
|
12
12
|
get center(): Vec2;
|
|
13
13
|
set center(value: Vec2);
|
|
14
14
|
get bounds(): Bounds2D;
|
|
15
|
-
/**
|
|
16
|
-
* Test only.
|
|
17
|
-
* @internal
|
|
18
|
-
*/
|
|
19
|
-
get impl_internal(): px2Impl.Collider | undefined;
|
|
20
15
|
onContactBegin: import("@cyclonium/event").ManagedEventEmitter<[Collider2D, Collider2D, Contact2DInfo]>;
|
|
21
16
|
onContactStay: import("@cyclonium/event").ManagedEventEmitter<[Collider2D, Collider2D, Contact2DInfo]>;
|
|
22
17
|
onContactEnd: import("@cyclonium/event").ManagedEventEmitter<[Collider2D, Collider2D, Contact2DInfo]>;
|
|
23
18
|
intersect(opts: ShapeIntersectionQueryOptions): ColliderShapeIntersection | undefined;
|
|
24
19
|
cast(opts: ShapeCastQueryOptions): ColliderShapeCastHit | undefined;
|
|
25
20
|
castRay(ray: Ray2D, maxDistance: number, solid?: boolean): RayColliderIntersection | undefined;
|
|
26
|
-
/**
|
|
27
|
-
* @internal
|
|
28
|
-
*/
|
|
29
|
-
_enableCollisionEventsSinceBody(value: boolean): void;
|
|
30
|
-
/**
|
|
31
|
-
* @internal
|
|
32
|
-
*/
|
|
33
|
-
_responseToBodyActiveCollisionTypes(value: number): void;
|
|
34
|
-
/**
|
|
35
|
-
* @internal
|
|
36
|
-
*/
|
|
37
|
-
_responseToBodyCollisionGroups(value: number): void;
|
|
38
|
-
/**
|
|
39
|
-
* @internal
|
|
40
|
-
*/
|
|
41
|
-
_responseToBodySolverGroups(value: number): void;
|
|
42
|
-
/**
|
|
43
|
-
* @internal
|
|
44
|
-
*/
|
|
45
|
-
_responseToAttachedRigidBodyChanged(): void;
|
|
46
21
|
protected get _implCollider(): px2Impl.Collider | undefined;
|
|
47
22
|
protected recreateCollider(): void;
|
|
48
23
|
protected onAttachToWorld(): void;
|
|
@@ -2,6 +2,7 @@ import { Asset } from 'cc';
|
|
|
2
2
|
import { CollisionMatrix } from './collision-matrix.js';
|
|
3
3
|
export declare class Physics2DSettings extends Asset {
|
|
4
4
|
fps: number;
|
|
5
|
+
maxSubsteps: number;
|
|
5
6
|
get tags(): Record<string, number>;
|
|
6
7
|
private get tags_editor();
|
|
7
8
|
private set tags_editor(value);
|
|
@@ -4,13 +4,14 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { Asset } from 'cc';
|
|
7
|
+
import { Asset, CCInteger } from 'cc';
|
|
8
8
|
import { editable, serializable } from '@cyclonium/core/legacy-decorator';
|
|
9
9
|
import { cycloBuiltinClass } from '@cyclonium/core/internal';
|
|
10
10
|
import { CollisionMatrix } from './collision-matrix.js';
|
|
11
11
|
import { dumpRaw } from '@cyclonium/core/utils';
|
|
12
12
|
let Physics2DSettings = class Physics2DSettings extends Asset {
|
|
13
13
|
fps = 60;
|
|
14
|
+
maxSubsteps = 4;
|
|
14
15
|
get tags() {
|
|
15
16
|
return this._tags;
|
|
16
17
|
}
|
|
@@ -31,8 +32,12 @@ let Physics2DSettings = class Physics2DSettings extends Asset {
|
|
|
31
32
|
};
|
|
32
33
|
__decorate([
|
|
33
34
|
serializable,
|
|
34
|
-
editable
|
|
35
|
+
editable({ min: 1 })
|
|
35
36
|
], Physics2DSettings.prototype, "fps", void 0);
|
|
37
|
+
__decorate([
|
|
38
|
+
serializable,
|
|
39
|
+
editable({ type: CCInteger, min: 1, step: 1 })
|
|
40
|
+
], Physics2DSettings.prototype, "maxSubsteps", void 0);
|
|
36
41
|
__decorate([
|
|
37
42
|
editable,
|
|
38
43
|
dumpRaw
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CycloComponent } from '@cyclonium/core/framework';
|
|
2
|
-
import { PhysicsWorld2D } from './physics-world-2d.js';
|
|
3
2
|
import { Physics2DSettings } from './physics-2d-settings.js';
|
|
3
|
+
import { PhysicsWorld2D } from './physics-world-2d.js';
|
|
4
4
|
export declare class PhysicsWorld2DSceneComponent extends CycloComponent {
|
|
5
5
|
get debug(): boolean;
|
|
6
6
|
set debug(v: boolean);
|
|
@@ -13,6 +13,9 @@ export declare class PhysicsWorld2DSceneComponent extends CycloComponent {
|
|
|
13
13
|
private _physicsWorld;
|
|
14
14
|
private _physicsDebugger;
|
|
15
15
|
private _lastUpdateFrame;
|
|
16
|
+
private _maxSubsteps;
|
|
17
|
+
private _timeAccumulator;
|
|
18
|
+
private _overloading;
|
|
16
19
|
private _debug;
|
|
17
20
|
private _settings;
|
|
18
21
|
private _updateFrame;
|
|
@@ -6,13 +6,17 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
6
6
|
};
|
|
7
7
|
import { EDITOR_NOT_IN_PREVIEW } from 'cc/env';
|
|
8
8
|
import { editable, executionOrder, idem, serializable } from '@cyclonium/core/legacy-decorator';
|
|
9
|
-
import { CycloComponent } from '@cyclonium/core/framework';
|
|
10
|
-
import { PhysicsWorld2D } from './physics-world-2d.js';
|
|
11
|
-
import { Physics2DDebugger } from '#physics-2d-debugger';
|
|
12
|
-
import { PredefinedExecutionOrder } from '@cyclonium/core/framework';
|
|
9
|
+
import { CycloComponent, PredefinedExecutionOrder } from '@cyclonium/core/framework';
|
|
13
10
|
import { director } from 'cc';
|
|
14
|
-
import { cycloBuiltinClass } from '@cyclonium/core/internal';
|
|
11
|
+
import { cycloBuiltinClass, TimeAccumulator } from '@cyclonium/core/internal';
|
|
12
|
+
import { logger } from '@cyclonium/core/log';
|
|
13
|
+
import { Physics2DDebugger } from '#physics-2d-debugger';
|
|
15
14
|
import { Physics2DSettings } from './physics-2d-settings.js';
|
|
15
|
+
import { PhysicsWorld2D } from './physics-world-2d.js';
|
|
16
|
+
const getDefaultSettings = (() => {
|
|
17
|
+
let defaultSettings;
|
|
18
|
+
return () => defaultSettings ??= new Physics2DSettings();
|
|
19
|
+
})();
|
|
16
20
|
let PhysicsWorld2DSceneComponent = class PhysicsWorld2DSceneComponent extends CycloComponent {
|
|
17
21
|
get debug() {
|
|
18
22
|
return this._debug;
|
|
@@ -35,7 +39,19 @@ let PhysicsWorld2DSceneComponent = class PhysicsWorld2DSceneComponent extends Cy
|
|
|
35
39
|
}
|
|
36
40
|
onAwake() {
|
|
37
41
|
if (!EDITOR_NOT_IN_PREVIEW) {
|
|
38
|
-
const settings = this._settings ??
|
|
42
|
+
const settings = this._settings ?? getDefaultSettings();
|
|
43
|
+
let fps = settings.fps;
|
|
44
|
+
let maxSubsteps = settings.maxSubsteps;
|
|
45
|
+
if (!Number.isFinite(fps) || fps <= 0) {
|
|
46
|
+
logger.error(`Invalid Physics2DSettings.fps (${fps});`);
|
|
47
|
+
fps = getDefaultSettings().fps;
|
|
48
|
+
}
|
|
49
|
+
if (!Number.isInteger(maxSubsteps) || maxSubsteps <= 0) {
|
|
50
|
+
logger.error(`Invalid Physics2DSettings.maxSubsteps (${maxSubsteps});`);
|
|
51
|
+
maxSubsteps = getDefaultSettings().maxSubsteps;
|
|
52
|
+
}
|
|
53
|
+
this._timeAccumulator = new TimeAccumulator(1 / fps);
|
|
54
|
+
this._maxSubsteps = maxSubsteps;
|
|
39
55
|
this._physicsWorld = new PhysicsWorld2D({
|
|
40
56
|
scene: this.node.scene,
|
|
41
57
|
tags: settings.tags,
|
|
@@ -69,9 +85,12 @@ let PhysicsWorld2DSceneComponent = class PhysicsWorld2DSceneComponent extends Cy
|
|
|
69
85
|
_physicsWorld = null;
|
|
70
86
|
_physicsDebugger = undefined;
|
|
71
87
|
_lastUpdateFrame = -1;
|
|
88
|
+
_maxSubsteps = 4;
|
|
89
|
+
_timeAccumulator = new TimeAccumulator(1 / 60);
|
|
90
|
+
_overloading = false;
|
|
72
91
|
_debug = false;
|
|
73
92
|
_settings = null;
|
|
74
|
-
_updateFrame(
|
|
93
|
+
_updateFrame(deltaTime) {
|
|
75
94
|
const world = this._physicsWorld;
|
|
76
95
|
if (!world) {
|
|
77
96
|
return;
|
|
@@ -82,7 +101,17 @@ let PhysicsWorld2DSceneComponent = class PhysicsWorld2DSceneComponent extends Cy
|
|
|
82
101
|
this._lastUpdateFrame = actualFrame;
|
|
83
102
|
world.setOutdated();
|
|
84
103
|
}
|
|
85
|
-
|
|
104
|
+
const timeAccumulator = this._timeAccumulator;
|
|
105
|
+
const fixedDeltaTime = timeAccumulator.timeStep;
|
|
106
|
+
const maxSubsteps = this._maxSubsteps;
|
|
107
|
+
const actualSubsteps = timeAccumulator.advance(deltaTime, maxSubsteps);
|
|
108
|
+
const maximumDeltaTime = maxSubsteps * fixedDeltaTime;
|
|
109
|
+
const overloading = deltaTime > maximumDeltaTime;
|
|
110
|
+
if (overloading && !this._overloading) {
|
|
111
|
+
logger.warn(`PhysicsWorld2D clamped an update to the ${maxSubsteps}-substep limit.`);
|
|
112
|
+
}
|
|
113
|
+
this._overloading = overloading;
|
|
114
|
+
world.advanceSubsteps_internal(fixedDeltaTime, actualSubsteps);
|
|
86
115
|
this._physicsDebugger?.render();
|
|
87
116
|
}
|
|
88
117
|
};
|
|
@@ -41,7 +41,8 @@ export declare class PhysicsWorld2D {
|
|
|
41
41
|
get listenersOnWillDestroy(): import("@cyclonium/event").EventListenerRegistry<[]>;
|
|
42
42
|
get impl(): px2Impl.World;
|
|
43
43
|
destroy(): void;
|
|
44
|
-
step(
|
|
44
|
+
step(deltaTime: number): void;
|
|
45
|
+
private _step;
|
|
45
46
|
setOutdated(): void;
|
|
46
47
|
getTagId(tag: string): number;
|
|
47
48
|
intersectionWithPoint(point: Vec2, filter: SceneQueryFilter): Generator<Collider2D, void, unknown>;
|
package/lib/physics-world-2d.js
CHANGED
|
@@ -64,7 +64,22 @@ export class PhysicsWorld2D {
|
|
|
64
64
|
this._worldImpl.free();
|
|
65
65
|
this._worldImpl = null;
|
|
66
66
|
}
|
|
67
|
-
step(
|
|
67
|
+
step(deltaTime) {
|
|
68
|
+
this.advanceSubsteps_internal(deltaTime, 1);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Advances a batch of physics steps where `deltaTime` is the length of each substep.
|
|
72
|
+
* @internal
|
|
73
|
+
*/
|
|
74
|
+
advanceSubsteps_internal(deltaTime, substepCount) {
|
|
75
|
+
this._worldImpl.timestep = deltaTime;
|
|
76
|
+
for (let i = 0; i < substepCount; i++) {
|
|
77
|
+
const remainingSubsteps = substepCount - i;
|
|
78
|
+
const stepFraction = 1 / remainingSubsteps;
|
|
79
|
+
this._step(stepFraction, remainingSubsteps === 1);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
_step(stepFraction, isLastSubstep) {
|
|
68
83
|
const outdated = this._outDated;
|
|
69
84
|
this._outDated = false;
|
|
70
85
|
for (const component of this._physicsComponents) {
|
|
@@ -73,6 +88,12 @@ export class PhysicsWorld2D {
|
|
|
73
88
|
}
|
|
74
89
|
invokeOnSyncTransforms(component, outdated, outdated);
|
|
75
90
|
}
|
|
91
|
+
for (const { component } of this._rigidBodies.values()) {
|
|
92
|
+
if (!component.enabled) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
component.applyKinematicTargetForStep_internal(stepFraction, isLastSubstep);
|
|
96
|
+
}
|
|
76
97
|
this._worldImpl.step(this._eventQueue);
|
|
77
98
|
for (const component of this._physicsComponents) {
|
|
78
99
|
if (!component.enabled) {
|
package/lib/rigid-body-2d.d.ts
CHANGED
|
@@ -36,7 +36,9 @@ export declare class RigidBody2D extends PhysicsComponent2DBase {
|
|
|
36
36
|
set linearVelocity(value: Vec2);
|
|
37
37
|
hasTag(tag: string): boolean;
|
|
38
38
|
addTag(tag: string): void;
|
|
39
|
+
/** Sets the position target reached across the next physics step batch. */
|
|
39
40
|
setNextKinematicPosition(position: Vec2): void;
|
|
41
|
+
/** Sets the rotation target reached across the next physics step batch. */
|
|
40
42
|
setNextKinematicRotation(rotation: number): void;
|
|
41
43
|
get impl(): px2Impl.RigidBody | undefined;
|
|
42
44
|
protected onDestroy(): void;
|
|
@@ -56,6 +58,11 @@ export declare class RigidBody2D extends PhysicsComponent2DBase {
|
|
|
56
58
|
private _physicsPosition;
|
|
57
59
|
private _physicsRotation;
|
|
58
60
|
private _linearVelocity;
|
|
61
|
+
private _kinematicPositionTarget;
|
|
62
|
+
private _substepKinematicPositionTarget;
|
|
63
|
+
private _kinematicRotationTarget;
|
|
64
|
+
private _hasKinematicPositionTarget;
|
|
65
|
+
private _hasKinematicRotationTarget;
|
|
59
66
|
private _listenerFlags;
|
|
60
67
|
private _transformChangeFlagsObserver;
|
|
61
68
|
private get _transform();
|
package/lib/rigid-body-2d.js
CHANGED
|
@@ -15,8 +15,8 @@ import { createCollisionEventEmitter, ContactEventListenerFlagIndex } from './sh
|
|
|
15
15
|
import { CCString } from 'cc';
|
|
16
16
|
import { EDITOR_NOT_IN_PREVIEW } from 'cc/env';
|
|
17
17
|
import { cycloBuiltinClass } from '@cyclonium/core/internal';
|
|
18
|
-
import { approxEqual } from '@cyclonium/core/math/number';
|
|
19
|
-
import { to0ToPI2 } from '@cyclonium/core/math/trigonometry';
|
|
18
|
+
import { approxEqual, lerp } from '@cyclonium/core/math/number';
|
|
19
|
+
import { lerpAngle, to0ToPI2 } from '@cyclonium/core/math/trigonometry';
|
|
20
20
|
export var RigidBody2DType;
|
|
21
21
|
(function (RigidBody2DType) {
|
|
22
22
|
RigidBody2DType["fixed"] = "fixed";
|
|
@@ -141,10 +141,16 @@ let RigidBody2D = class RigidBody2D extends PhysicsComponent2DBase {
|
|
|
141
141
|
this._tags.push(tag);
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
|
+
/** Sets the position target reached across the next physics step batch. */
|
|
144
145
|
setNextKinematicPosition(position) {
|
|
146
|
+
this._kinematicPositionTarget.copyFrom(position);
|
|
147
|
+
this._hasKinematicPositionTarget = true;
|
|
145
148
|
this._rigidBodyControlBlock?.impl.setNextKinematicTranslation(position);
|
|
146
149
|
}
|
|
150
|
+
/** Sets the rotation target reached across the next physics step batch. */
|
|
147
151
|
setNextKinematicRotation(rotation) {
|
|
152
|
+
this._kinematicRotationTarget = rotation;
|
|
153
|
+
this._hasKinematicRotationTarget = true;
|
|
148
154
|
this._rigidBodyControlBlock?.impl.setNextKinematicRotation(rotation);
|
|
149
155
|
}
|
|
150
156
|
get impl() {
|
|
@@ -188,6 +194,35 @@ let RigidBody2D = class RigidBody2D extends PhysicsComponent2DBase {
|
|
|
188
194
|
onSyncTransforms(forceTransform, _forceScale) {
|
|
189
195
|
this._syncToPhysics(forceTransform);
|
|
190
196
|
}
|
|
197
|
+
/** @internal */
|
|
198
|
+
applyKinematicTargetForStep_internal(stepFraction, isLastSubstep) {
|
|
199
|
+
const implBody = this._rigidBodyControlBlock?.impl;
|
|
200
|
+
if (!implBody || this._type !== RigidBody2DType.kinematicPositionBased) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (this._hasKinematicPositionTarget) {
|
|
204
|
+
const substepTarget = this._substepKinematicPositionTarget;
|
|
205
|
+
if (isLastSubstep) {
|
|
206
|
+
substepTarget.copyFrom(this._kinematicPositionTarget);
|
|
207
|
+
this._hasKinematicPositionTarget = false;
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
const position = this._physicsPosition;
|
|
211
|
+
const target = this._kinematicPositionTarget;
|
|
212
|
+
substepTarget.set(lerp(position.x, target.x, stepFraction), lerp(position.y, target.y, stepFraction));
|
|
213
|
+
}
|
|
214
|
+
implBody.setNextKinematicTranslation(substepTarget);
|
|
215
|
+
}
|
|
216
|
+
if (this._hasKinematicRotationTarget) {
|
|
217
|
+
const substepTarget = isLastSubstep
|
|
218
|
+
? this._kinematicRotationTarget
|
|
219
|
+
: lerpAngle(this._physicsRotation, this._kinematicRotationTarget, stepFraction);
|
|
220
|
+
if (isLastSubstep) {
|
|
221
|
+
this._hasKinematicRotationTarget = false;
|
|
222
|
+
}
|
|
223
|
+
implBody.setNextKinematicRotation(substepTarget);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
191
226
|
onAfterPhysicsStep() {
|
|
192
227
|
this._syncFromPhysics();
|
|
193
228
|
}
|
|
@@ -200,6 +235,11 @@ let RigidBody2D = class RigidBody2D extends PhysicsComponent2DBase {
|
|
|
200
235
|
_physicsPosition = new Vec2();
|
|
201
236
|
_physicsRotation = 0.0;
|
|
202
237
|
_linearVelocity = new Vec2();
|
|
238
|
+
_kinematicPositionTarget = new Vec2();
|
|
239
|
+
_substepKinematicPositionTarget = new Vec2();
|
|
240
|
+
_kinematicRotationTarget = 0;
|
|
241
|
+
_hasKinematicPositionTarget = false;
|
|
242
|
+
_hasKinematicRotationTarget = false;
|
|
203
243
|
_listenerFlags = 0;
|
|
204
244
|
_transformChangeFlagsObserver = new TransformChangeFlagsObserver();
|
|
205
245
|
get _transform() { return undefined; }
|
|
@@ -275,6 +315,8 @@ let RigidBody2D = class RigidBody2D extends PhysicsComponent2DBase {
|
|
|
275
315
|
this._rigidBodyControlBlock = null;
|
|
276
316
|
this._physicsPosition.set(0, 0);
|
|
277
317
|
this._physicsRotation = 0.0;
|
|
318
|
+
this._hasKinematicPositionTarget = false;
|
|
319
|
+
this._hasKinematicRotationTarget = false;
|
|
278
320
|
}
|
|
279
321
|
_setPhysicsPosition(position) {
|
|
280
322
|
this._physicsPosition.copyFrom(position);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyclonium/physics-2d",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/shrinktofit/cyclonium",
|
|
@@ -25,13 +25,13 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@cyclonium/algorithm": "1.0.0",
|
|
28
|
-
"@cyclonium/debug-draw": "0.0.
|
|
28
|
+
"@cyclonium/debug-draw": "0.0.105",
|
|
29
29
|
"@cyclonium/event": "0.0.103",
|
|
30
30
|
"@cyclonium/rapier2d": "0.0.102",
|
|
31
31
|
"@cyclonium/web-assembly": "0.0.102"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
|
-
"@cyclonium/core": "0.0.
|
|
34
|
+
"@cyclonium/core": "0.0.105"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/fs-extra": "^11.0.4",
|