@safe-engine/pixi 8.3.7 → 8.4.1
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/.github/workflows/npm-publish.yml +35 -0
- package/README.md +70 -5
- package/dist/app.d.ts +2 -5
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +44 -27
- package/dist/base/gworld.d.ts +2 -0
- package/dist/base/gworld.d.ts.map +1 -1
- package/dist/box2d-wasm/ContactListener.d.ts +12 -0
- package/dist/box2d-wasm/ContactListener.d.ts.map +1 -0
- package/dist/box2d-wasm/ContactListener.js +64 -0
- package/dist/box2d-wasm/PhysicsComponent.d.ts +50 -0
- package/dist/box2d-wasm/PhysicsComponent.d.ts.map +1 -0
- package/dist/box2d-wasm/PhysicsComponent.js +17 -0
- package/dist/box2d-wasm/PhysicsSprite.d.ts +11 -0
- package/dist/box2d-wasm/PhysicsSprite.d.ts.map +1 -0
- package/dist/box2d-wasm/PhysicsSprite.js +30 -0
- package/dist/box2d-wasm/PhysicsSystem.d.ts +17 -0
- package/dist/box2d-wasm/PhysicsSystem.d.ts.map +1 -0
- package/dist/box2d-wasm/PhysicsSystem.js +145 -0
- package/dist/box2d-wasm/debugDraw.d.ts +67 -0
- package/dist/box2d-wasm/debugDraw.d.ts.map +1 -0
- package/dist/box2d-wasm/debugDraw.js +224 -0
- package/dist/box2d-wasm/index.d.ts +6 -0
- package/dist/box2d-wasm/index.d.ts.map +1 -0
- package/dist/box2d-wasm/index.js +17 -0
- package/dist/collider/CollideComponent.d.ts.map +1 -1
- package/dist/collider/CollideComponent.js +12 -13
- package/dist/collider/CollideSystem.d.ts.map +1 -1
- package/dist/collider/CollideSystem.js +1 -2
- package/dist/collider/helper/utils.d.ts +2 -0
- package/dist/collider/helper/utils.d.ts.map +1 -1
- package/dist/collider/helper/utils.js +22 -0
- package/dist/collider/index.d.ts +1 -0
- package/dist/collider/index.d.ts.map +1 -1
- package/dist/collider/index.js +12 -0
- package/dist/components/NodeComp.d.ts +6 -4
- package/dist/components/NodeComp.d.ts.map +1 -1
- package/dist/components/NodeComp.js +13 -13
- package/dist/components/Scene.d.ts.map +1 -1
- package/dist/components/Scene.js +3 -4
- package/dist/core/director.d.ts.map +1 -1
- package/dist/core/director.js +4 -3
- package/dist/dragonbones/DragonBonesSystem.d.ts +2 -1
- package/dist/dragonbones/DragonBonesSystem.d.ts.map +1 -1
- package/dist/dragonbones/DragonBonesSystem.js +2 -0
- package/dist/dragonbones/index.d.ts +1 -0
- package/dist/dragonbones/index.d.ts.map +1 -1
- package/dist/dragonbones/index.js +7 -0
- package/dist/gui/GUIComponent.d.ts +0 -9
- package/dist/gui/GUIComponent.d.ts.map +1 -1
- package/dist/gui/GUIComponent.js +0 -37
- package/dist/gui/GUISystem.d.ts +1 -0
- package/dist/gui/GUISystem.d.ts.map +1 -1
- package/dist/gui/GUISystem.js +2 -15
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/planck/PhysicsComponent.d.ts +7 -7
- package/dist/planck/PhysicsComponent.js +4 -4
- package/dist/planck/PhysicsSystem.js +12 -12
- package/dist/richtext/RichTextComp.d.ts +17 -0
- package/dist/richtext/RichTextComp.d.ts.map +1 -0
- package/dist/richtext/RichTextComp.js +38 -0
- package/dist/richtext/RichTextSystem.d.ts +7 -0
- package/dist/richtext/RichTextSystem.d.ts.map +1 -0
- package/dist/richtext/RichTextSystem.js +25 -0
- package/dist/richtext/html-text-parser.d.ts +20 -0
- package/dist/richtext/html-text-parser.d.ts.map +1 -0
- package/dist/richtext/html-text-parser.js +64 -0
- package/dist/richtext/index.d.ts +3 -0
- package/dist/richtext/index.d.ts.map +1 -0
- package/dist/richtext/index.js +7 -0
- package/dist/spine/index.d.ts +1 -0
- package/dist/spine/index.d.ts.map +1 -1
- package/dist/spine/index.js +7 -0
- package/package.json +9 -11
- package/src/@types/index.d.ts +2 -0
- package/src/@types/safex.d.ts +15 -0
- package/src/app.ts +85 -0
- package/src/base/EnhancedComponent.ts +37 -0
- package/src/base/gworld.ts +19 -0
- package/src/base/index.ts +3 -0
- package/src/base/utils.ts +23 -0
- package/src/box2d-wasm/ContactListener.ts +66 -0
- package/src/box2d-wasm/PhysicsComponent.ts +83 -0
- package/src/box2d-wasm/PhysicsSprite.ts +42 -0
- package/src/box2d-wasm/PhysicsSystem.ts +145 -0
- package/src/box2d-wasm/debugDraw.ts +257 -0
- package/src/box2d-wasm/index.ts +19 -0
- package/src/collider/CollideComponent.ts +257 -0
- package/src/collider/CollideSystem.ts +166 -0
- package/src/collider/helper/Intersection.ts +139 -0
- package/src/collider/helper/utils.ts +37 -0
- package/src/collider/index.ts +16 -0
- package/src/components/BaseComponent.ts +17 -0
- package/src/components/NodeComp.ts +434 -0
- package/src/components/Scene.ts +17 -0
- package/src/core/Color.ts +7 -0
- package/src/core/LoadingBar.ts +63 -0
- package/src/core/NodePool.ts +28 -0
- package/src/core/Size.ts +21 -0
- package/src/core/director.ts +11 -0
- package/src/core/math.ts +13 -0
- package/src/dragonbones/DragonBonesComponent.ts +32 -0
- package/src/dragonbones/DragonBonesSystem.ts +35 -0
- package/src/dragonbones/index.ts +11 -0
- package/src/gui/GUIComponent.ts +159 -0
- package/src/gui/GUISystem.ts +116 -0
- package/src/helper/utils.ts +50 -0
- package/src/index.ts +23 -0
- package/src/norender/NoRenderComponent.ts +60 -0
- package/src/norender/NoRenderSystem.ts +66 -0
- package/src/planck/PhysicsComponent.ts +83 -0
- package/src/planck/PhysicsSprite.ts +43 -0
- package/src/planck/PhysicsSystem.ts +201 -0
- package/src/planck/index.ts +3 -0
- package/src/render/RenderComponent.ts +138 -0
- package/src/render/RenderSystem.ts +67 -0
- package/src/richtext/RichTextComp.ts +46 -0
- package/src/richtext/RichTextSystem.ts +26 -0
- package/src/richtext/html-text-parser.ts +87 -0
- package/src/richtext/index.ts +8 -0
- package/src/spine/SpineComponent.ts +18 -0
- package/src/spine/SpineSystem.ts +30 -0
- package/src/spine/index.ts +11 -0
- package/src/spine/lib/BatchableSpineSlot.ts +138 -0
- package/src/spine/lib/Spine.ts +910 -0
- package/src/spine/lib/SpineDebugRenderer.ts +615 -0
- package/src/spine/lib/SpinePipe.ts +203 -0
- package/src/spine/lib/SpineTexture.ts +143 -0
- package/src/spine/lib/assets/atlasLoader.ts +158 -0
- package/src/spine/lib/assets/skeletonLoader.ts +81 -0
- package/src/spine/lib/darktint/DarkTintBatchGeometry.ts +92 -0
- package/src/spine/lib/darktint/DarkTintBatcher.ts +186 -0
- package/src/spine/lib/darktint/DarkTintShader.ts +74 -0
- package/src/spine/lib/darktint/darkTintBit.ts +77 -0
- package/src/spine/lib/index.ts +43 -0
- package/src/spine/lib/require-shim.ts +43 -0
- package/tsconfig.json +18 -0
package/src/app.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { actionManager } from 'pixi-action-ease'
|
|
2
|
+
import { Application } from 'pixi.js'
|
|
3
|
+
|
|
4
|
+
import { GameWorld } from './base'
|
|
5
|
+
import { CollideSystem } from './collider'
|
|
6
|
+
import { GUISystem } from './gui/GUISystem'
|
|
7
|
+
import { NoRenderSystem } from './norender/NoRenderSystem'
|
|
8
|
+
import { RenderSystem } from './render/RenderSystem'
|
|
9
|
+
|
|
10
|
+
export async function startGame(defaultFont, designedResolution = { width: 720, height: 1280 }, id = 'game') {
|
|
11
|
+
const app = new Application()
|
|
12
|
+
await app.init({
|
|
13
|
+
antialias: true,
|
|
14
|
+
resolution: window.devicePixelRatio,
|
|
15
|
+
resizeTo: window,
|
|
16
|
+
eventFeatures: {
|
|
17
|
+
move: true,
|
|
18
|
+
/** disables the global move events which can be very expensive in large scenes */
|
|
19
|
+
globalMove: false,
|
|
20
|
+
click: true,
|
|
21
|
+
wheel: false,
|
|
22
|
+
},
|
|
23
|
+
canvas: document.getElementById(id) as HTMLCanvasElement
|
|
24
|
+
})
|
|
25
|
+
// GameWorld.Instance.setup(NodeComp, app.stage)
|
|
26
|
+
Object.assign(app.canvas.style, {
|
|
27
|
+
width: `${window.innerWidth}px`,
|
|
28
|
+
height: `${window.innerHeight}px`,
|
|
29
|
+
overflow: 'visible',
|
|
30
|
+
})
|
|
31
|
+
const { width, height } = designedResolution
|
|
32
|
+
app.renderer.resize(width, height)
|
|
33
|
+
// app.stage.position.y = app.renderer.height / app.renderer.resolution
|
|
34
|
+
// app.stage.scale.y = -1
|
|
35
|
+
GameWorld.Instance.app = app
|
|
36
|
+
initWorld(defaultFont)
|
|
37
|
+
startGameLoop(GameWorld.Instance)
|
|
38
|
+
return app
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function startGameLoop(world: GameWorld) {
|
|
42
|
+
// Listen for frame updates
|
|
43
|
+
world.app.ticker.add(() => {
|
|
44
|
+
const dt = world.app.ticker.deltaMS * 0.001
|
|
45
|
+
actionManager.update(dt)
|
|
46
|
+
world.update(dt)
|
|
47
|
+
})
|
|
48
|
+
// app.ticker.speed = 0.5
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// const systemsList = [RenderSystem, GUISystem, SpineSystem, DragonBonesSystem, CollideSystem, NoRenderSystem]
|
|
52
|
+
// export function startGameSystems(list = []) {
|
|
53
|
+
// const world = GameWorld.Instance
|
|
54
|
+
// systemsList.forEach(system => {
|
|
55
|
+
// world.systems.add(system)
|
|
56
|
+
// world.systems.configureOnce(system)
|
|
57
|
+
// })
|
|
58
|
+
// world.listUpdate.push(CollideSystem)
|
|
59
|
+
// // world.listUpdate.push(PhysicsSystem)
|
|
60
|
+
// list.forEach(system => {
|
|
61
|
+
// world.systems.add(system)
|
|
62
|
+
// world.systems.configureOnce(system)
|
|
63
|
+
// world.listUpdate.push(system)
|
|
64
|
+
// })
|
|
65
|
+
// startGameLoop(world)
|
|
66
|
+
// // console.log('startGameLoop', world.listUpdate)
|
|
67
|
+
// }
|
|
68
|
+
|
|
69
|
+
function initWorld(defaultFont?: string) {
|
|
70
|
+
const world = GameWorld.Instance
|
|
71
|
+
world.systems.add(RenderSystem)
|
|
72
|
+
world.systems.add(CollideSystem)
|
|
73
|
+
world.systems.add(GUISystem)
|
|
74
|
+
world.systems.add(NoRenderSystem)
|
|
75
|
+
world.listUpdate.push(CollideSystem)
|
|
76
|
+
world.systems.configureOnce(RenderSystem)
|
|
77
|
+
world.systems.configureOnce(CollideSystem)
|
|
78
|
+
world.systems.configureOnce(GUISystem)
|
|
79
|
+
world.systems.configureOnce(NoRenderSystem)
|
|
80
|
+
if (defaultFont) {
|
|
81
|
+
const guiSystem = world.systems.get(GUISystem)
|
|
82
|
+
guiSystem.defaultFont = defaultFont
|
|
83
|
+
}
|
|
84
|
+
// startGameLoop(world, app)
|
|
85
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Constructor } from 'entityx-ts'
|
|
2
|
+
import { BaseComponentProps } from '../@types/safex'
|
|
3
|
+
import { NodeComp } from '../components/NodeComp'
|
|
4
|
+
|
|
5
|
+
export class EnhancedComponent<Props = {}, N extends NodeComp<any> = NodeComp<any>> {
|
|
6
|
+
props: Props = {} as any
|
|
7
|
+
constructor(data?: BaseComponentProps & Props) {
|
|
8
|
+
this.init(data)
|
|
9
|
+
}
|
|
10
|
+
init(data?: Props) {
|
|
11
|
+
if (data) {
|
|
12
|
+
// console.log('constructor', this.constructor.name, data)
|
|
13
|
+
Object.keys(data).forEach((key) => {
|
|
14
|
+
this.props[key] = data[key]
|
|
15
|
+
})
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
node: N
|
|
19
|
+
// actionsMap: { [key: string]: Animation } = {}
|
|
20
|
+
addComponent<T extends EnhancedComponent>(instance): T {
|
|
21
|
+
return this.node.addComponent(instance)
|
|
22
|
+
}
|
|
23
|
+
getComponent<T extends ComponentType>(component: Constructor<T>): T {
|
|
24
|
+
return this.node.getComponent(component)
|
|
25
|
+
}
|
|
26
|
+
getComponentsInChildren<T extends ComponentType>(component: Constructor<T>): T[] {
|
|
27
|
+
return this.node.getComponentsInChildren(component)
|
|
28
|
+
}
|
|
29
|
+
getComponentInChildren<T extends ComponentType>(component: Constructor<T>): T {
|
|
30
|
+
return this.node.getComponentInChildren(component)
|
|
31
|
+
}
|
|
32
|
+
isEqual(other: EnhancedComponent) {
|
|
33
|
+
return this.node.entity.id === other.node.entity.id
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type ComponentType = EnhancedComponent | NodeComp
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Constructor, System, World } from 'entityx-ts'
|
|
2
|
+
import { Application } from 'pixi.js'
|
|
3
|
+
|
|
4
|
+
export class GameWorld extends World {
|
|
5
|
+
listUpdate: (System | Constructor<System>)[] = []
|
|
6
|
+
app: Application
|
|
7
|
+
update(dt: number) {
|
|
8
|
+
this.listUpdate.forEach((system: any) => {
|
|
9
|
+
this.systems.update(system, dt)
|
|
10
|
+
})
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
private static _instance: GameWorld
|
|
14
|
+
|
|
15
|
+
public static get Instance() {
|
|
16
|
+
// Do you need arguments? Make it a regular static method instead.
|
|
17
|
+
return this._instance || (this._instance = new this())
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Constructor } from 'entityx-ts';
|
|
2
|
+
|
|
3
|
+
import { GameWorld } from '..';
|
|
4
|
+
import { ComponentX, NoRenderComponentX } from '../components/BaseComponent';
|
|
5
|
+
|
|
6
|
+
export type GetProps<T> = T extends ComponentX<infer P> ? P : T extends NoRenderComponentX<infer Q> ? Q : never;
|
|
7
|
+
|
|
8
|
+
export function instantiate<T extends ComponentX>(ComponentType: Constructor<T>, data?: GetProps<T>): T {
|
|
9
|
+
const instance = new ComponentType()
|
|
10
|
+
instance.init(data)
|
|
11
|
+
// console.log(ComponentType.name, data, instance)
|
|
12
|
+
if (!instance.render) {
|
|
13
|
+
return instance
|
|
14
|
+
}
|
|
15
|
+
return instance.render()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function loadScene<T extends ComponentX>(ComponentType: Constructor<T>) {
|
|
19
|
+
const world = GameWorld.Instance
|
|
20
|
+
world.entities.reset()
|
|
21
|
+
const instance = new ComponentType()
|
|
22
|
+
instance.render()
|
|
23
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { NodeComp } from "..";
|
|
2
|
+
import { ColliderPhysics } from "./PhysicsComponent";
|
|
3
|
+
type Meta = { [key: number]: NodeComp }
|
|
4
|
+
export const makeContactListener = (world: Box2D.b2World, metadata: Meta, box2D: typeof Box2D) => {
|
|
5
|
+
const { JSContactListener, getPointer, NULL } = box2D
|
|
6
|
+
function getContactById(contact: number) {
|
|
7
|
+
for (let contactList = world.GetContactList(); getPointer(contactList) !== getPointer(NULL); contactList = contactList.GetNext()) {
|
|
8
|
+
if (getPointer(contactList) === contact) {
|
|
9
|
+
console.log('contactBegin', contact, getPointer(contactList), getPointer(NULL));
|
|
10
|
+
return contactList
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const listener = Object.assign(new JSContactListener(), {
|
|
15
|
+
BeginContact(contact: Box2D.b2Contact | number): void {
|
|
16
|
+
if (typeof contact === 'number') {
|
|
17
|
+
contact = getContactById(contact)
|
|
18
|
+
}
|
|
19
|
+
const ett1: NodeComp = metadata[getPointer(contact.GetFixtureA().GetBody())]
|
|
20
|
+
const ett2: NodeComp = metadata[getPointer(contact.GetFixtureB().GetBody())]
|
|
21
|
+
// world.addPostStepCallback(() => {
|
|
22
|
+
// // log('addPostStepCallback');
|
|
23
|
+
// listRemoveShape.forEach((s) => world.removeShape(s))
|
|
24
|
+
// listRemoveBody.forEach((b) => world.removeBody(b))
|
|
25
|
+
// listRemoveBody = []
|
|
26
|
+
// listRemoveShape = []
|
|
27
|
+
// })
|
|
28
|
+
const phys1 = ett1.getComponent(ColliderPhysics)
|
|
29
|
+
const phys2 = ett2.getComponent(ColliderPhysics)
|
|
30
|
+
if (phys1 && phys2) {
|
|
31
|
+
if (Object.prototype.hasOwnProperty.call(phys1, 'onCollisionEnter')) {
|
|
32
|
+
phys1.props.onCollisionEnter(phys2)
|
|
33
|
+
}
|
|
34
|
+
if (Object.prototype.hasOwnProperty.call(phys2, 'onCollisionEnter')) {
|
|
35
|
+
phys2.props.onCollisionEnter(phys1)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
EndContact(contact: Box2D.b2Contact | number): void {
|
|
40
|
+
if (typeof contact === 'number') {
|
|
41
|
+
contact = getContactById(contact)
|
|
42
|
+
}
|
|
43
|
+
const ett1: NodeComp = metadata[getPointer(contact.GetFixtureA().GetBody())]
|
|
44
|
+
const ett2: NodeComp = metadata[getPointer(contact.GetFixtureB().GetBody())]
|
|
45
|
+
// const event1 = ett1.getComponent(NodeComp)
|
|
46
|
+
const phys1 = ett1.getComponent(ColliderPhysics)
|
|
47
|
+
const phys2 = ett2.getComponent(ColliderPhysics)
|
|
48
|
+
// const event2 = ett2.getComponent(NodeComp)
|
|
49
|
+
if (phys1 && phys2) {
|
|
50
|
+
if (Object.prototype.hasOwnProperty.call(phys1, 'onCollisionExit')) {
|
|
51
|
+
phys1.props.onCollisionExit(phys2)
|
|
52
|
+
}
|
|
53
|
+
if (Object.prototype.hasOwnProperty.call(phys2, 'onCollisionExit')) {
|
|
54
|
+
phys2.props.onCollisionExit(phys1)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
PreSolve(contact: Box2D.b2Contact | number, oldManifold: Box2D.b2Manifold | number): void {
|
|
59
|
+
console.log('collisionSeparate');
|
|
60
|
+
},
|
|
61
|
+
PostSolve(contact: Box2D.b2Contact | number, impulse: Box2D.b2ContactImpulse | number): void {
|
|
62
|
+
console.log('collisionPost');
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
return listener
|
|
66
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { BodyType, Vec2 } from 'planck'
|
|
2
|
+
import { NoRenderComponentX } from '..'
|
|
3
|
+
import { PhysicsSprite } from './PhysicsSprite'
|
|
4
|
+
|
|
5
|
+
interface RigidBodyProps {
|
|
6
|
+
type?: BodyType
|
|
7
|
+
density?: Float
|
|
8
|
+
restitution?: Float
|
|
9
|
+
friction?: Float
|
|
10
|
+
gravityScale?: Float
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class RigidBody extends NoRenderComponentX<RigidBodyProps> {
|
|
14
|
+
body: Box2D.b2Body
|
|
15
|
+
// set linearVelocity(vel: Vec2) {
|
|
16
|
+
// if (!this.node) {
|
|
17
|
+
// return
|
|
18
|
+
// }
|
|
19
|
+
// const physics = this.node.instance
|
|
20
|
+
// if (physics instanceof Sprite) {
|
|
21
|
+
// physics.getBody().setVel(vel)
|
|
22
|
+
// }
|
|
23
|
+
// }
|
|
24
|
+
|
|
25
|
+
// get linearVelocity() {
|
|
26
|
+
// if (!this.node) {
|
|
27
|
+
// return Vec2.ZERO
|
|
28
|
+
// }
|
|
29
|
+
// const physics = this.node.instance
|
|
30
|
+
// const vel = (physics as Sprite).getBody().getVel()
|
|
31
|
+
// return v2(vel)
|
|
32
|
+
// }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface PhysicsMaterialProps {
|
|
36
|
+
friction?: number
|
|
37
|
+
restitution?: number
|
|
38
|
+
density?: number
|
|
39
|
+
}
|
|
40
|
+
export class PhysicsMaterial extends NoRenderComponentX<PhysicsMaterialProps> {
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface ColliderPhysicsProps {
|
|
45
|
+
tag?: number
|
|
46
|
+
group?: number
|
|
47
|
+
offset?: Vec2
|
|
48
|
+
onCollisionEnter?: (other: ColliderPhysics) => void
|
|
49
|
+
onCollisionExit?: (other: ColliderPhysics) => void
|
|
50
|
+
onCollisionStay?: (other: ColliderPhysics) => void
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export class ColliderPhysics<T extends ColliderPhysicsProps = ColliderPhysicsProps> extends NoRenderComponentX<T, PhysicsSprite['node']> {
|
|
54
|
+
enabled = true
|
|
55
|
+
instance: PhysicsSprite
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface BoxColliderPhysicsProps extends ColliderPhysicsProps {
|
|
59
|
+
width: number
|
|
60
|
+
height: number
|
|
61
|
+
}
|
|
62
|
+
export class BoxColliderPhysics extends ColliderPhysics<BoxColliderPhysicsProps> {
|
|
63
|
+
|
|
64
|
+
// set onCollisionEnter(val) {
|
|
65
|
+
// const phys1 = this.getComponent(ColliderPhysics)
|
|
66
|
+
// phys1._onCollisionEnter = val
|
|
67
|
+
// }
|
|
68
|
+
|
|
69
|
+
// get onCollisionEnter() {
|
|
70
|
+
// const phys1 = this.getComponent(ColliderPhysics)
|
|
71
|
+
// return phys1._onCollisionEnter
|
|
72
|
+
// }
|
|
73
|
+
}
|
|
74
|
+
interface CircleColliderPhysicsProps extends ColliderPhysicsProps {
|
|
75
|
+
radius: number
|
|
76
|
+
}
|
|
77
|
+
export class CircleColliderPhysics extends ColliderPhysics<CircleColliderPhysicsProps> {
|
|
78
|
+
}
|
|
79
|
+
interface PolygonColliderPhysicsProps extends ColliderPhysicsProps {
|
|
80
|
+
points: Array<Vec2>
|
|
81
|
+
}
|
|
82
|
+
export class PolygonColliderPhysics extends ColliderPhysics<PolygonColliderPhysicsProps> {
|
|
83
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Container } from 'pixi.js'
|
|
2
|
+
|
|
3
|
+
export class PhysicsSprite {
|
|
4
|
+
node: Container
|
|
5
|
+
physicsBody: Box2D.b2Body
|
|
6
|
+
|
|
7
|
+
constructor(node: Container, body: Box2D.b2Body) {
|
|
8
|
+
this.node = node
|
|
9
|
+
this.physicsBody = body
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// set position(val: Box2D.b2Vec2) {
|
|
13
|
+
// this.physicsBody.setPosition(val)
|
|
14
|
+
// }
|
|
15
|
+
|
|
16
|
+
// set x(val) {
|
|
17
|
+
// this.physicsBody.setPosition(Vec2(val, this.y))
|
|
18
|
+
// }
|
|
19
|
+
// set y(val) {
|
|
20
|
+
// this.physicsBody.setPosition(Vec2(this.x, val))
|
|
21
|
+
// }
|
|
22
|
+
|
|
23
|
+
get x() {
|
|
24
|
+
return this.physicsBody.GetPosition().x
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get y() {
|
|
28
|
+
return this.physicsBody.GetPosition().x
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// set angle(val: number) {
|
|
32
|
+
// this.physicsBody.setAngle(val)
|
|
33
|
+
// }
|
|
34
|
+
|
|
35
|
+
get angle() {
|
|
36
|
+
return this.physicsBody.GetAngle()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
addChild(child: Container) {
|
|
40
|
+
this.node.addChild(child)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import Box2DFactory from 'box2d-wasm';
|
|
2
|
+
import {
|
|
3
|
+
EntityManager,
|
|
4
|
+
EventManager,
|
|
5
|
+
EventTypes,
|
|
6
|
+
System
|
|
7
|
+
} from 'entityx-ts';
|
|
8
|
+
import { GameWorld, Graphics, instantiate, NodeComp, Vec2 } from '..';
|
|
9
|
+
|
|
10
|
+
import { makeContactListener } from './ContactListener';
|
|
11
|
+
import { makeDebugDraw } from './debugDraw';
|
|
12
|
+
import {
|
|
13
|
+
BoxColliderPhysics,
|
|
14
|
+
CircleColliderPhysics,
|
|
15
|
+
ColliderPhysics,
|
|
16
|
+
PhysicsMaterial,
|
|
17
|
+
PolygonColliderPhysics,
|
|
18
|
+
RigidBody,
|
|
19
|
+
} from './PhysicsComponent';
|
|
20
|
+
import { PhysicsSprite } from './PhysicsSprite';
|
|
21
|
+
|
|
22
|
+
// Box2D.b2Fixture.prototype.shouldCollide = function (other) {
|
|
23
|
+
// const nodeThis: NodeComp = this.getBody().getUserData()
|
|
24
|
+
// const nodeOther = other.getBody().getUserData() as NodeComp
|
|
25
|
+
// const { colliderMatrix } = GameWorld.Instance.systems.get(PhysicsSystem)
|
|
26
|
+
// return colliderMatrix[nodeOther.group][nodeThis.group]
|
|
27
|
+
// }
|
|
28
|
+
export let box2D: typeof Box2D
|
|
29
|
+
export async function initBox2d() {
|
|
30
|
+
box2D = await Box2DFactory();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function setColliderMatrix(colliderMatrix = [[true]]) {
|
|
34
|
+
const physicsSystem = GameWorld.Instance.systems.get(PhysicsSystem)
|
|
35
|
+
physicsSystem.colliderMatrix = colliderMatrix
|
|
36
|
+
}
|
|
37
|
+
const maxTimeStep = 1 / 60;
|
|
38
|
+
const velocityIterations = 1;
|
|
39
|
+
const positionIterations = 1;
|
|
40
|
+
const metadata: { [key: number]: NodeComp } = {}
|
|
41
|
+
const pixelsPerMeter = 1;
|
|
42
|
+
|
|
43
|
+
export class PhysicsSystem implements System {
|
|
44
|
+
world: Box2D.b2World
|
|
45
|
+
listRemoveBody: Body[] = []
|
|
46
|
+
listRemoveShape: Box2D.b2Shape[] = []
|
|
47
|
+
colliderMatrix = [[true]]
|
|
48
|
+
graphics: Graphics
|
|
49
|
+
|
|
50
|
+
addDebug() {
|
|
51
|
+
const debugDraw = makeDebugDraw(this.graphics, pixelsPerMeter, box2D)
|
|
52
|
+
this.world.SetDebugDraw(debugDraw)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
configure(event_manager: EventManager) {
|
|
56
|
+
const { b2BodyDef, b2_dynamicBody, b2_staticBody, b2FixtureDef, b2PolygonShape, b2Vec2, b2World, getPointer, b2ContactListener } = box2D as typeof Box2D;
|
|
57
|
+
const gravity = new b2Vec2(0, 10);
|
|
58
|
+
this.world = new b2World(gravity);
|
|
59
|
+
console.log('configure world', (event_manager.world as GameWorld).app)
|
|
60
|
+
// event_manager.world.physicsManager = this
|
|
61
|
+
const graphics = new Graphics();
|
|
62
|
+
this.graphics = graphics
|
|
63
|
+
graphics.zIndex = 1000
|
|
64
|
+
; (event_manager.world as GameWorld).app.stage.addChild(graphics);
|
|
65
|
+
// event_manager.subscribe(ComponentAddedEvent(RigidBody), this);
|
|
66
|
+
event_manager.subscribe(EventTypes.ComponentAdded, BoxColliderPhysics, ({ entity, component }) => {
|
|
67
|
+
console.log('ComponentAddedEvent BoxColliderPhysics', component)
|
|
68
|
+
let rigidBody = entity.getComponent(RigidBody)
|
|
69
|
+
if (!rigidBody) {
|
|
70
|
+
rigidBody = instantiate(RigidBody)
|
|
71
|
+
entity.assign(rigidBody)
|
|
72
|
+
}
|
|
73
|
+
const { type = 'static', gravityScale = 1, } = rigidBody.props
|
|
74
|
+
const physicsMaterial = entity.getComponent(PhysicsMaterial)
|
|
75
|
+
const { density = 1, friction = 0.5, restitution = 0.3 } = physicsMaterial?.props || {}
|
|
76
|
+
const box = component
|
|
77
|
+
const node = entity.getComponent(NodeComp)
|
|
78
|
+
const { width, height, ...colliderProps } = box.props
|
|
79
|
+
// ett.assign(instantiate(ColliderPhysics, { tag, offset }))
|
|
80
|
+
const { x = 0, y = 0 } = colliderProps.offset || {}
|
|
81
|
+
const zero = new b2Vec2(0, 0);
|
|
82
|
+
const position = new b2Vec2(node.posX, node.posY);
|
|
83
|
+
const offset = new b2Vec2(x, y);
|
|
84
|
+
|
|
85
|
+
const bd = new b2BodyDef();
|
|
86
|
+
bd.set_type(type === 'dynamic' ? b2_dynamicBody : b2_staticBody);
|
|
87
|
+
bd.set_position(zero);
|
|
88
|
+
bd.set_gravityScale(gravityScale)
|
|
89
|
+
const body = this.world.CreateBody(bd)
|
|
90
|
+
rigidBody.body = body
|
|
91
|
+
// console.log('body', type, b2_dynamicBody, b2_staticBody, getPointer(body));
|
|
92
|
+
// body.setMassData({ mass: 1 } as any)
|
|
93
|
+
const physicsNode = new PhysicsSprite(node.instance, body)
|
|
94
|
+
const square = new b2PolygonShape();
|
|
95
|
+
square.SetAsBox(width / 2, height / 2);
|
|
96
|
+
const fixtureDef = new b2FixtureDef();
|
|
97
|
+
fixtureDef.set_shape(square);
|
|
98
|
+
fixtureDef.set_density(density);
|
|
99
|
+
fixtureDef.set_friction(friction);
|
|
100
|
+
fixtureDef.set_restitution(restitution);
|
|
101
|
+
body.CreateFixture(fixtureDef);
|
|
102
|
+
body.SetTransform(position, 0);
|
|
103
|
+
body.SetLinearVelocity(zero);
|
|
104
|
+
body.SetAwake(true);
|
|
105
|
+
body.SetEnabled(true);
|
|
106
|
+
metadata[getPointer(body)] = node
|
|
107
|
+
|
|
108
|
+
const physicsCollide = entity.assign(instantiate(ColliderPhysics, colliderProps))
|
|
109
|
+
physicsCollide.instance = physicsNode
|
|
110
|
+
physicsCollide.node = node
|
|
111
|
+
box.node = node
|
|
112
|
+
})
|
|
113
|
+
event_manager.subscribe(EventTypes.ComponentAdded, (CircleColliderPhysics), () => { })
|
|
114
|
+
event_manager.subscribe(EventTypes.ComponentAdded, (PolygonColliderPhysics), () => { })
|
|
115
|
+
event_manager.subscribe(EventTypes.ComponentRemoved, (NodeComp), () => {
|
|
116
|
+
// log('ComponentRemovedEvent NodeComp', event);
|
|
117
|
+
// const node = event.entity.getComponent(NodeComp)
|
|
118
|
+
// if (node.instance instanceof Sprite) {
|
|
119
|
+
// const body = node.instance.getBody()
|
|
120
|
+
// this.listRemoveShape.push(...body.shapeList)
|
|
121
|
+
// this.listRemoveBody.push(body)
|
|
122
|
+
// }
|
|
123
|
+
})
|
|
124
|
+
const listener = makeContactListener(this.world, metadata, box2D)
|
|
125
|
+
this.world.SetContactListener(listener)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
update(entities: EntityManager, events: EventManager, dt: number) {
|
|
129
|
+
if (this.world) {
|
|
130
|
+
const clampedDelta = Math.min(dt, maxTimeStep);
|
|
131
|
+
this.world.Step(clampedDelta, velocityIterations, positionIterations);
|
|
132
|
+
this.graphics.clear()
|
|
133
|
+
this.world.DebugDraw();
|
|
134
|
+
this.graphics.fill();
|
|
135
|
+
// this.graphics.stroke();
|
|
136
|
+
// console.log('GetBodyCount', this.world.GetBodyCount());
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
set gravity(val: Vec2) {
|
|
141
|
+
this.world.SetGravity(new box2D.b2Vec2(val.x, val.y))
|
|
142
|
+
// this.world.iterations = 60
|
|
143
|
+
// this.world.collisionSlop = 0.5
|
|
144
|
+
}
|
|
145
|
+
}
|