@safe-engine/pixi 8.3.6 → 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.
Files changed (139) hide show
  1. package/.github/workflows/npm-publish.yml +35 -0
  2. package/README.md +70 -5
  3. package/dist/app.d.ts +2 -5
  4. package/dist/app.d.ts.map +1 -1
  5. package/dist/app.js +44 -27
  6. package/dist/base/gworld.d.ts +2 -0
  7. package/dist/base/gworld.d.ts.map +1 -1
  8. package/dist/box2d-wasm/ContactListener.d.ts +12 -0
  9. package/dist/box2d-wasm/ContactListener.d.ts.map +1 -0
  10. package/dist/box2d-wasm/ContactListener.js +64 -0
  11. package/dist/box2d-wasm/PhysicsComponent.d.ts +50 -0
  12. package/dist/box2d-wasm/PhysicsComponent.d.ts.map +1 -0
  13. package/dist/box2d-wasm/PhysicsComponent.js +17 -0
  14. package/dist/box2d-wasm/PhysicsSprite.d.ts +11 -0
  15. package/dist/box2d-wasm/PhysicsSprite.d.ts.map +1 -0
  16. package/dist/box2d-wasm/PhysicsSprite.js +30 -0
  17. package/dist/box2d-wasm/PhysicsSystem.d.ts +17 -0
  18. package/dist/box2d-wasm/PhysicsSystem.d.ts.map +1 -0
  19. package/dist/box2d-wasm/PhysicsSystem.js +145 -0
  20. package/dist/box2d-wasm/debugDraw.d.ts +67 -0
  21. package/dist/box2d-wasm/debugDraw.d.ts.map +1 -0
  22. package/dist/box2d-wasm/debugDraw.js +224 -0
  23. package/dist/box2d-wasm/index.d.ts +6 -0
  24. package/dist/box2d-wasm/index.d.ts.map +1 -0
  25. package/dist/box2d-wasm/index.js +17 -0
  26. package/dist/collider/CollideComponent.d.ts.map +1 -1
  27. package/dist/collider/CollideComponent.js +12 -13
  28. package/dist/collider/CollideSystem.d.ts.map +1 -1
  29. package/dist/collider/CollideSystem.js +1 -2
  30. package/dist/collider/helper/utils.d.ts +2 -0
  31. package/dist/collider/helper/utils.d.ts.map +1 -1
  32. package/dist/collider/helper/utils.js +22 -0
  33. package/dist/collider/index.d.ts +1 -0
  34. package/dist/collider/index.d.ts.map +1 -1
  35. package/dist/collider/index.js +12 -0
  36. package/dist/components/NodeComp.d.ts +6 -4
  37. package/dist/components/NodeComp.d.ts.map +1 -1
  38. package/dist/components/NodeComp.js +17 -17
  39. package/dist/components/Scene.d.ts.map +1 -1
  40. package/dist/components/Scene.js +3 -4
  41. package/dist/core/director.d.ts.map +1 -1
  42. package/dist/core/director.js +4 -3
  43. package/dist/dragonbones/DragonBonesSystem.d.ts +2 -1
  44. package/dist/dragonbones/DragonBonesSystem.d.ts.map +1 -1
  45. package/dist/dragonbones/DragonBonesSystem.js +2 -0
  46. package/dist/dragonbones/index.d.ts +1 -0
  47. package/dist/dragonbones/index.d.ts.map +1 -1
  48. package/dist/dragonbones/index.js +7 -0
  49. package/dist/gui/GUIComponent.d.ts +0 -9
  50. package/dist/gui/GUIComponent.d.ts.map +1 -1
  51. package/dist/gui/GUIComponent.js +0 -37
  52. package/dist/gui/GUISystem.d.ts +1 -0
  53. package/dist/gui/GUISystem.d.ts.map +1 -1
  54. package/dist/gui/GUISystem.js +2 -15
  55. package/dist/index.d.ts +1 -0
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +1 -0
  58. package/dist/planck/PhysicsComponent.d.ts +7 -7
  59. package/dist/planck/PhysicsComponent.js +4 -4
  60. package/dist/planck/PhysicsSystem.js +12 -12
  61. package/dist/richtext/RichTextComp.d.ts +17 -0
  62. package/dist/richtext/RichTextComp.d.ts.map +1 -0
  63. package/dist/richtext/RichTextComp.js +38 -0
  64. package/dist/richtext/RichTextSystem.d.ts +7 -0
  65. package/dist/richtext/RichTextSystem.d.ts.map +1 -0
  66. package/dist/richtext/RichTextSystem.js +25 -0
  67. package/dist/richtext/html-text-parser.d.ts +20 -0
  68. package/dist/richtext/html-text-parser.d.ts.map +1 -0
  69. package/dist/richtext/html-text-parser.js +64 -0
  70. package/dist/richtext/index.d.ts +3 -0
  71. package/dist/richtext/index.d.ts.map +1 -0
  72. package/dist/richtext/index.js +7 -0
  73. package/dist/spine/index.d.ts +1 -0
  74. package/dist/spine/index.d.ts.map +1 -1
  75. package/dist/spine/index.js +7 -0
  76. package/package.json +9 -11
  77. package/src/@types/index.d.ts +2 -0
  78. package/src/@types/safex.d.ts +15 -0
  79. package/src/app.ts +85 -0
  80. package/src/base/EnhancedComponent.ts +37 -0
  81. package/src/base/gworld.ts +19 -0
  82. package/src/base/index.ts +3 -0
  83. package/src/base/utils.ts +23 -0
  84. package/src/box2d-wasm/ContactListener.ts +66 -0
  85. package/src/box2d-wasm/PhysicsComponent.ts +83 -0
  86. package/src/box2d-wasm/PhysicsSprite.ts +42 -0
  87. package/src/box2d-wasm/PhysicsSystem.ts +145 -0
  88. package/src/box2d-wasm/debugDraw.ts +257 -0
  89. package/src/box2d-wasm/index.ts +19 -0
  90. package/src/collider/CollideComponent.ts +257 -0
  91. package/src/collider/CollideSystem.ts +166 -0
  92. package/src/collider/helper/Intersection.ts +139 -0
  93. package/src/collider/helper/utils.ts +37 -0
  94. package/src/collider/index.ts +16 -0
  95. package/src/components/BaseComponent.ts +17 -0
  96. package/src/components/NodeComp.ts +434 -0
  97. package/src/components/Scene.ts +17 -0
  98. package/src/core/Color.ts +7 -0
  99. package/src/core/LoadingBar.ts +63 -0
  100. package/src/core/NodePool.ts +28 -0
  101. package/src/core/Size.ts +21 -0
  102. package/src/core/director.ts +11 -0
  103. package/src/core/math.ts +13 -0
  104. package/src/dragonbones/DragonBonesComponent.ts +32 -0
  105. package/src/dragonbones/DragonBonesSystem.ts +35 -0
  106. package/src/dragonbones/index.ts +11 -0
  107. package/src/gui/GUIComponent.ts +159 -0
  108. package/src/gui/GUISystem.ts +116 -0
  109. package/src/helper/utils.ts +50 -0
  110. package/src/index.ts +23 -0
  111. package/src/norender/NoRenderComponent.ts +60 -0
  112. package/src/norender/NoRenderSystem.ts +66 -0
  113. package/src/planck/PhysicsComponent.ts +83 -0
  114. package/src/planck/PhysicsSprite.ts +43 -0
  115. package/src/planck/PhysicsSystem.ts +201 -0
  116. package/src/planck/index.ts +3 -0
  117. package/src/render/RenderComponent.ts +138 -0
  118. package/src/render/RenderSystem.ts +67 -0
  119. package/src/richtext/RichTextComp.ts +46 -0
  120. package/src/richtext/RichTextSystem.ts +26 -0
  121. package/src/richtext/html-text-parser.ts +87 -0
  122. package/src/richtext/index.ts +8 -0
  123. package/src/spine/SpineComponent.ts +18 -0
  124. package/src/spine/SpineSystem.ts +30 -0
  125. package/src/spine/index.ts +11 -0
  126. package/src/spine/lib/BatchableSpineSlot.ts +138 -0
  127. package/src/spine/lib/Spine.ts +910 -0
  128. package/src/spine/lib/SpineDebugRenderer.ts +615 -0
  129. package/src/spine/lib/SpinePipe.ts +203 -0
  130. package/src/spine/lib/SpineTexture.ts +143 -0
  131. package/src/spine/lib/assets/atlasLoader.ts +158 -0
  132. package/src/spine/lib/assets/skeletonLoader.ts +81 -0
  133. package/src/spine/lib/darktint/DarkTintBatchGeometry.ts +92 -0
  134. package/src/spine/lib/darktint/DarkTintBatcher.ts +186 -0
  135. package/src/spine/lib/darktint/DarkTintShader.ts +74 -0
  136. package/src/spine/lib/darktint/darkTintBit.ts +77 -0
  137. package/src/spine/lib/index.ts +43 -0
  138. package/src/spine/lib/require-shim.ts +43 -0
  139. 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,3 @@
1
+ export * from './EnhancedComponent'
2
+ export * from './gworld'
3
+ export * from './utils'
@@ -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
+ }