@gg-web-engine/rapier2d 0.0.24

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/README.md ADDED
@@ -0,0 +1,9 @@
1
+ <p align="center">
2
+ <img src="../../documentation/assets/logo.png" style="height: 400px; width:400px;" alt=''/>
3
+ </p>
4
+
5
+ ## [Rapier.js](https://github.com/dimforge/rapier.js) 2D integration for [gg-web-engine](https://github.com/AndyGura/gg-web-engine), providing 2D phycics simulation
6
+
7
+ ### Installation:
8
+ 1) make sure **@gg-web-engine/core** installed
9
+ 1) `npm install --save @gg-web-engine/rapier2d`
@@ -0,0 +1,26 @@
1
+ import { Body2DOptions, Entity2d, Gg2dWorld, IRigidBody2dComponent, IVisualScene2dComponent, Point2 } from '@gg-web-engine/core';
2
+ import { Collider, ColliderDesc, RigidBody, RigidBodyDesc } from '@dimforge/rapier2d';
3
+ import { Rapier2dWorldComponent } from './rapier-2d-world.component';
4
+ export declare class Rapier2dRigidBodyComponent implements IRigidBody2dComponent<Rapier2dWorldComponent> {
5
+ protected readonly world: Rapier2dWorldComponent;
6
+ protected _colliderDescr: ColliderDesc[];
7
+ protected _bodyDescr: RigidBodyDesc;
8
+ protected _colliderOptions: Omit<Omit<Body2DOptions, 'dynamic'>, 'mass'>;
9
+ entity: Entity2d | null;
10
+ get position(): Point2;
11
+ set position(value: Point2);
12
+ get rotation(): number;
13
+ set rotation(value: number);
14
+ protected _nativeBody: RigidBody | null;
15
+ protected _nativeBodyColliders: Collider[] | null;
16
+ get nativeBody(): RigidBody | null;
17
+ set nativeBody(value: RigidBody | null);
18
+ name: string;
19
+ get factoryProps(): [ColliderDesc[], RigidBodyDesc, Omit<Omit<Body2DOptions, 'dynamic'>, 'mass'>];
20
+ constructor(world: Rapier2dWorldComponent, _colliderDescr: ColliderDesc[], _bodyDescr: RigidBodyDesc, _colliderOptions: Omit<Omit<Body2DOptions, 'dynamic'>, 'mass'>);
21
+ clone(): Rapier2dRigidBodyComponent;
22
+ addToWorld(world: Gg2dWorld<IVisualScene2dComponent, Rapier2dWorldComponent>): void;
23
+ removeFromWorld(world: Gg2dWorld<IVisualScene2dComponent, Rapier2dWorldComponent>): void;
24
+ resetMotion(): void;
25
+ dispose(): void;
26
+ }
@@ -0,0 +1,88 @@
1
+ import { Pnt2, } from '@gg-web-engine/core';
2
+ import { Vector2 } from '@dimforge/rapier2d';
3
+ export class Rapier2dRigidBodyComponent {
4
+ constructor(world, _colliderDescr, _bodyDescr, _colliderOptions) {
5
+ this.world = world;
6
+ this._colliderDescr = _colliderDescr;
7
+ this._bodyDescr = _bodyDescr;
8
+ this._colliderOptions = _colliderOptions;
9
+ this.entity = null;
10
+ this._nativeBody = null;
11
+ this._nativeBodyColliders = null;
12
+ this.name = '';
13
+ }
14
+ get position() {
15
+ return Pnt2.clone(this.nativeBody ? this.nativeBody.translation() : this._bodyDescr.translation);
16
+ }
17
+ set position(value) {
18
+ if (this.nativeBody) {
19
+ this.nativeBody.setTranslation(new Vector2(value.x, value.y), false);
20
+ }
21
+ else {
22
+ this._bodyDescr.setTranslation(value.x, value.y);
23
+ }
24
+ }
25
+ get rotation() {
26
+ return this.nativeBody ? this.nativeBody.rotation() : this._bodyDescr.rotation;
27
+ }
28
+ set rotation(value) {
29
+ if (this.nativeBody) {
30
+ this.nativeBody.setRotation(value, false);
31
+ }
32
+ else {
33
+ this._bodyDescr.setRotation(value);
34
+ }
35
+ }
36
+ get nativeBody() {
37
+ return this._nativeBody;
38
+ }
39
+ set nativeBody(value) {
40
+ if (value == this._nativeBody || !value) {
41
+ return;
42
+ }
43
+ this._nativeBody = value;
44
+ }
45
+ get factoryProps() {
46
+ return [this._colliderDescr, this._bodyDescr, this._colliderOptions];
47
+ }
48
+ clone() {
49
+ // TODO probably need to clone factory props to not share the same reference?
50
+ return new Rapier2dRigidBodyComponent(this.world, ...this.factoryProps);
51
+ }
52
+ addToWorld(world) {
53
+ if (world.physicsWorld != this.world) {
54
+ throw new Error('Rapier2D bodies cannot be shared between different worlds');
55
+ }
56
+ this._nativeBody = this.world.nativeWorld.createRigidBody(this._bodyDescr);
57
+ this._nativeBodyColliders = this._colliderDescr.map(c => {
58
+ const col = this.world.nativeWorld.createCollider(c, this._nativeBody);
59
+ col.setFriction(this._colliderOptions.friction);
60
+ col.setRestitution(this._colliderOptions.restitution);
61
+ return col;
62
+ });
63
+ this.world.handleIdEntityMap.set(this._nativeBody.handle, this);
64
+ }
65
+ removeFromWorld(world) {
66
+ if (world.physicsWorld != this.world) {
67
+ throw new Error('Rapier2D bodies cannot be shared between different worlds');
68
+ }
69
+ if (this._nativeBody) {
70
+ for (const col of this._nativeBodyColliders) {
71
+ this.world.nativeWorld.removeCollider(col, false);
72
+ }
73
+ this.world.nativeWorld.removeRigidBody(this._nativeBody);
74
+ this.world.handleIdEntityMap.delete(this._nativeBody.handle);
75
+ this._nativeBody = null;
76
+ this._nativeBodyColliders = null;
77
+ }
78
+ }
79
+ resetMotion() {
80
+ this._nativeBody.setAngvel(0, false);
81
+ this._nativeBody.setLinvel(new Vector2(0, 0), false);
82
+ }
83
+ dispose() {
84
+ if (this.nativeBody) {
85
+ this.removeFromWorld({ physicsWorld: this.world });
86
+ }
87
+ }
88
+ }
@@ -0,0 +1,17 @@
1
+ import { Observable, Subject } from 'rxjs';
2
+ import { ColliderDesc, RigidBodyDesc } from '@dimforge/rapier2d';
3
+ import { Rapier2dRigidBodyComponent } from './rapier-2d-rigid-body.component';
4
+ import { Gg2dWorld, ITrigger2dComponent, IVisualScene2dComponent } from '@gg-web-engine/core';
5
+ import { Rapier2dWorldComponent } from './rapier-2d-world.component';
6
+ export declare class Rapier2dTriggerComponent extends Rapier2dRigidBodyComponent implements ITrigger2dComponent<Rapier2dWorldComponent> {
7
+ protected readonly world: Rapier2dWorldComponent;
8
+ protected _colliderDescr: ColliderDesc[];
9
+ protected _bodyDescr: RigidBodyDesc;
10
+ get onEntityEntered(): Observable<Rapier2dRigidBodyComponent>;
11
+ get onEntityLeft(): Observable<Rapier2dRigidBodyComponent>;
12
+ protected readonly onEnter$: Subject<Rapier2dRigidBodyComponent>;
13
+ protected readonly onLeft$: Subject<Rapier2dRigidBodyComponent>;
14
+ constructor(world: Rapier2dWorldComponent, _colliderDescr: ColliderDesc[], _bodyDescr: RigidBodyDesc);
15
+ addToWorld(world: Gg2dWorld<IVisualScene2dComponent, Rapier2dWorldComponent>): void;
16
+ checkOverlaps(): void;
17
+ }
@@ -0,0 +1,41 @@
1
+ import { Subject } from 'rxjs';
2
+ import { Rapier2dRigidBodyComponent } from './rapier-2d-rigid-body.component';
3
+ export class Rapier2dTriggerComponent extends Rapier2dRigidBodyComponent {
4
+ constructor(world, _colliderDescr, _bodyDescr) {
5
+ super(world, _colliderDescr, _bodyDescr, null);
6
+ this.world = world;
7
+ this._colliderDescr = _colliderDescr;
8
+ this._bodyDescr = _bodyDescr;
9
+ this.onEnter$ = new Subject();
10
+ this.onLeft$ = new Subject();
11
+ }
12
+ get onEntityEntered() {
13
+ return this.onEnter$.asObservable();
14
+ }
15
+ get onEntityLeft() {
16
+ return this.onLeft$.asObservable();
17
+ }
18
+ addToWorld(world) {
19
+ if (world.physicsWorld != this.world) {
20
+ throw new Error('Rapier2D bodies cannot be shared between different worlds');
21
+ }
22
+ this._nativeBody = this.world.nativeWorld.createRigidBody(this._bodyDescr);
23
+ this._nativeBodyColliders = this._colliderDescr.map(c => this.world.nativeWorld.createCollider(c, this._nativeBody));
24
+ this.world.handleIdEntityMap.set(this._nativeBody.handle, this);
25
+ }
26
+ checkOverlaps() {
27
+ this.world.eventQueue.drainCollisionEvents((h1, h2, started) => {
28
+ var _a, _b;
29
+ let otherBody;
30
+ if (h1 === ((_a = this.nativeBody) === null || _a === void 0 ? void 0 : _a.handle)) {
31
+ otherBody = this.world.handleIdEntityMap.get(h2);
32
+ }
33
+ else if (h2 === ((_b = this.nativeBody) === null || _b === void 0 ? void 0 : _b.handle)) {
34
+ otherBody = this.world.handleIdEntityMap.get(h1);
35
+ }
36
+ if (!otherBody || !otherBody.entity)
37
+ return;
38
+ (started ? this.onEnter$ : this.onLeft$).next(otherBody);
39
+ });
40
+ }
41
+ }
@@ -0,0 +1,25 @@
1
+ import { Gg2dWorld, IDebugPhysicsDrawer, IPhysicsWorld2dComponent, Point2 } from '@gg-web-engine/core';
2
+ import { EventQueue, World } from '@dimforge/rapier2d';
3
+ import { Rapier2dRigidBodyComponent } from './rapier-2d-rigid-body.component';
4
+ import { Rapier2dFactory } from '../rapier-2d-factory';
5
+ export declare class Rapier2dWorldComponent implements IPhysicsWorld2dComponent {
6
+ private _factory;
7
+ get factory(): Rapier2dFactory;
8
+ private readonly unitScale;
9
+ private _gravity;
10
+ get gravity(): Point2;
11
+ set gravity(value: Point2);
12
+ private _timeScale;
13
+ get timeScale(): number;
14
+ set timeScale(value: number);
15
+ get physicsDebugViewActive(): boolean;
16
+ protected _nativeWorld: World | undefined;
17
+ get nativeWorld(): World | undefined;
18
+ readonly eventQueue: EventQueue;
19
+ readonly handleIdEntityMap: Map<number, Rapier2dRigidBodyComponent>;
20
+ init(): Promise<void>;
21
+ simulate(delta: number): void;
22
+ startDebugger(world: Gg2dWorld, drawer: IDebugPhysicsDrawer<Point2, number>): void;
23
+ stopDebugger(): void;
24
+ dispose(): void;
25
+ }
@@ -0,0 +1,73 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { Pnt2 } from '@gg-web-engine/core';
11
+ import { EventQueue, Vector2, World } from '@dimforge/rapier2d';
12
+ import { Rapier2dFactory } from '../rapier-2d-factory';
13
+ export class Rapier2dWorldComponent {
14
+ constructor() {
15
+ this._factory = null;
16
+ this.unitScale = 100; // TODO abstractize somehow, hardcoded now
17
+ this._gravity = Pnt2.scalarMult({ x: 0, y: 9.82 }, this.unitScale);
18
+ this._timeScale = 1;
19
+ this.eventQueue = new EventQueue(true);
20
+ this.handleIdEntityMap = new Map();
21
+ }
22
+ get factory() {
23
+ if (!this._factory) {
24
+ throw new Error('Ammo world not initialized');
25
+ }
26
+ return this._factory;
27
+ }
28
+ get gravity() {
29
+ return Pnt2.scalarMult(this._gravity, 1 / this.unitScale);
30
+ }
31
+ set gravity(value) {
32
+ this._gravity = Pnt2.scalarMult(value, this.unitScale);
33
+ if (this.nativeWorld) {
34
+ this.nativeWorld.gravity.x = this._gravity.x;
35
+ this.nativeWorld.gravity.y = this._gravity.y;
36
+ }
37
+ }
38
+ get timeScale() {
39
+ return this._timeScale;
40
+ }
41
+ set timeScale(value) {
42
+ this._timeScale = value;
43
+ }
44
+ get physicsDebugViewActive() {
45
+ return false;
46
+ }
47
+ get nativeWorld() {
48
+ return this._nativeWorld;
49
+ }
50
+ init() {
51
+ return __awaiter(this, void 0, void 0, function* () {
52
+ this._nativeWorld = new World(new Vector2(this._gravity.x, this._gravity.y));
53
+ this._factory = new Rapier2dFactory(this);
54
+ });
55
+ }
56
+ simulate(delta) {
57
+ var _a;
58
+ this._nativeWorld.timestep = (this.timeScale * delta) / 1000;
59
+ (_a = this._nativeWorld) === null || _a === void 0 ? void 0 : _a.step(this.eventQueue);
60
+ }
61
+ startDebugger(world, drawer) {
62
+ // TODO
63
+ throw new Error('rapier-2d DebugDrawer not implemented');
64
+ }
65
+ stopDebugger() {
66
+ // TODO
67
+ throw new Error('rapier-2d DebugDrawer not implemented');
68
+ }
69
+ dispose() {
70
+ var _a;
71
+ (_a = this._nativeWorld) === null || _a === void 0 ? void 0 : _a.free();
72
+ }
73
+ }
@@ -0,0 +1,4 @@
1
+ export * from './components/rapier-2d-rigid-body.component';
2
+ export * from './components/rapier-2d-trigger.component';
3
+ export * from './components/rapier-2d-world.component';
4
+ export * from './rapier-2d-factory';
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export * from './components/rapier-2d-rigid-body.component';
2
+ export * from './components/rapier-2d-trigger.component';
3
+ export * from './components/rapier-2d-world.component';
4
+ export * from './rapier-2d-factory';
@@ -0,0 +1,22 @@
1
+ import { Body2DOptions, BodyShape2DDescriptor, IPhysicsBody2dComponentFactory, Point2, Shape2DDescriptor } from '@gg-web-engine/core';
2
+ import { ColliderDesc, RigidBodyDesc } from '@dimforge/rapier2d';
3
+ import { Rapier2dRigidBodyComponent } from './components/rapier-2d-rigid-body.component';
4
+ import { Rapier2dTriggerComponent } from './components/rapier-2d-trigger.component';
5
+ import { Rapier2dWorldComponent } from './components/rapier-2d-world.component';
6
+ export declare class Rapier2dFactory implements IPhysicsBody2dComponentFactory<Rapier2dRigidBodyComponent, Rapier2dTriggerComponent> {
7
+ protected readonly world: Rapier2dWorldComponent;
8
+ constructor(world: Rapier2dWorldComponent);
9
+ createRigidBody(descriptor: BodyShape2DDescriptor, transform?: {
10
+ position?: Point2;
11
+ rotation?: number;
12
+ }): Rapier2dRigidBodyComponent;
13
+ createTrigger(descriptor: Shape2DDescriptor, transform?: {
14
+ position?: Point2;
15
+ rotation?: number;
16
+ }): Rapier2dTriggerComponent;
17
+ createColliderDescr(descriptor: Shape2DDescriptor): ColliderDesc[];
18
+ createRigidBodyDescr(options: Partial<Body2DOptions>, transform?: {
19
+ position?: Point2;
20
+ rotation?: number;
21
+ }): RigidBodyDesc;
22
+ }
@@ -0,0 +1,43 @@
1
+ import { Pnt2, } from '@gg-web-engine/core';
2
+ import { ActiveEvents, ColliderDesc, RigidBodyDesc } from '@dimforge/rapier2d';
3
+ import { Rapier2dRigidBodyComponent } from './components/rapier-2d-rigid-body.component';
4
+ import { Rapier2dTriggerComponent } from './components/rapier-2d-trigger.component';
5
+ export class Rapier2dFactory {
6
+ constructor(world) {
7
+ this.world = world;
8
+ }
9
+ createRigidBody(descriptor, transform) {
10
+ return new Rapier2dRigidBodyComponent(this.world, this.createColliderDescr(descriptor.shape), this.createRigidBodyDescr(descriptor.body, transform), Object.assign({ friction: 0.5, restitution: 0.1 }, descriptor.body));
11
+ }
12
+ createTrigger(descriptor, transform) {
13
+ const colliderDescr = this.createColliderDescr(descriptor);
14
+ colliderDescr.forEach(c => {
15
+ c.isSensor = true;
16
+ c.setActiveEvents(ActiveEvents.COLLISION_EVENTS);
17
+ });
18
+ return new Rapier2dTriggerComponent(this.world, colliderDescr, this.createRigidBodyDescr({ dynamic: false }, transform));
19
+ }
20
+ createColliderDescr(descriptor) {
21
+ switch (descriptor.shape) {
22
+ case 'SQUARE':
23
+ return [ColliderDesc.cuboid(descriptor.dimensions.x / 2, descriptor.dimensions.y / 2)];
24
+ case 'CIRCLE':
25
+ return [ColliderDesc.ball(descriptor.radius)];
26
+ }
27
+ throw new Error(`Shape "${descriptor.shape}" not implemented for Rapier 2D`);
28
+ }
29
+ createRigidBodyDescr(options, transform) {
30
+ const pos = (transform === null || transform === void 0 ? void 0 : transform.position) || Pnt2.O;
31
+ const rot = (transform === null || transform === void 0 ? void 0 : transform.rotation) || 0;
32
+ const fixed = options.dynamic === false || !options.mass;
33
+ let bodyDesc;
34
+ if (fixed) {
35
+ bodyDesc = RigidBodyDesc.fixed();
36
+ }
37
+ else {
38
+ bodyDesc = RigidBodyDesc.dynamic();
39
+ bodyDesc.mass = options.mass || 1;
40
+ }
41
+ return bodyDesc.setTranslation(pos.x, pos.y).setRotation(rot);
42
+ }
43
+ }
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@gg-web-engine/rapier2d",
3
+ "version": "0.0.24",
4
+ "description": "An attempt to create open source game engine for browser",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "test": "echo \"Error: no test specified\" && exit 1",
9
+ "prettier-format": "prettier --config ../core/.prettierrc 'src/**/*.ts' --write",
10
+ "prepublish": "rm -rf ./dist/ && tsc",
11
+ "build": "tsc"
12
+ },
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/AndyGura/gg-web-engine.git"
16
+ },
17
+ "keywords": [
18
+ "game-development",
19
+ "game-engine",
20
+ "game-engine-framework",
21
+ "gamedev"
22
+ ],
23
+ "author": "AndyGura",
24
+ "license": "Apache-2.0",
25
+ "bugs": {
26
+ "url": "https://github.com/AndyGura/gg-web-engine/issues"
27
+ },
28
+ "homepage": "https://github.com/AndyGura/gg-web-engine#readme",
29
+ "devDependencies": {
30
+ "@dimforge/rapier2d": "^0.11.2",
31
+ "@gg-web-engine/core": "0.0.24",
32
+ "prettier": "^2.8.6",
33
+ "rxjs": "7.8.0",
34
+ "typescript": "~4.7.2"
35
+ },
36
+ "peerDependencies": {
37
+ "@dimforge/rapier2d": "^0.11.2",
38
+ "@gg-web-engine/core": "0.0.24",
39
+ "rxjs": "7.8.0"
40
+ }
41
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "./../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "baseUrl": "./src/",
5
+ "outDir": "./dist/",
6
+ },
7
+ "include": ["src/*.ts", "src/**/*.ts"],
8
+ }