Skip to content

Commit

Permalink
Implement scene rework
Browse files Browse the repository at this point in the history
  • Loading branch information
NouCake committed Feb 12, 2024
1 parent 78a3509 commit 69ada2c
Show file tree
Hide file tree
Showing 13 changed files with 230 additions and 155 deletions.
40 changes: 32 additions & 8 deletions src/scene-switcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { PacketType, SceneChangePacket, SceneReadyPacket } from "./types/client"

let switcher: any[] = []
export const SceneSwitcher = {
waitForPlayers: (aznopoly: AzNopolyGame, sceneKey: string, callback: () => void) => {
waitForPlayers: (aznopoly: AzNopolyGame, sceneKey: string, launchMethod: "launch" | "start" | "wake", callback: () => void) => {
switcher.push(new SceneReadyListener(aznopoly, sceneKey, callback));
sendSceneChangePacket(aznopoly, sceneKey, false);
sendSceneChangePacket(aznopoly, sceneKey.split("_")[0], launchMethod);
},
updateScene: sendSceneReadyPacket,
broadcastSceneReady: sendSceneReadyPacket,
listen: listenForSceneSwitch,
}

Expand All @@ -24,6 +24,8 @@ class SceneReadyListener {
private listener?: EventListener;
private readyList: Set<string> = new Set();

private id = Math.random();

constructor(aznopoly: AzNopolyGame, sceneName: string, callback: () => void) {
this.aznopoly = aznopoly;
this.sceneName = sceneName;
Expand All @@ -37,13 +39,15 @@ class SceneReadyListener {
this.readyList.add(packet.detail.sender);
if (this.readyList.size == this.aznopoly.room.connectedPlayerIds.length) {
this.callback();
console.log("Removing listener", this.id)
this.aznopoly.client.removeEventListener(PacketType.SCEEN_READY, this.listener!);
switcher = switcher.filter((listener) => listener != this);
}
}
}

private startListening() {
console.log("Starting listener", this.id)
this.listener = this.sceneReadyListener.bind(this) as EventListener;
this.aznopoly.client.addEventListener(PacketType.SCEEN_READY, this.listener);
}
Expand All @@ -68,32 +72,52 @@ function sendSceneReadyPacket(aznopoly: AzNopolyGame, sceneName: string) {
}
}

function sendSceneChangePacket(aznopoly: AzNopolyGame, sceneName: string, returnable: boolean) {
function sendSceneChangePacket(aznopoly: AzNopolyGame, sceneName: string, launchMethod: "start" | "launch" | "wake") {
const packet: SceneChangePacket = {
type: PacketType.SCENE_CHANGE,
sender: aznopoly.client.id,
data: {
scene: sceneName,
launchMethod: returnable ? "launch" : "start",
launchMethod,
}
}
console.log("Sending scene change packet", packet);
aznopoly.client.sendPacket(packet);
}

function listenForSceneSwitch(scene: Phaser.Scene, aznopoly: AzNopolyGame) {
const listener = aznopoly.addPacketListener(PacketType.SCENE_CHANGE, ((event: CustomEvent<SceneChangePacket>) => {
const id = Math.random();

console.log("Listening for scene switch", id, scene.scene.key)
const packetListener = aznopoly.addPacketListener(PacketType.SCENE_CHANGE, ((event: CustomEvent<SceneChangePacket>) => {
if (!scene.scene.isActive(scene.scene.key ) || scene.scene.isSleeping(scene.scene.key)) {
console.warn("Received scene change packet for inactive scene", id, scene.scene.key, scene.scene.isActive(scene.scene.key ), scene.scene.isSleeping(scene.scene.key ))
return;
}

const packet = event.detail
if (!aznopoly.isPlayerHost(packet.sender)) {
console.warn("Received scene change packet from non-host player");
return;
}

if (packet.data.launchMethod == "launch") {
console.log("Sleeping scene", id, scene.scene.key)
scene.scene.sleep();
scene.scene.launch(packet.data.scene, { returnScene: scene.scene.key});
} else {
} else if (packet.data.launchMethod == "wake") {
console.trace("Waking scene", id, scene, packet.data.scene)
scene.scene.stop();
scene.scene.wake(packet.data.scene);
} else if (packet.data.launchMethod == "start") {
console.log("Starting scene", id, packet.data.scene)
scene.scene.start(packet.data.scene);
} else {
console.error("Unknown launch method", packet.data.launchMethod);
}
}) as EventListener);
scene.events.once(Phaser.Scenes.Events.SHUTDOWN, () => aznopoly.removePacketListener(PacketType.SCENE_CHANGE, listener));
scene.events.once(Phaser.Scenes.Events.SHUTDOWN, () => {
console.log("Removing scene switch listener", id)
aznopoly.removePacketListener(PacketType.SCENE_CHANGE, packetListener)
});
}
2 changes: 1 addition & 1 deletion src/scene/base/base-scene-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default abstract class NetworkSceneController {
constructor(scene: Phaser.Scene, aznopoly: AzNopolyGame) {
this.scene = scene;
this.aznopoly = aznopoly;
this.packetType = "CLIENT_MINIGAME_" + this.constructor.name.toUpperCase();
this.packetType = "CLIENT_" + this.constructor.name.toUpperCase();

scene.events.once(Phaser.Scenes.Events.CREATE, () => {
this.registerPacketListener();
Expand Down
12 changes: 7 additions & 5 deletions src/scene/base/minigame-scene-controller.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import AzNopolyGame from "../../game";
import { SceneSwitcher } from "../../scene-switcher";
import MinigameScene from "./minigame-scene";
import SyncedSceneController from "./synced-scene-controller";


const RESULT_DISPLAY_TIME = 2000;
export default abstract class MinigameSceneController extends SyncedSceneController {

declare protected scene: MinigameScene<MinigameSceneController>;
private previousScene: string;

constructor(scene: Phaser.Scene, aznopoly: AzNopolyGame, /*previousScene: string */) {
super(scene, aznopoly);
super(scene, aznopoly, "launch");
this.previousScene = "game";

this.registerSyncedMethod(this.showReady, true);
Expand Down Expand Up @@ -37,14 +38,15 @@ export default abstract class MinigameSceneController extends SyncedSceneControl

protected endGame(playerWon: string[], sorted: boolean) {
this.scene.showResultOverlay(playerWon);
setTimeout(() => {
this.onGameOver();
}, 3000);
setTimeout(() => this.onGameOver(), RESULT_DISPLAY_TIME);
}

abstract onMiniGameStart() : void;

private onGameOver() {
if (!this.aznopoly.isHost) {
return;
}
this.scene.scene.stop();
this.scene.scene.wake(this.previousScene);
}
Expand Down
20 changes: 10 additions & 10 deletions src/scene/base/minigame-scene.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const START_TIME = 500;
export default abstract class MinigameScene<T extends MinigameSceneController> extends BaseScene<T> {

private overlay!: Phaser.GameObjects.Image;
private waitingForPlayersText!: Phaser.GameObjects.Text;
private centerText!: Phaser.GameObjects.Text;

private startTimer = 0;

Expand All @@ -24,9 +24,9 @@ export default abstract class MinigameScene<T extends MinigameSceneController> e
this.overlay.setDepth(1000);
this.overlay.setVisible(false);

this.waitingForPlayersText = this.add.text(WIDTH/2, HEIGHT/2, 'Waiting for players...', FONT_STYLE_HEADLINE);
this.waitingForPlayersText.setOrigin(0.5, 0.5);
this.waitingForPlayersText.setDepth(1000);
this.centerText = this.add.text(WIDTH/2, HEIGHT/2, 'Waiting for players...', FONT_STYLE_HEADLINE);
this.centerText.setOrigin(0.5, 0.5);
this.centerText.setDepth(1000);
}

update(time: number, delta: number) {
Expand All @@ -45,7 +45,7 @@ export default abstract class MinigameScene<T extends MinigameSceneController> e
public showReadyOverlay() {
this.overlay.setTexture('minigame_ready');
this.overlay.setVisible(true);
this.waitingForPlayersText.setVisible(false);
this.centerText.setVisible(false);
}

public showStartOverlay() {
Expand All @@ -61,15 +61,15 @@ export default abstract class MinigameScene<T extends MinigameSceneController> e

public showResultOverlay(playerWon: string[]) {
const won = playerWon.includes(this.aznopoly.uuid);
console.log("showResultOverlay", won);
this.overlay.setVisible(false);
this.overlay.alpha = 1;
this.overlay.scale = 1;
this.overlay.y -= 100;

const names = playerWon.map(uuid => this.aznopoly.room.getPlayerName(uuid) + " won");
this.centerText.setText(names.join("\n"))
this.centerText.setVisible(true);

const names = playerWon.map(uuid => this.aznopoly.room.getPlayerName(uuid) + "won");
this.waitingForPlayersText.setText(names.join("\n"))
this.waitingForPlayersText.setVisible(true);

if (won) {
this.showGameWon();
} else {
Expand Down
31 changes: 26 additions & 5 deletions src/scene/base/synced-scene-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,52 @@ import NetworkSceneController from "./base-scene-controller";

export default abstract class SyncedSceneController extends NetworkSceneController {

constructor(scene: Phaser.Scene, aznopoly: AzNopolyGame) {
private launchMethod: "launch" | "start" | "wake";

constructor(scene: Phaser.Scene, aznopoly: AzNopolyGame, launchMethod: "launch" | "start" | "wake") {
super(scene, aznopoly);
this.launchMethod = launchMethod;

this.registerSyncedMethod(this.onAllPlayersReady, true);
this.registerSyncedMethod(this.onAllPlayersWake, true);
SceneSwitcher.listen(scene, aznopoly)

const listener = this.onSceneWake.bind(this);
scene.events.on(Phaser.Scenes.Events.WAKE, listener);
scene.events.once(Phaser.Scenes.Events.SHUTDOWN, () => scene.events.off(Phaser.Scenes.Events.WAKE, listener));
}

onSceneCreate(): void {
this.updateSceneSwitcher();
if (this.aznopoly.isHost) {
SceneSwitcher.waitForPlayers(this.aznopoly, this.scene.scene.key + "_CREATE", this.launchMethod, this.onAllPlayersJoined.bind(this));
}
SceneSwitcher.broadcastSceneReady(this.aznopoly, this.scene.scene.key + "_CREATE")
}

private updateSceneSwitcher() {
onSceneWake(): void {
if (this.aznopoly.isHost) {
SceneSwitcher.waitForPlayers(this.aznopoly, this.scene.scene.key, this.onAllPlayersJoined.bind(this));
SceneSwitcher.waitForPlayers(this.aznopoly, this.scene.scene.key + "_WAKE", "wake", this.onAllPlayersRejoined.bind(this));
}
SceneSwitcher.updateScene(this.aznopoly, this.scene.scene.key)
SceneSwitcher.broadcastSceneReady(this.aznopoly, this.scene.scene.key + "_WAKE")
}

/**
* Will be called after all the host as acknowledged that that all players have joined the scene
*/
abstract onAllPlayersReady(): void;
/**
* Will be called after all the host as acknowledged that that all players have waked the scene and is ready
*/
onAllPlayersWake(): void {

}

private onAllPlayersJoined() {
this.syncProxy.onAllPlayersReady();
}

private onAllPlayersRejoined() {
this.syncProxy.onAllPlayersWake();
}

}
12 changes: 4 additions & 8 deletions src/scene/board-scene-controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import AzNopolyGame from "../game";
import { SceneSwitcher } from "../scene-switcher";
import SyncedSceneController from "./base/synced-scene-controller";
import BoardScene from "./board-scene";

Expand All @@ -17,7 +18,7 @@ export default class BoardSceneController extends SyncedSceneController {
private players!: Player[];

constructor(scene: BoardScene, aznopoly: AzNopolyGame) {
super(scene, aznopoly);
super(scene, aznopoly, "start");

this.registerSyncedMethod(this.addPlayersToBoard, true);
this.registerSyncedMethod(this.updatePlayerPosition, true);
Expand All @@ -38,7 +39,6 @@ export default class BoardSceneController extends SyncedSceneController {
this.syncProxy.addPlayersToBoard(players);
this.syncProxy.startTurn(players[0].uuid);
}

}

private addPlayersToBoard(players: Player[]) {
Expand Down Expand Up @@ -87,17 +87,13 @@ export default class BoardSceneController extends SyncedSceneController {
const nextIndex = (currentIndex + 1) % this.players.length;
const nextPlayer = this.players[nextIndex];

this.syncProxy.startTurn(nextPlayer.uuid);

if (nextIndex == 0) {
this.syncProxy.startMinigame();
} else {
this.syncProxy.startTurn(nextPlayer.uuid);
}
}

private onMinigameResult() {

}

private startMinigame() {
this.scene.showMinigameSelect("Roomba Outrage").then(() => {
setTimeout(() => {
Expand Down
1 change: 0 additions & 1 deletion src/scene/board-scene.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import GameBoard from "../board/board";
import { HEIGHT, WIDTH } from "../main";
import { FONT_STYLE_BODY } from "../style";
import { GameTurnRollPacket, GameTurnStartPacket, PacketType } from "../types/client";
import { AzNopolyButton } from "../ui/button";
import PlayerList from "../ui/player-list";
import RandomSelectionWheel from "../ui/random-selection-wheel";
Expand Down
53 changes: 34 additions & 19 deletions src/scene/minigame/roomba-scene-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default class RoombaSceneController extends MinigameSceneController {

private locked = false;

private colorUuuidMap = new Map<number, string>();
private colorUuuidMap = new Map<string, string>();

constructor(scene: RoombaScene, aznopoly: AzNopolyGame) {
super(scene, aznopoly);
Expand All @@ -29,36 +29,39 @@ export default class RoombaSceneController extends MinigameSceneController {
}

onMiniGameStart(): void {
this.scene.events.on("roomba-dragged", ({id, offset} : {id: string, offset: Phaser.Math.Vector2}) => {
if (this.locked) return;

this.syncProxy.updateRoombaDirection(id, offset);
});
this.scene.events.on("roomba-dragged", this.onRoombaDragged.bind(this));

if (!this.aznopoly.isHost) {
return;
}
const roombaConfigs = [];
for (let j = 0; j < this.aznopoly.connectedUuids.length; j++) {
const uuid = this.aznopoly.connectedUuids[j] ;
for (let i = 0; i < 5; i++) {
roombaConfigs.push(this.generateRandomRoombaConfig(uuid));
}
this.colorUuuidMap.set(roombaConfigs[roombaConfigs.length-1].color, uuid);
}

const roombaConfigs = this.generateRoombaConfigs();
this.syncProxy.initRoombas(roombaConfigs);

setTimeout(() => {
this.syncProxy.lockAllGameplay();

const array = this.scene.getAAAAA();
Object.keys(array).map((key) => {
console.log(this.colorUuuidMap.get(array[key]));
});
this.syncProxy.endGame([], false);
const won = this.getPlayersWon();
this.syncProxy.endGame(won, false);
}, MAX_GAME_TIME)
}

private getPlayersWon() {
const paintMap = this.scene.getPaintMap();
const paintedColors = Object.keys(paintMap).filter(e => e != "000000");

const won = paintedColors.sort()
.map((key) => this.colorUuuidMap.get(key)!)
.slice(0, 1);

return won;
}

private onRoombaDragged({ id, offset}: {id: string, offset: Phaser.Math.Vector2}) {
if (this.locked) return;
this.syncProxy.updateRoombaDirection(id, offset);
}

private updateRoombaDirection(id: string, direction: Phaser.Math.Vector2) {
this.scene.updateRoombaDirection(id, new Phaser.Math.Vector2(direction.x, direction.y));
}
Expand All @@ -72,6 +75,18 @@ export default class RoombaSceneController extends MinigameSceneController {
this.scene.stopRoombas();
}

private generateRoombaConfigs() {
const roombaConfigs = [];
for (let j = 0; j < this.aznopoly.connectedUuids.length; j++) {
const uuid = this.aznopoly.connectedUuids[j] ;
for (let i = 0; i < 5; i++) {
roombaConfigs.push(this.generateRandomRoombaConfig(uuid));
}
this.colorUuuidMap.set(roombaConfigs[roombaConfigs.length-1].paintColor.toString(16).toUpperCase(), uuid);
}
return roombaConfigs;
}

private generateRandomRoombaConfig(playerid: string) {
const x = Math.random() * (GAME_WIDTH - Roomba.SIZE * 2) + Roomba.SIZE;
const y = Math.random() * (GAME_HEIGHT - Roomba.SIZE * 2) + Roomba.SIZE;
Expand Down
Loading

0 comments on commit 69ada2c

Please sign in to comment.