brick-engine-js 1.0.1 → 1.0.2
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/dist/docs/GAME_DEVELOPER_GUIDE.html +1 -1
- package/dist/docs/brick-engine-guide.html +1 -1
- package/dist/docs/getting-started.html +1 -1
- package/dist/docs/jsdoc_standard.html +1 -1
- package/dist/docs/publishing.html +1 -1
- package/dist/docs/reference/interfaces/modules/Session.html +1 -1
- package/dist/docs/reference/modules/GameMenu.html +1 -1
- package/dist/docs/reference/modules/GameSession.html +1 -1
- package/dist/docs/reference/modules/InitialStateSnapshot.html +1 -1
- package/dist/docs/reference/modules/SessionModal.html +1 -1
- package/dist/docs/testing_best_practices.html +1 -1
- package/package.json +7 -1
- package/.env.local.example +0 -2
- package/.github/workflows/publish.yml +0 -73
- package/.prettierignore +0 -2
- package/.prettierrc.json +0 -8
- package/eslint.config.mjs +0 -29
- package/public/CNAME +0 -1
- package/public/docs/GAME_DEVELOPER_GUIDE.html +0 -727
- package/public/docs/brick-engine-guide.html +0 -610
- package/public/docs/diagrams/lifecycle.mmd +0 -19
- package/public/docs/documentation_style_guide.html +0 -994
- package/public/docs/getting-started.html +0 -648
- package/public/docs/images/lifecycle.svg +0 -1
- package/public/docs/index.html +0 -593
- package/public/docs/jsdoc_standard.html +0 -656
- package/public/docs/publishing.html +0 -573
- package/public/docs/reference/enums/Color.html +0 -533
- package/public/docs/reference/enums/ControlEventType.html +0 -505
- package/public/docs/reference/enums/ControlKey.html +0 -529
- package/public/docs/reference/enums/FontAlignment.html +0 -545
- package/public/docs/reference/enums/FontSize.html +0 -517
- package/public/docs/reference/enums/Sound.html +0 -558
- package/public/docs/reference/enums/StateProperty.html +0 -525
- package/public/docs/reference/helpers/CellHelper.html +0 -520
- package/public/docs/reference/helpers/ControlInputHandlerHelper.html +0 -569
- package/public/docs/reference/helpers/CoordinateHelper.html +0 -703
- package/public/docs/reference/helpers/RelativeValuesHelper.html +0 -560
- package/public/docs/reference/interfaces/Debuggable.html +0 -501
- package/public/docs/reference/interfaces/GameModules.html +0 -544
- package/public/docs/reference/interfaces/Initializable.html +0 -495
- package/public/docs/reference/interfaces/RendererInitializable.html +0 -517
- package/public/docs/reference/interfaces/StateSyncable.html +0 -542
- package/public/docs/reference/interfaces/modules/Control.html +0 -648
- package/public/docs/reference/interfaces/modules/Grid.html +0 -1256
- package/public/docs/reference/interfaces/modules/Renderer.html +0 -522
- package/public/docs/reference/interfaces/modules/RendererComposite.html +0 -577
- package/public/docs/reference/interfaces/modules/Score.html +0 -669
- package/public/docs/reference/interfaces/modules/Session.html +0 -585
- package/public/docs/reference/interfaces/modules/State.html +0 -897
- package/public/docs/reference/interfaces/modules/Text.html +0 -668
- package/public/docs/reference/interfaces/modules/Time.html +0 -684
- package/public/docs/reference/modules/Debugger.html +0 -579
- package/public/docs/reference/modules/DisplayRenderer.html +0 -557
- package/public/docs/reference/modules/Game.html +0 -909
- package/public/docs/reference/modules/GameControl.html +0 -716
- package/public/docs/reference/modules/GameGrid.html +0 -1910
- package/public/docs/reference/modules/GameHudGrid.html +0 -508
- package/public/docs/reference/modules/GameMenu.html +0 -538
- package/public/docs/reference/modules/GameRenderer.html +0 -589
- package/public/docs/reference/modules/GameScore.html +0 -664
- package/public/docs/reference/modules/GameSession.html +0 -533
- package/public/docs/reference/modules/GameSound.html +0 -636
- package/public/docs/reference/modules/GameState.html +0 -922
- package/public/docs/reference/modules/GameText.html +0 -701
- package/public/docs/reference/modules/GameTime.html +0 -696
- package/public/docs/reference/modules/HudRenderer.html +0 -568
- package/public/docs/reference/modules/InitialStateSnapshot.html +0 -557
- package/public/docs/reference/modules/SessionModal.html +0 -520
- package/public/docs/reference/types/Axis.html +0 -505
- package/public/docs/reference/types/Cell.html +0 -514
- package/public/docs/reference/types/ControlCallback.html +0 -488
- package/public/docs/reference/types/Coordinate.html +0 -510
- package/public/docs/reference/types/GameEntry.html +0 -514
- package/public/docs/reference/types/GameEvent.html +0 -514
- package/public/docs/reference/types/Piece.html +0 -506
- package/public/docs/reference/types/RendererMetrics.html +0 -514
- package/public/docs/reference/types/Vector.html +0 -509
- package/public/docs/testing_best_practices.html +0 -770
- package/public/favicon.ico +0 -0
- package/public/fonts/digital-7.monoitalic.ttf +0 -0
- package/public/images/cell.svg +0 -32
- package/public/images/close.png +0 -0
- package/public/images/games.png +0 -0
- package/public/images/github.png +0 -0
- package/public/images/letter-a.png +0 -0
- package/public/images/letter-d.png +0 -0
- package/public/images/letter-j.png +0 -0
- package/public/images/letter-s.png +0 -0
- package/public/images/letter-w.png +0 -0
- package/public/images/meta-image.png +0 -0
- package/public/images/number-1.png +0 -0
- package/public/images/number-2.png +0 -0
- package/public/images/number-3.png +0 -0
- package/public/images/number-4.png +0 -0
- package/public/images/number-5.png +0 -0
- package/public/images/number-6.png +0 -0
- package/public/images/splash.gif +0 -0
- package/public/index.html +0 -15
- package/public/sounds/sound_00.wav +0 -0
- package/public/sounds/sound_01.wav +0 -0
- package/public/sounds/sound_02.wav +0 -0
- package/public/sounds/sound_03.wav +0 -0
- package/public/sounds/sound_04.wav +0 -0
- package/public/sounds/sound_05.wav +0 -0
- package/public/sounds/sound_06.wav +0 -0
- package/public/sounds/sound_07.wav +0 -0
- package/public/sounds/sound_08.wav +0 -0
- package/public/sounds/sound_09.wav +0 -0
- package/public/sounds/sound_10.wav +0 -0
- package/public/sounds/sound_11.wav +0 -0
- package/public/sounds/sound_12.wav +0 -0
- package/public/sounds/sound_13.wav +0 -0
- package/public/sounds/sound_14.wav +0 -0
- package/public/sounds/sound_15.wav +0 -0
- package/public/style/body.css +0 -86
- package/public/style/buttons.css +0 -233
- package/public/style/debugger.css +0 -117
- package/public/style/sessionModal.css +0 -155
- package/public/style/sourceCodeAndCommands.css +0 -74
- package/public/style/splash.css +0 -13
- package/public/style/theme.css +0 -137
- package/scripts/generate-diagrams.sh +0 -20
- package/scripts/generate-docs.js +0 -111
- package/src/client-game.d.ts +0 -1
- package/src/config/configs.test.ts +0 -20
- package/src/config/configs.ts +0 -197
- package/src/config/env.test.ts +0 -59
- package/src/config/env.ts +0 -7
- package/src/config/styles.ts +0 -5
- package/src/core/Game.test.ts +0 -167
- package/src/core/Game.ts +0 -307
- package/src/core/InitialStateSnapshot.test.ts +0 -51
- package/src/core/InitialStateSnapshot.ts +0 -46
- package/src/core/helpers/CellHelper.test.ts +0 -33
- package/src/core/helpers/CellHelper.ts +0 -21
- package/src/core/helpers/ControlInputHandlerHelper.test.ts +0 -116
- package/src/core/helpers/ControlInputHandlerHelper.ts +0 -68
- package/src/core/helpers/CoordinateHelper.test.ts +0 -113
- package/src/core/helpers/CoordinateHelper.ts +0 -82
- package/src/core/helpers/InterfaceIdentifierHelper.test.ts +0 -122
- package/src/core/helpers/InterfaceIdentifierHelper.ts +0 -43
- package/src/core/helpers/RelativeValuesHelper.test.ts +0 -47
- package/src/core/helpers/RelativeValuesHelper.ts +0 -29
- package/src/core/module/control/GameControl.test.ts +0 -82
- package/src/core/module/control/GameControl.ts +0 -142
- package/src/core/module/control/GameControlKeyBinding.test.ts +0 -59
- package/src/core/module/control/GameControlKeyBinding.ts +0 -92
- package/src/core/module/grid/GameGrid.test.ts +0 -83
- package/src/core/module/grid/GameGrid.ts +0 -610
- package/src/core/module/grid/GameHudGrid.test.ts +0 -22
- package/src/core/module/grid/GameHudGrid.ts +0 -40
- package/src/core/module/grid/engines/GridAnalysisEngine.test.ts +0 -157
- package/src/core/module/grid/engines/GridAnalysisEngine.ts +0 -124
- package/src/core/module/grid/engines/GridLineEngine.test.ts +0 -132
- package/src/core/module/grid/engines/GridLineEngine.ts +0 -165
- package/src/core/module/grid/engines/GridMovementEngine.test.ts +0 -125
- package/src/core/module/grid/engines/GridMovementEngine.ts +0 -113
- package/src/core/module/grid/engines/GridRegionEngine.test.ts +0 -136
- package/src/core/module/grid/engines/GridRegionEngine.ts +0 -52
- package/src/core/module/grid/engines/GridTransformEngine.test.ts +0 -98
- package/src/core/module/grid/engines/GridTransformEngine.ts +0 -70
- package/src/core/module/renderer/DisplayRenderer.test.ts +0 -86
- package/src/core/module/renderer/DisplayRenderer.ts +0 -152
- package/src/core/module/renderer/GameRenderer.test.ts +0 -103
- package/src/core/module/renderer/GameRenderer.ts +0 -144
- package/src/core/module/renderer/HudRenderer.test.ts +0 -108
- package/src/core/module/renderer/HudRenderer.ts +0 -203
- package/src/core/module/score/GameScore.test.ts +0 -71
- package/src/core/module/score/GameScore.ts +0 -188
- package/src/core/module/session/GameSession.test.ts +0 -176
- package/src/core/module/session/GameSession.ts +0 -103
- package/src/core/module/sound/GameSound.test.ts +0 -117
- package/src/core/module/sound/GameSound.ts +0 -229
- package/src/core/module/state/GameState.test.ts +0 -101
- package/src/core/module/state/GameState.ts +0 -339
- package/src/core/module/text/GameText.test.ts +0 -87
- package/src/core/module/text/GameText.ts +0 -150
- package/src/core/module/time/GameTime.test.ts +0 -86
- package/src/core/module/time/GameTime.ts +0 -144
- package/src/core/types/Interfaces.ts +0 -59
- package/src/core/types/Types.ts +0 -124
- package/src/core/types/enums.ts +0 -113
- package/src/core/types/modules.ts +0 -841
- package/src/index.test.ts +0 -15
- package/src/index.ts +0 -9
- package/src/main.test.ts +0 -137
- package/src/main.ts +0 -77
- package/src/menu/GameMenu.test.ts +0 -157
- package/src/menu/GameMenu.ts +0 -124
- package/src/menu/GameMenuSingleton.test.ts +0 -26
- package/src/menu/GameMenuSingleton.ts +0 -13
- package/src/menu/GameRepository.test.ts +0 -46
- package/src/menu/GameRepository.ts +0 -47
- package/src/menu/manager/GameManager.test.ts +0 -68
- package/src/menu/manager/GameManager.ts +0 -50
- package/src/types/global.d.ts +0 -8
- package/src/types/interfaces.ts +0 -5
- package/src/view/Debugger.test.ts +0 -152
- package/src/view/Debugger.ts +0 -124
- package/src/view/GameView.test.ts +0 -95
- package/src/view/GameView.ts +0 -244
- package/src/view/SessionModal.test.ts +0 -141
- package/src/view/SessionModal.ts +0 -73
- package/src/view/components/layout/ButtonLayout.test.ts +0 -28
- package/src/view/components/layout/ButtonLayout.ts +0 -63
- package/src/view/components/layout/ContainerLayout.test.ts +0 -48
- package/src/view/components/layout/ContainerLayout.ts +0 -50
- package/src/view/components/layout/FrameLayout.test.ts +0 -24
- package/src/view/components/layout/FrameLayout.ts +0 -25
- package/src/view/components/ui/BigButton.test.ts +0 -28
- package/src/view/components/ui/BigButton.ts +0 -31
- package/src/view/components/ui/Button.test.ts +0 -30
- package/src/view/components/ui/Button.ts +0 -30
- package/src/view/components/ui/Canvas.test.ts +0 -32
- package/src/view/components/ui/Canvas.ts +0 -34
- package/src/view/components/ui/SmallButton.test.ts +0 -48
- package/src/view/components/ui/SmallButton.ts +0 -32
- package/src/view/theme/applyColors.test.ts +0 -47
- package/src/view/theme/applyColors.ts +0 -38
- package/src/view/theme/dimensions.test.ts +0 -34
- package/src/view/theme/dimensions.ts +0 -53
- package/tsconfig.json +0 -16
- package/vitest.config.ts +0 -14
- package/webpack.config.js +0 -133
package/src/index.test.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import * as BrickEngine from './index';
|
|
3
|
-
|
|
4
|
-
describe('index (Library Exports)', () => {
|
|
5
|
-
it('should export the core modules and configurations', () => {
|
|
6
|
-
// [ASSERT]
|
|
7
|
-
expect(BrickEngine.Game).toBeDefined();
|
|
8
|
-
expect(BrickEngine.GameView).toBeDefined();
|
|
9
|
-
expect(BrickEngine.configs).toBeDefined();
|
|
10
|
-
|
|
11
|
-
// Exported enums/types check
|
|
12
|
-
expect(BrickEngine.Color).toBeDefined();
|
|
13
|
-
expect(BrickEngine.FontSize).toBeDefined();
|
|
14
|
-
});
|
|
15
|
-
});
|
package/src/index.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
// Library Exports Only
|
|
2
|
-
export * from './core/types/enums';
|
|
3
|
-
export * from './core/types/Interfaces';
|
|
4
|
-
export * from './core/types/modules';
|
|
5
|
-
export * from './core/types/Types';
|
|
6
|
-
export * from './types/interfaces';
|
|
7
|
-
export { default as Game } from './core/Game';
|
|
8
|
-
export { default as GameView } from './view/GameView';
|
|
9
|
-
export { default as configs } from './config/configs';
|
package/src/main.test.ts
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
/** @vitest-environment jsdom */
|
|
2
|
-
import { describe, it, expect, vi, beforeEach, Mock } from 'vitest';
|
|
3
|
-
import p5 from 'p5';
|
|
4
|
-
import Game from './core/Game';
|
|
5
|
-
|
|
6
|
-
// Mocking everything before importing main.ts logic
|
|
7
|
-
const createMockGame = () => ({
|
|
8
|
-
setup: vi.fn(),
|
|
9
|
-
setSwitchHandler: vi.fn(),
|
|
10
|
-
propagateSwitchHandler: vi.fn(),
|
|
11
|
-
draw: vi.fn(),
|
|
12
|
-
modules: {
|
|
13
|
-
state: { turnOn: vi.fn(), turnOff: vi.fn(), isOn: vi.fn() },
|
|
14
|
-
control: { subscribe: vi.fn() },
|
|
15
|
-
time: { update: vi.fn() },
|
|
16
|
-
},
|
|
17
|
-
view: {
|
|
18
|
-
unbindControls: vi.fn(),
|
|
19
|
-
bindControls: vi.fn(),
|
|
20
|
-
updateDebuggerGameModules: vi.fn(),
|
|
21
|
-
setupDebugger: vi.fn(),
|
|
22
|
-
},
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const mockGame = createMockGame();
|
|
26
|
-
|
|
27
|
-
vi.mock('p5', () => {
|
|
28
|
-
return {
|
|
29
|
-
default: vi.fn().mockImplementation(function (sketch: (p: unknown) => void) {
|
|
30
|
-
const p = {
|
|
31
|
-
loop: vi.fn(),
|
|
32
|
-
noLoop: vi.fn(),
|
|
33
|
-
setup: vi.fn(),
|
|
34
|
-
draw: vi.fn(),
|
|
35
|
-
};
|
|
36
|
-
sketch(p);
|
|
37
|
-
return p;
|
|
38
|
-
}),
|
|
39
|
-
};
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
vi.mock('./view/GameView', () => {
|
|
43
|
-
return {
|
|
44
|
-
default: vi.fn().mockImplementation(function () {
|
|
45
|
-
return {
|
|
46
|
-
build: vi.fn().mockReturnValue({ canvas: {}, canvasHeight: 100, canvasWidth: 100 }),
|
|
47
|
-
bindControls: vi.fn(),
|
|
48
|
-
unbindControls: vi.fn(),
|
|
49
|
-
setupDebugger: vi.fn(),
|
|
50
|
-
updateDebuggerGameModules: vi.fn(),
|
|
51
|
-
};
|
|
52
|
-
}),
|
|
53
|
-
};
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
vi.mock('./menu/GameMenu', () => {
|
|
57
|
-
return {
|
|
58
|
-
default: vi.fn().mockImplementation(function () {
|
|
59
|
-
return mockGame;
|
|
60
|
-
}),
|
|
61
|
-
};
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
vi.mock('./core/Debugger', () => ({
|
|
65
|
-
default: vi.fn().mockImplementation(function () {
|
|
66
|
-
return { setup: vi.fn(), update: vi.fn(), destroy: vi.fn() };
|
|
67
|
-
}),
|
|
68
|
-
}));
|
|
69
|
-
|
|
70
|
-
vi.mock('./config/env', () => ({
|
|
71
|
-
isClientMode: vi.fn(),
|
|
72
|
-
isServerMode: vi.fn(),
|
|
73
|
-
}));
|
|
74
|
-
|
|
75
|
-
vi.mock('@client-game', () => ({
|
|
76
|
-
default: vi.fn().mockImplementation(function () {
|
|
77
|
-
return mockGame;
|
|
78
|
-
}),
|
|
79
|
-
}));
|
|
80
|
-
|
|
81
|
-
vi.mock('./menu/GameMenuSingleton', () => ({
|
|
82
|
-
default: {
|
|
83
|
-
setInstance: vi.fn(),
|
|
84
|
-
getInstance: vi.fn().mockReturnValue(mockGame),
|
|
85
|
-
},
|
|
86
|
-
}));
|
|
87
|
-
|
|
88
|
-
vi.mock('./config/styles', () => ({}));
|
|
89
|
-
|
|
90
|
-
describe('main.ts', () => {
|
|
91
|
-
beforeEach(() => {
|
|
92
|
-
vi.clearAllMocks();
|
|
93
|
-
vi.resetModules();
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('should initialize the p5 instance and GameMenu in server mode', async () => {
|
|
97
|
-
const { isClientMode, isServerMode } = await import('./config/env');
|
|
98
|
-
const GameMenu = (await import('./menu/GameMenu')).default;
|
|
99
|
-
|
|
100
|
-
(isClientMode as unknown as Mock).mockReturnValue(false);
|
|
101
|
-
(isServerMode as unknown as Mock).mockReturnValue(true);
|
|
102
|
-
|
|
103
|
-
const main = await import('./main');
|
|
104
|
-
|
|
105
|
-
expect(p5).toHaveBeenCalled();
|
|
106
|
-
expect(GameMenu).toHaveBeenCalled();
|
|
107
|
-
expect(main.p5Instance).toBeDefined();
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it('should initialize ClientGame in client mode', async () => {
|
|
111
|
-
const { isClientMode, isServerMode } = await import('./config/env');
|
|
112
|
-
const ClientGame = (await import('@client-game')).default;
|
|
113
|
-
|
|
114
|
-
(isClientMode as unknown as Mock).mockReturnValue(true);
|
|
115
|
-
(isServerMode as unknown as Mock).mockReturnValue(false);
|
|
116
|
-
|
|
117
|
-
await import('./main');
|
|
118
|
-
|
|
119
|
-
expect(ClientGame).toHaveBeenCalled();
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('should handle game switching', async () => {
|
|
123
|
-
const { isClientMode, isServerMode } = await import('./config/env');
|
|
124
|
-
(isClientMode as unknown as Mock).mockReturnValue(false);
|
|
125
|
-
(isServerMode as unknown as Mock).mockReturnValue(true);
|
|
126
|
-
|
|
127
|
-
await import('./main');
|
|
128
|
-
|
|
129
|
-
const switchHandler = (mockGame.setSwitchHandler as unknown as Mock).mock.calls[0][0];
|
|
130
|
-
const nextGame = createMockGame();
|
|
131
|
-
|
|
132
|
-
switchHandler(nextGame as unknown as Game);
|
|
133
|
-
|
|
134
|
-
expect(nextGame.setup).toHaveBeenCalled();
|
|
135
|
-
expect(nextGame.modules.state.turnOn).toHaveBeenCalled();
|
|
136
|
-
});
|
|
137
|
-
});
|
package/src/main.ts
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import p5 from 'p5';
|
|
2
|
-
import Game from './core/Game';
|
|
3
|
-
import GameView from './view/GameView';
|
|
4
|
-
import GameMenu from './menu/GameMenu';
|
|
5
|
-
|
|
6
|
-
import './config/styles';
|
|
7
|
-
|
|
8
|
-
import { isClientMode, isServerMode } from './config/env';
|
|
9
|
-
import ClientGame from '@client-game';
|
|
10
|
-
import { ControlEventType, ControlKey } from './core/types/enums';
|
|
11
|
-
import GameMenuSingleton from './menu/GameMenuSingleton';
|
|
12
|
-
|
|
13
|
-
export const p5Instance = new p5((p: p5) => {
|
|
14
|
-
const view = new GameView(p, document.body);
|
|
15
|
-
let activeGame: Game;
|
|
16
|
-
|
|
17
|
-
if (isClientMode()) {
|
|
18
|
-
// In client mode, we instantiate the game provided via alias
|
|
19
|
-
activeGame = new ClientGame(p, view);
|
|
20
|
-
activeGame.gameId = 'client-game';
|
|
21
|
-
} else if (isServerMode()) {
|
|
22
|
-
// In server mode, we instantiate the game menu
|
|
23
|
-
activeGame = new GameMenu(p, view);
|
|
24
|
-
activeGame.gameId = 'game-menu';
|
|
25
|
-
GameMenuSingleton.setInstance(activeGame as GameMenu);
|
|
26
|
-
} else {
|
|
27
|
-
throw new Error('Invalid APP_MODE');
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Register the switch handler
|
|
31
|
-
activeGame.setSwitchHandler((newGame: Game) => {
|
|
32
|
-
try {
|
|
33
|
-
// Unbind the previous game controls
|
|
34
|
-
activeGame.view.unbindControls();
|
|
35
|
-
|
|
36
|
-
// Propagate the switch handler to the new game
|
|
37
|
-
newGame.propagateSwitchHandler(activeGame);
|
|
38
|
-
|
|
39
|
-
// Set the new game
|
|
40
|
-
activeGame = newGame;
|
|
41
|
-
activeGame.setup();
|
|
42
|
-
|
|
43
|
-
// Update debugger
|
|
44
|
-
activeGame.view.updateDebuggerGameModules(activeGame.modules);
|
|
45
|
-
|
|
46
|
-
// Bind the new game controls
|
|
47
|
-
activeGame.view.bindControls(activeGame.modules.control);
|
|
48
|
-
activeGame.modules.state.turnOn();
|
|
49
|
-
|
|
50
|
-
// Setup exit and power buttons
|
|
51
|
-
if (isServerMode() && newGame !== GameMenuSingleton.getInstance()) {
|
|
52
|
-
newGame.modules.control.subscribe(ControlKey.EXIT, ControlEventType.PRESSED, () => {
|
|
53
|
-
newGame.switchGame(GameMenuSingleton.getInstance());
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
newGame.modules.control.subscribe(ControlKey.POWER, ControlEventType.PRESSED, () => {
|
|
57
|
-
newGame.switchGame(GameMenuSingleton.getInstance());
|
|
58
|
-
activeGame.modules.state.turnOff();
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
} catch (error) {
|
|
62
|
-
console.error('Error switching game:', error);
|
|
63
|
-
}
|
|
64
|
-
p.loop();
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
p.setup = () => {
|
|
68
|
-
activeGame.setup();
|
|
69
|
-
activeGame.view.setupDebugger(activeGame.modules);
|
|
70
|
-
activeGame.view.setupSessionModal();
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
p.draw = () => {
|
|
74
|
-
activeGame.draw();
|
|
75
|
-
activeGame.view.updateDebugger();
|
|
76
|
-
};
|
|
77
|
-
}, document.body);
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
/** @vitest-environment jsdom */
|
|
2
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
3
|
-
import GameMenu from './GameMenu';
|
|
4
|
-
import GameView from '../view/GameView';
|
|
5
|
-
import p5 from 'p5';
|
|
6
|
-
import { ControlEventType, ControlKey } from '../core/types/enums';
|
|
7
|
-
|
|
8
|
-
// Mock GameRepository to avoid external dependencies
|
|
9
|
-
vi.mock('./GameRepository', () => {
|
|
10
|
-
return {
|
|
11
|
-
default: vi.fn().mockImplementation(function () {
|
|
12
|
-
return {
|
|
13
|
-
games: [
|
|
14
|
-
{ id: '1', name: 'Game 1', url: 'url1' },
|
|
15
|
-
{ id: '2', name: 'Game 2', url: 'url2' },
|
|
16
|
-
],
|
|
17
|
-
};
|
|
18
|
-
}),
|
|
19
|
-
};
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
// Mock GameManager
|
|
23
|
-
vi.mock('./manager/GameManager', () => {
|
|
24
|
-
return {
|
|
25
|
-
default: vi.fn().mockImplementation(function () {
|
|
26
|
-
return {
|
|
27
|
-
handleGameSwitch: vi.fn(),
|
|
28
|
-
};
|
|
29
|
-
}),
|
|
30
|
-
};
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
describe('GameMenu', () => {
|
|
34
|
-
let menu: GameMenu;
|
|
35
|
-
let mockP5: Record<string, unknown>;
|
|
36
|
-
let mockView: Record<string, unknown>;
|
|
37
|
-
|
|
38
|
-
beforeEach(() => {
|
|
39
|
-
vi.stubGlobal('localStorage', {
|
|
40
|
-
getItem: vi.fn().mockReturnValue(null),
|
|
41
|
-
setItem: vi.fn(),
|
|
42
|
-
clear: vi.fn(),
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
vi.stubGlobal(
|
|
46
|
-
'AudioContext',
|
|
47
|
-
vi.fn().mockImplementation(function () {
|
|
48
|
-
return {
|
|
49
|
-
createGain: vi.fn().mockReturnValue({
|
|
50
|
-
connect: vi.fn(),
|
|
51
|
-
gain: { setValueAtTime: vi.fn() },
|
|
52
|
-
}),
|
|
53
|
-
createBufferSource: vi.fn().mockReturnValue({
|
|
54
|
-
connect: vi.fn(),
|
|
55
|
-
start: vi.fn(),
|
|
56
|
-
buffer: null,
|
|
57
|
-
}),
|
|
58
|
-
destination: {},
|
|
59
|
-
decodeAudioData: vi.fn().mockResolvedValue({}),
|
|
60
|
-
resume: vi.fn().mockResolvedValue({}),
|
|
61
|
-
};
|
|
62
|
-
}),
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
vi.stubGlobal(
|
|
66
|
-
'fetch',
|
|
67
|
-
vi.fn().mockResolvedValue({
|
|
68
|
-
arrayBuffer: vi.fn().mockResolvedValue(new ArrayBuffer(0)),
|
|
69
|
-
}),
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
mockP5 = {
|
|
73
|
-
deltaTime: 16,
|
|
74
|
-
noLoop: vi.fn(),
|
|
75
|
-
push: vi.fn(),
|
|
76
|
-
pop: vi.fn(),
|
|
77
|
-
translate: vi.fn(),
|
|
78
|
-
strokeWeight: vi.fn(),
|
|
79
|
-
stroke: vi.fn(),
|
|
80
|
-
noFill: vi.fn(),
|
|
81
|
-
rect: vi.fn(),
|
|
82
|
-
fill: vi.fn(),
|
|
83
|
-
text: vi.fn(),
|
|
84
|
-
textFont: vi.fn(),
|
|
85
|
-
textSize: vi.fn(),
|
|
86
|
-
textAlign: vi.fn(),
|
|
87
|
-
image: vi.fn(),
|
|
88
|
-
createGraphics: vi.fn().mockReturnValue({
|
|
89
|
-
background: vi.fn(),
|
|
90
|
-
strokeWeight: vi.fn(),
|
|
91
|
-
noFill: vi.fn(),
|
|
92
|
-
stroke: vi.fn(),
|
|
93
|
-
rect: vi.fn(),
|
|
94
|
-
}),
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
mockView = {
|
|
98
|
-
build: vi.fn(),
|
|
99
|
-
bindControls: vi.fn(),
|
|
100
|
-
showSessionModal: vi.fn(),
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
menu = new GameMenu(mockP5 as unknown as p5, mockView as unknown as GameView);
|
|
104
|
-
menu.setup();
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it('should cycle through games on LEFT/RIGHT arrow press', () => {
|
|
108
|
-
const { control, state } = menu.modules;
|
|
109
|
-
|
|
110
|
-
// Ensure game is ON and STARTED/PLAYING
|
|
111
|
-
state.turnOn();
|
|
112
|
-
state.startGame();
|
|
113
|
-
|
|
114
|
-
expect(state.isPlaying()).toBe(true);
|
|
115
|
-
|
|
116
|
-
// Initial selection should be 0 (Game 1)
|
|
117
|
-
expect((menu as unknown as Record<string, unknown>)['_gameSelectionPointer']).toBe(0);
|
|
118
|
-
|
|
119
|
-
// Press RIGHT
|
|
120
|
-
control.notify(ControlKey.RIGHT, ControlEventType.PRESSED);
|
|
121
|
-
expect((menu as unknown as Record<string, unknown>)['_gameSelectionPointer']).toBe(1);
|
|
122
|
-
|
|
123
|
-
// Press RIGHT again (should cycle)
|
|
124
|
-
control.notify(ControlKey.RIGHT, ControlEventType.PRESSED);
|
|
125
|
-
expect((menu as unknown as Record<string, unknown>)['_gameSelectionPointer']).toBe(0);
|
|
126
|
-
|
|
127
|
-
// Press LEFT (should cycle back)
|
|
128
|
-
control.notify(ControlKey.LEFT, ControlEventType.PRESSED);
|
|
129
|
-
expect((menu as unknown as Record<string, unknown>)['_gameSelectionPointer']).toBe(1);
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
it('should handle game switch on ACTION press', () => {
|
|
133
|
-
const { control, state } = menu.modules;
|
|
134
|
-
state.turnOn();
|
|
135
|
-
state.startGame();
|
|
136
|
-
|
|
137
|
-
expect(state.isStarted()).toBe(true);
|
|
138
|
-
|
|
139
|
-
const managerSpy = (menu as unknown as { _gameManager: { handleGameSwitch: import('vitest').Mock } })._gameManager.handleGameSwitch;
|
|
140
|
-
|
|
141
|
-
control.notify(ControlKey.ACTION, ControlEventType.PRESSED);
|
|
142
|
-
|
|
143
|
-
expect(managerSpy).toHaveBeenCalledWith(expect.objectContaining({ name: 'Game 1' }), menu);
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
it('should play theme when turned on', () => {
|
|
147
|
-
const { state, sound } = menu.modules;
|
|
148
|
-
|
|
149
|
-
// Mock play to resolve
|
|
150
|
-
const soundSpy = vi.spyOn(sound, 'play').mockResolvedValue(undefined as unknown as void);
|
|
151
|
-
|
|
152
|
-
state.turnOn();
|
|
153
|
-
|
|
154
|
-
expect(state.isOn()).toBe(true);
|
|
155
|
-
expect(soundSpy).toHaveBeenCalled();
|
|
156
|
-
});
|
|
157
|
-
});
|
package/src/menu/GameMenu.ts
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import p5 from 'p5';
|
|
2
|
-
import GameView from '../view/GameView';
|
|
3
|
-
import Game from '../core/Game';
|
|
4
|
-
import { ControlEventType, ControlKey, FontAlign, FontSize, FontVerticalAlign, Sound, StateProperty } from '../core/types/enums';
|
|
5
|
-
import GameRepository from './GameRepository';
|
|
6
|
-
import GameManager from './manager/GameManager';
|
|
7
|
-
|
|
8
|
-
export default class GameMenu extends Game {
|
|
9
|
-
private _gameSelectionPointer = 0;
|
|
10
|
-
private _isLoading = false;
|
|
11
|
-
|
|
12
|
-
private _gameRepository = new GameRepository();
|
|
13
|
-
private _gameManager = new GameManager();
|
|
14
|
-
|
|
15
|
-
constructor(p: p5, view: GameView) {
|
|
16
|
-
super(p, view);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
setupGame() {
|
|
20
|
-
const { state, control, sound } = this.modules;
|
|
21
|
-
|
|
22
|
-
control.subscribe(ControlKey.ACTION, ControlEventType.PRESSED, () => {
|
|
23
|
-
if (this._isLoading) return;
|
|
24
|
-
|
|
25
|
-
if (state.isStarted()) {
|
|
26
|
-
const selectedGame = this._gameRepository.games[this._gameSelectionPointer];
|
|
27
|
-
this._gameManager.handleGameSwitch(selectedGame, this);
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
control.subscribe(ControlKey.LEFT, ControlEventType.PRESSED, () => {
|
|
32
|
-
if (state.isPlaying()) {
|
|
33
|
-
sound.play(Sound.ACTION_1);
|
|
34
|
-
if (this._gameSelectionPointer === 0) {
|
|
35
|
-
this._gameSelectionPointer = this._gameRepository.games.length - 1;
|
|
36
|
-
} else {
|
|
37
|
-
this._gameSelectionPointer--;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
control.subscribe(ControlKey.RIGHT, ControlEventType.PRESSED, () => {
|
|
43
|
-
if (state.isPlaying()) {
|
|
44
|
-
sound.play(Sound.ACTION_1);
|
|
45
|
-
if (this._gameSelectionPointer === this._gameRepository.games.length - 1) {
|
|
46
|
-
this._gameSelectionPointer = 0;
|
|
47
|
-
} else {
|
|
48
|
-
this._gameSelectionPointer++;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
state.subscribe(StateProperty.ON, on => {
|
|
54
|
-
if (on) {
|
|
55
|
-
sound.play(Sound.START_THEME);
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
update() {}
|
|
61
|
-
|
|
62
|
-
render() {
|
|
63
|
-
const { text } = this.modules;
|
|
64
|
-
|
|
65
|
-
const { p } = this;
|
|
66
|
-
p.push();
|
|
67
|
-
|
|
68
|
-
text.setTextSize(FontSize.LARGE);
|
|
69
|
-
text.setActiveText();
|
|
70
|
-
text.setTextAlign(FontAlign.CENTER, FontVerticalAlign.BOTTOM);
|
|
71
|
-
|
|
72
|
-
text.textOnDisplay('Menu', { x: 0.5, y: 0.15 });
|
|
73
|
-
|
|
74
|
-
text.setTextSize(FontSize.SMALL);
|
|
75
|
-
|
|
76
|
-
text.textOnDisplay('Choose a game and', { x: 0.5, y: 0.25 });
|
|
77
|
-
text.textOnDisplay('Press action to play', { x: 0.5, y: 0.32 });
|
|
78
|
-
|
|
79
|
-
text.setTextAlign(FontAlign.RIGHT, FontVerticalAlign.BOTTOM);
|
|
80
|
-
text.textOnDisplay('<', { x: 0.1, y: 0.54 });
|
|
81
|
-
|
|
82
|
-
text.setTextAlign(FontAlign.LEFT, FontVerticalAlign.BOTTOM);
|
|
83
|
-
text.textOnDisplay('>', { x: 0.9, y: 0.54 });
|
|
84
|
-
|
|
85
|
-
text.setTextSize(FontSize.MEDIUM);
|
|
86
|
-
text.setTextAlign(FontAlign.CENTER, FontVerticalAlign.BOTTOM);
|
|
87
|
-
text.textOnDisplay(this._gameRepository.games[this._gameSelectionPointer].name, { x: 0.5, y: 0.55 });
|
|
88
|
-
|
|
89
|
-
text.setTextSize(FontSize.EXTRA_SMALL);
|
|
90
|
-
text.setTextAlign(FontAlign.LEFT, FontVerticalAlign.BOTTOM);
|
|
91
|
-
|
|
92
|
-
text.textOnDisplay('Left: Previous option', { x: 0.05, y: 0.78 });
|
|
93
|
-
text.textOnDisplay('Right: Next option', { x: 0.05, y: 0.84 });
|
|
94
|
-
text.textOnDisplay('Action: Select', { x: 0.05, y: 0.9 });
|
|
95
|
-
|
|
96
|
-
p.pop();
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
drawTitleScreen() {
|
|
100
|
-
const { text } = this.modules;
|
|
101
|
-
|
|
102
|
-
this.p.push();
|
|
103
|
-
|
|
104
|
-
text.setTextSize(FontSize.LARGE);
|
|
105
|
-
text.setActiveText();
|
|
106
|
-
text.setTextAlign(FontAlign.CENTER, FontVerticalAlign.TOP);
|
|
107
|
-
|
|
108
|
-
text.textOnDisplay('Menu', { x: 0.5, y: 0.15 });
|
|
109
|
-
|
|
110
|
-
text.setTextSize(FontSize.SMALL);
|
|
111
|
-
|
|
112
|
-
text.textOnDisplay('Wellcome to your', { x: 0.5, y: 0.25 });
|
|
113
|
-
text.textOnDisplay('favorite brick game', { x: 0.5, y: 0.32 });
|
|
114
|
-
text.textOnDisplay('simulator!', { x: 0.5, y: 0.39 });
|
|
115
|
-
text.textOnDisplay('Press start', { x: 0.5, y: 0.66 });
|
|
116
|
-
text.textOnDisplay('to continue.', { x: 0.5, y: 0.72 });
|
|
117
|
-
|
|
118
|
-
this.p.pop();
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
drawGameOverScreen() {
|
|
122
|
-
// Menu doesn't have a game over screen
|
|
123
|
-
}
|
|
124
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import GameMenuSingleton from './GameMenuSingleton';
|
|
3
|
-
import GameMenu from './GameMenu';
|
|
4
|
-
|
|
5
|
-
describe('GameMenuSingleton', () => {
|
|
6
|
-
it('should store and retrieve a GameMenu instance', () => {
|
|
7
|
-
const mockInstance = { name: 'MockGameMenu' } as unknown as GameMenu;
|
|
8
|
-
|
|
9
|
-
GameMenuSingleton.setInstance(mockInstance);
|
|
10
|
-
const retrieved = GameMenuSingleton.getInstance();
|
|
11
|
-
|
|
12
|
-
expect(retrieved).toBe(mockInstance);
|
|
13
|
-
expect((retrieved as unknown as { name: string }).name).toBe('MockGameMenu');
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('should overwrite the previous instance when setInstance is called again', () => {
|
|
17
|
-
const mockInstance1 = { id: 1 } as unknown as GameMenu;
|
|
18
|
-
const mockInstance2 = { id: 2 } as unknown as GameMenu;
|
|
19
|
-
|
|
20
|
-
GameMenuSingleton.setInstance(mockInstance1);
|
|
21
|
-
expect(GameMenuSingleton.getInstance()).toBe(mockInstance1);
|
|
22
|
-
|
|
23
|
-
GameMenuSingleton.setInstance(mockInstance2);
|
|
24
|
-
expect(GameMenuSingleton.getInstance()).toBe(mockInstance2);
|
|
25
|
-
});
|
|
26
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import GameMenu from './GameMenu';
|
|
2
|
-
|
|
3
|
-
export default class GameMenuSingleton {
|
|
4
|
-
private static _instance: GameMenu;
|
|
5
|
-
|
|
6
|
-
static setInstance(instance: GameMenu) {
|
|
7
|
-
GameMenuSingleton._instance = instance;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
static getInstance(): GameMenu {
|
|
11
|
-
return GameMenuSingleton._instance;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import GameRepository from './GameRepository';
|
|
3
|
-
|
|
4
|
-
describe('GameRepository', () => {
|
|
5
|
-
beforeEach(() => {
|
|
6
|
-
vi.stubGlobal(
|
|
7
|
-
'fetch',
|
|
8
|
-
vi.fn().mockResolvedValue({
|
|
9
|
-
ok: true,
|
|
10
|
-
json: vi.fn().mockResolvedValue({
|
|
11
|
-
games: [{ id: 'test-game', name: 'Test Game', url: 'http://localhost:8080/game.bundle.js' }],
|
|
12
|
-
}),
|
|
13
|
-
}),
|
|
14
|
-
);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
afterEach(() => {
|
|
18
|
-
vi.unstubAllGlobals();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('should start with a loading state', () => {
|
|
22
|
-
const repo = new GameRepository();
|
|
23
|
-
expect(repo.games).toBeDefined();
|
|
24
|
-
expect(repo.games.length).toBeGreaterThan(0);
|
|
25
|
-
expect(repo.games[0].name).toBe('Loading...');
|
|
26
|
-
expect(repo.games[0].id).toBe('loading');
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('should load games asynchronously', async () => {
|
|
30
|
-
const repo = new GameRepository();
|
|
31
|
-
// Wait for the microtask queue to process the fetch
|
|
32
|
-
await new Promise(resolve => setTimeout(resolve, 0));
|
|
33
|
-
|
|
34
|
-
expect(repo.games[0].id).toBe('test-game');
|
|
35
|
-
expect(repo.games[0].name).toBe('Test Game');
|
|
36
|
-
expect(repo.games[0].url).toBe('http://localhost:8080/game.bundle.js');
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('should return a frozen list of games', () => {
|
|
40
|
-
const repo = new GameRepository();
|
|
41
|
-
const games = repo.games;
|
|
42
|
-
|
|
43
|
-
// This should throw in strict mode, or at least not change if we tried to mutate it
|
|
44
|
-
expect(Object.isFrozen(games)).toBe(true);
|
|
45
|
-
});
|
|
46
|
-
});
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { GameEntry } from '../types/interfaces';
|
|
2
|
-
|
|
3
|
-
export default class GameRepository {
|
|
4
|
-
private _games: GameEntry[] = [{ id: 'loading', name: 'Loading...', url: '' }];
|
|
5
|
-
|
|
6
|
-
constructor() {
|
|
7
|
-
this.fetchGames();
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
private async fetchGames(): Promise<void> {
|
|
11
|
-
try {
|
|
12
|
-
// Read from injected env variables, or fallback to local
|
|
13
|
-
const supabaseUrl = process.env.SUPABASE_URL || 'http://127.0.0.1:54321';
|
|
14
|
-
const anonKey = process.env.SUPABASE_ANON_KEY || '';
|
|
15
|
-
|
|
16
|
-
const headers: HeadersInit = {};
|
|
17
|
-
if (anonKey) {
|
|
18
|
-
headers['Authorization'] = `Bearer ${anonKey}`;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const response = await fetch(`${supabaseUrl}/functions/v1/list`, {
|
|
22
|
-
headers,
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
if (!response.ok) {
|
|
26
|
-
throw new Error(`Error fetching games: ${response.statusText}`);
|
|
27
|
-
}
|
|
28
|
-
const data = await response.json();
|
|
29
|
-
if (data && data.games && data.games.length > 0) {
|
|
30
|
-
this._games = data.games.map((game: GameEntry) => ({
|
|
31
|
-
id: game.id,
|
|
32
|
-
name: game.name,
|
|
33
|
-
url: game.url,
|
|
34
|
-
}));
|
|
35
|
-
} else {
|
|
36
|
-
this._games = [{ id: 'empty', name: 'Not found', url: '' }];
|
|
37
|
-
}
|
|
38
|
-
} catch (error) {
|
|
39
|
-
console.error(error);
|
|
40
|
-
this._games = [{ id: 'error', name: 'Error', url: '' }];
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
get games(): readonly GameEntry[] {
|
|
45
|
-
return Object.freeze(this._games);
|
|
46
|
-
}
|
|
47
|
-
}
|