diff --git a/package-lock.json b/package-lock.json index 7850df2..3581de6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1765,9 +1765,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.14.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.0.tgz", - "integrity": "sha512-5cHBxFGJx6L4s56Bubp4fglrEpmyJypsqI6RgzMfBHWUJQGWAAi8cWcgetEbZXHYXo9C2Fa4EEds/uSyS4cxmA==", + "version": "20.14.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.1.tgz", + "integrity": "sha512-T2MzSGEu+ysB/FkWfqmhV3PLyQlowdptmmgD20C6QxsS8Fmv5SjpZ1ayXaEC0S21/h5UJ9iA6W/5vSNU5l00OA==", "dev": true, "license": "MIT", "dependencies": { @@ -3401,9 +3401,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.788", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.788.tgz", - "integrity": "sha512-ubp5+Ev/VV8KuRoWnfP2QF2Bg+O2ZFdb49DiiNbz2VmgkIqrnyYaqIOqj8A6K/3p1xV0QcU5hBQ1+BmB6ot1OA==", + "version": "1.4.789", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.789.tgz", + "integrity": "sha512-0VbyiaXoT++Fi2vHGo2ThOeS6X3vgRCWrjPeO2FeIAWL6ItiSJ9BqlH8LfCXe3X1IdcG+S0iLoNaxQWhfZoGzQ==", "dev": true, "license": "ISC" }, @@ -4544,9 +4544,9 @@ "license": "ISC" }, "node_modules/jackspeak": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.1.2.tgz", - "integrity": "sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.2.3.tgz", + "integrity": "sha512-htOzIMPbpLid/Gq9/zaz9SfExABxqRe1sSCdxntlO/aMD6u0issZQiY25n2GKQUtJ02j7z5sfptlAOMpWWOmvw==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { diff --git a/src/components/Game.vue b/src/components/Game.vue index c780e89..2ef00a1 100644 --- a/src/components/Game.vue +++ b/src/components/Game.vue @@ -1,8 +1,6 @@ <template> <div class="game-container"> - <div class="top-ui"> - <Hud /> - </div> + <div class="top-ui"><Hud /></div> <Game :config="gameConfig" class="game" @create="bootGame"> <Scene name="main" @preload="preloadScene" @create="bootScene"> @@ -57,7 +55,7 @@ const preloadScene = (scene: Phaser.Scene) => { scene.load.image('tiles', '/assets/tiles/default.png') scene.load.image('waypoint', '/assets/waypoint.png') scene.textures.addBase64( - 'player', + 'character', 'data:image/png;base64,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' ) } diff --git a/src/components/World.vue b/src/components/World.vue index ce65386..fa832a9 100644 --- a/src/components/World.vue +++ b/src/components/World.vue @@ -1,19 +1,19 @@ <template> - <TilemapLayer v-if="zoneStore.isLoaded" :tilemap="tileMap" :tileset="zoneStore.getTiles" ref="tilemapLayer" :layerIndex="0" :cull-padding-x="10" :cull-padding-y="10" /> + <TilemapLayerC v-if="zoneStore.isLoaded" :tilemap="tileMap" :tileset="zoneStore.getTiles" ref="tilemapLayer" :layerIndex="0" :cull-padding-x="10" :cull-padding-y="10" /> <Controls :layer="layer" /> - <Character :layer="layer" /> - <Container v-if="zoneStore.isLoaded && zoneStore.getCharacters.length > 0"> + <Container v-if="zoneStore.isLoaded && zoneStore.getCharacters.length"> <Character :layer="layer" v-for="character in zoneStore.getCharacters" :key="character.id" :character="character" /> </Container> </template> <script setup lang="ts"> -import { Container, refObj, TilemapLayer, useScene } from 'phavuer' -import Character from '@/components/sprites/Character.vue' -import {Character as CharacterType} from '@/types' import config from '@/config' -import { onBeforeMount, onMounted, reactive, ref, type Ref, toRaw, watch } from 'vue' import Tileset = Phaser.Tilemaps.Tileset +import TilemapLayer = Phaser.Tilemaps.TilemapLayer +import { Container, TilemapLayer as TilemapLayerC, useScene } from 'phavuer' +import Character from '@/components/sprites/Character.vue' +import {type Character as CharacterType} from '@/types' +import { onBeforeMount, ref, type Ref, watch } from 'vue' import Controls from '@/components/Controls.vue' import { useSocketStore } from '@/stores/socket' import { useZoneStore } from '@/stores/zone' @@ -30,8 +30,8 @@ let zoneData = new Phaser.Tilemaps.MapData({ format: Phaser.Tilemaps.Formats.ARRAY_2D }) let tileMap = new Phaser.Tilemaps.Tilemap(scene, zoneData) -let tileset: any = tileMap.addTilesetImage('default', 'tiles') -let layer: typeof TilemapLayer | null = tileMap.createBlankLayer('layer', tileset, 0, config.tile_size.y) +let tileset: Tileset = tileMap.addTilesetImage('default', 'tiles') as Tileset +let layer: TilemapLayer = tileMap.createBlankLayer('layer', tileset, 0, config.tile_size.y) as TilemapLayer // center camera const centerY = (tileMap.height * tileMap.tileHeight) / 2 @@ -43,44 +43,37 @@ const zoneStore = useZoneStore() const socket = useSocketStore() // Watch for changes in the zoneStore and update the layer -watch( - () => zoneStore.tiles, - () => { +watch(() => zoneStore.tiles, () => { // @TODO : change to tiles for when loading other maps zoneStore.getTiles.forEach((row, y) => row.forEach((tile, x) => layer.putTileAt(tile, x, y))) - }, - { deep: true } + }, { deep: true } ) // Load the zone from the server onBeforeMount(() => { - socket.getConnection.emit('character:zone:load') + socket.getConnection.emit('character:zone:load', {zoneId: socket.character.zoneId}) }) // Listen for the zone event from the server and load the zone socket.getConnection.on('character:zone:load', (data) => { console.log('character:zone:load', data) zoneStore.loadTiles(data.zone.tiles) - /** - * @TODO - * bug , when 2nd player joins, the first player is not added to the zone - */ - // console.log(data.players); - // console.log(data.players[1]); // key is user id - // - // // remove self from the players list - // delete data.players[socket.getConnection.id]; - // - // zoneStore.addPlayers(data.players); + let characters = data.characters; + zoneStore.setCharacters(characters); }) // Listen for player join events -socket.getConnection.on('character:zone:character_join', (data: CharacterType) => { - console.log('character:zone:character_join', data) +socket.getConnection.on('zone:character:join', (data: CharacterType) => { + console.log('character:zone:join', data) zoneStore.addCharacter(data) }) +// Listen for user:disconnect +socket.getConnection.on('user:disconnect', (data: CharacterType) => { + zoneStore.removeCharacter(data) +}) + /** * 1 tile is 64x32 * the zone is 10x10 diff --git a/src/components/sprites/Character.vue b/src/components/sprites/Character.vue index f518f2e..c049f6f 100644 --- a/src/components/sprites/Character.vue +++ b/src/components/sprites/Character.vue @@ -1,8 +1,9 @@ <template> <Container> + <!-- @TODO : Text position X must be calculated based on the character name length --> <Text - :text="props.character?.name ?? socket.character.name" - :x="position.x - 50" + :text="props.character?.name" + :x="position.x - 40" :y="position.y - 80" :style="{ fontFamily: 'Helvetica, Arial', @@ -13,91 +14,76 @@ stroke: '#213547' }" /> - <Sprite ref="sprite" texture="player" :x="position.x" :y="position.y" /> + <Sprite ref="sprite" texture="character" :x="position.x" :y="position.y" /> </Container> </template> <script lang="ts" setup> import { Container, onPostUpdate, onPreUpdate, Sprite, Text, useScene } from 'phavuer' -import { reactive, type Ref, ref } from 'vue' +import { onMounted, reactive, type Ref, ref } from 'vue' import config from '@/config' import { useSocketStore } from '@/stores/socket' -import {type Character as CharacterT } from '@/types' +import { type Character as CharacterT } from '@/types' const socket = useSocketStore() const props = defineProps({ layer: Phaser.Tilemaps.TilemapLayer, - character: { - type: Object as () => CharacterT | undefined, - default: undefined - } + character: Object as () => CharacterT }) const scene = useScene() +const position = reactive({ x: props.character.position_x, y: props.character.position_y }) +const isSelf = props.character.id === socket.character.id; -// onPreUpdate((time, delta) => { -// console.log(time, delta); -// }) +onMounted(() => { + if (isSelf) setupSelf() -const position = reactive({ x: 0, y: 0 }) - -if (props.character !== undefined) { - console.log('character', props.character) - position.x = props.character?.position_x - position.y = props.character?.position_y -} - -const pointer_tile = ref(undefined) - -function onPointerClick(pointer: Phaser.Input.Pointer) { - const px = scene.cameras.main.worldView.x + pointer.x - const py = scene.cameras.main.worldView.y + pointer.y - - pointer_tile.value = getTile(px, py, props.layer) - if (pointer_tile.value) { - const worldPoint = props.layer.tileToWorldXY(pointer_tile.value.x, pointer_tile.value.y) - position.x = worldPoint.x + config.tile_size.y - position.y = worldPoint.y - - socket.getConnection.emit('move', { x: position.x, y: position.y }) + if (!isSelf) { } +}); - //Directions for player sprites + animations - if (px < 0 && py > 0) { - console.log('down left') - } else if (px < 0 && py < 0) { - console.log('top left') - } else if (px > 0 && py > 0) { - console.log('down right') - } else if (px > 0 && py < 0) { - console.log('top right') - } -} - -if (!props.character) { +function setupSelf() +{ scene.input.on(Phaser.Input.Events.POINTER_UP, onPointerClick) -} + const pointer_tile = ref(undefined) + function onPointerClick(pointer: Phaser.Input.Pointer) { + if (!isSelf) return; -socket.getConnection.on('character:move', (data: any) => { - console.log('character moved', data) + const px = scene.cameras.main.worldView.x + pointer.x + const py = scene.cameras.main.worldView.y + pointer.y - if (data.id !== props.character?.id) { - console.log('not you') - return + pointer_tile.value = getTile(px, py, props.layer) as Phaser.Tilemaps.Tile + if (pointer_tile.value) { + const worldPoint = props.layer.tileToWorldXY(pointer_tile.value.x, pointer_tile.value.y) + const position_x = worldPoint.x + config.tile_size.y + const position_y = worldPoint.y + socket.getConnection.emit('character:move', { position_x, position_y }) + } + + //Directions for player sprites + animations + if (px < 0 && py > 0) { + console.log('down left') + } else if (px < 0 && py < 0) { + console.log('top left') + } else if (px > 0 && py > 0) { + console.log('down right') + } else if (px > 0 && py < 0) { + console.log('top right') + } } + function getTile(x: number, y: number, layer: Phaser.Tilemaps.TilemapLayer): Phaser.Tilemaps.Tile | undefined { + const tile: Phaser.Tilemaps.Tile = layer.getTileAtWorldXY(x, y) + if (!tile) return undefined; + return tile + } +} + +socket.getConnection.on('character:moved', (data: CharacterT) => { + console.log('character:moved', data); + if (data.id !== props.character.id) return; // Only update the character that moved position.x = data.position_x position.y = data.position_y }) - -function getTile(x: number, y: number, layer: Phaser.Tilemaps.TilemapLayer): Phaser.Tilemaps.Tile | undefined { - const tile: Phaser.Tilemaps.Tile = layer.getTileAtWorldXY(x, y) - - if (!tile) { - return undefined - } - - return tile -} </script> diff --git a/src/engine/Map/IMap.ts b/src/engine/Map/IMap.ts deleted file mode 100644 index 240d5cd..0000000 --- a/src/engine/Map/IMap.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { Character } from '@/types' - -export default interface IMap { - readonly id: number - name: string - width: number - height: number - data: any - characters: Array<Character> | [] -} diff --git a/src/engine/Map/Map.ts b/src/engine/Map/Map.ts deleted file mode 100644 index 32ceb15..0000000 --- a/src/engine/Map/Map.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type IMap from '@/engine/Map/IMap' -import Player from '@/engine/Player/Player' -import type { Character } from '@/types' - -export default class Map implements IMap { - id: number - name: string - width: number - height: number - data: any - characters: Character[] - - constructor(id: number, name: string, width: number, height: number, data: any, characters: Character[]) { - this.id = id - this.name = name - this.width = width - this.height = height - this.data = data - this.characters = characters - } - - public addCharacter(character: Character) { - this.characters.push(character) - } - - public removeCharacter(character: Character) { - this.characters = this.characters.filter((c: Character) => c.id !== character.id) - } - - public moveCharacter(character: Character, x: number, y: number) { - const index = this.characters.findIndex((c: Character) => c.id === character.id) - this.characters[index].position_x = x - this.characters[index].position_y = y - } -} diff --git a/src/engine/Player/IPlayer.ts b/src/engine/Player/IPlayer.ts deleted file mode 100644 index 433f41b..0000000 --- a/src/engine/Player/IPlayer.ts +++ /dev/null @@ -1,8 +0,0 @@ -export default interface IPlayer { - readonly id: number - name: string - coords: { - x: number - y: number - } -} diff --git a/src/engine/Player/Player.ts b/src/engine/Player/Player.ts deleted file mode 100644 index 8e99a2c..0000000 --- a/src/engine/Player/Player.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type IPlayer from '@/engine/Player/IPlayer' - -export default class Player implements IPlayer { - id: number - name: string - coords: { x: number; y: number } - - constructor(id: number, name: string, coords: { x: number; y: number }) { - this.id = id - this.name = name - this.coords = coords - } -} diff --git a/src/stores/socket.ts b/src/stores/socket.ts index 77e038f..fde5f35 100644 --- a/src/stores/socket.ts +++ b/src/stores/socket.ts @@ -3,7 +3,6 @@ import { io, Socket } from 'socket.io-client' import { useCookies } from '@vueuse/integrations/useCookies' import config from '@/config' import type { Character, User } from '@/types' -import { useNotificationStore } from '@/stores/notifications' export const useSocketStore: StoreDefinition = defineStore('socket', { state: () => ({