Skip to content

Commit f204c54

Browse files
authored
Game: Refactor Game Simulator (source-academy#2836)
* Move Game Simulator subcomponent files to respective directories * Refactor AssetViewer * Refactor ChapterPublisher * Refactor ChapterSimulator * Refactor GameSimulator and Remove GameSimulatorGame * Consolidate Types to GameSimulatorTypes * Consolidate Utils to GameSimulatorUtils * Refactor features/gameSimulator * Move GameSimulatorAssets into GameSimulatorConstants * Apply React.FC Type
1 parent 34952d1 commit f204c54

20 files changed

+472
-474
lines changed

src/features/game/SourceAcademyGame.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import RoomPreview from 'src/features/game/scenes/roomPreview/RoomPreview';
1313
import Settings from 'src/features/game/scenes/settings/Settings';
1414
import GameSoundManager from 'src/features/game/sound/GameSoundManager';
1515
import { mandatory } from 'src/features/game/utils/GameUtils';
16-
import { GameSimState } from 'src/features/gameSimulator/GameSimulatorTypes';
16+
import { GameSimulatorState } from 'src/features/gameSimulator/GameSimulatorTypes';
1717

1818
import { AchievementGoal, AchievementItem } from '../achievement/AchievementTypes';
1919
import { fetchGameChapters } from './chapter/GameChapterHelpers';
@@ -123,7 +123,7 @@ export default class SourceAcademyGame extends Phaser.Game {
123123
this.global.roomCode = await getRoomPreviewCode();
124124
}
125125

126-
public setGameSimState(state: GameSimState) {
126+
public setGameSimState(state: GameSimulatorState) {
127127
this.global.setGameSimState(state);
128128
}
129129

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import * as Phaser from 'phaser';
2+
import { AssetMap, AssetType, ImageAsset } from 'src/features/game/assets/AssetsTypes';
3+
import FontAssets from 'src/features/game/assets/FontAssets';
4+
import { screenSize } from 'src/features/game/commons/CommonConstants';
5+
import { BitmapFontStyle } from 'src/features/game/commons/CommonTypes';
6+
7+
import { dateOneYearFromNow } from './GameSimulatorUtils';
8+
9+
export const gameSimulatorConfig = {
10+
debug: true,
11+
type: Phaser.CANVAS,
12+
width: screenSize.x,
13+
height: screenSize.y,
14+
physics: {
15+
default: 'arcade'
16+
},
17+
scale: {
18+
mode: Phaser.Scale.FIT,
19+
parent: 'game-display'
20+
},
21+
fps: {
22+
target: 24
23+
}
24+
};
25+
26+
export const gameSimulatorMenuAssets: AssetMap<ImageAsset> = {
27+
gameSimBg: {
28+
type: AssetType.Image,
29+
key: 'student-room',
30+
path: '/locations/deathCube_ext/shields-down.png'
31+
},
32+
shortButton: { type: AssetType.Image, key: 'short-button', path: '/ui/shortButton.png' },
33+
invertedButton: {
34+
type: AssetType.Image,
35+
key: 'inverted-button',
36+
path: '/ui/invertedColorButton.png'
37+
},
38+
blueUnderlay: { type: AssetType.Image, key: 'blue-underlay', path: '/ui/blueUnderlay.png' },
39+
topButton: { type: AssetType.Image, key: 'top-button', path: '/ui/topButton.png' },
40+
colorIcon: { type: AssetType.Image, key: 'color-icon', path: '/ui/colorIcon.png' },
41+
imageIcon: { type: AssetType.Image, key: 'image-icon', path: '/ui/imageIcon.png' },
42+
bboxIcon: { type: AssetType.Image, key: 'bbox-icon', path: '/ui/bboxIcon.png' },
43+
handIcon: { type: AssetType.Image, key: 'hand-icon', path: '/ui/handIcon.png' },
44+
listIcon: { type: AssetType.Image, key: 'list-icon', path: '/ui/listIcon.png' },
45+
eraseIcon: { type: AssetType.Image, key: 'erase-icon', path: '/ui/eraserIcon.png' },
46+
iconBg: { type: AssetType.Image, key: 'icon-bg', path: '/ui/modeIconBg.png' }
47+
};
48+
49+
export const gameSimulatorMenuOptStyle: BitmapFontStyle = {
50+
key: FontAssets.zektonDarkFont.key,
51+
size: 35,
52+
align: Phaser.GameObjects.BitmapText.ALIGN_CENTER
53+
};
54+
55+
export const gameSimulatorMenuConstants = {
56+
maxOptButtonsRow: 2,
57+
optButton: { xSpace: screenSize.x * 0.9, ySpace: screenSize.y * 0.5 },
58+
gameTxtStorageName: {
59+
defaultChapter: 'defaultChapter',
60+
checkpointTxt: 'checkpointTxt'
61+
}
62+
};
63+
64+
export const defaultChapter = {
65+
id: -1,
66+
title: '',
67+
imageUrl: '/locations/spaceshipBackground.png',
68+
openAt: new Date().toISOString(),
69+
closeAt: dateOneYearFromNow(new Date()).toISOString(),
70+
isPublished: false,
71+
filenames: []
72+
};

src/features/gameSimulator/scenes/MainMenu.ts renamed to src/features/gameSimulator/GameSimulatorMenu.ts

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,20 @@ import { createButton } from 'src/features/game/utils/ButtonUtils';
1111
import { mandatory, toS3Path } from 'src/features/game/utils/GameUtils';
1212
import { calcTableFormatPos } from 'src/features/game/utils/StyleUtils';
1313

14-
import SSImageAssets from '../assets/ImageAssets';
15-
import { GameSimState } from '../GameSimulatorTypes';
16-
import mainMenuConstants, { mainMenuOptStyle } from './MainMenuConstants';
14+
import {
15+
gameSimulatorMenuAssets,
16+
gameSimulatorMenuConstants,
17+
gameSimulatorMenuOptStyle
18+
} from './GameSimulatorConstants';
19+
import { GameSimulatorState } from './GameSimulatorTypes';
1720

1821
/**
1922
* Entry point for Game simulator.
2023
*
2124
* User can access different Game simulator
2225
* functionalities from here.
2326
*/
24-
class MainMenu extends Phaser.Scene {
27+
class GameSimulatorMenu extends Phaser.Scene {
2528
private layerManager?: GameLayerManager;
2629

2730
constructor() {
@@ -36,7 +39,7 @@ class MainMenu extends Phaser.Scene {
3639
Object.values(ImageAssets).forEach(asset =>
3740
this.load.image(asset.key, toS3Path(asset.path, false))
3841
);
39-
Object.values(SSImageAssets).forEach(asset =>
42+
Object.values(gameSimulatorMenuAssets).forEach(asset =>
4043
this.load.image(asset.key, toS3Path(asset.path, false))
4144
);
4245
Object.values(FontAssets).forEach(asset =>
@@ -60,9 +63,9 @@ class MainMenu extends Phaser.Scene {
6063

6164
const buttonPositions = calcTableFormatPos({
6265
numOfItems: buttons.length,
63-
maxXSpace: mainMenuConstants.optButton.xSpace,
64-
maxYSpace: mainMenuConstants.optButton.ySpace,
65-
numItemLimit: mainMenuConstants.maxOptButtonsRow,
66+
maxXSpace: gameSimulatorMenuConstants.optButton.xSpace,
67+
maxYSpace: gameSimulatorMenuConstants.optButton.ySpace,
68+
numItemLimit: gameSimulatorMenuConstants.maxOptButtonsRow,
6669
redistributeLast: true
6770
});
6871

@@ -82,41 +85,41 @@ class MainMenu extends Phaser.Scene {
8285
private getOptionButtons() {
8386
return [
8487
{
85-
text: 'Checkpoint Simulator',
88+
text: 'Simulate Chapters',
8689
callback: () => {
87-
SourceAcademyGame.getInstance().setGameSimState(GameSimState.CheckpointSim);
90+
SourceAcademyGame.getInstance().setGameSimState(GameSimulatorState.CHAPTERSIMULATOR);
8891
}
8992
},
9093
{
91-
text: 'Asset Uploader',
94+
text: 'Publish / Edit Chapters',
9295
callback: () => {
93-
SourceAcademyGame.getInstance().setGameSimState(GameSimState.AssetUploader);
96+
SourceAcademyGame.getInstance().setGameSimState(GameSimulatorState.CHAPTERPUBLISHER);
9497
}
9598
},
9699
{
97-
text: 'Chapter Simulator',
100+
text: 'View / Upload Assets',
98101
callback: () => {
99-
SourceAcademyGame.getInstance().setGameSimState(GameSimState.ChapterSim);
102+
SourceAcademyGame.getInstance().setGameSimState(GameSimulatorState.ASSETVIEWER);
100103
}
101104
}
102105
];
103106
}
104107

105108
private createOptButton(text: string, xPos: number, yPos: number, callback: any) {
106109
return createButton(this, {
107-
assetKey: SSImageAssets.invertedButton.key,
110+
assetKey: gameSimulatorMenuAssets.invertedButton.key,
108111
message: text,
109112
textConfig: { x: 0, y: 0, oriX: 0.5, oriY: 0.5 },
110-
bitMapTextStyle: mainMenuOptStyle,
113+
bitMapTextStyle: gameSimulatorMenuOptStyle,
111114
onUp: callback
112115
}).setPosition(xPos, yPos);
113116
}
114117

115118
public simulateCheckpoint() {
116119
const defaultChapterText =
117-
sessionStorage.getItem(mainMenuConstants.gameTxtStorageName.defaultChapter) || '';
120+
sessionStorage.getItem(gameSimulatorMenuConstants.gameTxtStorageName.defaultChapter) || '';
118121
const checkpointTxt =
119-
sessionStorage.getItem(mainMenuConstants.gameTxtStorageName.checkpointTxt) || '';
122+
sessionStorage.getItem(gameSimulatorMenuConstants.gameTxtStorageName.checkpointTxt) || '';
120123
if (defaultChapterText === '' && checkpointTxt === '') {
121124
return;
122125
}
@@ -141,19 +144,19 @@ class MainMenu extends Phaser.Scene {
141144
this,
142145
screenCenter.x,
143146
screenCenter.y,
144-
SSImageAssets.gameSimBg.key
147+
gameSimulatorMenuAssets.gameSimBg.key
145148
);
146149
backgroundImg.setDisplaySize(screenSize.x, screenSize.y);
147150
const backgroundUnderlay = new Phaser.GameObjects.Image(
148151
this,
149152
screenCenter.x,
150153
screenCenter.y,
151-
SSImageAssets.blueUnderlay.key
154+
gameSimulatorMenuAssets.blueUnderlay.key
152155
).setAlpha(0.5);
153156
this.getLayerManager().addToLayer(Layer.Background, backgroundImg);
154157
this.getLayerManager().addToLayer(Layer.Background, backgroundUnderlay);
155158
}
156159
public getLayerManager = () => mandatory(this.layerManager);
157160
}
158161

159-
export default MainMenu;
162+
export default GameSimulatorMenu;
Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
export enum GameSimState {
2-
Default = 'Default',
3-
AssetUploader = 'AssetUploader',
4-
CheckpointSim = 'CheckpointSim',
5-
ChapterSim = 'ChapterSim'
1+
export enum GameSimulatorState {
2+
DEFAULT = 'DEFAULT',
3+
ASSETVIEWER = 'ASSETVIEWER',
4+
CHAPTERSIMULATOR = 'CHAPTERSIMULATOR',
5+
CHAPTERPUBLISHER = 'CHAPTERPUBLISHER'
66
}
77

88
export type ChapterDetail = {
@@ -14,3 +14,17 @@ export type ChapterDetail = {
1414
isPublished: boolean;
1515
imageUrl: string;
1616
};
17+
18+
export type ChapterSimProps = {
19+
chapterDetail: ChapterDetail;
20+
chapterFilenames?: string[];
21+
};
22+
23+
export type AssetProps = {
24+
assetPath: string;
25+
};
26+
27+
export type StorageProps = {
28+
storageName: string;
29+
s3TxtFiles: string[];
30+
};
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
export const createHeadersWithCors = (): Headers => {
2+
const headers = new Headers();
3+
headers.append('Access-Control-Allow-Origin', '*');
4+
return headers;
5+
};
6+
7+
export const loadFileLocally = (storageName: string, txtFile: File) => {
8+
const reader = new FileReader();
9+
reader.readAsText(txtFile);
10+
reader.onloadend = _ => {
11+
if (!reader.result) {
12+
return;
13+
}
14+
sessionStorage.setItem(storageName, reader.result.toString());
15+
};
16+
};
17+
18+
export const dateOneYearFromNow = (date: Date) => {
19+
date.setFullYear(date.getFullYear() + 1);
20+
return date;
21+
};

src/features/gameSimulator/assets/ImageAssets.ts

Lines changed: 0 additions & 26 deletions
This file was deleted.

src/features/gameSimulator/scenes/MainMenuConstants.ts

Lines changed: 0 additions & 20 deletions
This file was deleted.
Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,44 @@
11
import React from 'react';
22
import { useTypedSelector } from 'src/commons/utils/Hooks';
3-
import SourceAcademyGame, { AccountInfo } from 'src/features/game/SourceAcademyGame';
4-
import { GameSimState } from 'src/features/gameSimulator/GameSimulatorTypes';
3+
import CheckpointTransition from 'src/features/game/scenes/checkpointTransition/CheckpointTransition';
4+
import GameManager from 'src/features/game/scenes/gameManager/GameManager';
5+
import SourceAcademyGame, { AccountInfo, GameType } from 'src/features/game/SourceAcademyGame';
6+
import { gameSimulatorConfig } from 'src/features/gameSimulator/GameSimulatorConstants';
7+
import GameSimulatorMenu from 'src/features/gameSimulator/GameSimulatorMenu';
8+
import { GameSimulatorState } from 'src/features/gameSimulator/GameSimulatorTypes';
59

6-
import GameSimulatorAssetFileUploader from './subcomponents/GameSimulatorAssetFileUploader';
7-
import GameSimulatorAssetSelection from './subcomponents/GameSimulatorAssetSelection';
8-
import GameSimulatorChapterSim from './subcomponents/GameSimulatorChapterSim';
9-
import GameSimulatorCheckpointSim from './subcomponents/GameSimulatorCheckpointSim';
10-
import { createGameSimulatorGame } from './subcomponents/GameSimulatorGame';
10+
import AssetViewer from './subcomponents/assetViewer/AssetViewer';
11+
import ChapterPublisher from './subcomponents/chapterPublisher/ChapterPublisher';
12+
import ChapterSimulator from './subcomponents/chapterSimulator/ChapterSimulator';
1113

1214
/**
13-
* Game simulator main page
15+
* This component renders the Main Page of the Game Simulator.
1416
*
15-
* Displays the following elements:
17+
* It displays the following elements:
1618
* (1) Game Simulator phaser canvas
1719
* (2) Game Simulator control panel
1820
*
1921
* Game Simulator control panel's content can be altered using
20-
* `setGameSimState` function. This function is passed into story
21-
* simulator phaser game, so that the GameSimulatorMainMenu buttons
22+
* `setGameSimulatorState` function. This function is passed into story
23+
* simulator phaser game, so that the GameSimulatorMenu buttons
2224
* are able to control what is shown on the Game Simulator panel.
2325
*/
24-
function GameSimulator() {
26+
const GameSimulator: React.FC = () => {
2527
const session = useTypedSelector(state => state.session);
26-
const [gameSimState, setGameSimState] = React.useState<string>(GameSimState.Default);
28+
const [gameSimulatorState, setGameSimulatorState] = React.useState<string>(
29+
GameSimulatorState.DEFAULT
30+
);
31+
32+
const createGameSimulatorGame = () => {
33+
const game = new SourceAcademyGame(gameSimulatorConfig, GameType.Simulator);
34+
game.scene.add('GameSimulatorMenu', GameSimulatorMenu, true);
35+
game.scene.add('GameManager', GameManager);
36+
game.scene.add('CheckpointTransition', CheckpointTransition);
37+
return game;
38+
};
2739

2840
React.useEffect(() => {
29-
createGameSimulatorGame().setGameSimStateSetter(setGameSimState);
41+
createGameSimulatorGame().setGameSimStateSetter(setGameSimulatorState);
3042
}, []);
3143

3244
React.useEffect(() => {
@@ -42,20 +54,13 @@ function GameSimulator() {
4254
<div className="GameSimulatorWrapper">
4355
<div id="game-display" />
4456
<div className="LeftAlign GameSimulatorPanel">
45-
{gameSimState === GameSimState.Default && <h3>Welcome to Game simulator!</h3>}
46-
{gameSimState === GameSimState.CheckpointSim && <GameSimulatorCheckpointSim />}
47-
{gameSimState === GameSimState.AssetUploader && (
48-
<>
49-
<h3>Asset uploader</h3>
50-
<GameSimulatorAssetFileUploader />
51-
<h3>Asset Viewer</h3>
52-
<GameSimulatorAssetSelection />
53-
</>
54-
)}
55-
{gameSimState === GameSimState.ChapterSim && <GameSimulatorChapterSim />}
57+
{gameSimulatorState === GameSimulatorState.DEFAULT && <h3>Welcome to Game simulator!</h3>}
58+
{gameSimulatorState === GameSimulatorState.CHAPTERSIMULATOR && <ChapterSimulator />}
59+
{gameSimulatorState === GameSimulatorState.CHAPTERPUBLISHER && <ChapterPublisher />}
60+
{gameSimulatorState === GameSimulatorState.ASSETVIEWER && <AssetViewer />}
5661
</div>
5762
</div>
5863
);
59-
}
64+
};
6065

6166
export default GameSimulator;

0 commit comments

Comments
 (0)