pixi-fusion 2.0.0 → 2.0.4
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 +3 -9
- package/dist/src/assets-manager/AssetsManager.js +1 -1
- package/dist/src/camera/Camera.js +8 -8
- package/dist/src/game-context/Game.context.js +12 -12
- package/dist/src/game-objects/usePhysicalObject.js +1 -1
- package/dist/src/game-objects/usePhysicalObjectFromConfig.js +1 -1
- package/dist/src/game-objects/useWalls.js +2 -2
- package/dist/src/hooks/useAnimatedSprite.js +4 -4
- package/dist/src/hooks/useCamera.d.ts +1 -1
- package/dist/src/hooks/useGame.d.ts +1 -1
- package/dist/src/hooks/useObject.js +9 -9
- package/dist/src/hooks/useSprite.js +1 -1
- package/dist/src/hooks/useTexture.js +1 -1
- package/dist/src/hooks/useTickerCallback.js +1 -1
- package/dist/src/hooks/useTilingSprite.js +2 -2
- package/dist/src/hooks/useWorld.d.ts +1 -1
- package/dist/src/layer/Layer.js +4 -4
- package/dist/src/physics/MatterPhysics.context.js +11 -11
- package/dist/src/physics/useCollisionEventHandler.js +1 -1
- package/dist/src/physics/usePhysicsEngineEventHandler.js +1 -1
- package/dist/src/physics/usePhysicsTickerCallback.js +1 -1
- package/dist/src/stage/Stage.js +2 -2
- package/dist/src/world/World.js +7 -6
- package/package.json +15 -4
- package/src/assets-manager/AssetsManager.tsx +13 -16
- package/src/camera/Camera.tsx +16 -28
- package/src/game-context/Game.context.tsx +12 -12
- package/src/game-objects/usePhysicalObject.ts +1 -1
- package/src/game-objects/usePhysicalObjectFromConfig.ts +1 -1
- package/src/game-objects/useWalls.ts +2 -2
- package/src/hooks/useAnimatedSprite.ts +4 -4
- package/src/hooks/useObject.ts +9 -9
- package/src/hooks/useSprite.ts +1 -1
- package/src/hooks/useTexture.ts +1 -1
- package/src/hooks/useTickerCallback.ts +1 -1
- package/src/hooks/useTilingSprite.ts +2 -2
- package/src/layer/Layer.tsx +4 -4
- package/src/physics/MatterPhysics.context.tsx +23 -17
- package/src/physics/useCollisionEventHandler.ts +1 -1
- package/src/physics/usePhysicsEngineEventHandler.ts +1 -1
- package/src/physics/usePhysicsTickerCallback.ts +1 -1
- package/src/stage/Stage.tsx +6 -12
- package/src/world/World.tsx +7 -6
package/README.md
CHANGED
|
@@ -14,14 +14,14 @@ npm i --save pixi-fusion
|
|
|
14
14
|
|
|
15
15
|
# Basic Usage Example
|
|
16
16
|
|
|
17
|
-
1. Create a component with `GameContextProvider` and `
|
|
17
|
+
1. Create a component with `GameContextProvider` and `Stage`.
|
|
18
18
|
|
|
19
19
|
```
|
|
20
20
|
<GameContextProvider timeout={10}>
|
|
21
21
|
<World size={{width: 300, height: 300}} eventMode="dynamic">
|
|
22
|
-
<
|
|
22
|
+
<Layer>
|
|
23
23
|
<MyAwesomeStage />
|
|
24
|
-
</
|
|
24
|
+
</layer>
|
|
25
25
|
</World>
|
|
26
26
|
</GameContextProvider>
|
|
27
27
|
```
|
|
@@ -76,12 +76,6 @@ export const MyAwesomeStage: React.FC<MazeHeroProps> = () => {
|
|
|
76
76
|
};
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
# Demos
|
|
80
|
-
|
|
81
|
-
- [Maze](https://laverve.github.io/fusion/?path=/story/games-maze-gameplay--maze-story)
|
|
82
|
-
- [WordSearch](https://laverve.github.io/fusion/?path=/story/games-wordsearch-gameplay--word-search-story)
|
|
83
|
-
- [Spelling spree](https://laverve.github.io/fusion/?path=/story/games-spelling-spree-gameplay--spelling-spree)
|
|
84
|
-
|
|
85
79
|
# Contribution guidelines
|
|
86
80
|
|
|
87
81
|
You are encouraged to contribute to this project as soon as you see any defects or issues.
|
|
@@ -22,10 +22,10 @@ export const Camera = ({ children, clampZoom }) => {
|
|
|
22
22
|
: null, [size, application]);
|
|
23
23
|
const addObject = useCallback((thing) => {
|
|
24
24
|
setThings((oldThings) => [...oldThings, thing]);
|
|
25
|
-
}, [
|
|
25
|
+
}, []);
|
|
26
26
|
const removeObject = useCallback((thing) => {
|
|
27
27
|
setThings((oldThings) => oldThings.filter(({ uid }) => uid === thing.uid));
|
|
28
|
-
}, [
|
|
28
|
+
}, []);
|
|
29
29
|
const conextValue = useMemo(() => ({
|
|
30
30
|
addObject,
|
|
31
31
|
removeObject
|
|
@@ -34,7 +34,7 @@ export const Camera = ({ children, clampZoom }) => {
|
|
|
34
34
|
if (viewport && clampZoom && application) {
|
|
35
35
|
viewport.clampZoom(clampZoom);
|
|
36
36
|
}
|
|
37
|
-
}, [clampZoom]);
|
|
37
|
+
}, [clampZoom, application, viewport]);
|
|
38
38
|
useEffect(() => {
|
|
39
39
|
if (viewport) {
|
|
40
40
|
if (size.width) {
|
|
@@ -44,7 +44,7 @@ export const Camera = ({ children, clampZoom }) => {
|
|
|
44
44
|
viewport.height = size.height;
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
-
}, [size, viewport
|
|
47
|
+
}, [size, viewport, application]);
|
|
48
48
|
useEffect(() => {
|
|
49
49
|
if (!application || !viewport) {
|
|
50
50
|
return;
|
|
@@ -61,7 +61,7 @@ export const Camera = ({ children, clampZoom }) => {
|
|
|
61
61
|
removeObjectFromStage(viewport);
|
|
62
62
|
setIsReady(false);
|
|
63
63
|
};
|
|
64
|
-
}, [viewport
|
|
64
|
+
}, [viewport, addObjectToStage, removeObjectFromStage]);
|
|
65
65
|
useEffect(() => {
|
|
66
66
|
if (!viewport || !isReady) {
|
|
67
67
|
return;
|
|
@@ -83,16 +83,16 @@ export const Camera = ({ children, clampZoom }) => {
|
|
|
83
83
|
}, [isReady, viewport, ensureVisibleOptions]);
|
|
84
84
|
const followCallback = useCallback((container) => {
|
|
85
85
|
setFollowContainer(container);
|
|
86
|
-
}, [
|
|
86
|
+
}, []);
|
|
87
87
|
const ensureVisibleCallback = useCallback((options) => {
|
|
88
88
|
setEnsureVisibleOptions(options);
|
|
89
|
-
}, [
|
|
89
|
+
}, []);
|
|
90
90
|
const value = useMemo(() => {
|
|
91
91
|
return {
|
|
92
92
|
follow: followCallback,
|
|
93
93
|
ensureVisible: ensureVisibleCallback
|
|
94
94
|
};
|
|
95
|
-
}, [followCallback]);
|
|
95
|
+
}, [followCallback, ensureVisibleCallback]);
|
|
96
96
|
return (React.createElement(CameraContext.Provider, { value: value },
|
|
97
97
|
React.createElement(LayerContext.Provider, { value: conextValue },
|
|
98
98
|
React.createElement(Layer, null, children))));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { createContext, useMemo, useRef, useState } from "react";
|
|
1
|
+
import React, { createContext, useCallback, useMemo, useRef, useState } from "react";
|
|
2
2
|
import { GameStatus } from "../types";
|
|
3
3
|
export const GameContext = createContext({
|
|
4
4
|
reset: () => { },
|
|
@@ -19,7 +19,7 @@ export const GameContextProvider = ({ children, timeout: inputTimeout = 0, event
|
|
|
19
19
|
const [endTime, setEndTime] = useState(null);
|
|
20
20
|
const [pauseTime, setPauseTime] = useState(0);
|
|
21
21
|
const [pausedAtTime, setPausedAtTime] = useState(null);
|
|
22
|
-
const onTimedOut = () => {
|
|
22
|
+
const onTimedOut = useCallback(() => {
|
|
23
23
|
const newEndTime = +new Date();
|
|
24
24
|
const newStatus = GameStatus.TIMEDOUT;
|
|
25
25
|
setEndTime(newEndTime);
|
|
@@ -31,8 +31,8 @@ export const GameContextProvider = ({ children, timeout: inputTimeout = 0, event
|
|
|
31
31
|
pausedAtTime: null,
|
|
32
32
|
pauseTime
|
|
33
33
|
});
|
|
34
|
-
};
|
|
35
|
-
const start = () => {
|
|
34
|
+
}, [events, pauseTime, startTime]);
|
|
35
|
+
const start = useCallback(() => {
|
|
36
36
|
const newStartTime = startTime || +new Date();
|
|
37
37
|
const newStatus = GameStatus.IN_PROGRESS;
|
|
38
38
|
const newEndTime = null;
|
|
@@ -54,8 +54,8 @@ export const GameContextProvider = ({ children, timeout: inputTimeout = 0, event
|
|
|
54
54
|
pausedAtTime: null,
|
|
55
55
|
pauseTime: newPauseTime
|
|
56
56
|
});
|
|
57
|
-
};
|
|
58
|
-
const reset = () => {
|
|
57
|
+
}, [events, onTimedOut, pauseTime, pausedAtTime, startTime, timeout]);
|
|
58
|
+
const reset = useCallback(() => {
|
|
59
59
|
const newStartTime = null;
|
|
60
60
|
const newStatus = GameStatus.READY;
|
|
61
61
|
const newEndTime = null;
|
|
@@ -76,8 +76,8 @@ export const GameContextProvider = ({ children, timeout: inputTimeout = 0, event
|
|
|
76
76
|
pausedAtTime: newPausedAtTime,
|
|
77
77
|
pauseTime: newPauseTime
|
|
78
78
|
});
|
|
79
|
-
};
|
|
80
|
-
const stop = () => {
|
|
79
|
+
}, [events]);
|
|
80
|
+
const stop = useCallback(() => {
|
|
81
81
|
const newStatus = GameStatus.COMPLETED;
|
|
82
82
|
const newEndTime = +new Date();
|
|
83
83
|
if (timerRef.current) {
|
|
@@ -92,8 +92,8 @@ export const GameContextProvider = ({ children, timeout: inputTimeout = 0, event
|
|
|
92
92
|
pausedAtTime,
|
|
93
93
|
pauseTime
|
|
94
94
|
});
|
|
95
|
-
};
|
|
96
|
-
const pause = () => {
|
|
95
|
+
}, [events, pauseTime, pausedAtTime, startTime]);
|
|
96
|
+
const pause = useCallback(() => {
|
|
97
97
|
const newStatus = GameStatus.PAUSED;
|
|
98
98
|
const newPausedAtTime = +new Date();
|
|
99
99
|
if (timerRef.current) {
|
|
@@ -108,7 +108,7 @@ export const GameContextProvider = ({ children, timeout: inputTimeout = 0, event
|
|
|
108
108
|
status: newStatus,
|
|
109
109
|
pauseTime
|
|
110
110
|
});
|
|
111
|
-
};
|
|
111
|
+
}, [events, pauseTime, startTime]);
|
|
112
112
|
const contextValue = useMemo(() => ({
|
|
113
113
|
status,
|
|
114
114
|
startTime,
|
|
@@ -119,6 +119,6 @@ export const GameContextProvider = ({ children, timeout: inputTimeout = 0, event
|
|
|
119
119
|
start,
|
|
120
120
|
reset,
|
|
121
121
|
pause
|
|
122
|
-
}), [timeout, status, startTime, endTime, pauseTime,
|
|
122
|
+
}), [timeout, status, startTime, endTime, pauseTime, pause, reset, start, stop]);
|
|
123
123
|
return React.createElement(GameContext.Provider, { value: contextValue }, children);
|
|
124
124
|
};
|
|
@@ -7,7 +7,7 @@ export const usePhysicalObjectFromConfig = ({ position = { x: 0, y: 0 }, ...phys
|
|
|
7
7
|
return Body.create({ position, ...physicalObjectConfig });
|
|
8
8
|
}
|
|
9
9
|
return null;
|
|
10
|
-
}, []);
|
|
10
|
+
}, [physicalObjectConfig, position]);
|
|
11
11
|
usePhysicalObject({ physicalObject });
|
|
12
12
|
return { physicalObject };
|
|
13
13
|
};
|
|
@@ -49,11 +49,11 @@ export const useWalls = ({ left = true, right = true, top = true, bottom = true
|
|
|
49
49
|
}
|
|
50
50
|
Composite.add(walls, parts);
|
|
51
51
|
return walls;
|
|
52
|
-
}, [width, height]);
|
|
52
|
+
}, [width, height, bottom, center.x, center.y, left, right, top]);
|
|
53
53
|
useEffect(() => {
|
|
54
54
|
addBody(body);
|
|
55
55
|
return () => {
|
|
56
56
|
removeBody(body);
|
|
57
57
|
};
|
|
58
|
-
}, [body
|
|
58
|
+
}, [body, addBody, removeBody]);
|
|
59
59
|
};
|
|
@@ -14,19 +14,19 @@ export const useAnimatedSprite = ({ texture, spritesheet: spritesheetJSON, anima
|
|
|
14
14
|
return sheet;
|
|
15
15
|
}
|
|
16
16
|
return null;
|
|
17
|
-
}, [spritesheetJSON]);
|
|
17
|
+
}, [spritesheetJSON, isFetched, textures]);
|
|
18
18
|
const sprite = useMemo(() => {
|
|
19
19
|
if (spritesheet?.animations?.[animation]) {
|
|
20
20
|
return new AnimatedSprite({ textures: spritesheet?.animations?.[animation] });
|
|
21
21
|
}
|
|
22
22
|
return null;
|
|
23
|
-
}, [
|
|
23
|
+
}, [animation, spritesheet?.animations]);
|
|
24
24
|
useObject({ object: sprite, ...options });
|
|
25
25
|
useEffect(() => {
|
|
26
26
|
if (sprite) {
|
|
27
27
|
sprite.animationSpeed = animationSpeed;
|
|
28
28
|
}
|
|
29
|
-
}, [animationSpeed, sprite
|
|
29
|
+
}, [animationSpeed, sprite]);
|
|
30
30
|
useEffect(() => {
|
|
31
31
|
if (sprite) {
|
|
32
32
|
if (isPlaying) {
|
|
@@ -36,6 +36,6 @@ export const useAnimatedSprite = ({ texture, spritesheet: spritesheetJSON, anima
|
|
|
36
36
|
sprite.stop();
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
}, [isPlaying, sprite
|
|
39
|
+
}, [isPlaying, sprite]);
|
|
40
40
|
return sprite;
|
|
41
41
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const useCamera: () => import("
|
|
1
|
+
export declare const useCamera: () => import("..").CameraContextValue;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const useGame: () => import("
|
|
1
|
+
export declare const useGame: () => import("..").GameContextValue;
|
|
@@ -10,45 +10,45 @@ export const useObject = ({ object, anchor, position, skew, scale, width, angle,
|
|
|
10
10
|
return () => {
|
|
11
11
|
removeObject(object);
|
|
12
12
|
};
|
|
13
|
-
}, [object
|
|
13
|
+
}, [object, addObject, removeObject]);
|
|
14
14
|
useEffect(() => {
|
|
15
15
|
if (anchor !== undefined && object) {
|
|
16
16
|
object.anchor = anchor;
|
|
17
17
|
}
|
|
18
|
-
}, [anchor, object
|
|
18
|
+
}, [anchor, object]);
|
|
19
19
|
useEffect(() => {
|
|
20
20
|
if (angle !== undefined && object) {
|
|
21
21
|
object.angle = angle;
|
|
22
22
|
}
|
|
23
|
-
}, [angle, object
|
|
23
|
+
}, [angle, object]);
|
|
24
24
|
useEffect(() => {
|
|
25
25
|
if (object && position !== undefined) {
|
|
26
26
|
object.position = position;
|
|
27
27
|
}
|
|
28
|
-
}, [position, object
|
|
28
|
+
}, [position, object]);
|
|
29
29
|
useEffect(() => {
|
|
30
30
|
if (object && skew !== undefined) {
|
|
31
31
|
object.skew = skew;
|
|
32
32
|
}
|
|
33
|
-
}, [skew, object
|
|
33
|
+
}, [skew, object]);
|
|
34
34
|
useEffect(() => {
|
|
35
35
|
if (object && alpha !== undefined) {
|
|
36
36
|
object.alpha = alpha;
|
|
37
37
|
}
|
|
38
|
-
}, [alpha, object
|
|
38
|
+
}, [alpha, object]);
|
|
39
39
|
useEffect(() => {
|
|
40
40
|
if (object && scale !== undefined) {
|
|
41
41
|
object.scale = scale;
|
|
42
42
|
}
|
|
43
|
-
}, [scale, object
|
|
43
|
+
}, [scale, object]);
|
|
44
44
|
useEffect(() => {
|
|
45
45
|
if (object) {
|
|
46
46
|
object.visible = visible;
|
|
47
47
|
}
|
|
48
|
-
}, [visible, object
|
|
48
|
+
}, [visible, object]);
|
|
49
49
|
useEffect(() => {
|
|
50
50
|
if (object && width !== undefined) {
|
|
51
51
|
object.width = width;
|
|
52
52
|
}
|
|
53
|
-
}, [width, object
|
|
53
|
+
}, [width, object]);
|
|
54
54
|
};
|
|
@@ -4,7 +4,7 @@ export const useTextures = ({ keys = [] }) => {
|
|
|
4
4
|
const { getAsset, isFetched, isFetching, isError } = useAssetManager();
|
|
5
5
|
const textures = useMemo(() => {
|
|
6
6
|
return isFetched ? keys.map((key) => getAsset(key)) : [];
|
|
7
|
-
}, [keys, isFetched,
|
|
7
|
+
}, [keys, isFetched, getAsset]);
|
|
8
8
|
return useMemo(() => ({
|
|
9
9
|
textures: textures,
|
|
10
10
|
isFetched,
|
|
@@ -15,12 +15,12 @@ export const useTilingSprite = ({ texture = "", tilePosition, ...options }) => {
|
|
|
15
15
|
return TilingSprite.from(texture);
|
|
16
16
|
}
|
|
17
17
|
return new TilingSprite({});
|
|
18
|
-
}, [texture,
|
|
18
|
+
}, [texture, isFetched]);
|
|
19
19
|
useObject({ object: sprite, ...options });
|
|
20
20
|
useEffect(() => {
|
|
21
21
|
if (tilePosition && sprite) {
|
|
22
22
|
sprite.tilePosition = tilePosition;
|
|
23
23
|
}
|
|
24
|
-
}, [tilePosition, sprite
|
|
24
|
+
}, [tilePosition, sprite]);
|
|
25
25
|
return sprite;
|
|
26
26
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const useWorld: () => import("
|
|
1
|
+
export declare const useWorld: () => import("..").WorldContextValue;
|
package/dist/src/layer/Layer.js
CHANGED
|
@@ -19,16 +19,16 @@ export const Layer = ({ options, children }) => {
|
|
|
19
19
|
return () => {
|
|
20
20
|
removeObjectFromStaeg(container);
|
|
21
21
|
};
|
|
22
|
-
}, [container
|
|
22
|
+
}, [container, addObjectIntoParent, addObjectIntoStage, removeObjectFromParent, removeObjectFromStaeg]);
|
|
23
23
|
const addObject = useCallback((thing) => {
|
|
24
24
|
container.addChild(thing);
|
|
25
|
-
}, [container
|
|
25
|
+
}, [container]);
|
|
26
26
|
const removeObject = useCallback((thing) => {
|
|
27
27
|
container.removeChild(thing);
|
|
28
|
-
}, [container
|
|
28
|
+
}, [container]);
|
|
29
29
|
const conextValue = useMemo(() => ({
|
|
30
30
|
addObject,
|
|
31
31
|
removeObject
|
|
32
|
-
}), [
|
|
32
|
+
}), [addObject, removeObject]);
|
|
33
33
|
return React.createElement(LayerContext.Provider, { value: conextValue }, children);
|
|
34
34
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { createContext, useEffect, useMemo, useRef, useState } from "react";
|
|
1
|
+
import React, { createContext, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
2
|
import { Engine, Runner, World } from "matter-js";
|
|
3
3
|
export const MatterPhysicsContext = createContext({
|
|
4
4
|
config: {
|
|
@@ -31,28 +31,28 @@ export const MatterPhysicsContextProvider = ({ isRunning = false, children, conf
|
|
|
31
31
|
});
|
|
32
32
|
}, [world]);
|
|
33
33
|
const runner = useMemo(() => Runner.create(), []);
|
|
34
|
-
const addBody = (body) => {
|
|
34
|
+
const addBody = useCallback((body) => {
|
|
35
35
|
if (engine?.world) {
|
|
36
36
|
World.add(engine?.world, body);
|
|
37
37
|
}
|
|
38
|
-
};
|
|
39
|
-
const removeBody = (body) => {
|
|
38
|
+
}, [engine]);
|
|
39
|
+
const removeBody = useCallback((body) => {
|
|
40
40
|
if (engine?.world) {
|
|
41
41
|
World.remove(engine?.world, body);
|
|
42
42
|
}
|
|
43
|
-
};
|
|
44
|
-
const run = () => {
|
|
43
|
+
}, [engine]);
|
|
44
|
+
const run = useCallback(() => {
|
|
45
45
|
if (!isRunningRef.current) {
|
|
46
46
|
Runner.run(runner, engine);
|
|
47
47
|
isRunningRef.current = true;
|
|
48
48
|
}
|
|
49
|
-
};
|
|
50
|
-
const stop = () => {
|
|
49
|
+
}, [runner, engine]);
|
|
50
|
+
const stop = useCallback(() => {
|
|
51
51
|
if (isRunningRef.current) {
|
|
52
52
|
Runner.stop(runner);
|
|
53
53
|
isRunningRef.current = false;
|
|
54
54
|
}
|
|
55
|
-
};
|
|
55
|
+
}, [runner]);
|
|
56
56
|
const conextValue = useMemo(() => ({
|
|
57
57
|
config: localConfig,
|
|
58
58
|
runner,
|
|
@@ -61,7 +61,7 @@ export const MatterPhysicsContextProvider = ({ isRunning = false, children, conf
|
|
|
61
61
|
stop,
|
|
62
62
|
addBody,
|
|
63
63
|
removeBody
|
|
64
|
-
}), [runner, engine, localConfig]);
|
|
64
|
+
}), [runner, engine, localConfig, addBody, removeBody, run, stop]);
|
|
65
65
|
useEffect(() => {
|
|
66
66
|
if (isRunning) {
|
|
67
67
|
run();
|
|
@@ -69,6 +69,6 @@ export const MatterPhysicsContextProvider = ({ isRunning = false, children, conf
|
|
|
69
69
|
return () => {
|
|
70
70
|
stop();
|
|
71
71
|
};
|
|
72
|
-
}, [isRunning]);
|
|
72
|
+
}, [isRunning, run, stop]);
|
|
73
73
|
return React.createElement(MatterPhysicsContext.Provider, { value: conextValue }, children);
|
|
74
74
|
};
|
package/dist/src/stage/Stage.js
CHANGED
|
@@ -7,10 +7,10 @@ export const Stage = ({ children }) => {
|
|
|
7
7
|
const [things, setThings] = useState([]);
|
|
8
8
|
const addObject = useCallback((thing) => {
|
|
9
9
|
setThings((oldThings) => [...oldThings, thing]);
|
|
10
|
-
}, [
|
|
10
|
+
}, []);
|
|
11
11
|
const removeObject = useCallback((thing) => {
|
|
12
12
|
setThings((oldThings) => oldThings.filter(({ uid }) => uid === thing.uid));
|
|
13
|
-
}, [
|
|
13
|
+
}, []);
|
|
14
14
|
const conextValue = useMemo(() => ({
|
|
15
15
|
addObject,
|
|
16
16
|
removeObject
|
package/dist/src/world/World.js
CHANGED
|
@@ -27,7 +27,7 @@ export const World = ({ children, eventMode, size }) => {
|
|
|
27
27
|
width: applicationRef.screen.width,
|
|
28
28
|
height: applicationRef.screen.height
|
|
29
29
|
};
|
|
30
|
-
}, [size, canvasRef
|
|
30
|
+
}, [size, canvasRef, applicationRef]);
|
|
31
31
|
useEffect(() => {
|
|
32
32
|
if (!applicationRef) {
|
|
33
33
|
const application = new Application();
|
|
@@ -35,13 +35,13 @@ export const World = ({ children, eventMode, size }) => {
|
|
|
35
35
|
setApplicationRef(application);
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
|
-
}, []);
|
|
38
|
+
}, [applicationRef]);
|
|
39
39
|
useEffect(() => {
|
|
40
40
|
if (applicationRef && canvasRef.current) {
|
|
41
41
|
applicationRef.resizeTo = canvasRef.current;
|
|
42
42
|
applicationRef.resize();
|
|
43
43
|
}
|
|
44
|
-
}, [canvasRef
|
|
44
|
+
}, [canvasRef, applicationRef]);
|
|
45
45
|
const conextValue = useMemo(() => ({
|
|
46
46
|
application: applicationRef,
|
|
47
47
|
size: worldSize
|
|
@@ -50,13 +50,14 @@ export const World = ({ children, eventMode, size }) => {
|
|
|
50
50
|
if (!applicationRef) {
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
|
-
canvasRef.current
|
|
53
|
+
const canvas = canvasRef.current;
|
|
54
|
+
canvas?.appendChild(applicationRef.canvas);
|
|
54
55
|
return () => {
|
|
55
56
|
if (applicationRef) {
|
|
56
|
-
|
|
57
|
+
canvas?.removeChild(applicationRef.canvas);
|
|
57
58
|
}
|
|
58
59
|
};
|
|
59
|
-
}, [canvasRef
|
|
60
|
+
}, [canvasRef, applicationRef]);
|
|
60
61
|
useEffect(() => {
|
|
61
62
|
if (applicationRef) {
|
|
62
63
|
applicationRef.stage.eventMode = eventMode;
|
package/package.json
CHANGED
|
@@ -5,14 +5,23 @@
|
|
|
5
5
|
"url": "https://github.com/laverve/fusion/issues"
|
|
6
6
|
},
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@types/matter-js": "^0.
|
|
8
|
+
"@types/matter-js": "^0.20.0",
|
|
9
9
|
"matter-js": "^0.20.0",
|
|
10
|
-
"pixi.js": "^8.
|
|
10
|
+
"pixi.js": "^8.8.0",
|
|
11
11
|
"pixi-viewport": "^6.0.3"
|
|
12
12
|
},
|
|
13
13
|
"peerDependencies": {
|
|
14
14
|
"react": "^19.0.0"
|
|
15
15
|
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@laverve/eslint-utils": "^5.1.11",
|
|
18
|
+
"@laverve/test-utils": "^5.1.11",
|
|
19
|
+
"@types/react": "^19.0.10",
|
|
20
|
+
"husky": "9.1.7",
|
|
21
|
+
"lint-staged": "^16.0.0",
|
|
22
|
+
"ts-node": "^10.9.1",
|
|
23
|
+
"typescript": "^5.7.3"
|
|
24
|
+
},
|
|
16
25
|
"description": "This module offers a set of common components needed for playing games.",
|
|
17
26
|
"keywords": [
|
|
18
27
|
"game",
|
|
@@ -41,12 +50,14 @@
|
|
|
41
50
|
"url": "https://github.com/laverve/fusion.git"
|
|
42
51
|
},
|
|
43
52
|
"scripts": {
|
|
44
|
-
"lint": "eslint
|
|
53
|
+
"lint": "eslint ./src/",
|
|
54
|
+
"lint:fix": "eslint ./src/ --fix",
|
|
45
55
|
"lint:staged": "lint-staged",
|
|
56
|
+
"prepare": "husky",
|
|
46
57
|
"test": "jest --passWithNoTests",
|
|
47
58
|
"build": "tsc",
|
|
48
59
|
"build:dev": "tsc -w"
|
|
49
60
|
},
|
|
50
|
-
"version": "2.0.
|
|
61
|
+
"version": "2.0.4",
|
|
51
62
|
"webpack": "./src/index.ts"
|
|
52
63
|
}
|
|
@@ -12,22 +12,19 @@ export const AssetsManager: React.FC<PropsWithChildren> = ({ children }) => {
|
|
|
12
12
|
Assets.cache.reset();
|
|
13
13
|
}, []);
|
|
14
14
|
|
|
15
|
-
const load = useCallback(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
},
|
|
29
|
-
[isFetching, isError, isFetched, error]
|
|
30
|
-
);
|
|
15
|
+
const load = useCallback(async (groupId: string, localAsset: Asset[]) => {
|
|
16
|
+
try {
|
|
17
|
+
Assets.addBundle(groupId, localAsset);
|
|
18
|
+
await Assets.loadBundle(groupId);
|
|
19
|
+
setIsFetched(true);
|
|
20
|
+
} catch (e) {
|
|
21
|
+
setIsError(true);
|
|
22
|
+
setIsFetched(false);
|
|
23
|
+
setError(e);
|
|
24
|
+
} finally {
|
|
25
|
+
setIsFetching(false);
|
|
26
|
+
}
|
|
27
|
+
}, []);
|
|
31
28
|
|
|
32
29
|
const unload = useCallback((groupId: string) => {
|
|
33
30
|
Assets.unloadBundle(groupId);
|
package/src/camera/Camera.tsx
CHANGED
|
@@ -32,19 +32,13 @@ export const Camera: React.FC<CameraProps & PropsWithChildren> = ({ children, cl
|
|
|
32
32
|
[size, application]
|
|
33
33
|
);
|
|
34
34
|
|
|
35
|
-
const addObject = useCallback(
|
|
36
|
-
(
|
|
37
|
-
|
|
38
|
-
},
|
|
39
|
-
[things]
|
|
40
|
-
);
|
|
35
|
+
const addObject = useCallback((thing: Container) => {
|
|
36
|
+
setThings((oldThings) => [...oldThings, thing]);
|
|
37
|
+
}, []);
|
|
41
38
|
|
|
42
|
-
const removeObject = useCallback(
|
|
43
|
-
(
|
|
44
|
-
|
|
45
|
-
},
|
|
46
|
-
[application]
|
|
47
|
-
);
|
|
39
|
+
const removeObject = useCallback((thing: Container) => {
|
|
40
|
+
setThings((oldThings) => oldThings.filter(({ uid }) => uid === thing.uid));
|
|
41
|
+
}, []);
|
|
48
42
|
|
|
49
43
|
const conextValue = useMemo<StageContextValue>(
|
|
50
44
|
() => ({
|
|
@@ -58,7 +52,7 @@ export const Camera: React.FC<CameraProps & PropsWithChildren> = ({ children, cl
|
|
|
58
52
|
if (viewport && clampZoom && application) {
|
|
59
53
|
viewport.clampZoom(clampZoom);
|
|
60
54
|
}
|
|
61
|
-
}, [clampZoom]);
|
|
55
|
+
}, [clampZoom, application, viewport]);
|
|
62
56
|
|
|
63
57
|
useEffect(() => {
|
|
64
58
|
if (viewport) {
|
|
@@ -69,7 +63,7 @@ export const Camera: React.FC<CameraProps & PropsWithChildren> = ({ children, cl
|
|
|
69
63
|
viewport.height = size.height;
|
|
70
64
|
}
|
|
71
65
|
}
|
|
72
|
-
}, [size, viewport
|
|
66
|
+
}, [size, viewport, application]);
|
|
73
67
|
|
|
74
68
|
useEffect(() => {
|
|
75
69
|
if (!application || !viewport) {
|
|
@@ -90,7 +84,7 @@ export const Camera: React.FC<CameraProps & PropsWithChildren> = ({ children, cl
|
|
|
90
84
|
removeObjectFromStage(viewport);
|
|
91
85
|
setIsReady(false);
|
|
92
86
|
};
|
|
93
|
-
}, [viewport
|
|
87
|
+
}, [viewport, addObjectToStage, removeObjectFromStage]);
|
|
94
88
|
|
|
95
89
|
useEffect(() => {
|
|
96
90
|
if (!viewport || !isReady) {
|
|
@@ -122,26 +116,20 @@ export const Camera: React.FC<CameraProps & PropsWithChildren> = ({ children, cl
|
|
|
122
116
|
}
|
|
123
117
|
}, [isReady, viewport, ensureVisibleOptions]);
|
|
124
118
|
|
|
125
|
-
const followCallback = useCallback(
|
|
126
|
-
(container
|
|
127
|
-
|
|
128
|
-
},
|
|
129
|
-
[followContainer]
|
|
130
|
-
);
|
|
119
|
+
const followCallback = useCallback((container: Container) => {
|
|
120
|
+
setFollowContainer(container);
|
|
121
|
+
}, []);
|
|
131
122
|
|
|
132
|
-
const ensureVisibleCallback = useCallback(
|
|
133
|
-
(options
|
|
134
|
-
|
|
135
|
-
},
|
|
136
|
-
[followContainer]
|
|
137
|
-
);
|
|
123
|
+
const ensureVisibleCallback = useCallback((options: EnsureVisibleOptions) => {
|
|
124
|
+
setEnsureVisibleOptions(options);
|
|
125
|
+
}, []);
|
|
138
126
|
|
|
139
127
|
const value = useMemo(() => {
|
|
140
128
|
return {
|
|
141
129
|
follow: followCallback,
|
|
142
130
|
ensureVisible: ensureVisibleCallback
|
|
143
131
|
};
|
|
144
|
-
}, [followCallback]);
|
|
132
|
+
}, [followCallback, ensureVisibleCallback]);
|
|
145
133
|
|
|
146
134
|
return (
|
|
147
135
|
<CameraContext.Provider value={value}>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { PropsWithChildren, createContext, useMemo, useRef, useState } from "react";
|
|
1
|
+
import React, { PropsWithChildren, createContext, useCallback, useMemo, useRef, useState } from "react";
|
|
2
2
|
import { GameStatus, GameStatusChangeEvent } from "../types";
|
|
3
3
|
|
|
4
4
|
export type GameContextValue = {
|
|
@@ -52,7 +52,7 @@ export const GameContextProvider: React.FC<GameContextProviderProps> = ({
|
|
|
52
52
|
const [pauseTime, setPauseTime] = useState<number>(0);
|
|
53
53
|
const [pausedAtTime, setPausedAtTime] = useState<number | null>(null);
|
|
54
54
|
|
|
55
|
-
const onTimedOut = () => {
|
|
55
|
+
const onTimedOut = useCallback(() => {
|
|
56
56
|
const newEndTime = +new Date();
|
|
57
57
|
const newStatus = GameStatus.TIMEDOUT;
|
|
58
58
|
|
|
@@ -66,9 +66,9 @@ export const GameContextProvider: React.FC<GameContextProviderProps> = ({
|
|
|
66
66
|
pausedAtTime: null,
|
|
67
67
|
pauseTime
|
|
68
68
|
});
|
|
69
|
-
};
|
|
69
|
+
}, [events, pauseTime, startTime]);
|
|
70
70
|
|
|
71
|
-
const start = () => {
|
|
71
|
+
const start = useCallback(() => {
|
|
72
72
|
const newStartTime = startTime || +new Date();
|
|
73
73
|
const newStatus = GameStatus.IN_PROGRESS;
|
|
74
74
|
const newEndTime = null;
|
|
@@ -93,9 +93,9 @@ export const GameContextProvider: React.FC<GameContextProviderProps> = ({
|
|
|
93
93
|
pausedAtTime: null,
|
|
94
94
|
pauseTime: newPauseTime
|
|
95
95
|
});
|
|
96
|
-
};
|
|
96
|
+
}, [events, onTimedOut, pauseTime, pausedAtTime, startTime, timeout]);
|
|
97
97
|
|
|
98
|
-
const reset = () => {
|
|
98
|
+
const reset = useCallback(() => {
|
|
99
99
|
const newStartTime = null;
|
|
100
100
|
const newStatus = GameStatus.READY;
|
|
101
101
|
const newEndTime = null;
|
|
@@ -119,9 +119,9 @@ export const GameContextProvider: React.FC<GameContextProviderProps> = ({
|
|
|
119
119
|
pausedAtTime: newPausedAtTime,
|
|
120
120
|
pauseTime: newPauseTime
|
|
121
121
|
});
|
|
122
|
-
};
|
|
122
|
+
}, [events]);
|
|
123
123
|
|
|
124
|
-
const stop = () => {
|
|
124
|
+
const stop = useCallback(() => {
|
|
125
125
|
const newStatus = GameStatus.COMPLETED;
|
|
126
126
|
const newEndTime = +new Date();
|
|
127
127
|
|
|
@@ -138,9 +138,9 @@ export const GameContextProvider: React.FC<GameContextProviderProps> = ({
|
|
|
138
138
|
pausedAtTime,
|
|
139
139
|
pauseTime
|
|
140
140
|
});
|
|
141
|
-
};
|
|
141
|
+
}, [events, pauseTime, pausedAtTime, startTime]);
|
|
142
142
|
|
|
143
|
-
const pause = () => {
|
|
143
|
+
const pause = useCallback(() => {
|
|
144
144
|
const newStatus = GameStatus.PAUSED;
|
|
145
145
|
const newPausedAtTime = +new Date();
|
|
146
146
|
|
|
@@ -157,7 +157,7 @@ export const GameContextProvider: React.FC<GameContextProviderProps> = ({
|
|
|
157
157
|
status: newStatus,
|
|
158
158
|
pauseTime
|
|
159
159
|
});
|
|
160
|
-
};
|
|
160
|
+
}, [events, pauseTime, startTime]);
|
|
161
161
|
|
|
162
162
|
const contextValue = useMemo(
|
|
163
163
|
() => ({
|
|
@@ -171,7 +171,7 @@ export const GameContextProvider: React.FC<GameContextProviderProps> = ({
|
|
|
171
171
|
reset,
|
|
172
172
|
pause
|
|
173
173
|
}),
|
|
174
|
-
[timeout, status, startTime, endTime, pauseTime,
|
|
174
|
+
[timeout, status, startTime, endTime, pauseTime, pause, reset, start, stop]
|
|
175
175
|
);
|
|
176
176
|
|
|
177
177
|
return <GameContext.Provider value={contextValue}>{children}</GameContext.Provider>;
|
|
@@ -81,7 +81,7 @@ export const useWalls = ({ left = true, right = true, top = true, bottom = true
|
|
|
81
81
|
Composite.add(walls, parts);
|
|
82
82
|
|
|
83
83
|
return walls;
|
|
84
|
-
}, [width, height]);
|
|
84
|
+
}, [width, height, bottom, center.x, center.y, left, right, top]);
|
|
85
85
|
|
|
86
86
|
useEffect(() => {
|
|
87
87
|
addBody(body);
|
|
@@ -89,5 +89,5 @@ export const useWalls = ({ left = true, right = true, top = true, bottom = true
|
|
|
89
89
|
return () => {
|
|
90
90
|
removeBody(body);
|
|
91
91
|
};
|
|
92
|
-
}, [body
|
|
92
|
+
}, [body, addBody, removeBody]);
|
|
93
93
|
};
|
|
@@ -33,7 +33,7 @@ export const useAnimatedSprite = ({
|
|
|
33
33
|
return sheet;
|
|
34
34
|
}
|
|
35
35
|
return null;
|
|
36
|
-
}, [spritesheetJSON]);
|
|
36
|
+
}, [spritesheetJSON, isFetched, textures]);
|
|
37
37
|
|
|
38
38
|
const sprite = useMemo(() => {
|
|
39
39
|
if (spritesheet?.animations?.[animation]) {
|
|
@@ -41,7 +41,7 @@ export const useAnimatedSprite = ({
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
return null;
|
|
44
|
-
}, [
|
|
44
|
+
}, [animation, spritesheet?.animations]);
|
|
45
45
|
|
|
46
46
|
useObject({ object: sprite, ...options });
|
|
47
47
|
|
|
@@ -49,7 +49,7 @@ export const useAnimatedSprite = ({
|
|
|
49
49
|
if (sprite) {
|
|
50
50
|
sprite.animationSpeed = animationSpeed;
|
|
51
51
|
}
|
|
52
|
-
}, [animationSpeed, sprite
|
|
52
|
+
}, [animationSpeed, sprite]);
|
|
53
53
|
|
|
54
54
|
useEffect(() => {
|
|
55
55
|
if (sprite) {
|
|
@@ -59,7 +59,7 @@ export const useAnimatedSprite = ({
|
|
|
59
59
|
sprite.stop();
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
-
}, [isPlaying, sprite
|
|
62
|
+
}, [isPlaying, sprite]);
|
|
63
63
|
|
|
64
64
|
return sprite;
|
|
65
65
|
};
|
package/src/hooks/useObject.ts
CHANGED
|
@@ -29,53 +29,53 @@ export const useObject = ({
|
|
|
29
29
|
return () => {
|
|
30
30
|
removeObject(object);
|
|
31
31
|
};
|
|
32
|
-
}, [object
|
|
32
|
+
}, [object, addObject, removeObject]);
|
|
33
33
|
|
|
34
34
|
useEffect(() => {
|
|
35
35
|
if (anchor !== undefined && object) {
|
|
36
36
|
object.anchor = anchor;
|
|
37
37
|
}
|
|
38
|
-
}, [anchor, object
|
|
38
|
+
}, [anchor, object]);
|
|
39
39
|
|
|
40
40
|
useEffect(() => {
|
|
41
41
|
if (angle !== undefined && object) {
|
|
42
42
|
object.angle = angle;
|
|
43
43
|
}
|
|
44
|
-
}, [angle, object
|
|
44
|
+
}, [angle, object]);
|
|
45
45
|
|
|
46
46
|
useEffect(() => {
|
|
47
47
|
if (object && position !== undefined) {
|
|
48
48
|
object.position = position;
|
|
49
49
|
}
|
|
50
|
-
}, [position, object
|
|
50
|
+
}, [position, object]);
|
|
51
51
|
|
|
52
52
|
useEffect(() => {
|
|
53
53
|
if (object && skew !== undefined) {
|
|
54
54
|
object.skew = skew;
|
|
55
55
|
}
|
|
56
|
-
}, [skew, object
|
|
56
|
+
}, [skew, object]);
|
|
57
57
|
|
|
58
58
|
useEffect(() => {
|
|
59
59
|
if (object && alpha !== undefined) {
|
|
60
60
|
object.alpha = alpha;
|
|
61
61
|
}
|
|
62
|
-
}, [alpha, object
|
|
62
|
+
}, [alpha, object]);
|
|
63
63
|
|
|
64
64
|
useEffect(() => {
|
|
65
65
|
if (object && scale !== undefined) {
|
|
66
66
|
object.scale = scale;
|
|
67
67
|
}
|
|
68
|
-
}, [scale, object
|
|
68
|
+
}, [scale, object]);
|
|
69
69
|
|
|
70
70
|
useEffect(() => {
|
|
71
71
|
if (object) {
|
|
72
72
|
object.visible = visible;
|
|
73
73
|
}
|
|
74
|
-
}, [visible, object
|
|
74
|
+
}, [visible, object]);
|
|
75
75
|
|
|
76
76
|
useEffect(() => {
|
|
77
77
|
if (object && width !== undefined) {
|
|
78
78
|
object.width = width;
|
|
79
79
|
}
|
|
80
|
-
}, [width, object
|
|
80
|
+
}, [width, object]);
|
|
81
81
|
};
|
package/src/hooks/useSprite.ts
CHANGED
package/src/hooks/useTexture.ts
CHANGED
|
@@ -8,7 +8,7 @@ export const useTextures = ({ keys = [] }: { keys?: string[] }) => {
|
|
|
8
8
|
|
|
9
9
|
const textures = useMemo(() => {
|
|
10
10
|
return isFetched ? keys.map((key) => getAsset(key) as Texture) : [];
|
|
11
|
-
}, [keys, isFetched,
|
|
11
|
+
}, [keys, isFetched, getAsset]);
|
|
12
12
|
|
|
13
13
|
return useMemo(
|
|
14
14
|
() => ({
|
|
@@ -25,7 +25,7 @@ export const useTilingSprite = ({ texture = "", tilePosition, ...options }: UseT
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
return new TilingSprite({});
|
|
28
|
-
}, [texture,
|
|
28
|
+
}, [texture, isFetched]);
|
|
29
29
|
|
|
30
30
|
useObject({ object: sprite, ...options });
|
|
31
31
|
|
|
@@ -33,7 +33,7 @@ export const useTilingSprite = ({ texture = "", tilePosition, ...options }: UseT
|
|
|
33
33
|
if (tilePosition && sprite) {
|
|
34
34
|
sprite.tilePosition = tilePosition;
|
|
35
35
|
}
|
|
36
|
-
}, [tilePosition, sprite
|
|
36
|
+
}, [tilePosition, sprite]);
|
|
37
37
|
|
|
38
38
|
return sprite;
|
|
39
39
|
};
|
package/src/layer/Layer.tsx
CHANGED
|
@@ -29,20 +29,20 @@ export const Layer: React.FC<PropsWithChildren & LayerOptions> = ({ options, chi
|
|
|
29
29
|
return () => {
|
|
30
30
|
removeObjectFromStaeg(container);
|
|
31
31
|
};
|
|
32
|
-
}, [container
|
|
32
|
+
}, [container, addObjectIntoParent, addObjectIntoStage, removeObjectFromParent, removeObjectFromStaeg]);
|
|
33
33
|
|
|
34
34
|
const addObject = useCallback(
|
|
35
35
|
(thing: Container) => {
|
|
36
36
|
container.addChild(thing);
|
|
37
37
|
},
|
|
38
|
-
[container
|
|
38
|
+
[container]
|
|
39
39
|
);
|
|
40
40
|
|
|
41
41
|
const removeObject = useCallback(
|
|
42
42
|
(thing: Container) => {
|
|
43
43
|
container.removeChild(thing);
|
|
44
44
|
},
|
|
45
|
-
[container
|
|
45
|
+
[container]
|
|
46
46
|
);
|
|
47
47
|
|
|
48
48
|
const conextValue = useMemo<LayerContextValue>(
|
|
@@ -50,7 +50,7 @@ export const Layer: React.FC<PropsWithChildren & LayerOptions> = ({ options, chi
|
|
|
50
50
|
addObject,
|
|
51
51
|
removeObject
|
|
52
52
|
}),
|
|
53
|
-
[
|
|
53
|
+
[addObject, removeObject]
|
|
54
54
|
);
|
|
55
55
|
|
|
56
56
|
return <LayerContext.Provider value={conextValue}>{children}</LayerContext.Provider>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { PropsWithChildren, createContext, useEffect, useMemo, useRef, useState } from "react";
|
|
1
|
+
import React, { PropsWithChildren, createContext, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
2
|
import Matter, { Engine, Runner, World } from "matter-js";
|
|
3
3
|
import { MatterPhysicsConfig, MatterPhysics } from "./types";
|
|
4
4
|
|
|
@@ -47,31 +47,37 @@ export const MatterPhysicsContextProvider: React.FC<PropsWithChildren & MatterPh
|
|
|
47
47
|
|
|
48
48
|
const runner = useMemo(() => Runner.create(), []);
|
|
49
49
|
|
|
50
|
-
const addBody = (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
const addBody = useCallback(
|
|
51
|
+
(body: Matter.Body | Matter.Composite) => {
|
|
52
|
+
if (engine?.world) {
|
|
53
|
+
World.add(engine?.world, body);
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
[engine]
|
|
57
|
+
);
|
|
55
58
|
|
|
56
|
-
const removeBody = (
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
const removeBody = useCallback(
|
|
60
|
+
(body: Matter.Body | Matter.Composite) => {
|
|
61
|
+
if (engine?.world) {
|
|
62
|
+
World.remove(engine?.world, body);
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
[engine]
|
|
66
|
+
);
|
|
61
67
|
|
|
62
|
-
const run = () => {
|
|
68
|
+
const run = useCallback(() => {
|
|
63
69
|
if (!isRunningRef.current) {
|
|
64
70
|
Runner.run(runner, engine);
|
|
65
71
|
isRunningRef.current = true;
|
|
66
72
|
}
|
|
67
|
-
};
|
|
73
|
+
}, [runner, engine]);
|
|
68
74
|
|
|
69
|
-
const stop = () => {
|
|
75
|
+
const stop = useCallback(() => {
|
|
70
76
|
if (isRunningRef.current) {
|
|
71
77
|
Runner.stop(runner);
|
|
72
78
|
isRunningRef.current = false;
|
|
73
79
|
}
|
|
74
|
-
};
|
|
80
|
+
}, [runner]);
|
|
75
81
|
|
|
76
82
|
const conextValue = useMemo(
|
|
77
83
|
() => ({
|
|
@@ -83,7 +89,7 @@ export const MatterPhysicsContextProvider: React.FC<PropsWithChildren & MatterPh
|
|
|
83
89
|
addBody,
|
|
84
90
|
removeBody
|
|
85
91
|
}),
|
|
86
|
-
[runner, engine, localConfig]
|
|
92
|
+
[runner, engine, localConfig, addBody, removeBody, run, stop]
|
|
87
93
|
);
|
|
88
94
|
|
|
89
95
|
useEffect(() => {
|
|
@@ -94,7 +100,7 @@ export const MatterPhysicsContextProvider: React.FC<PropsWithChildren & MatterPh
|
|
|
94
100
|
return () => {
|
|
95
101
|
stop();
|
|
96
102
|
};
|
|
97
|
-
}, [isRunning]);
|
|
103
|
+
}, [isRunning, run, stop]);
|
|
98
104
|
|
|
99
105
|
return <MatterPhysicsContext.Provider value={conextValue}>{children}</MatterPhysicsContext.Provider>;
|
|
100
106
|
};
|
package/src/stage/Stage.tsx
CHANGED
|
@@ -8,19 +8,13 @@ export const Stage: React.FC<PropsWithChildren> = ({ children }) => {
|
|
|
8
8
|
const { application } = useWorld();
|
|
9
9
|
const [things, setThings] = useState<Container[]>([]);
|
|
10
10
|
|
|
11
|
-
const addObject = useCallback(
|
|
12
|
-
(
|
|
13
|
-
|
|
14
|
-
},
|
|
15
|
-
[things]
|
|
16
|
-
);
|
|
11
|
+
const addObject = useCallback((thing: Container) => {
|
|
12
|
+
setThings((oldThings) => [...oldThings, thing]);
|
|
13
|
+
}, []);
|
|
17
14
|
|
|
18
|
-
const removeObject = useCallback(
|
|
19
|
-
(
|
|
20
|
-
|
|
21
|
-
},
|
|
22
|
-
[application]
|
|
23
|
-
);
|
|
15
|
+
const removeObject = useCallback((thing: Container) => {
|
|
16
|
+
setThings((oldThings) => oldThings.filter(({ uid }) => uid === thing.uid));
|
|
17
|
+
}, []);
|
|
24
18
|
|
|
25
19
|
const conextValue = useMemo<StageContextValue>(
|
|
26
20
|
() => ({
|
package/src/world/World.tsx
CHANGED
|
@@ -41,7 +41,7 @@ export const World: React.FC<PropsWithChildren & WorldProps> = ({ children, even
|
|
|
41
41
|
width: applicationRef.screen.width,
|
|
42
42
|
height: applicationRef.screen.height
|
|
43
43
|
};
|
|
44
|
-
}, [size, canvasRef
|
|
44
|
+
}, [size, canvasRef, applicationRef]);
|
|
45
45
|
|
|
46
46
|
useEffect(() => {
|
|
47
47
|
if (!applicationRef) {
|
|
@@ -50,14 +50,14 @@ export const World: React.FC<PropsWithChildren & WorldProps> = ({ children, even
|
|
|
50
50
|
setApplicationRef(application);
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
|
-
}, []);
|
|
53
|
+
}, [applicationRef]);
|
|
54
54
|
|
|
55
55
|
useEffect(() => {
|
|
56
56
|
if (applicationRef && canvasRef.current) {
|
|
57
57
|
applicationRef.resizeTo = canvasRef.current;
|
|
58
58
|
applicationRef.resize();
|
|
59
59
|
}
|
|
60
|
-
}, [canvasRef
|
|
60
|
+
}, [canvasRef, applicationRef]);
|
|
61
61
|
|
|
62
62
|
const conextValue = useMemo<WorldContextValue>(
|
|
63
63
|
() => ({
|
|
@@ -71,14 +71,15 @@ export const World: React.FC<PropsWithChildren & WorldProps> = ({ children, even
|
|
|
71
71
|
if (!applicationRef) {
|
|
72
72
|
return;
|
|
73
73
|
}
|
|
74
|
-
canvasRef.current
|
|
74
|
+
const canvas = canvasRef.current;
|
|
75
|
+
canvas?.appendChild(applicationRef.canvas);
|
|
75
76
|
|
|
76
77
|
return () => {
|
|
77
78
|
if (applicationRef) {
|
|
78
|
-
|
|
79
|
+
canvas?.removeChild(applicationRef.canvas);
|
|
79
80
|
}
|
|
80
81
|
};
|
|
81
|
-
}, [canvasRef
|
|
82
|
+
}, [canvasRef, applicationRef]);
|
|
82
83
|
|
|
83
84
|
useEffect(() => {
|
|
84
85
|
if (applicationRef) {
|