diff --git a/package-lock.json b/package-lock.json index 14348e8..75d3cda 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4222,9 +4222,9 @@ "dev": true }, "node_modules/json-parse-even-better-errors": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", - "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", + "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", "dev": true, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -4456,9 +4456,9 @@ } }, "node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.0.tgz", + "integrity": "sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig==", "dev": true, "engines": { "node": ">=16 || 14 >=14.17" @@ -4583,9 +4583,9 @@ "dev": true }, "node_modules/nopt": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", - "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", "dev": true, "dependencies": { "abbrev": "^2.0.0" @@ -5918,9 +5918,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.14.tgz", - "integrity": "sha512-JixKH8GR2pWYshIPUg/NujK3JO7JiqEEUiNArE86NQyrgUuZeTlZQN3xuS/yiV5Kb48ev9K6RqNkaJjXsdg7Jw==", + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.15.tgz", + "integrity": "sha512-K9HWH62x3/EalU1U6sjSZiylm9C8tgq2mSvshZpqc7QE69RaA2qjhkW2HlNA0tFpEbtyFz7HTqbSdN4MSwUodA==", "dev": true, "funding": [ { diff --git a/src/assets/login.scss b/src/assets/login.scss index 38eb903..09676a9 100644 --- a/src/assets/login.scss +++ b/src/assets/login.scss @@ -66,11 +66,11 @@ gap: 0.5rem; .button { - padding: 0.8rem 0; + padding: 0.6rem 0; min-width: 6.25rem; text-align: center; position: relative; - font-size: 0.80rem; + font-size: 0.65rem; background-color: rgba(71, 65, 230, 0.75); border: rgba(255, 255, 255, 0.35) 1px solid; border-radius: 5px; diff --git a/src/components/World.vue b/src/components/World.vue index c8dd1dd..62ccccf 100644 --- a/src/components/World.vue +++ b/src/components/World.vue @@ -1,41 +1,23 @@ <template> - <TilemapLayer ref="tilemapLayer" :tilemap="map" :layerIndex="0" :cull-padding-x="10" :cull-padding-y="10" :tileset="data" /> - <Controls :layer="layer" /> - <Player :layer="layer" /> - <div v-for="player in playerList"> - <Player :layer="layer"/> - </div> + <TilemapLayer ref="tilemapLayer" :tilemap="map" :layerIndex="0" :cull-padding-x="10" :cull-padding-y="10" :tileset="mapTiles" /> +<!-- <Controls :layer="layer" />--> </template> <script setup lang="ts"> import { refObj, TilemapLayer, useScene } from 'phavuer' import Player from '@/components/sprites/player/Player.vue' import config from '@/config' -import { ref, type Ref } from 'vue' +import { reactive, ref, type Ref } from 'vue' import Tileset = Phaser.Tilemaps.Tileset import Controls from '@/components/Controls.vue' import { useSocketStore } from '@/stores/socket' +import Map from '@/engine/Map/Map' -let playerList = ref([]); - +const isMapLoaded = ref(false); const socket = useSocketStore(); +const serverMapData = ref([]); +const mapTiles = ref([]); -socket.socket?.on('playerList', (players) => { - playerList.value = players; - console.log('players', players); - console.log('playerList', playerList.value); -}); - -socket.socket?.on('player_moved', (username, coords) => { - console.log('player_moved', username, coords); - const player = playerList.value.find((player: any) => player.username === username); - if (player) { - player.x = coords.x; - player.y = coords.y; - } -}); - -const scene = useScene() const mapData = new Phaser.Tilemaps.MapData({ width: 10, height: 10, @@ -45,9 +27,27 @@ const mapData = new Phaser.Tilemaps.MapData({ format: Phaser.Tilemaps.Formats.ARRAY_2D, }); +socket.socket?.emit('get_map'); +socket.socket?.on('map', (map) => { + // Get map from server + mapTiles.value = map.data; + map.data.forEach((row, y) => { + row.forEach((tile, x) => { + layer.putTileAt(tile, x, y); + }); + }); + + isMapLoaded.value = true; + console.log('map', map); +}); + + +const scene = useScene() + const { width: tileSizeWidth } = mapData; const { width, height } = scene.cameras.main; const map = new Phaser.Tilemaps.Tilemap(scene, mapData); + /** * 1 tile is 64x32 * the map is 10x10 @@ -57,26 +57,11 @@ const tileset: (Tileset|null) = map.addTilesetImage('default', 'tiles'); // const layer: (Layer|null) = map.createBlankLayer('layer', tileset); const layer:TilemapLayer = map.createBlankLayer('layer', tileset, 0, config.tile_size.y); -const tilemapLayer: Ref<(TilemapLayer|undefined)> = refObj(); +const tilemapLayer= ref(); + +// const mapp = new Map('default', 10, 10, config.tile_size.x, config.tile_size.y, data, []); -const data: any = [ - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], - [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 ], - [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 ], - [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 ], - [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 ], - [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 ], - [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 ], - [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 ], - [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 ], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], -]; -data.forEach((row, y) => { - row.forEach((tile, x) => { - layer.putTileAt(tile, x, y); - }); -}); // center camera const centerY = (map.height * map.tileHeight) / 2 diff --git a/src/components/screens/Login.vue b/src/components/screens/Login.vue index 4ae6995..fa3439c 100644 --- a/src/components/screens/Login.vue +++ b/src/components/screens/Login.vue @@ -9,7 +9,7 @@ <form method="post"> <div class="form-field"> <label for="username">Username</label> - <input v-model="username" type="text" name="username" required> + <input v-model="username" type="text" name="username" required autofocus> </div> <div class="form-field"> <label for="password">Password</label> diff --git a/src/components/sprites/player/Player.vue b/src/components/sprites/player/Player.vue index 50af0fb..b6a74b7 100644 --- a/src/components/sprites/player/Player.vue +++ b/src/components/sprites/player/Player.vue @@ -1,55 +1,60 @@ <template> - <Sprite ref="sprite" texture="player" :x :y /> + <Sprite ref="sprite" texture="IMap" :x="position.x" :y="position.y" /> </template> <script lang="ts" setup> -import { Sprite, useScene } from 'phavuer' -import { type Ref, ref } from 'vue' +import { onPostUpdate, onPreUpdate, Sprite, useScene } from 'phavuer' +import { reactive, type Ref, ref } from 'vue' import config from '@/config' import { useSocketStore } from '@/stores/socket' const socket = useSocketStore(); -socket.socket?.emit('joinRoom', 'game'); - const props = defineProps({ layer: Phaser.Tilemaps.TilemapLayer, - player: Object + player: { + type: Object, + default: undefined + }, }) const scene = useScene() -const pointer_tile = ref(undefined); -const x: Ref<number> = ref(0); -const y: Ref<number> = ref(0); -if (props.player) { - x.value = props.player.x; - y.value = props.player.y; +// onPreUpdate((time, delta) => { +// console.log(time, delta); +// }) + +const pointer_tile = ref(undefined); +const position = reactive({ x: 0, y: 0 }); + +if (props.player !== undefined) { + position.x = props.player?.coords.x; + position.y = props.player?.coords.y; } function onPointerClick(pointer: Phaser.Input.Pointer) { - /** - * @TODO : Check if player was dragging, if so, don't move player - */ 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) { - // Convert tile coordinates to world coordinates const worldPoint = props.layer.tileToWorldXY(pointer_tile.value.x, pointer_tile.value.y); - x.value = worldPoint.x + config.tile_size.y; - y.value = worldPoint.y; + position.x = worldPoint.x + config.tile_size.y; + position.y = worldPoint.y; + + socket.socket?.emit('move', { x: position.x, y: position.y }); } } -scene.input.on(Phaser.Input.Events.POINTER_DOWN, onPointerClick); + +/** + * @BUG + * when this component is spawned multiple times, the event listener is also added multiple times + */ +scene.input.on(Phaser.Input.Events.POINTER_UP, onPointerClick); function getTile (x: number, y: number, layer: Phaser.Tilemaps.TilemapLayer): Phaser.Tilemaps.Tile | undefined { const tile: Phaser.Tilemaps.Tile = layer.getTileAtWorldXY(x, y); - console.log(x,y); - console.log('tile', tile); - if (!tile) { return undefined; } diff --git a/src/engine/Map/IMap.ts b/src/engine/Map/IMap.ts new file mode 100644 index 0000000..154a374 --- /dev/null +++ b/src/engine/Map/IMap.ts @@ -0,0 +1,10 @@ +import Player from '../Player/Player'; + +export default interface IMap { + readonly id: number; + name: string; + width: number; + height: number; + data: any; + players: Array<Player>|[]; +} \ No newline at end of file diff --git a/src/engine/Map/Map.ts b/src/engine/Map/Map.ts new file mode 100644 index 0000000..e86b648 --- /dev/null +++ b/src/engine/Map/Map.ts @@ -0,0 +1,36 @@ +import type IMap from '@/engine/Map/IMap'; +import Player from '@/engine/Player/Player'; + +export default class Map implements IMap { + id: number; + name: string; + width: number; + height: number; + data: any; + players: Array<Player>|[]; + + constructor(id: number, name: string, width: number, height: number, data: any, players: Array<Player>|[]) { + this.id = id; + this.name = name; + this.width = width; + this.height = height; + this.data = data; + this.players = players; + } + + public addPlayer(player: Player) { + this.players.push(player); + } + + public removePlayer(player: Player) { + this.players = this.players.filter(p => p.id !== player.id); + } + + public movePlayer(player: Player, x: number, y: number) { + const playerIndex = this.players.findIndex(p => p.id === player.id); + if (playerIndex !== -1) { + this.players[playerIndex].coords.x = x; + this.players[playerIndex].coords.y = y; + } + } +} \ No newline at end of file diff --git a/src/engine/Player/IPlayer.ts b/src/engine/Player/IPlayer.ts new file mode 100644 index 0000000..f7be52a --- /dev/null +++ b/src/engine/Player/IPlayer.ts @@ -0,0 +1,8 @@ +export default interface IPlayer { + readonly id: number; + username: string; + coords: { + x: number; + y: number; + }; +} \ No newline at end of file diff --git a/src/engine/Player/Player.ts b/src/engine/Player/Player.ts new file mode 100644 index 0000000..753fde8 --- /dev/null +++ b/src/engine/Player/Player.ts @@ -0,0 +1,13 @@ +import type IPlayer from '@/engine/Player/IPlayer'; + +export default class Player implements IPlayer { + id: number; + username: string; + coords: { x: number; y: number; }; + + constructor(id: number, username: string, coords: { x: number; y: number; }) { + this.id = id; + this.username = username; + this.coords = coords; + } +} \ No newline at end of file diff --git a/src/engine/init.js b/src/engine/init.js deleted file mode 100644 index e69de29..0000000 diff --git a/src/engine/map.js b/src/engine/map.js deleted file mode 100644 index e69de29..0000000 diff --git a/src/stores/map.ts b/src/stores/map.ts index e69de29..88078bd 100644 --- a/src/stores/map.ts +++ b/src/stores/map.ts @@ -0,0 +1,14 @@ +import { defineStore } from 'pinia'; +import Map from '@/engine/Map/Map' + +export const useMapStore = defineStore('map', { + state: () => ({ + map: null as Map | null, + }), + + actions: { + setMap(map: Map) { + this.map = map; + } + } +}); \ No newline at end of file diff --git a/src/stores/player.ts b/src/stores/player.ts new file mode 100644 index 0000000..3438e61 --- /dev/null +++ b/src/stores/player.ts @@ -0,0 +1,14 @@ +import { defineStore } from 'pinia'; +import Player from '@/engine/Player/Player' + +export const usePlayerStore = defineStore('player', { + state: () => ({ + player: null as Player | null, + }), + + actions: { + setPlayer(player: Player) { + this.player = player; + }, + } +}); \ No newline at end of file