Compare commits

..

25 Commits

Author SHA1 Message Date
9e96b2b32a Merge remote-tracking branch 'origin/main' into feature/151-broken-zoom 2024-09-28 20:30:36 +02:00
8eec2e12ce #165 : Show message if player runs in canvas mode, then disconnect 2024-09-28 20:30:26 +02:00
adc85d49a4 Change zoom to camera property 2024-09-28 20:22:01 +02:00
3dbd68d5cf Put zoom calculation in variable 2024-09-28 20:17:37 +02:00
2a34c7eea9 ENV bs 2024-09-28 20:16:57 +02:00
3c5ceaae2d Added min and max to zoom 2024-09-28 20:14:46 +02:00
31ce0a8264 Added dot env support 2024-09-28 20:02:59 +02:00
b4050bee01 Use WebGL by default. 2024-09-28 19:24:11 +02:00
cffab00974 #81 : Prevent walk after dragging zone 2024-09-28 19:19:00 +02:00
a92675e4c0 Position fix for texts 2024-09-28 17:46:05 +02:00
b2266f5a10 More whitespace around chat bubble 2024-09-28 03:11:49 +02:00
6cee0b93e6 Set char. limit of 90 to chat bubble 2024-09-28 03:10:02 +02:00
b4403f3267 Chat res. fix 2024-09-28 03:07:44 +02:00
fa12ce2ec8 Minor improvements 2024-09-28 02:52:36 +02:00
130df8f144 npm run format 2024-09-28 02:17:51 +02:00
1105a53feb Minor improvements 2024-09-28 02:17:33 +02:00
104e9e46fb Receive frameCount for assets from server 2024-09-28 00:59:10 +02:00
2223491571 #155 : Hide HUD elements if Game.vue is unloaded 2024-09-28 00:45:19 +02:00
ff61f88d62 #157 : Somewhat fixed resolution 2024-09-28 00:37:54 +02:00
0f231e10fa #159 : Camera control fixes 2024-09-28 00:21:24 +02:00
71042881dc Fix for #132 (character continues anim after moving is finished) 2024-09-27 23:56:02 +02:00
50feea0c9c Disabled dev 2024-09-26 00:43:22 +02:00
dd6b6f2a96 Potential fix 2024-09-26 00:41:40 +02:00
c09f503d54 Removed placeholder text 2024-09-25 14:06:22 +02:00
5f44a9aebd Removed scale, added resolution to game config and phaser text obj 2024-09-25 14:03:04 +02:00
17 changed files with 467 additions and 440 deletions

5
.env.example Normal file
View File

@ -0,0 +1,5 @@
VITE_NAME=New Quest
VITE_DEVELOPMENT=true
VITE_SERVER_ENDPOINT=http://localhost:4000
VITE_TILE_SIZE_X=64
VITE_TILE_SIZE_Y=32

View File

@ -4,6 +4,24 @@ WORKDIR /usr/src/app
COPY package*.json ./
RUN npm ci
COPY . .
# Set environment variables
ARG VITE_NAME=${VITE_NAME}
ENV VITE_NAME=${VITE_NAME}
ARG VITE_DEVELOPMENT=${VITE_DEVELOPMENT}
ENV VITE_DEVELOPMENT=${VITE_DEVELOPMENT}
ARG VITE_SERVER_ENDPOINT=${VITE_SERVER_ENDPOINT}
ENV VITE_SERVER_ENDPOINT=${VITE_SERVER_ENDPOINT}
ARG VITE_TILE_SIZE_X=${VITE_TILE_SIZE_X}
ENV VITE_TILE_SIZE_X=${VITE_TILE_SIZE_X}
ARG VITE_TILE_SIZE_Y=${VITE_TILE_SIZE_Y}
ENV VITE_TILE_SIZE_Y=${VITE_TILE_SIZE_Y}
# Build the application
RUN npm run build-ntc
# Production stage

294
package-lock.json generated
View File

@ -1436,9 +1436,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz",
"integrity": "sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==",
"version": "4.22.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.5.tgz",
"integrity": "sha512-SU5cvamg0Eyu/F+kLeMXS7GoahL+OoizlclVFX3l5Ql6yNlywJJ0OuqTzUx0v+aHhPHEB/56CT06GQrRrGNYww==",
"cpu": [
"arm"
],
@ -1450,9 +1450,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.4.tgz",
"integrity": "sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA==",
"version": "4.22.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.5.tgz",
"integrity": "sha512-S4pit5BP6E5R5C8S6tgU/drvgjtYW76FBuG6+ibG3tMvlD1h9LHVF9KmlmaUBQ8Obou7hEyS+0w+IR/VtxwNMQ==",
"cpu": [
"arm64"
],
@ -1464,9 +1464,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.4.tgz",
"integrity": "sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q==",
"version": "4.22.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.5.tgz",
"integrity": "sha512-250ZGg4ipTL0TGvLlfACkIxS9+KLtIbn7BCZjsZj88zSg2Lvu3Xdw6dhAhfe/FjjXPVNCtcSp+WZjVsD3a/Zlw==",
"cpu": [
"arm64"
],
@ -1478,9 +1478,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.4.tgz",
"integrity": "sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw==",
"version": "4.22.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.5.tgz",
"integrity": "sha512-D8brJEFg5D+QxFcW6jYANu+Rr9SlKtTenmsX5hOSzNYVrK5oLAEMTUgKWYJP+wdKyCdeSwnapLsn+OVRFycuQg==",
"cpu": [
"x64"
],
@ -1492,9 +1492,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.4.tgz",
"integrity": "sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ==",
"version": "4.22.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.5.tgz",
"integrity": "sha512-PNqXYmdNFyWNg0ma5LdY8wP+eQfdvyaBAojAXgO7/gs0Q/6TQJVXAXe8gwW9URjbS0YAammur0fynYGiWsKlXw==",
"cpu": [
"arm"
],
@ -1506,9 +1506,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.4.tgz",
"integrity": "sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg==",
"version": "4.22.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.5.tgz",
"integrity": "sha512-kSSCZOKz3HqlrEuwKd9TYv7vxPYD77vHSUvM2y0YaTGnFc8AdI5TTQRrM1yIp3tXCKrSL9A7JLoILjtad5t8pQ==",
"cpu": [
"arm"
],
@ -1520,9 +1520,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.4.tgz",
"integrity": "sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw==",
"version": "4.22.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.5.tgz",
"integrity": "sha512-oTXQeJHRbOnwRnRffb6bmqmUugz0glXaPyspp4gbQOPVApdpRrY/j7KP3lr7M8kTfQTyrBUzFjj5EuHAhqH4/w==",
"cpu": [
"arm64"
],
@ -1534,9 +1534,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.4.tgz",
"integrity": "sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA==",
"version": "4.22.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.5.tgz",
"integrity": "sha512-qnOTIIs6tIGFKCHdhYitgC2XQ2X25InIbZFor5wh+mALH84qnFHvc+vmWUpyX97B0hNvwNUL4B+MB8vJvH65Fw==",
"cpu": [
"arm64"
],
@ -1548,9 +1548,9 @@
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.4.tgz",
"integrity": "sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg==",
"version": "4.22.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.5.tgz",
"integrity": "sha512-TMYu+DUdNlgBXING13rHSfUc3Ky5nLPbWs4bFnT+R6Vu3OvXkTkixvvBKk8uO4MT5Ab6lC3U7x8S8El2q5o56w==",
"cpu": [
"ppc64"
],
@ -1562,9 +1562,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.4.tgz",
"integrity": "sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA==",
"version": "4.22.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.5.tgz",
"integrity": "sha512-PTQq1Kz22ZRvuhr3uURH+U/Q/a0pbxJoICGSprNLAoBEkyD3Sh9qP5I0Asn0y0wejXQBbsVMRZRxlbGFD9OK4A==",
"cpu": [
"riscv64"
],
@ -1576,9 +1576,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.4.tgz",
"integrity": "sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q==",
"version": "4.22.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.5.tgz",
"integrity": "sha512-bR5nCojtpuMss6TDEmf/jnBnzlo+6n1UhgwqUvRoe4VIotC7FG1IKkyJbwsT7JDsF2jxR+NTnuOwiGv0hLyDoQ==",
"cpu": [
"s390x"
],
@ -1590,9 +1590,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.4.tgz",
"integrity": "sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg==",
"version": "4.22.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.5.tgz",
"integrity": "sha512-N0jPPhHjGShcB9/XXZQWuWBKZQnC1F36Ce3sDqWpujsGjDz/CQtOL9LgTrJ+rJC8MJeesMWrMWVLKKNR/tMOCA==",
"cpu": [
"x64"
],
@ -1604,9 +1604,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.4.tgz",
"integrity": "sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g==",
"version": "4.22.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.5.tgz",
"integrity": "sha512-uBa2e28ohzNNwjr6Uxm4XyaA1M/8aTgfF2T7UIlElLaeXkgpmIJ2EitVNQxjO9xLLLy60YqAgKn/AqSpCUkE9g==",
"cpu": [
"x64"
],
@ -1618,9 +1618,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.4.tgz",
"integrity": "sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw==",
"version": "4.22.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.5.tgz",
"integrity": "sha512-RXT8S1HP8AFN/Kr3tg4fuYrNxZ/pZf1HemC5Tsddc6HzgGnJm0+Lh5rAHJkDuW3StI0ynNXukidROMXYl6ew8w==",
"cpu": [
"arm64"
],
@ -1632,9 +1632,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.4.tgz",
"integrity": "sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g==",
"version": "4.22.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.5.tgz",
"integrity": "sha512-ElTYOh50InL8kzyUD6XsnPit7jYCKrphmddKAe1/Ytt74apOxDq5YEcbsiKs0fR3vff3jEneMM+3I7jbqaMyBg==",
"cpu": [
"ia32"
],
@ -1646,9 +1646,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.22.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz",
"integrity": "sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q==",
"version": "4.22.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.5.tgz",
"integrity": "sha512-+lvL/4mQxSV8MukpkKyyvfwhH266COcWlXE/1qxwN08ajovta3459zrjLghYMgDerlzNwLAcFpvU+WWE5y6nAQ==",
"cpu": [
"x64"
],
@ -1686,9 +1686,9 @@
"license": "MIT"
},
"node_modules/@types/estree": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
"dev": true,
"license": "MIT"
},
@ -1705,9 +1705,9 @@
}
},
"node_modules/@types/node": {
"version": "20.16.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.7.tgz",
"integrity": "sha512-QkDQjAY3gkvJNcZOWwzy3BN34RweT0OQ9zJyvLCU0kSK22dO2QYh/NHGfbEAYylPYzRB1/iXcojS79wOg5gFSw==",
"version": "20.16.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.10.tgz",
"integrity": "sha512-vQUKgWTjEIRFCvK6CyriPH3MZYiYlNy0fKiEYHWbcoWLEgs4opurGGKlebrTLqdSMIbXImH6XExNiIyNUv3WpA==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -2148,39 +2148,39 @@
}
},
"node_modules/@vue/compiler-core": {
"version": "3.5.8",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.8.tgz",
"integrity": "sha512-Uzlxp91EPjfbpeO5KtC0KnXPkuTfGsNDeaKQJxQN718uz+RqDYarEf7UhQJGK+ZYloD2taUbHTI2J4WrUaZQNA==",
"version": "3.5.10",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.10.tgz",
"integrity": "sha512-iXWlk+Cg/ag7gLvY0SfVucU8Kh2CjysYZjhhP70w9qI4MvSox4frrP+vDGvtQuzIcgD8+sxM6lZvCtdxGunTAA==",
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.25.3",
"@vue/shared": "3.5.8",
"@vue/shared": "3.5.10",
"entities": "^4.5.0",
"estree-walker": "^2.0.2",
"source-map-js": "^1.2.0"
}
},
"node_modules/@vue/compiler-dom": {
"version": "3.5.8",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.8.tgz",
"integrity": "sha512-GUNHWvoDSbSa5ZSHT9SnV5WkStWfzJwwTd6NMGzilOE/HM5j+9EB9zGXdtu/fCNEmctBqMs6C9SvVPpVPuk1Eg==",
"version": "3.5.10",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.10.tgz",
"integrity": "sha512-DyxHC6qPcktwYGKOIy3XqnHRrrXyWR2u91AjP+nLkADko380srsC2DC3s7Y1Rk6YfOlxOlvEQKa9XXmLI+W4ZA==",
"license": "MIT",
"dependencies": {
"@vue/compiler-core": "3.5.8",
"@vue/shared": "3.5.8"
"@vue/compiler-core": "3.5.10",
"@vue/shared": "3.5.10"
}
},
"node_modules/@vue/compiler-sfc": {
"version": "3.5.8",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.8.tgz",
"integrity": "sha512-taYpngQtSysrvO9GULaOSwcG5q821zCoIQBtQQSx7Uf7DxpR6CIHR90toPr9QfDD2mqHQPCSgoWBvJu0yV9zjg==",
"version": "3.5.10",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.10.tgz",
"integrity": "sha512-to8E1BgpakV7224ZCm8gz1ZRSyjNCAWEplwFMWKlzCdP9DkMKhRRwt0WkCjY7jkzi/Vz3xgbpeig5Pnbly4Tow==",
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.25.3",
"@vue/compiler-core": "3.5.8",
"@vue/compiler-dom": "3.5.8",
"@vue/compiler-ssr": "3.5.8",
"@vue/shared": "3.5.8",
"@vue/compiler-core": "3.5.10",
"@vue/compiler-dom": "3.5.10",
"@vue/compiler-ssr": "3.5.10",
"@vue/shared": "3.5.10",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.11",
"postcss": "^8.4.47",
@ -2188,13 +2188,13 @@
}
},
"node_modules/@vue/compiler-ssr": {
"version": "3.5.8",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.8.tgz",
"integrity": "sha512-W96PtryNsNG9u0ZnN5Q5j27Z/feGrFV6zy9q5tzJVyJaLiwYxvC0ek4IXClZygyhjm+XKM7WD9pdKi/wIRVC/Q==",
"version": "3.5.10",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.10.tgz",
"integrity": "sha512-hxP4Y3KImqdtyUKXDRSxKSRkSm1H9fCvhojEYrnaoWhE4w/y8vwWhnosJoPPe2AXm5sU7CSbYYAgkt2ZPhDz+A==",
"license": "MIT",
"dependencies": {
"@vue/compiler-dom": "3.5.8",
"@vue/shared": "3.5.8"
"@vue/compiler-dom": "3.5.10",
"@vue/shared": "3.5.10"
}
},
"node_modules/@vue/devtools-api": {
@ -2314,53 +2314,53 @@
}
},
"node_modules/@vue/reactivity": {
"version": "3.5.8",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.8.tgz",
"integrity": "sha512-mlgUyFHLCUZcAYkqvzYnlBRCh0t5ZQfLYit7nukn1GR96gc48Bp4B7OIcSfVSvlG1k3BPfD+p22gi1t2n9tsXg==",
"version": "3.5.10",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.10.tgz",
"integrity": "sha512-kW08v06F6xPSHhid9DJ9YjOGmwNDOsJJQk0ax21wKaUYzzuJGEuoKNU2Ujux8FLMrP7CFJJKsHhXN9l2WOVi2g==",
"license": "MIT",
"dependencies": {
"@vue/shared": "3.5.8"
"@vue/shared": "3.5.10"
}
},
"node_modules/@vue/runtime-core": {
"version": "3.5.8",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.8.tgz",
"integrity": "sha512-fJuPelh64agZ8vKkZgp5iCkPaEqFJsYzxLk9vSC0X3G8ppknclNDr61gDc45yBGTaN5Xqc1qZWU3/NoaBMHcjQ==",
"version": "3.5.10",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.10.tgz",
"integrity": "sha512-9Q86I5Qq3swSkFfzrZ+iqEy7Vla325M7S7xc1NwKnRm/qoi1Dauz0rT6mTMmscqx4qz0EDJ1wjB+A36k7rl8mA==",
"license": "MIT",
"dependencies": {
"@vue/reactivity": "3.5.8",
"@vue/shared": "3.5.8"
"@vue/reactivity": "3.5.10",
"@vue/shared": "3.5.10"
}
},
"node_modules/@vue/runtime-dom": {
"version": "3.5.8",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.8.tgz",
"integrity": "sha512-DpAUz+PKjTZPUOB6zJgkxVI3GuYc2iWZiNeeHQUw53kdrparSTG6HeXUrYDjaam8dVsCdvQxDz6ZWxnyjccUjQ==",
"version": "3.5.10",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.10.tgz",
"integrity": "sha512-t3x7ht5qF8ZRi1H4fZqFzyY2j+GTMTDxRheT+i8M9Ph0oepUxoadmbwlFwMoW7RYCpNQLpP2Yx3feKs+fyBdpA==",
"license": "MIT",
"dependencies": {
"@vue/reactivity": "3.5.8",
"@vue/runtime-core": "3.5.8",
"@vue/shared": "3.5.8",
"@vue/reactivity": "3.5.10",
"@vue/runtime-core": "3.5.10",
"@vue/shared": "3.5.10",
"csstype": "^3.1.3"
}
},
"node_modules/@vue/server-renderer": {
"version": "3.5.8",
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.8.tgz",
"integrity": "sha512-7AmC9/mEeV9mmXNVyUIm1a1AjUhyeeGNbkLh39J00E7iPeGks8OGRB5blJiMmvqSh8SkaS7jkLWSpXtxUCeagA==",
"version": "3.5.10",
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.10.tgz",
"integrity": "sha512-IVE97tt2kGKwHNq9yVO0xdh1IvYfZCShvDSy46JIh5OQxP1/EXSpoDqetVmyIzL7CYOWnnmMkVqd7YK2QSWkdw==",
"license": "MIT",
"dependencies": {
"@vue/compiler-ssr": "3.5.8",
"@vue/shared": "3.5.8"
"@vue/compiler-ssr": "3.5.10",
"@vue/shared": "3.5.10"
},
"peerDependencies": {
"vue": "3.5.8"
"vue": "3.5.10"
}
},
"node_modules/@vue/shared": {
"version": "3.5.8",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.8.tgz",
"integrity": "sha512-mJleSWbAGySd2RJdX1RBtcrUBX6snyOc0qHpgk3lGi4l9/P/3ny3ELqFWqYdkXIwwNN/kdm8nD9ky8o6l/Lx2A==",
"version": "3.5.10",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.10.tgz",
"integrity": "sha512-VkkBhU97Ki+XJ0xvl4C9YJsIZ2uIlQ7HqPpZOS3m9VCvmROPaChZU6DexdMJqvz9tbgG+4EtFVrSuailUq5KGQ==",
"license": "MIT"
},
"node_modules/@vue/test-utils": {
@ -2900,9 +2900,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001663",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001663.tgz",
"integrity": "sha512-o9C3X27GLKbLeTYZ6HBOLU1tsAcBZsLis28wrVzddShCS16RujjHp9GDHKZqrB3meE0YjhawvMFsGb/igqiPzA==",
"version": "1.0.30001664",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001664.tgz",
"integrity": "sha512-AmE7k4dXiNKQipgn7a2xg558IRqPN3jMQY/rOsbxDhrd0tyChwbITBfiwtnqz8bi2M5mIWbxAYBvk7W7QBUS2g==",
"dev": true,
"funding": [
{
@ -3343,9 +3343,9 @@
}
},
"node_modules/electron-to-chromium": {
"version": "1.5.28",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.28.tgz",
"integrity": "sha512-VufdJl+rzaKZoYVUijN13QcXVF5dWPZANeFTLNy+OSpHdDL5ynXTF35+60RSBbaQYB1ae723lQXHCrf4pyLsMw==",
"version": "1.5.29",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.29.tgz",
"integrity": "sha512-PF8n2AlIhCKXQ+gTpiJi0VhcHDb69kYX4MtCiivctc2QD3XuNZ/XIOlbGzt7WAjjEev0TtaH6Cu3arZExm5DOw==",
"dev": true,
"license": "ISC"
},
@ -5204,9 +5204,9 @@
}
},
"node_modules/nwsapi": {
"version": "2.2.12",
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz",
"integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==",
"version": "2.2.13",
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.13.tgz",
"integrity": "sha512-cTGB9ptp9dY9A5VbMSe7fQBcl/tt22Vcqdq8+eN93rblOuE0aCFu4aZ2vMwct/2t+lFnosm8RkQW1I0Omb1UtQ==",
"dev": true,
"license": "MIT"
},
@ -5326,9 +5326,9 @@
}
},
"node_modules/package-json-from-dist": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz",
"integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
"dev": true,
"license": "BlueOak-1.0.0"
},
@ -6028,13 +6028,13 @@
}
},
"node_modules/rollup": {
"version": "4.22.4",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.4.tgz",
"integrity": "sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A==",
"version": "4.22.5",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.5.tgz",
"integrity": "sha512-WoinX7GeQOFMGznEcWA1WrTQCd/tpEbMkc3nuMs9BT0CPjMdSjPMTVClwWd4pgSQwJdP65SK9mTCNvItlr5o7w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "1.0.5"
"@types/estree": "1.0.6"
},
"bin": {
"rollup": "dist/bin/rollup"
@ -6044,22 +6044,22 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.22.4",
"@rollup/rollup-android-arm64": "4.22.4",
"@rollup/rollup-darwin-arm64": "4.22.4",
"@rollup/rollup-darwin-x64": "4.22.4",
"@rollup/rollup-linux-arm-gnueabihf": "4.22.4",
"@rollup/rollup-linux-arm-musleabihf": "4.22.4",
"@rollup/rollup-linux-arm64-gnu": "4.22.4",
"@rollup/rollup-linux-arm64-musl": "4.22.4",
"@rollup/rollup-linux-powerpc64le-gnu": "4.22.4",
"@rollup/rollup-linux-riscv64-gnu": "4.22.4",
"@rollup/rollup-linux-s390x-gnu": "4.22.4",
"@rollup/rollup-linux-x64-gnu": "4.22.4",
"@rollup/rollup-linux-x64-musl": "4.22.4",
"@rollup/rollup-win32-arm64-msvc": "4.22.4",
"@rollup/rollup-win32-ia32-msvc": "4.22.4",
"@rollup/rollup-win32-x64-msvc": "4.22.4",
"@rollup/rollup-android-arm-eabi": "4.22.5",
"@rollup/rollup-android-arm64": "4.22.5",
"@rollup/rollup-darwin-arm64": "4.22.5",
"@rollup/rollup-darwin-x64": "4.22.5",
"@rollup/rollup-linux-arm-gnueabihf": "4.22.5",
"@rollup/rollup-linux-arm-musleabihf": "4.22.5",
"@rollup/rollup-linux-arm64-gnu": "4.22.5",
"@rollup/rollup-linux-arm64-musl": "4.22.5",
"@rollup/rollup-linux-powerpc64le-gnu": "4.22.5",
"@rollup/rollup-linux-riscv64-gnu": "4.22.5",
"@rollup/rollup-linux-s390x-gnu": "4.22.5",
"@rollup/rollup-linux-x64-gnu": "4.22.5",
"@rollup/rollup-linux-x64-musl": "4.22.5",
"@rollup/rollup-win32-arm64-msvc": "4.22.5",
"@rollup/rollup-win32-ia32-msvc": "4.22.5",
"@rollup/rollup-win32-x64-msvc": "4.22.5",
"fsevents": "~2.3.2"
}
},
@ -6115,9 +6115,9 @@
"license": "MIT"
},
"node_modules/sass": {
"version": "1.79.3",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.79.3.tgz",
"integrity": "sha512-m7dZxh0W9EZ3cw50Me5GOuYm/tVAJAn91SUnohLRo9cXBixGUOdvmryN+dXpwR831bhoY3Zv7rEFt85PUwTmzA==",
"version": "1.79.4",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.79.4.tgz",
"integrity": "sha512-K0QDSNPXgyqO4GZq2HO5Q70TLxTH6cIT59RdoCHMivrC8rqzaTw5ab9prjz9KUN1El4FLXrBXJhik61JR4HcGg==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -6841,9 +6841,9 @@
}
},
"node_modules/update-browserslist-db": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz",
"integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz",
"integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==",
"dev": true,
"funding": [
{
@ -6861,8 +6861,8 @@
],
"license": "MIT",
"dependencies": {
"escalade": "^3.1.2",
"picocolors": "^1.0.1"
"escalade": "^3.2.0",
"picocolors": "^1.1.0"
},
"bin": {
"update-browserslist-db": "cli.js"
@ -7135,16 +7135,16 @@
}
},
"node_modules/vue": {
"version": "3.5.8",
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.8.tgz",
"integrity": "sha512-hvuvuCy51nP/1fSRvrrIqTLSvrSyz2Pq+KQ8S8SXCxTWVE0nMaOnSDnSOxV1eYmGfvK7mqiwvd1C59CEEz7dAQ==",
"version": "3.5.10",
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.10.tgz",
"integrity": "sha512-Vy2kmJwHPlouC/tSnIgXVg03SG+9wSqT1xu1Vehc+ChsXsRd7jLkKgMltVEFOzUdBr3uFwBCG+41LJtfAcBRng==",
"license": "MIT",
"dependencies": {
"@vue/compiler-dom": "3.5.8",
"@vue/compiler-sfc": "3.5.8",
"@vue/runtime-dom": "3.5.8",
"@vue/server-renderer": "3.5.8",
"@vue/shared": "3.5.8"
"@vue/compiler-dom": "3.5.10",
"@vue/compiler-sfc": "3.5.10",
"@vue/runtime-dom": "3.5.10",
"@vue/server-renderer": "3.5.10",
"@vue/shared": "3.5.10"
},
"peerDependencies": {
"typescript": "*"

View File

@ -248,32 +248,6 @@ function handleMove() {
console.log('move btn clicked')
}
onBeforeMount(async () => {
tileArray.forEach((row, y) => row.forEach((_, x) => placeTile(zoneTilemap, tiles, x, y, 'blank_tile')))
if (zone.value?.tiles) {
setAllTiles(zoneTilemap, tiles, zone.value.tiles)
tileArray = zone.value.tiles.map((row) => row.map((tileId) => tileId || 'blank_tile'))
}
zoneEventTiles.value = zone.value?.zoneEventTiles ?? []
zoneObjects.value = sortByIsometricDepth(zone.value?.zoneObjects ?? [])
// Center camera
const centerY = (zoneTilemap.height * zoneTilemap.tileHeight) / 2
const centerX = (zoneTilemap.width * zoneTilemap.tileWidth) / 2
scene.cameras.main.centerOn(centerX, centerY)
})
onUnmounted(() => {
zoneEventTiles.value = []
zoneObjects.value = []
tiles?.destroy()
zoneTilemap?.removeAllLayers()
zoneTilemap?.destroy()
zoneEditorStore.reset()
})
// watch zoneEditorStore.objectList and update originX and originY of objects in zoneObjects
watch(
objectList,
@ -317,5 +291,29 @@ const setSelectedZoneObject = (zoneObject: ZoneObject | null) => {
onBeforeMount(async () => {
await gameStore.fetchAllZoneAssets()
await loadAssets(scene)
tileArray.forEach((row, y) => row.forEach((_, x) => placeTile(zoneTilemap, tiles, x, y, 'blank_tile')))
if (zone.value?.tiles) {
setAllTiles(zoneTilemap, tiles, zone.value.tiles)
tileArray = zone.value.tiles.map((row) => row.map((tileId) => tileId || 'blank_tile'))
}
zoneEventTiles.value = zone.value?.zoneEventTiles ?? []
zoneObjects.value = sortByIsometricDepth(zone.value?.zoneObjects ?? [])
// Center camera
const centerY = (zoneTilemap.height * zoneTilemap.tileHeight) / 2
const centerX = (zoneTilemap.width * zoneTilemap.tileWidth) / 2
scene.cameras.main.centerOn(centerX, centerY)
})
onUnmounted(() => {
zoneEventTiles.value = []
zoneObjects.value = []
tiles?.destroy()
zoneTilemap?.removeAllLayers()
zoneTilemap?.destroy()
zoneEditorStore.reset()
})
</script>

View File

@ -74,24 +74,26 @@ const scrollToBottom = () => {
function calculateTextWidth(text: string, font: string, fontSize: number): number {
// Create a canvas element
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const canvas = document.createElement('canvas')
const context = canvas.getContext('2d')
if (!context) {
throw new Error('Unable to create canvas context');
throw new Error('Unable to create canvas context')
}
// Set the font
context.font = `${fontSize}px ${font}`;
context.font = `${fontSize}px ${font}`
// Measure the text width
const metrics = context.measureText(text);
const metrics = context.measureText(text)
return metrics.width;
return metrics.width
}
chatBubble.width = calculateTextWidth(data.message, 'Arial', 13) + 10
chatText.setText(data.message)
chatBubble.width = calculateTextWidth(data.message.substring(0, 90), 'Arial', 13) + 30
// setText but with max. char limit of 90
chatText.setText(data.message.substring(0, 90))
charChatContainer.setVisible(true)

View File

@ -1,58 +1,54 @@
<template>
<Container ref="charChatContainer" :depth="999" v-if="props.character" :x="currentX" :y="currentY">>
<Container ref="charChatContainer" :depth="999" :x="currentX" :y="currentY">
<RoundRectangle @create="createChatBubble" :origin-x="0.5" :origin-y="7.5" :fillColor="0xffffff" :width="194" :height="21" :radius="5" />
<Text @create="createChatText" :text="`This is a chat message 🤯👋`" :origin-x="0.5" :origin-y="10.9" :style="{ fontSize: 13, fontFamily: 'Arial', color: '#000' }" />
<Text @create="createChatText" text="" :origin-x="0.5" :origin-y="10.9" :style="{ fontSize: 13, fontFamily: 'Arial', color: '#000' }" />
</Container>
<Container :depth="999" v-if="props.character" :x="currentX" :y="currentY">
<Text @create="createText" :text="props.character.name" :origin-x="0.5" :origin-y="9" />
<Container :depth="999" :x="currentX" :y="currentY">
<Text @create="createText" :text="character.name" :origin-x="0.5" :origin-y="9" />
<RoundRectangle :origin-x="0.5" :origin-y="18.5" :fillColor="0xffffff" :width="74" :height="6" :radius="5" />
<RoundRectangle :origin-x="0.5" :origin-y="36.4" :fillColor="0x00b3b3" :width="70" :height="3" :radius="5" />
</Container>
<Container :depth="isometricDepth" v-if="props.character" :x="currentX" :y="currentY" ref="charContainer">
<Image v-if="!props.character.characterType" texture="character" :origin-y="1" />
<Sprite v-else :texture="charTexture" :play="props.character.isMoving ? charTexture : undefined" :origin-y="1" :flipX="props.character.rotation === 6 || props.character.rotation === 4" :flipY="false" />
<Container :depth="isometricDepth" :x="currentX" :y="currentY" ref="charContainer">
<Sprite ref="charSprite" :origin-y="1" :flipX="isFlippedX" :flipY="false" />
</Container>
</template>
<script lang="ts" setup>
import { Container, Image, refObj, RoundRectangle, Sprite, Text, useScene } from 'phavuer'
import { type ExtendedCharacter as CharacterT } from '@/types'
import { calculateIsometricDepth, tileToWorldX, tileToWorldY } from '@/composables/zoneComposable'
import { watch, computed, ref, onMounted, onUnmounted, type Ref } from 'vue'
import config from '@/config'
import { type ExtendedCharacter } from '@/types'
import { useGameStore } from '@/stores/gameStore'
import { useZoneStore } from '@/stores/zoneStore'
import { watch, computed, ref, onMounted, onUnmounted } from 'vue'
import { Container, refObj, RoundRectangle, Sprite, Text, useGame } from 'phavuer'
import { calculateIsometricDepth, tileToWorldX, tileToWorldY } from '@/composables/zoneComposable'
enum Direction {
POSITIVE,
NEGATIVE,
NOCHANGE
UNCHANGED
}
const charChatContainer = refObj() as Ref<Phaser.GameObjects.Container>;
const charContainer = refObj() as Ref<Phaser.GameObjects.Container>;
interface Props {
const props = defineProps<{
layer: Phaser.Tilemaps.TilemapLayer
character?: CharacterT
}
character: ExtendedCharacter
}>()
const props = withDefaults(defineProps<Props>(), {
character: undefined
})
const charChatContainer = refObj<Phaser.GameObjects.Container>()
const charContainer = refObj<Phaser.GameObjects.Container>()
const charSprite = refObj<Phaser.GameObjects.Sprite>()
const game = useGame()
const gameStore = useGameStore()
const zoneStore = useZoneStore()
const scene = useScene()
const isometricDepth = ref(calculateIsometricDepth(props.character!.positionX, props.character!.positionY, 28, 94, true))
const currentX = ref(0)
const currentY = ref(0)
const tween = ref<Phaser.Tweens.Tween | null>(null)
const isometricDepth = ref(1)
const isInitialPosition = ref(true)
const tween = ref<Phaser.Tweens.Tween | null>(null)
const calculateLocalDepth = (x: number, y: number, width: number, height: number, isCharacter: boolean) => {
isometricDepth.value = calculateIsometricDepth(x, y, width, height, isCharacter)
const updateIsometricDepth = (x: number, y: number) => {
isometricDepth.value = calculateIsometricDepth(x, y, 28, 94, true)
}
const updatePosition = (x: number, y: number, direction: Direction) => {
@ -66,133 +62,129 @@ const updatePosition = (x: number, y: number, direction: Direction) => {
return
}
if (tween.value && tween.value.isPlaying()) {
if (tween.value?.isPlaying()) {
tween.value.stop()
}
/**
* Calculate the distance between the current and target positions
*/
const distance = Math.sqrt(Math.pow(targetX - currentX.value, 2) + Math.pow(targetY - currentY.value, 2))
/**
* Teleport: No animation, only if the distance is greater than the tile size / 1.5
*/
if (distance >= config.tile_size.x / 1.2) {
// Teleport: No animation
if (distance >= config.tile_size.x / 1.1) {
currentX.value = targetX
currentY.value = targetY
return
}
/**
* Normal movement: Animate
*/
if (distance <= config.tile_size.x / 1.2) {
// Normal movement: Animate
const duration = distance * 6 // Adjust this multiplier to control overall speed
const duration = distance * 6
tween.value = props.layer.scene.tweens.add({
targets: { x: currentX.value, y: currentY.value },
x: targetX,
y: targetY,
duration: duration,
duration,
ease: 'Linear',
onStart: () => {
if (direction === Direction.POSITIVE) {
calculateLocalDepth(x, y, 28, 94, true)
updateIsometricDepth(x, y)
}
},
onUpdate: (tween) => {
currentX.value = tween.targets[0].x ?? 0
currentY.value = tween.targets[0].y ?? 0
currentX.value = tween.targets[0].x
currentY.value = tween.targets[0].y
},
onComplete: () => {
if (direction === Direction.NEGATIVE) {
calculateLocalDepth(x, y, 28, 94, true)
updateIsometricDepth(x, y)
}
}
})
}
const calcDirection = (oldX: number, oldY: number, newX: number, newY: number): Direction => {
if (newY < oldY || newX < oldX) return Direction.NEGATIVE
if (newX > oldX || newY > oldY) return Direction.POSITIVE
return Direction.UNCHANGED
}
const isFlippedX = computed(() => [6, 4].includes(props.character.rotation ?? 0))
const charTexture = computed(() => {
const { rotation, characterType, isMoving } = props.character
const spriteId = characterType?.sprite.id ?? 'idle_right_down'
const action = isMoving ? 'walk' : 'idle'
const direction = [0, 6].includes(rotation) ? 'left_up' : 'right_down'
return `${spriteId}-${action}_${direction}`
})
const updateSprite = () => {
if (props.character.isMoving) {
charSprite.value!.anims.play(charTexture.value, true)
return
}
charSprite.value!.anims.stop()
charSprite.value!.setFrame(0)
charSprite.value!.setTexture(charTexture.value)
}
const createChatBubble = (container: Phaser.GameObjects.Container) => {
container.setName(`${props.character.name}_chatBubble`)
}
const createChatText = (text: Phaser.GameObjects.Text) => {
text.setName(`${props.character.name}_chatText`)
text.setFontSize(13)
text.setFontStyle('bold')
text.setFontFamily('Arial')
// Fix text alignment on Windows
if (game.device.os.windows) {
text.setOrigin(0.5, 9.8)
}
}
const createText = (text: Phaser.GameObjects.Text) => {
text.setFontSize(13)
text.setFontFamily('Arial')
// Fix text alignment on Windows
if (game.device.os.windows) {
text.setOrigin(0.5, 8)
}
}
watch(
() => props.character,
(newChar, oldChar) => {
if (!newChar) return
if (!oldChar || newChar.positionX !== oldChar.positionX || newChar.positionY !== oldChar.positionY) {
if (!oldChar) {
updatePosition(newChar.positionX, newChar.positionY, Direction.POSITIVE)
} else {
const direction = calcDirection(oldChar.positionX, oldChar.positionY, newChar.positionX, newChar.positionY)
const direction = !oldChar ? Direction.POSITIVE : calcDirection(oldChar.positionX, oldChar.positionY, newChar.positionX, newChar.positionY)
updatePosition(newChar.positionX, newChar.positionY, direction)
}
}
},
{ immediate: true, deep: true }
)
const calcDirection = (oldX: number, oldY: number, newX: number, newY: number) => {
if (newY < oldY || newX < oldX) {
return Direction.NEGATIVE
}
if (newX > oldX || newY > oldY) {
return Direction.POSITIVE
}
return Direction.NOCHANGE
}
const charTexture = computed(() => {
if (!props.character?.characterType?.sprite) {
return 'idle_right_down'
}
const rotation = props.character.rotation
const spriteId = props.character.characterType.sprite.id
const action = props.character.isMoving ? 'walk' : 'idle'
if (rotation === 0 || rotation === 6) {
return `${spriteId}-${action}_left_up`
} else if (rotation === 2 || rotation === 4) {
return `${spriteId}-${action}_right_down`
}
return `${spriteId}-${action}_left_up`
})
const createChatBubble = (container: Phaser.GameObjects.Container) => {
container.setName(props.character?.name + '_chatBubble')
}
const createChatText = (text: Phaser.GameObjects.Text) => {
text.setName(props.character?.name + '_chatText')
text.setFontSize(13)
text.setFontFamily('Arial')
}
const createText = (text: Phaser.GameObjects.Text) => {
text.setFontSize(13)
text.setFontFamily('Arial')
}
watch(() => props.character.isMoving, updateSprite)
watch(() => props.character.rotation, updateSprite)
onMounted(() => {
// Check if player is this character, then lock with camera
if (props.character && props.character.id === gameStore.character?.id) {
charChatContainer.value?.setName(props.character.name + '_chatContainer')
charChatContainer.value?.setVisible(false)
charChatContainer.value!.setName(`${props.character!.name}_chatContainer`)
charChatContainer.value!.setVisible(false)
charContainer.value!.setName(props.character!.name)
charContainer.value?.setName(props.character.name)
zoneStore.characterLoaded = true;
if (props.character.id === gameStore.character!.id) {
zoneStore.setCharacterLoaded(true)
}
if (props.character) {
updatePosition(props.character.positionX, props.character.positionY, Direction.POSITIVE)
}
// Set sprite
charSprite.value!.setTexture(charTexture.value)
charSprite.value!.setFlipX(isFlippedX.value)
updatePosition(props.character.positionX, props.character.positionY, props.character.rotation)
})
onUnmounted(() => {
if (tween.value) {
tween.value.stop()
}
tween.value?.stop()
})
</script>

View File

@ -46,6 +46,7 @@ function createTileLayer() {
const layer = zoneTilemap.createBlankLayer('tiles', tilesetImages, 0, config.tile_size.y) as Phaser.Tilemaps.TilemapLayer
layer.setDepth(0)
layer.setCullPadding(2, 2)
return layer
}

View File

@ -8,7 +8,7 @@
import { useScene } from 'phavuer'
import { useGameStore } from '@/stores/gameStore'
import { useZoneStore } from '@/stores/zoneStore'
import { onBeforeUnmount, ref } from 'vue'
import { onBeforeMount, onBeforeUnmount, onMounted, ref } from 'vue'
import type { Character as CharacterT, Zone as ZoneT, ExtendedCharacter as ExtendedCharacterT } from '@/types'
import Tiles from '@/components/zone/Tiles.vue'
import Objects from '@/components/zone/Objects.vue'
@ -26,16 +26,6 @@ type zoneLoadData = {
characters: CharacterT[]
}
gameStore.connection!.emit('zone:character:join', async (response: zoneLoadData) => {
// Fetch assets for new zone
await gameStore.fetchZoneAssets(response.zone.id)
await loadAssets(scene)
// Set zone and characters
zoneStore.setZone(response.zone)
zoneStore.setCharacters(response.characters)
})
// Event listeners
gameStore.connection!.on('zone:character:teleport', async (data: zoneLoadData) => {
/**
@ -58,6 +48,8 @@ gameStore.connection!.on('zone:character:teleport', async (data: zoneLoadData) =
})
gameStore.connection!.on('zone:character:join', async (data: ExtendedCharacterT) => {
// If data is from the current user, don't add it to the store
if (data.id === gameStore.character?.id) return
zoneStore.addCharacter(data)
})
@ -69,6 +61,18 @@ gameStore.connection!.on('character:move', (data: ExtendedCharacterT) => {
zoneStore.updateCharacter(data)
})
onBeforeMount(() => {
gameStore.connection!.emit('zone:character:join', async (response: zoneLoadData) => {
// Fetch assets for new zone
await gameStore.fetchZoneAssets(response.zone.id)
await loadAssets(scene)
// Set zone and characters
zoneStore.setZone(response.zone)
zoneStore.setCharacters(response.characters)
})
})
onBeforeUnmount(() => {
zoneStore.reset()
gameStore.connection!.off('zone:character:teleport')

View File

@ -1,19 +1,19 @@
import { type Ref } from 'vue'
import { ref, type Ref } from 'vue'
import { getTile, tileToWorldXY } from '@/composables/zoneComposable'
import { useGameStore } from '@/stores/gameStore'
import config from '@/config'
export function useGamePointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>, camera: Phaser.Cameras.Scene2D.Camera) {
const gameStore = useGameStore()
const lastDragTime = ref(0)
const dragTimeout = 500 // 500ms timeout for dragging, to prevent accidental clicks
function updateWaypoint(pointer: Phaser.Input.Pointer) {
const { x: px, y: py } = camera.getWorldPoint(pointer.x, pointer.y)
const pointerTile = getTile(px, py, layer)
waypoint.value.visible = !!pointerTile
if (!pointerTile) {
return
}
if (!pointerTile) return
const worldPoint = tileToWorldXY(layer, pointerTile.x, pointerTile.y)
waypoint.value.x = worldPoint.positionX
@ -21,13 +21,13 @@ export function useGamePointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilema
}
function dragZone(pointer: Phaser.Input.Pointer) {
if (!gameStore.isPlayerDraggingCamera) {
return
}
if (!gameStore.isPlayerDraggingCamera) return
const { x, y, prevPosition } = pointer
const { scrollX, scrollY, zoom } = camera
camera.setScroll(scrollX - (x - prevPosition.x) / zoom, scrollY - (y - prevPosition.y) / zoom)
lastDragTime.value = Date.now()
}
function handlePointerMove(pointer: Phaser.Input.Pointer) {
@ -36,12 +36,15 @@ export function useGamePointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilema
}
function clickTile(pointer: Phaser.Input.Pointer) {
const currentTime = Date.now()
if (currentTime - lastDragTime.value < dragTimeout) {
return
}
const { x: px, y: py } = camera.getWorldPoint(pointer.x, pointer.y)
const pointerTile = getTile(px, py, layer)
if (!pointerTile) {
return
}
if (!pointerTile) return
gameStore.connection?.emit('character:initMove', {
positionX: pointerTile.x,
@ -49,13 +52,13 @@ export function useGamePointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilema
})
}
function handleZoom({ event, deltaY }: Phaser.Input.Pointer) {
if (event instanceof WheelEvent && event.shiftKey) {
return
}
function handleZoom(pointer: Phaser.Input.Pointer) {
if (!(pointer.event instanceof WheelEvent) || !pointer.event.shiftKey) return
scene.scale.setZoom(scene.scale.zoom - deltaY * 0.01)
camera = scene.cameras.main
const deltaY = pointer.event.deltaY
let zoomLevel = camera.zoom - deltaY * 0.005
if(zoomLevel <= 0 || zoomLevel >= 3) return
camera.setZoom(zoomLevel)
}
const setupPointerHandlers = () => {

View File

@ -1,4 +1,4 @@
import { computed, type Ref, ref } from 'vue'
import { computed, type Ref } from 'vue'
import { getTile, tileToWorldXY } from '@/composables/zoneComposable'
import { useZoneEditorStore } from '@/stores/zoneEditorStore'
import config from '@/config'
@ -14,9 +14,7 @@ export function useZoneEditorPointerHandlers(scene: Phaser.Scene, layer: Phaser.
const pointerTile = getTile(px, py, layer)
waypoint.value.visible = !!pointerTile
if (!pointerTile) {
return
}
if (!pointerTile) return
const worldPoint = tileToWorldXY(layer, pointerTile.x, pointerTile.y)
waypoint.value.x = worldPoint.positionX
@ -24,12 +22,12 @@ export function useZoneEditorPointerHandlers(scene: Phaser.Scene, layer: Phaser.
}
function dragZone(pointer: Phaser.Input.Pointer) {
if (gameStore.isPlayerDraggingCamera) {
if (!gameStore.isPlayerDraggingCamera) return
const { x, y, prevPosition } = pointer
const { scrollX, scrollY, zoom } = camera
camera.setScroll(scrollX - (x - prevPosition.x) / zoom, scrollY - (y - prevPosition.y) / zoom)
}
}
function handlePointerMove(pointer: Phaser.Input.Pointer) {
if (isMoveTool.value || pointer.event.shiftKey) {
@ -38,13 +36,13 @@ export function useZoneEditorPointerHandlers(scene: Phaser.Scene, layer: Phaser.
updateWaypoint(pointer)
}
function handleZoom({ event, deltaY }: Phaser.Input.Pointer) {
if (event! instanceof WheelEvent && !event.shiftKey) {
return
}
function handleZoom(pointer: Phaser.Input.Pointer) {
if (!(pointer.event instanceof WheelEvent) || !pointer.event.shiftKey) return
scene.scale.setZoom(scene.scale.zoom - deltaY * 0.01)
camera = scene.cameras.main
const deltaY = pointer.event.deltaY
let zoomLevel = camera.zoom - deltaY * 0.005
if(zoomLevel <= 0 || zoomLevel >= 3) return
camera.setZoom(zoomLevel)
}
const setupPointerHandlers = () => {

View File

@ -1,5 +1,4 @@
import { useGameStore } from '@/stores/gameStore'
import { useScene } from 'phavuer'
import { watch } from 'vue'
import { useZoneStore } from '@/stores/zoneStore'
@ -9,10 +8,8 @@ export function useCameraControls(scene: Phaser.Scene): any {
const camera = scene.cameras.main
function onPointerDown(pointer: Phaser.Input.Pointer) {
if (pointer.event instanceof MouseEvent || pointer.event.shiftKey) {
gameStore.setPlayerDraggingCamera(true)
}
}
function onPointerUp() {
gameStore.setPlayerDraggingCamera(false)
@ -21,9 +18,8 @@ export function useCameraControls(scene: Phaser.Scene): any {
watch(
() => zoneStore.characterLoaded,
(characterLoaded) => {
if(characterLoaded) {
scene.cameras.main.startFollow(scene.children.getByName(gameStore.character!.name) as Phaser.GameObjects.Container);
}
if (!characterLoaded) return
// scene.cameras.main.startFollow(scene.children.getByName(gameStore.character!.name) as Phaser.GameObjects.Container);
}
)

View File

@ -4,12 +4,11 @@ import { useGamePointerHandlers } from '@/composables/pointerHandlers/useGamePoi
import { useZoneEditorPointerHandlers } from '@/composables/pointerHandlers/useZoneEditorPointerHandlers'
import { useGameStore } from '@/stores/gameStore'
export function usePointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>, camera: Ref<Phaser.Cameras.Scene2D.Camera>, isDragging: Ref<boolean>) {
const gameStore = useGameStore()
export function usePointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>, camera: Phaser.Cameras.Scene2D.Camera) {
const zoneEditorStore = useZoneEditorStore()
const gameHandlers = useGamePointerHandlers(scene, layer, waypoint, camera, isDragging)
const zoneEditorHandlers = useZoneEditorPointerHandlers(scene, layer, waypoint, camera, isDragging)
const gameHandlers = useGamePointerHandlers(scene, layer, waypoint, camera)
const zoneEditorHandlers = useZoneEditorPointerHandlers(scene, layer, waypoint, camera)
const currentHandlers = computed(() => (zoneEditorStore.active ? zoneEditorHandlers : gameHandlers))

View File

@ -1,12 +1,9 @@
const dev: boolean = true
export default {
name: 'New Quest',
development: dev,
server_endpoint: dev ? 'http://localhost:4000' : 'https://nq-server.cr-a.directonline.io',
tile_size: { x: 64, y: 32, z: 1 }
name: import.meta.env.VITE_NAME,
development: import.meta.env.VITE_DEVELOPMENT === 'true',
server_endpoint: import.meta.env.VITE_SERVER_ENDPOINT,
tile_size: {
x: Number(import.meta.env.VITE_TILE_SIZE_X),
y: Number(import.meta.env.VITE_TILE_SIZE_Y),
}
}
/**
* @TODO: Implement .env like server has
*/

View File

@ -1,18 +1,19 @@
<template>
<div class="flex justify-center items-center h-dvh relative">
<GmTools v-if="isLoaded && gameStore.character?.role === 'gm'" />
<GmPanel v-if="isLoaded && gameStore.character?.role === 'gm'" />
<Inventory />
<GmTools v-if="gameStore.character?.role === 'gm'" />
<GmPanel v-if="gameStore.character?.role === 'gm'" />
<div v-if="!zoneEditorStore.active">
<Game :config="gameConfig" @create="createGame" class="111mt-[-60px]">
<Game :config="gameConfig" @create="createGame">
<Scene name="main" @preload="preloadScene" @create="createScene">
<div v-if="isLoaded">
<Inventory />
<div class="fixed inset-x-0 top-0 flex justify-start items-end p-10 pointer-events-none">
<div class="pointer-events-auto">
<Hud />
</div>
</div>
<Zone v-if="isLoaded" />
<Zone />
<div class="fixed inset-x-0 bottom-0 flex justify-between gap-5 items-end py-10 px-5 xxs:p-10 pointer-events-none max-md:flex-wrap max-md:flex-col-reverse">
<div class="pointer-events-auto w-full">
<Chat />
@ -21,6 +22,7 @@
<Menubar />
</div>
</div>
</div>
</Scene>
</Game>
</div>
@ -59,14 +61,9 @@ const gameConfig = {
width: window.innerWidth,
height: window.innerHeight,
type: Phaser.AUTO, // AUTO, CANVAS, WEBGL, HEADLESS
scale: {
mode: Phaser.Scale.RESIZE,
autoCenter: Phaser.Scale.CENTER_BOTH,
width: window.innerWidth,
height: window.innerHeight
},
resolution: 2,
pixelArt: true
resolution: 3,
render: { pixelArt: true, antialias: false }
}
const createGame = (game: Phaser.Game) => {
@ -76,9 +73,20 @@ const createGame = (game: Phaser.Game) => {
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
*/
@ -144,14 +152,14 @@ const createScene = async (scene: Phaser.Scene) => {
scene.anims.create({
key: asset.key,
frameRate: 7,
/** @TODO: Fix end, which is total amount of frames */
frames: scene.anims.generateFrameNumbers(asset.key, { start: 0, end: 4 }),
frames: scene.anims.generateFrameNumbers(asset.key, { start: 0, end: asset.frameCount! - 1 }),
repeat: -1
})
})
}
onBeforeUnmount(() => {
isLoaded.value = false
gameStore.disconnectSocket()
})
</script>

View File

@ -5,7 +5,7 @@ export const useZoneStore = defineStore('zone', {
state: () => ({
zone: null as Zone | null,
characters: [] as ExtendedCharacter[],
characterLoaded: false,
characterLoaded: false
}),
getters: {
getCharacterById: (state) => {
@ -37,9 +37,13 @@ export const useZoneStore = defineStore('zone', {
removeCharacter(character_id: number) {
this.characters = this.characters.filter((char) => char.id !== character_id)
},
setCharacterLoaded(loaded: boolean) {
this.characterLoaded = loaded
},
reset() {
this.zone = null
this.characters = []
this.characterLoaded = false
}
}
})

View File

@ -1,5 +1,6 @@
export type Notification = {
id?: string
title?: string
message?: string
}
@ -7,6 +8,7 @@ export type Asset = {
key: string
url: string
group: 'tiles' | 'objects' | 'sprites' | 'sprite_animations' | 'sound' | 'music' | 'ui' | 'font' | 'other'
frameCount?: number
frameWidth?: number
frameHeight?: number
}