-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #19 from Abstractolotl/minigame/clicker-race
Clicker Race Minigame
- Loading branch information
Showing
9 changed files
with
385 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import {COLOR_CONTRAST, COLOR_PRIMARY, FONT_STYLE_BUTTON} from "@/style.ts"; | ||
|
||
export class AzNopolySlider extends Phaser.GameObjects.Container { | ||
|
||
public static preload(scene: Phaser.Scene) { | ||
} | ||
|
||
private max: number; | ||
private value = 10; | ||
private graphic!: Phaser.GameObjects.Graphics; | ||
|
||
private disabled = false; | ||
private dragging = false; | ||
|
||
private onChange: (value: number) => void; | ||
|
||
constructor(scene: Phaser.Scene, x: number, y: number, width: number, height: number, max: number, onChange: (value: number) => void) { | ||
super(scene, x + width/2, y + height/2); | ||
|
||
this.height = height; | ||
this.width = width; | ||
|
||
this.max = max | ||
this.onChange = onChange; | ||
|
||
this.graphic = new Phaser.GameObjects.Graphics(scene); | ||
|
||
// background | ||
this.graphic.fillStyle(COLOR_PRIMARY); | ||
this.graphic.fillRect(-width/2, -height/2, width, height); | ||
|
||
// fill | ||
this.graphic.fillStyle(COLOR_CONTRAST); | ||
this.graphic.fillRect(-width/2 + 5, -height/2 + 5, this.value * (width / this.max) -10, height - 10); | ||
|
||
const text = new Phaser.GameObjects.Text(scene, 0, 0, "Refill", FONT_STYLE_BUTTON); | ||
text.setOrigin(0.5, 0.5); | ||
|
||
this.add(this.graphic); | ||
this.add(text); | ||
|
||
this.setSize(width, height); | ||
|
||
this.initDrag() | ||
} | ||
|
||
preUpdate(time: number, delta: number) { | ||
this.graphic.clear() | ||
|
||
this.graphic.fillStyle(COLOR_PRIMARY); | ||
this.graphic.fillRect(-this.width/2, -this.height/2, this.width, this.height); | ||
|
||
// fill | ||
this.graphic.fillStyle(COLOR_CONTRAST); | ||
this.graphic.fillRect(-this.width/2 + 5, -this.height/2 + 5, this.value * (this.width / this.max) -10, this.height - 10); | ||
|
||
} | ||
|
||
reset(){ | ||
this.value = 10; | ||
} | ||
|
||
public changeMax(max: number){ | ||
this.max = max; | ||
} | ||
|
||
public getMax(){ | ||
return this.max; | ||
} | ||
|
||
public disable(){ | ||
this.value = 10; | ||
this.disabled = true; | ||
this.dragging = false; | ||
} | ||
|
||
public enable() { | ||
this.disabled = false; | ||
} | ||
|
||
private initDrag() { | ||
this.setInteractive({ | ||
hitArea: new Phaser.Geom.Rectangle(0, 0, this.height, this.width), | ||
hitAreaCallback: Phaser.Geom.Rectangle.Contains, | ||
useHandCursor: true, | ||
draggable: true | ||
}, Phaser.Geom.Rectangle.Contains); | ||
|
||
this.on('dragstart', (event: any) => { | ||
if (this.disabled) return; | ||
|
||
this.dragging = true; | ||
}); | ||
|
||
this.on('drag', (event: any) => { | ||
if (this.disabled) return; | ||
if (!this.dragging) return; | ||
|
||
const dragOffset = new Phaser.Math.Vector2((event.x * 1.5) - this.x, event.y - this.y); | ||
this.value = Math.max(10, Math.min(this.max, dragOffset.x / (this.width - 10) * this.max)); | ||
|
||
this.onChange(this.value); | ||
if (this.value === this.max) { | ||
this.dragging = false; | ||
} | ||
}); | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
82 changes: 82 additions & 0 deletions
82
src/phaser/scenes/minigame/clicker-race-scene-controller.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import MinigameSceneController, {ResultData} from "@/phaser/scenes/base/minigame-scene-controller.ts"; | ||
import ClickerRaceScene from "@/phaser/scenes/minigame/clicker-race-scene.ts"; | ||
import AzNopolyGame from "@/game.ts"; | ||
|
||
const GAME_TIME = 20000; | ||
|
||
export default class ClickerRaceSceneController extends MinigameSceneController { | ||
|
||
declare protected scene: ClickerRaceScene; | ||
private schedule: NodeJS.Timeout | null = null; | ||
|
||
constructor(scene: ClickerRaceScene, aznopoly: AzNopolyGame) { | ||
super(scene, aznopoly); | ||
|
||
this.registerSyncedProp("scene"); | ||
this.registerSyncedMethod(this.scene.initPlayer, true); | ||
this.registerSyncedMethod(this.scene.movePlayer, true); | ||
this.registerSyncedMethod(this.scene.stopAllPlayers, true); | ||
this.registerSyncedMethod(this.scene.startTimeBar, true); | ||
|
||
this.registerSyncedMethod(this.requestPlayerMove, false); | ||
this.registerSyncedMethod(this.finishedGame, false) | ||
} | ||
|
||
onMiniGameStart(): void { | ||
if (!this.aznopoly.isHost) { | ||
return; | ||
} | ||
|
||
this.aznopoly.connectedUuids.forEach((uuid, index) => { | ||
this.syncProxy.scene.initPlayer(uuid, index); | ||
}) | ||
this.syncProxy.scene.startTimeBar(); | ||
|
||
this.schedule = setTimeout(() => { | ||
this.syncProxy.scene.stopAllPlayers() | ||
|
||
const scores = this.scene.getScore(); | ||
const result: ResultData = { | ||
playerWon: Object.keys(scores).sort().slice(0, 1), | ||
sorted: false | ||
} | ||
|
||
this.endGame(result); | ||
}, GAME_TIME); | ||
} | ||
|
||
public finishedGame() { | ||
if (!this.aznopoly.isHost) { | ||
return; | ||
} | ||
|
||
clearTimeout(this.schedule!); | ||
|
||
const scores = this.scene.getScore(); | ||
const result: ResultData = { | ||
playerWon: Object.keys(scores).sort().slice(0, 1), | ||
sorted: false | ||
} | ||
|
||
this.endGame(result); | ||
} | ||
|
||
public requestPlayerMove(uuid: string) { | ||
if (!this.aznopoly.isHost) { | ||
return; | ||
} | ||
|
||
this.syncProxy.scene.movePlayer(uuid); | ||
|
||
} | ||
|
||
public onPlayerClick(uuid: string) { | ||
this.syncProxy.requestPlayerMove(uuid); | ||
this.scene.randomInput() | ||
} | ||
|
||
public onPlayerFinished() { | ||
this.syncProxy.finishedGame(); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
import MinigameScene from "@/phaser/scenes/base/minigame-scene.ts"; | ||
import ClickerRaceSceneController from "@/phaser/scenes/minigame/clicker-race-scene-controller.ts"; | ||
import {TimeBar} from "@/phaser/components/ui/time-bar.ts"; | ||
import AzNopolyAvatar from "@/phaser/components/ui/avatar.ts"; | ||
import AzNopolyBar from "@/phaser/components/ui/bar.ts"; | ||
import AzNopolyPanel from "@/phaser/components/ui/panel.ts"; | ||
import {FRAME_PADDING} from "@/style.ts"; | ||
import Racer from "@/phaser/scenes/minigame/clicker-racer/racer.ts"; | ||
import {AzNopolyButton} from "@/phaser/components/ui/button.ts"; | ||
import {AzNopolySlider} from "@/phaser/components/ui/range-slider.ts"; | ||
|
||
const ACTION_BOUNDS = { | ||
width: 500, | ||
height: 80 | ||
} | ||
|
||
const PLAYER_SIZE = 50; | ||
|
||
const gameBounds = MinigameScene.getGameBounds(); | ||
const rightBounds = MinigameScene.getRightBounds(); | ||
|
||
export default class ClickerRaceScene extends MinigameScene<ClickerRaceSceneController> { | ||
|
||
private button!: AzNopolyButton; | ||
private slider!: AzNopolySlider; | ||
private bar!: TimeBar; | ||
|
||
private racers: { [uuid: string]: Racer } = {}; | ||
|
||
preload() { | ||
super.preload(); | ||
AzNopolyAvatar.preload(this); | ||
} | ||
|
||
init() { | ||
this.controller = new ClickerRaceSceneController(this, this.aznopoly); | ||
} | ||
|
||
create() { | ||
super.create(); | ||
} | ||
|
||
update(time: number, delta: number) { | ||
super.update(time, delta); | ||
} | ||
|
||
stopAllPlayers() { | ||
Object.values(this.racers).forEach(racer => { | ||
racer.stop(); | ||
}); | ||
this.button.disable(); | ||
} | ||
|
||
getScore() { | ||
const scores: {[key: string]: number} = {}; | ||
|
||
this.aznopoly.connectedUuids.forEach((uuid, index) => { | ||
scores[uuid] = this.racers[uuid].getProgress() | ||
}); | ||
|
||
return scores; | ||
} | ||
|
||
public initPlayer(uuid: string, position: number) { | ||
let trackWidth = gameBounds.width + rightBounds.width - FRAME_PADDING - PLAYER_SIZE; | ||
|
||
const profile = this.aznopoly.getProfile(uuid); | ||
const avatar = new Racer(this, gameBounds.x + FRAME_PADDING, gameBounds.y + FRAME_PADDING + (PLAYER_SIZE + FRAME_PADDING) * position, profile, trackWidth + (PLAYER_SIZE / 2)); | ||
|
||
this.add.rectangle(avatar.x + (PLAYER_SIZE / 2), avatar.y + (PLAYER_SIZE / 2), trackWidth, 5, 0x000000, 0.5).setOrigin(0, 0) | ||
this.add.existing(avatar); | ||
|
||
this.racers[uuid] = avatar; | ||
} | ||
|
||
public movePlayer(uuid: string) { | ||
if (this.racers[uuid]) { | ||
this.racers[uuid].move(() => { | ||
this.controller.onPlayerFinished() | ||
}); | ||
} | ||
} | ||
|
||
public startTimeBar() { | ||
this.bar.resume(); | ||
} | ||
|
||
public randomInput() { | ||
if (Math.random() > 0.5) { | ||
this.button.setVisible(true) | ||
this.button.enable() | ||
this.slider.disable() | ||
this.slider.setVisible(false) | ||
} else { | ||
this.button.disable() | ||
this.button.setVisible(false) | ||
this.slider.setVisible(true) | ||
this.slider.enable() | ||
this.slider.changeMax(100 + Math.random() * 100) | ||
} | ||
} | ||
|
||
protected drawSceneLayout() { | ||
this.add.existing(new AzNopolyBar(this, "Clicker Race")) | ||
|
||
const gamePanel = new AzNopolyPanel(this, gameBounds.x, gameBounds.y, (gameBounds.width + rightBounds.width + FRAME_PADDING), gameBounds.height); | ||
this.add.existing(gamePanel); | ||
|
||
const actionPanel = new AzNopolyPanel(this, gamePanel.width / 2 - (ACTION_BOUNDS.width / 2), (gameBounds.y / 2) + gameBounds.height - ACTION_BOUNDS.height, ACTION_BOUNDS.width, ACTION_BOUNDS.height) | ||
this.add.existing(actionPanel) | ||
|
||
this.button = new AzNopolyButton(this, "Race", actionPanel.x + (FRAME_PADDING * 3), actionPanel.y + FRAME_PADDING, actionPanel.width - (FRAME_PADDING * 6)); | ||
this.slider = new AzNopolySlider(this, actionPanel.x + (FRAME_PADDING * 3), actionPanel.y + FRAME_PADDING, actionPanel.width - (FRAME_PADDING * 6), 50, 100, this.onSlider.bind(this)) | ||
this.button.setOnClick(() => { | ||
this.controller.onPlayerClick(this.aznopoly.uuid); | ||
}); | ||
|
||
this.add.existing(this.slider); | ||
this.add.existing(this.button); | ||
|
||
this.bar = new TimeBar(this, actionPanel.x, actionPanel.y - (FRAME_PADDING * 3), ACTION_BOUNDS.width, 25, 20000); | ||
this.bar.pause() | ||
this.add.existing(this.bar); | ||
|
||
this.randomInput() | ||
} | ||
|
||
private onSlider(value: number) { | ||
if (value === this.slider.getMax()) { | ||
this.controller.onPlayerClick(this.aznopoly.uuid); | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.