<template> <div class="flex justify-center items-center h-dvh relative"> <GmTools v-if="gameStore.character?.role === 'gm'" /> <GmPanel v-if="gameStore.character?.role === 'gm'" /> <Game :config="gameConfig" @create="createGame"> <Scene name="main" @preload="preloadScene" @create="createScene"> <ZoneEditor v-if="isLoaded" :key="JSON.stringify(`${zoneEditorStore.zone?.id}_${zoneEditorStore.zone?.createdAt}_${zoneEditorStore.zone?.updatedAt}`)" /> </Scene> </Game> </div> </template> <script setup lang="ts"> import config from '@/config' import 'phaser' import { ref, onBeforeUnmount } from 'vue' import { Game, Scene } from 'phavuer' import { useGameStore } from '@/stores/gameStore' import { useZoneEditorStore } from '@/stores/zoneEditorStore' import GmTools from '@/components/gameMaster/GmTools.vue' import ZoneEditor from '@/components/gameMaster/zoneEditor/ZoneEditor.vue' import GmPanel from '@/components/gameMaster/GmPanel.vue' import { loadAssets } from '@/composables/zoneComposable' const gameStore = useGameStore() const zoneEditorStore = useZoneEditorStore() const isLoaded = ref(false) const gameConfig = { name: config.name, width: window.innerWidth, height: window.innerHeight, type: Phaser.AUTO, // AUTO, CANVAS, WEBGL, HEADLESS resolution: 5 } const createGame = (game: Phaser.Game) => { /** * Resize the game when the window is resized */ addEventListener('resize', () => { game.scale.resize(window.innerWidth, window.innerHeight) }) // We don't support canvas mode, only WebGL if (game.renderer.type === Phaser.CANVAS) { gameStore.addNotification({ title: 'Warning', message: 'Your browser does not support WebGL. Please use a modern browser like Chrome, Firefox, or Edge.' }) gameStore.disconnectSocket() } } const preloadScene = async (scene: Phaser.Scene) => { isLoaded.value = false /** * Create loading bar */ const width = scene.cameras.main.width const height = scene.cameras.main.height const progressBox = scene.add.graphics() const progressBar = scene.add.graphics() progressBox.fillStyle(0x222222, 0.8) progressBox.fillRect(width / 2 - 180, height / 2, 320, 50) const loadingText = scene.make.text({ x: width / 2, y: height / 2 - 50, text: 'Loading...', style: { font: '20px monospace', fill: '#ffffff' } }) loadingText.setOrigin(0.5, 0.5) scene.load.on(Phaser.Loader.Events.PROGRESS, function (value: any) { progressBar.clear() progressBar.fillStyle(0x368f8b, 1) progressBar.fillRect(width / 2 - 180 + 10, height / 2 + 10, 300 * value, 30) }) scene.load.on(Phaser.Loader.Events.COMPLETE, function () { progressBar.destroy() progressBox.destroy() loadingText.destroy() isLoaded.value = true }) /** * Load the base assets into the Phaser scene */ scene.load.image('BLOCK', '/assets/zone/bt_tile.png') scene.load.image('TELEPORT', '/assets/zone/tp_tile.png') scene.load.image('blank_tile', '/assets/zone/blank_tile.png') scene.load.image('waypoint', '/assets/waypoint.png') /** * Load the assets into the Phaser scene */ await loadAssets(scene) } const createScene = async (scene: Phaser.Scene) => { /** * Create sprite animations * This is done here because phaser forces us to */ gameStore.assets.forEach((asset) => { if (asset.group !== 'sprite_animations') return scene.anims.create({ key: asset.key, frameRate: 7, frames: scene.anims.generateFrameNumbers(asset.key, { start: 0, end: asset.frameCount! - 1 }), repeat: -1 }) }) } onBeforeUnmount(() => { isLoaded.value = false }) </script>