progress
This commit is contained in:
parent
3755f2857a
commit
5392dce264
2
.env
2
.env
@ -1,2 +1,2 @@
|
|||||||
VITE_LOG_LEVEL= 'error'
|
VITE_LOG_LEVEL= 'trace'
|
||||||
VITE_API_URL= 'http://localhost:3000/api'
|
VITE_API_URL= 'http://localhost:3000/api'
|
@ -3,13 +3,13 @@ require('@rushstack/eslint-patch/modern-module-resolution')
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
root: true,
|
root: true,
|
||||||
'extends': [
|
extends: [
|
||||||
'plugin:vue/vue3-essential',
|
'plugin:vue/vue3-essential',
|
||||||
'eslint:recommended',
|
'eslint:recommended',
|
||||||
'@vue/eslint-config-typescript',
|
'@vue/eslint-config-typescript',
|
||||||
'@vue/eslint-config-prettier/skip-formatting'
|
'@vue/eslint-config-prettier/skip-formatting',
|
||||||
],
|
],
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
ecmaVersion: 'latest'
|
ecmaVersion: 'latest',
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
@ -4,5 +4,5 @@
|
|||||||
"tabWidth": 2,
|
"tabWidth": 2,
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"printWidth": 100,
|
"printWidth": 100,
|
||||||
"trailingComma": "none"
|
"trailingComma": "all"
|
||||||
}
|
}
|
||||||
|
9
package-lock.json
generated
9
package-lock.json
generated
@ -8,6 +8,7 @@
|
|||||||
"name": "domino-client",
|
"name": "domino-client",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@pixi/sound": "^6.0.0",
|
||||||
"bulma": "^1.0.1",
|
"bulma": "^1.0.1",
|
||||||
"colorette": "^2.0.20",
|
"colorette": "^2.0.20",
|
||||||
"dayjs": "^1.11.11",
|
"dayjs": "^1.11.11",
|
||||||
@ -664,6 +665,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@pixi/colord/-/colord-2.9.6.tgz",
|
"resolved": "https://registry.npmjs.org/@pixi/colord/-/colord-2.9.6.tgz",
|
||||||
"integrity": "sha512-nezytU2pw587fQstUu1AsJZDVEynjskwOL+kibwcdxsMBFqPsFFNA7xl0ii/gXuDi6M0xj3mfRJj8pBSc2jCfA=="
|
"integrity": "sha512-nezytU2pw587fQstUu1AsJZDVEynjskwOL+kibwcdxsMBFqPsFFNA7xl0ii/gXuDi6M0xj3mfRJj8pBSc2jCfA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@pixi/sound": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@pixi/sound/-/sound-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-fEaCs2JmyYT1qqouFS3DydSccI35dyYD0pKK2hEbIGVDKUTvl224x0p4qme2YU9l465WRtM7gspLzP5fFf1mxQ==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"pixi.js": "^8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@pkgjs/parseargs": {
|
"node_modules/@pkgjs/parseargs": {
|
||||||
"version": "0.11.0",
|
"version": "0.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
"format": "prettier --write src/"
|
"format": "prettier --write src/"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@pixi/sound": "^6.0.0",
|
||||||
"bulma": "^1.0.1",
|
"bulma": "^1.0.1",
|
||||||
"colorette": "^2.0.20",
|
"colorette": "^2.0.20",
|
||||||
"dayjs": "^1.11.11",
|
"dayjs": "^1.11.11",
|
||||||
|
BIN
src/assets/images/backgrounds/bg-blue.png
Normal file
BIN
src/assets/images/backgrounds/bg-blue.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.9 MiB |
BIN
src/assets/images/backgrounds/bg-red.png
Normal file
BIN
src/assets/images/backgrounds/bg-red.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.9 MiB |
BIN
src/assets/images/backgrounds/bg-yellow.png
Normal file
BIN
src/assets/images/backgrounds/bg-yellow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.8 MiB |
BIN
src/assets/sounds/intro.mp3
Normal file
BIN
src/assets/sounds/intro.mp3
Normal file
Binary file not shown.
BIN
src/assets/sounds/move-1.mp3
Normal file
BIN
src/assets/sounds/move-1.mp3
Normal file
Binary file not shown.
BIN
src/assets/sounds/move-2.mp3
Normal file
BIN
src/assets/sounds/move-2.mp3
Normal file
Binary file not shown.
BIN
src/assets/sounds/move-3.mp3
Normal file
BIN
src/assets/sounds/move-3.mp3
Normal file
Binary file not shown.
BIN
src/assets/sounds/move-4.mp3
Normal file
BIN
src/assets/sounds/move-4.mp3
Normal file
Binary file not shown.
BIN
src/assets/sounds/move-sprite.mp3
Normal file
BIN
src/assets/sounds/move-sprite.mp3
Normal file
Binary file not shown.
BIN
src/assets/sounds/move-sprite.ogg
Normal file
BIN
src/assets/sounds/move-sprite.ogg
Normal file
Binary file not shown.
@ -17,8 +17,13 @@ export function getColorBackground(container: Container, colorName: string, alph
|
|||||||
export function createContainer(options: ContainerOptions) {
|
export function createContainer(options: ContainerOptions) {
|
||||||
const opts = { ...DEFAULT_CONTAINER_OPTIONS, ...options }
|
const opts = { ...DEFAULT_CONTAINER_OPTIONS, ...options }
|
||||||
const container = new Container()
|
const container = new Container()
|
||||||
|
container.x = opts.x
|
||||||
|
container.y = opts.y
|
||||||
|
if (opts.parent) {
|
||||||
|
opts.parent.addChild(container)
|
||||||
|
}
|
||||||
|
|
||||||
const rect = new Graphics().rect(opts.x, opts.y, opts.width, opts.height)
|
const rect = new Graphics().rect(0, 0, opts.width, opts.height)
|
||||||
|
|
||||||
if (opts.color) {
|
if (opts.color) {
|
||||||
rect.fill(opts.color)
|
rect.fill(opts.color)
|
||||||
@ -29,19 +34,17 @@ export function createContainer(options: ContainerOptions) {
|
|||||||
|
|
||||||
rect.visible = opts.visible
|
rect.visible = opts.visible
|
||||||
container.addChild(rect)
|
container.addChild(rect)
|
||||||
if (opts.parent) {
|
|
||||||
opts.parent.addChild(container)
|
|
||||||
}
|
|
||||||
return container
|
return container
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createButton(
|
export function createButton(options: {
|
||||||
textStr: string,
|
text: string
|
||||||
dimension: Dimension,
|
dimension: Dimension
|
||||||
action: Function,
|
action: Function
|
||||||
parent?: Container
|
parent?: Container
|
||||||
): Container {
|
}): Container {
|
||||||
const { x, y, width, height } = dimension
|
const { text: textStr, dimension, action, parent } = options
|
||||||
|
const { x, y, width, height = 25 } = dimension
|
||||||
const rectangle = new Graphics().roundRect(x, y, width + 4, height + 4, 5).fill(0xffff00)
|
const rectangle = new Graphics().roundRect(x, y, width + 4, height + 4, 5).fill(0xffff00)
|
||||||
const text = new Text({
|
const text = new Text({
|
||||||
text: textStr,
|
text: textStr,
|
||||||
@ -50,8 +53,8 @@ export function createButton(
|
|||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
fill: 0x121212,
|
fill: 0x121212,
|
||||||
align: 'center'
|
align: 'center',
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
text.anchor = 0.5
|
text.anchor = 0.5
|
||||||
const container = new Container()
|
const container = new Container()
|
||||||
|
@ -34,7 +34,7 @@ export interface MatchSessionDto {
|
|||||||
maxPlayers: number
|
maxPlayers: number
|
||||||
numPlayers: number
|
numPlayers: number
|
||||||
waitingSeconds: number
|
waitingSeconds: number
|
||||||
scoreboard: Map<string, number>
|
scoreboard: { id: string; name: string; score: number }[]
|
||||||
matchWinner: PlayerDto | null
|
matchWinner: PlayerDto | null
|
||||||
matchInProgress: boolean
|
matchInProgress: boolean
|
||||||
playersReady: number
|
playersReady: number
|
||||||
@ -98,3 +98,20 @@ export interface AnimationOptions {
|
|||||||
width?: number
|
width?: number
|
||||||
height?: number
|
height?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GameOptions {
|
||||||
|
boardScale?: number
|
||||||
|
handScale?: number
|
||||||
|
width?: number
|
||||||
|
height?: number
|
||||||
|
background?: string
|
||||||
|
teamed?: boolean
|
||||||
|
}
|
||||||
|
export interface GameSummary {
|
||||||
|
gameId: string
|
||||||
|
isBlocked: boolean
|
||||||
|
isTied: boolean
|
||||||
|
winner: PlayerDto
|
||||||
|
score: { id: string; name: string; score: number }[]
|
||||||
|
players?: PlayerDto[]
|
||||||
|
}
|
||||||
|
269
src/common/summarymock.ts
Normal file
269
src/common/summarymock.ts
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
export const summaryMock = {
|
||||||
|
lastGame: {
|
||||||
|
gameId: '6cd2b32c-185e-4869-a3f9-7a1a718a00f7',
|
||||||
|
isBlocked: true,
|
||||||
|
isTied: false,
|
||||||
|
winner: {
|
||||||
|
id: '23ed7e37-84e2-4e4e-b833-e97aef351f18',
|
||||||
|
name: 'Bob (AI)',
|
||||||
|
score: 14,
|
||||||
|
hand: [
|
||||||
|
{
|
||||||
|
id: '69c6e996-7dd4-4565-a49c-96b7ba35db7d',
|
||||||
|
flipped: false,
|
||||||
|
revealed: true,
|
||||||
|
playerId: '23ed7e37-84e2-4e4e-b833-e97aef351f18',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
teamedWith: null,
|
||||||
|
ready: true,
|
||||||
|
},
|
||||||
|
score: [
|
||||||
|
{
|
||||||
|
id: '668977662eb15e2ef3bdac3f',
|
||||||
|
name: 'arhuako',
|
||||||
|
score: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3494d8b9-6b15-49e5-8fec-15e2d6539f71',
|
||||||
|
name: 'Alice (AI)',
|
||||||
|
score: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '23ed7e37-84e2-4e4e-b833-e97aef351f18',
|
||||||
|
name: 'Bob (AI)',
|
||||||
|
score: 14,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2eda2a20-a97a-4310-a431-3aaef916e602',
|
||||||
|
name: 'Charlie (AI)',
|
||||||
|
score: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
players: [
|
||||||
|
{
|
||||||
|
id: '668977662eb15e2ef3bdac3f',
|
||||||
|
name: 'arhuako',
|
||||||
|
score: 0,
|
||||||
|
hand: [
|
||||||
|
{
|
||||||
|
id: '93d523a2-ae4d-4b51-a7a7-2e740be2da14',
|
||||||
|
flipped: false,
|
||||||
|
revealed: true,
|
||||||
|
playerId: '668977662eb15e2ef3bdac3f',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
teamedWith: null,
|
||||||
|
ready: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3494d8b9-6b15-49e5-8fec-15e2d6539f71',
|
||||||
|
name: 'Alice (AI)',
|
||||||
|
score: 0,
|
||||||
|
hand: [
|
||||||
|
{
|
||||||
|
id: 'cf9a04f9-3d8e-4feb-afa6-34a8a61ec014',
|
||||||
|
flipped: false,
|
||||||
|
revealed: true,
|
||||||
|
playerId: '3494d8b9-6b15-49e5-8fec-15e2d6539f71',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
teamedWith: null,
|
||||||
|
ready: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '23ed7e37-84e2-4e4e-b833-e97aef351f18',
|
||||||
|
name: 'Bob (AI)',
|
||||||
|
score: 14,
|
||||||
|
hand: [
|
||||||
|
{
|
||||||
|
id: '69c6e996-7dd4-4565-a49c-96b7ba35db7d',
|
||||||
|
flipped: false,
|
||||||
|
revealed: true,
|
||||||
|
playerId: '23ed7e37-84e2-4e4e-b833-e97aef351f18',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
teamedWith: null,
|
||||||
|
ready: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2eda2a20-a97a-4310-a431-3aaef916e602',
|
||||||
|
name: 'Charlie (AI)',
|
||||||
|
score: 0,
|
||||||
|
hand: [
|
||||||
|
{
|
||||||
|
id: '22d0a60c-b9e9-43f6-804b-6899221de04d',
|
||||||
|
flipped: false,
|
||||||
|
revealed: true,
|
||||||
|
playerId: '2eda2a20-a97a-4310-a431-3aaef916e602',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
teamedWith: null,
|
||||||
|
ready: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
sessionState: {
|
||||||
|
id: '669524c8b78825b8f9ede908',
|
||||||
|
name: 'Test #26',
|
||||||
|
creator: '668977662eb15e2ef3bdac3f',
|
||||||
|
players: [
|
||||||
|
{
|
||||||
|
id: '668977662eb15e2ef3bdac3f',
|
||||||
|
name: 'arhuako',
|
||||||
|
score: 0,
|
||||||
|
hand: [],
|
||||||
|
teamedWith: null,
|
||||||
|
ready: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3494d8b9-6b15-49e5-8fec-15e2d6539f71',
|
||||||
|
name: 'Alice (AI)',
|
||||||
|
score: 0,
|
||||||
|
hand: [],
|
||||||
|
teamedWith: null,
|
||||||
|
ready: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '23ed7e37-84e2-4e4e-b833-e97aef351f18',
|
||||||
|
name: 'Bob (AI)',
|
||||||
|
score: 0,
|
||||||
|
hand: [],
|
||||||
|
teamedWith: null,
|
||||||
|
ready: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2eda2a20-a97a-4310-a431-3aaef916e602',
|
||||||
|
name: 'Charlie (AI)',
|
||||||
|
score: 0,
|
||||||
|
hand: [],
|
||||||
|
teamedWith: null,
|
||||||
|
ready: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
playersReady: 0,
|
||||||
|
sessionInProgress: true,
|
||||||
|
maxPlayers: 4,
|
||||||
|
numPlayers: 4,
|
||||||
|
waitingForPlayers: false,
|
||||||
|
waitingSeconds: 0,
|
||||||
|
seed: '1721050312717-840b4s07gb8-8d980dd8',
|
||||||
|
mode: 'classic',
|
||||||
|
pointsToWin: 50,
|
||||||
|
status: 'in progress',
|
||||||
|
scoreboard: [
|
||||||
|
['arhuako', 0],
|
||||||
|
['Alice (AI)', 0],
|
||||||
|
['Bob (AI)', 14],
|
||||||
|
['Charlie (AI)', 0],
|
||||||
|
],
|
||||||
|
matchWinner: null,
|
||||||
|
matchInProgress: true,
|
||||||
|
gameSummaries: [
|
||||||
|
{
|
||||||
|
gameId: '6cd2b32c-185e-4869-a3f9-7a1a718a00f7',
|
||||||
|
isBlocked: true,
|
||||||
|
isTied: false,
|
||||||
|
winner: {
|
||||||
|
id: '23ed7e37-84e2-4e4e-b833-e97aef351f18',
|
||||||
|
name: 'Bob (AI)',
|
||||||
|
score: 14,
|
||||||
|
hand: [
|
||||||
|
{
|
||||||
|
id: '69c6e996-7dd4-4565-a49c-96b7ba35db7d',
|
||||||
|
flipped: false,
|
||||||
|
revealed: true,
|
||||||
|
playerId: '23ed7e37-84e2-4e4e-b833-e97aef351f18',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
teamedWith: null,
|
||||||
|
ready: true,
|
||||||
|
},
|
||||||
|
score: [
|
||||||
|
{
|
||||||
|
id: '668977662eb15e2ef3bdac3f',
|
||||||
|
name: 'arhuako',
|
||||||
|
score: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3494d8b9-6b15-49e5-8fec-15e2d6539f71',
|
||||||
|
name: 'Alice (AI)',
|
||||||
|
score: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '23ed7e37-84e2-4e4e-b833-e97aef351f18',
|
||||||
|
name: 'Bob (AI)',
|
||||||
|
score: 14,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2eda2a20-a97a-4310-a431-3aaef916e602',
|
||||||
|
name: 'Charlie (AI)',
|
||||||
|
score: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
players: [
|
||||||
|
{
|
||||||
|
id: '668977662eb15e2ef3bdac3f',
|
||||||
|
name: 'arhuako',
|
||||||
|
score: 0,
|
||||||
|
hand: [
|
||||||
|
{
|
||||||
|
id: '93d523a2-ae4d-4b51-a7a7-2e740be2da14',
|
||||||
|
flipped: false,
|
||||||
|
revealed: true,
|
||||||
|
playerId: '668977662eb15e2ef3bdac3f',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
teamedWith: null,
|
||||||
|
ready: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3494d8b9-6b15-49e5-8fec-15e2d6539f71',
|
||||||
|
name: 'Alice (AI)',
|
||||||
|
score: 0,
|
||||||
|
hand: [
|
||||||
|
{
|
||||||
|
id: 'cf9a04f9-3d8e-4feb-afa6-34a8a61ec014',
|
||||||
|
flipped: false,
|
||||||
|
revealed: true,
|
||||||
|
playerId: '3494d8b9-6b15-49e5-8fec-15e2d6539f71',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
teamedWith: null,
|
||||||
|
ready: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '23ed7e37-84e2-4e4e-b833-e97aef351f18',
|
||||||
|
name: 'Bob (AI)',
|
||||||
|
score: 14,
|
||||||
|
hand: [
|
||||||
|
{
|
||||||
|
id: '69c6e996-7dd4-4565-a49c-96b7ba35db7d',
|
||||||
|
flipped: false,
|
||||||
|
revealed: true,
|
||||||
|
playerId: '23ed7e37-84e2-4e4e-b833-e97aef351f18',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
teamedWith: null,
|
||||||
|
ready: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2eda2a20-a97a-4310-a431-3aaef916e602',
|
||||||
|
name: 'Charlie (AI)',
|
||||||
|
score: 0,
|
||||||
|
hand: [
|
||||||
|
{
|
||||||
|
id: '22d0a60c-b9e9-43f6-804b-6899221de04d',
|
||||||
|
flipped: false,
|
||||||
|
revealed: true,
|
||||||
|
playerId: '2eda2a20-a97a-4310-a431-3aaef916e602',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
teamedWith: null,
|
||||||
|
ready: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
@ -5,13 +5,16 @@ import { Game } from '@/game/Game'
|
|||||||
import { useGameStore } from '@/stores/game'
|
import { useGameStore } from '@/stores/game'
|
||||||
import { useEventBusStore } from '@/stores/eventBus'
|
import { useEventBusStore } from '@/stores/eventBus'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { useGameOptionsStore } from '@/stores/gameOptions'
|
||||||
|
|
||||||
const socketService: any = inject('socket')
|
const socketService: any = inject('socket')
|
||||||
|
|
||||||
const gameStore = useGameStore()
|
const gameStore = useGameStore()
|
||||||
|
const gameOptionsStore = useGameOptionsStore()
|
||||||
const eventBus = useEventBusStore()
|
const eventBus = useEventBusStore()
|
||||||
const { playerState, sessionState } = storeToRefs(gameStore)
|
const { playerState, sessionState } = storeToRefs(gameStore)
|
||||||
const { updateGameState } = gameStore
|
const { updateGameState } = gameStore
|
||||||
|
const { gameOptions } = storeToRefs(gameOptionsStore)
|
||||||
|
|
||||||
const minScreenWidth = 800
|
const minScreenWidth = 800
|
||||||
const minScreenHeight = 700
|
const minScreenHeight = 700
|
||||||
@ -31,11 +34,12 @@ const game = new Game(
|
|||||||
width: screenWidth,
|
width: screenWidth,
|
||||||
height: screenHeight,
|
height: screenHeight,
|
||||||
boardScale,
|
boardScale,
|
||||||
handScale: 1
|
handScale: 1,
|
||||||
|
background: gameOptions.value?.background || 'green',
|
||||||
},
|
},
|
||||||
socketService,
|
socketService,
|
||||||
playerState.value?.id || '',
|
playerState.value?.id || '',
|
||||||
sessionState.value?.id || ''
|
sessionState.value?.id || '',
|
||||||
)
|
)
|
||||||
|
|
||||||
// watch(
|
// watch(
|
||||||
|
@ -8,6 +8,7 @@ import { LoggingService } from '@/services/LoggingService'
|
|||||||
import { GlowFilter } from 'pixi-filters'
|
import { GlowFilter } from 'pixi-filters'
|
||||||
import { ORIENTATION_ANGLES } from '@/common/constants'
|
import { ORIENTATION_ANGLES } from '@/common/constants'
|
||||||
import type { OtherHand } from './OtherHand'
|
import type { OtherHand } from './OtherHand'
|
||||||
|
import { sound } from '@pixi/sound'
|
||||||
|
|
||||||
export class Board extends EventEmitter {
|
export class Board extends EventEmitter {
|
||||||
private _scale: number = 1
|
private _scale: number = 1
|
||||||
@ -46,63 +47,61 @@ export class Board extends EventEmitter {
|
|||||||
constructor(app: Application) {
|
constructor(app: Application) {
|
||||||
super()
|
super()
|
||||||
this.ticker = app.ticker
|
this.ticker = app.ticker
|
||||||
this.height = app.canvas.height - 130
|
this.height = app.canvas.height - 130 - 130
|
||||||
this.width = app.canvas.width
|
this.width = app.canvas.width
|
||||||
this.scaleX = Scale([0, this.width], [0, this.width])
|
this.scaleX = Scale([0, this.width], [0, this.width])
|
||||||
this.scaleY = Scale([0, this.height], [0, this.height])
|
this.scaleY = Scale([0, this.height], [0, this.height])
|
||||||
this.calculateScale()
|
this.calculateScale()
|
||||||
|
|
||||||
this.container = createContainer({
|
this.container = createContainer({
|
||||||
|
y: 130,
|
||||||
width: this.width,
|
width: this.width,
|
||||||
height: this.height,
|
height: this.height,
|
||||||
parent: app.stage
|
parent: app.stage,
|
||||||
})
|
})
|
||||||
|
|
||||||
const background = new Sprite(Assets.get('bg-green'))
|
// this.container.y = 130
|
||||||
// background.width = this.width
|
|
||||||
// background.height = this.height
|
|
||||||
this.container.addChild(background)
|
|
||||||
|
|
||||||
this.initialContainer = createContainer({
|
this.initialContainer = createContainer({
|
||||||
width: this.width,
|
width: this.width,
|
||||||
height: this.height,
|
height: this.height,
|
||||||
// color: 0x1e2f23,
|
// color: 0x1e2f23,
|
||||||
visible: false,
|
visible: false,
|
||||||
parent: this.container
|
parent: this.container,
|
||||||
})
|
})
|
||||||
|
|
||||||
this.tilesContainer = createContainer({
|
this.tilesContainer = createContainer({
|
||||||
width: this.width,
|
width: this.width,
|
||||||
height: this.height,
|
height: this.height,
|
||||||
// color: 0x1e2f23,
|
// color: 0x1e2f23,
|
||||||
parent: this.container
|
parent: this.container,
|
||||||
})
|
})
|
||||||
|
|
||||||
this.interactionContainer = createContainer({
|
this.interactionContainer = createContainer({
|
||||||
width: this.width,
|
width: this.width,
|
||||||
height: this.height,
|
height: this.height,
|
||||||
parent: this.container,
|
parent: this.container,
|
||||||
visible: false
|
visible: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
createCrosshair(this.tilesContainer, 0xff0000, {
|
createCrosshair(this.tilesContainer, 0xff0000, {
|
||||||
width: this.width,
|
width: this.width,
|
||||||
height: this.height,
|
height: this.height,
|
||||||
x: this.scaleX(0),
|
x: this.scaleX(0),
|
||||||
y: this.scaleY(0)
|
y: this.scaleY(0),
|
||||||
})
|
})
|
||||||
|
|
||||||
createCrosshair(this.interactionContainer, 0xffff00, {
|
createCrosshair(this.interactionContainer, 0xffff00, {
|
||||||
width: this.width,
|
width: this.width,
|
||||||
height: this.height,
|
height: this.height,
|
||||||
x: this.scaleX(0),
|
x: this.scaleX(0),
|
||||||
y: this.scaleY(0)
|
y: this.scaleY(0),
|
||||||
})
|
})
|
||||||
|
|
||||||
this.textContainer = createContainer({
|
this.textContainer = createContainer({
|
||||||
width: this.width,
|
width: this.width,
|
||||||
height: this.height,
|
height: this.height,
|
||||||
parent: this.container
|
parent: this.container,
|
||||||
})
|
})
|
||||||
|
|
||||||
this.showText('Starting game...')
|
this.showText('Starting game...')
|
||||||
@ -134,7 +133,13 @@ export class Board extends EventEmitter {
|
|||||||
|
|
||||||
showText(text: string) {
|
showText(text: string) {
|
||||||
this.textContainer.removeChildren()
|
this.textContainer.removeChildren()
|
||||||
this.textContainer.addChild(createText(text, this.scaleX(0), 100))
|
this.textContainer.addChild(
|
||||||
|
createText({
|
||||||
|
text,
|
||||||
|
x: this.scaleX(0),
|
||||||
|
y: -10,
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async setPlayerTurn(player: PlayerDto) {
|
async setPlayerTurn(player: PlayerDto) {
|
||||||
@ -169,7 +174,6 @@ export class Board extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async addTile(tile: Tile, move: Movement) {
|
async addTile(tile: Tile, move: Movement) {
|
||||||
console.log('adding tile', tile.pips)
|
|
||||||
let orientation = ''
|
let orientation = ''
|
||||||
let x: number =
|
let x: number =
|
||||||
move.type === 'left'
|
move.type === 'left'
|
||||||
@ -234,11 +238,18 @@ export class Board extends EventEmitter {
|
|||||||
tile.addTo(this.tilesContainer)
|
tile.addTo(this.tilesContainer)
|
||||||
tile.reScale(this.scale)
|
tile.reScale(this.scale)
|
||||||
this.tiles.push(tile)
|
this.tiles.push(tile)
|
||||||
|
const moveSound = this.getRandomClickSound()
|
||||||
await this.animateTile(tile, x, y, orientation, move)
|
await this.animateTile(tile, x, y, orientation, move)
|
||||||
|
sound.play(moveSound)
|
||||||
this.emit('game:tile-animation-ended', tile.toPlain())
|
this.emit('game:tile-animation-ended', tile.toPlain())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getRandomClickSound() {
|
||||||
|
const sounds = ['snd-move-1', 'snd-move-2', 'snd-move-3', 'snd-move-4']
|
||||||
|
const index = Math.floor(Math.random() * sounds.length)
|
||||||
|
return sounds[index]
|
||||||
|
}
|
||||||
|
|
||||||
async animateTile(tile: Tile, x: number, y: number, orientation: string, move: Movement) {
|
async animateTile(tile: Tile, x: number, y: number, orientation: string, move: Movement) {
|
||||||
const targetX = this.scaleX(x)
|
const targetX = this.scaleX(x)
|
||||||
const targetY = this.scaleY(y)
|
const targetY = this.scaleY(y)
|
||||||
@ -246,13 +257,13 @@ export class Board extends EventEmitter {
|
|||||||
x: targetX,
|
x: targetX,
|
||||||
y: targetY,
|
y: targetY,
|
||||||
rotation: ORIENTATION_ANGLES[orientation],
|
rotation: ORIENTATION_ANGLES[orientation],
|
||||||
duration: 20
|
duration: 20,
|
||||||
}
|
}
|
||||||
const tempAlpha = tile.alpha
|
const tempAlpha = tile.alpha
|
||||||
tile.alpha = 0
|
tile.alpha = 0
|
||||||
const clonedTile = tile.clone()
|
const clonedTile = tile.clone()
|
||||||
clonedTile.addTo(this.tilesContainer)
|
clonedTile.addTo(this.tilesContainer)
|
||||||
const pos = this.getAnimationInitialPoosition(move)
|
const pos = this.getAnimationInitialPosition(move)
|
||||||
clonedTile.setPosition(this.scaleX(pos.x), this.scaleY(pos.y))
|
clonedTile.setPosition(this.scaleX(pos.x), this.scaleY(pos.y))
|
||||||
await clonedTile.animateTo(animation)
|
await clonedTile.animateTo(animation)
|
||||||
clonedTile.removeFromParent()
|
clonedTile.removeFromParent()
|
||||||
@ -261,7 +272,7 @@ export class Board extends EventEmitter {
|
|||||||
tile.alpha = tempAlpha
|
tile.alpha = tempAlpha
|
||||||
}
|
}
|
||||||
|
|
||||||
getAnimationInitialPoosition(move: Movement): { x: number; y: number } {
|
getAnimationInitialPosition(move: Movement): { x: number; y: number } {
|
||||||
const otherHand = this.otherPlayerHands.find((h) => h.player?.id === move.playerId)
|
const otherHand = this.otherPlayerHands.find((h) => h.player?.id === move.playerId)
|
||||||
if (otherHand === undefined) {
|
if (otherHand === undefined) {
|
||||||
return { x: 0, y: this.scaleY.inverse(this.height + 50) }
|
return { x: 0, y: this.scaleY.inverse(this.height + 50) }
|
||||||
@ -271,9 +282,9 @@ export class Board extends EventEmitter {
|
|||||||
case 'left':
|
case 'left':
|
||||||
return { x: this.scaleX.inverse(100), y: this.scaleY.inverse(100) }
|
return { x: this.scaleX.inverse(100), y: this.scaleY.inverse(100) }
|
||||||
case 'right':
|
case 'right':
|
||||||
return { x: 0, y: this.scaleY.inverse(100) }
|
|
||||||
case 'top':
|
|
||||||
return { x: this.scaleX.inverse(this.width - 100), y: this.scaleY.inverse(20) }
|
return { x: this.scaleX.inverse(this.width - 100), y: this.scaleY.inverse(20) }
|
||||||
|
case 'top':
|
||||||
|
return { x: 0, y: this.scaleY.inverse(100) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,7 +376,7 @@ export class Board extends EventEmitter {
|
|||||||
nextTileValidPoints(
|
nextTileValidPoints(
|
||||||
tile: TileDto,
|
tile: TileDto,
|
||||||
side: string,
|
side: string,
|
||||||
validMoves: boolean[]
|
validMoves: boolean[],
|
||||||
): ([number, number] | undefined)[] {
|
): ([number, number] | undefined)[] {
|
||||||
const isLeft = side === 'left'
|
const isLeft = side === 'left'
|
||||||
const end = isLeft ? this.leftTile : this.rightTile
|
const end = isLeft ? this.leftTile : this.rightTile
|
||||||
@ -450,8 +461,8 @@ export class Board extends EventEmitter {
|
|||||||
outerStrength: 1,
|
outerStrength: 1,
|
||||||
innerStrength: 0,
|
innerStrength: 0,
|
||||||
color: 0xffffff,
|
color: 0xffffff,
|
||||||
quality: 0.5
|
quality: 0.5,
|
||||||
})
|
}),
|
||||||
])
|
])
|
||||||
dot.setOrientation(direction ?? 'north')
|
dot.setOrientation(direction ?? 'north')
|
||||||
// const dot = new Dot(this.ticker, this.scale)
|
// const dot = new Dot(this.ticker, this.scale)
|
||||||
|
@ -1,13 +1,30 @@
|
|||||||
import { Application, Assets } from 'pixi.js'
|
import { Application, Assets, Container, Sprite } from 'pixi.js'
|
||||||
import { Board } from '@/game/Board'
|
import { Board } from '@/game/Board'
|
||||||
import { assets } from '@/game/utilities/assets'
|
import { assets } from '@/game/utilities/assets'
|
||||||
import { Tile } from '@/game/Tile'
|
import { Tile } from '@/game/Tile'
|
||||||
import { Hand } from '@/game/Hand'
|
import { Hand } from '@/game/Hand'
|
||||||
import type { GameDto, Movement, PlayerDto, TileDto } from '@/common/interfaces'
|
import type {
|
||||||
|
GameDto,
|
||||||
|
GameSummary,
|
||||||
|
MatchSessionDto,
|
||||||
|
Movement,
|
||||||
|
PlayerDto,
|
||||||
|
TileDto,
|
||||||
|
} from '@/common/interfaces'
|
||||||
import type { SocketIoClientService } from '@/services/SocketIoClientService'
|
import type { SocketIoClientService } from '@/services/SocketIoClientService'
|
||||||
import { wait } from '@/common/helpers'
|
import { wait } from '@/common/helpers'
|
||||||
import { Actions } from 'pixi-actions'
|
import { Actions } from 'pixi-actions'
|
||||||
import { OtherHand } from './OtherHand'
|
import { OtherHand } from './OtherHand'
|
||||||
|
import { GameSummayView } from './GameSummayView'
|
||||||
|
import { summaryMock } from '@/common/summarymock'
|
||||||
|
|
||||||
|
interface GameOptions {
|
||||||
|
boardScale: number
|
||||||
|
handScale: number
|
||||||
|
width: number
|
||||||
|
height: number
|
||||||
|
background: string
|
||||||
|
}
|
||||||
|
|
||||||
export class Game {
|
export class Game {
|
||||||
public board!: Board
|
public board!: Board
|
||||||
@ -16,17 +33,20 @@ export class Game {
|
|||||||
private selectedTile: TileDto | undefined
|
private selectedTile: TileDto | undefined
|
||||||
private currentMove: Movement | undefined
|
private currentMove: Movement | undefined
|
||||||
private otherHands: OtherHand[] = []
|
private otherHands: OtherHand[] = []
|
||||||
|
private backgroundLayer: Container = new Container()
|
||||||
|
private gameSummaryView!: GameSummayView
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private options: { boardScale: number; handScale: number; width: number; height: number } = {
|
private options: GameOptions = {
|
||||||
boardScale: 1,
|
boardScale: 1,
|
||||||
handScale: 1,
|
handScale: 1,
|
||||||
width: 1200,
|
width: 1200,
|
||||||
height: 800
|
height: 800,
|
||||||
|
background: 'bg-green',
|
||||||
},
|
},
|
||||||
private socketService: SocketIoClientService,
|
private socketService: SocketIoClientService,
|
||||||
private playerId: string,
|
private playerId: string,
|
||||||
private sessionId: string
|
private sessionId: string,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async setup(): Promise<HTMLCanvasElement> {
|
async setup(): Promise<HTMLCanvasElement> {
|
||||||
@ -39,14 +59,16 @@ export class Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async start(players: PlayerDto[] = []) {
|
async start(players: PlayerDto[] = []) {
|
||||||
|
this.iniialStuff(this.app)
|
||||||
this.board = new Board(this.app)
|
this.board = new Board(this.app)
|
||||||
this.hand = new Hand(this.app)
|
this.hand = new Hand(this.app)
|
||||||
this.otherHands = [
|
this.otherHands = [
|
||||||
new OtherHand(this.app, 'left'),
|
new OtherHand(this.app, 'left'),
|
||||||
new OtherHand(this.app, 'top'),
|
new OtherHand(this.app, 'top'),
|
||||||
new OtherHand(this.app, 'right')
|
new OtherHand(this.app, 'right'),
|
||||||
]
|
]
|
||||||
this.initOtherHands(players)
|
this.initOtherHands(players)
|
||||||
|
this.gameSummaryView = new GameSummayView(this.app)
|
||||||
this.hand.scale = this.options.handScale
|
this.hand.scale = this.options.handScale
|
||||||
this.board.scale = this.options.boardScale
|
this.board.scale = this.options.boardScale
|
||||||
this.setBoardEvents()
|
this.setBoardEvents()
|
||||||
@ -55,10 +77,18 @@ export class Game {
|
|||||||
wait(3000)
|
wait(3000)
|
||||||
this.socketService.sendMessage('client:set-client-ready', {
|
this.socketService.sendMessage('client:set-client-ready', {
|
||||||
sessionId: this.sessionId,
|
sessionId: this.sessionId,
|
||||||
userId: this.playerId
|
userId: this.playerId,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iniialStuff(app: Application) {
|
||||||
|
app.stage.addChild(this.backgroundLayer)
|
||||||
|
const background = new Sprite(Assets.get(`bg-${this.options.background}`))
|
||||||
|
background.width = this.app.canvas.width
|
||||||
|
background.height = this.app.canvas.height
|
||||||
|
this.backgroundLayer.addChild(background)
|
||||||
|
}
|
||||||
|
|
||||||
initOtherHands(players: PlayerDto[]) {
|
initOtherHands(players: PlayerDto[]) {
|
||||||
const myIndex = players.findIndex((player) => player.id === this.playerId)
|
const myIndex = players.findIndex((player) => player.id === this.playerId)
|
||||||
const copy = [...players]
|
const copy = [...players]
|
||||||
@ -107,25 +137,36 @@ export class Game {
|
|||||||
const move: Movement = {
|
const move: Movement = {
|
||||||
id: '',
|
id: '',
|
||||||
type: 'pass',
|
type: 'pass',
|
||||||
playerId: this.playerId
|
playerId: this.playerId,
|
||||||
}
|
}
|
||||||
this.socketService.sendMessage('client:player-move', {
|
this.socketService.sendMessage('client:player-move', {
|
||||||
sessionId: this.sessionId,
|
sessionId: this.sessionId,
|
||||||
move: move
|
move: move,
|
||||||
})
|
})
|
||||||
await this.board.updateBoard(move, undefined)
|
await this.board.updateBoard(move, undefined)
|
||||||
})
|
})
|
||||||
|
|
||||||
this.hand.on('nextClick', () => {
|
this.gameSummaryView.on('nextClick', (data) => {
|
||||||
|
this.updateScoreboard(data.sessionState)
|
||||||
this.socketService.sendMessage('client:set-client-ready-for-next-game', {
|
this.socketService.sendMessage('client:set-client-ready-for-next-game', {
|
||||||
userId: this.playerId,
|
userId: this.playerId,
|
||||||
sessionId: this.sessionId
|
sessionId: this.sessionId,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
this.hand.on('hand-initialized', () => {})
|
this.hand.on('hand-initialized', () => {})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updateScoreboard(sessionState: MatchSessionDto) {
|
||||||
|
const scoreboard = sessionState.scoreboard
|
||||||
|
this.otherHands.forEach((hand) => {
|
||||||
|
const player: PlayerDto | undefined = hand.player
|
||||||
|
const name: string = player?.name || ''
|
||||||
|
const score = scoreboard.find((d) => d.name === name)?.score || 0
|
||||||
|
hand.setScore(score)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
highlightMoves(tile: TileDto) {
|
highlightMoves(tile: TileDto) {
|
||||||
this.selectedTile = tile
|
this.selectedTile = tile
|
||||||
if (tile !== undefined) {
|
if (tile !== undefined) {
|
||||||
@ -168,7 +209,7 @@ export class Game {
|
|||||||
tile: this.selectedTile,
|
tile: this.selectedTile,
|
||||||
type: 'left',
|
type: 'left',
|
||||||
playerId: this.playerId,
|
playerId: this.playerId,
|
||||||
...data
|
...data,
|
||||||
}
|
}
|
||||||
this.currentMove = move
|
this.currentMove = move
|
||||||
const tile = this.hand.tileMoved(this.selectedTile)
|
const tile = this.hand.tileMoved(this.selectedTile)
|
||||||
@ -181,7 +222,7 @@ export class Game {
|
|||||||
tile: this.selectedTile,
|
tile: this.selectedTile,
|
||||||
type: 'right',
|
type: 'right',
|
||||||
playerId: this.playerId,
|
playerId: this.playerId,
|
||||||
...data
|
...data,
|
||||||
}
|
}
|
||||||
this.currentMove = move
|
this.currentMove = move
|
||||||
const tile = this.hand.tileMoved(this.selectedTile)
|
const tile = this.hand.tileMoved(this.selectedTile)
|
||||||
@ -192,12 +233,12 @@ export class Game {
|
|||||||
if (tile !== null && tile !== undefined && tile.playerId === this.playerId) {
|
if (tile !== null && tile !== undefined && tile.playerId === this.playerId) {
|
||||||
this.socketService.sendMessage('client:player-move', {
|
this.socketService.sendMessage('client:player-move', {
|
||||||
sessionId: this.sessionId,
|
sessionId: this.sessionId,
|
||||||
move: this.currentMove
|
move: this.currentMove,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.socketService.sendMessage('client:animation-ended', {
|
this.socketService.sendMessage('client:animation-ended', {
|
||||||
sessionId: this.sessionId,
|
sessionId: this.sessionId,
|
||||||
userId: this.playerId
|
userId: this.playerId,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -206,11 +247,13 @@ export class Game {
|
|||||||
gameFinished(data: any) {
|
gameFinished(data: any) {
|
||||||
this.hand.gameFinished()
|
this.hand.gameFinished()
|
||||||
this.board.gameFinished(data)
|
this.board.gameFinished(data)
|
||||||
|
this.gameSummaryView.setGameSummary(data, 'round')
|
||||||
}
|
}
|
||||||
|
|
||||||
matchFinished(data: any) {
|
matchFinished(data: any) {
|
||||||
// this.hand.matchFinished()
|
// this.hand.matchFinished()
|
||||||
this.board.matchFinished(data)
|
this.board.matchFinished(data)
|
||||||
|
this.gameSummaryView.setGameSummary(data, 'match')
|
||||||
}
|
}
|
||||||
|
|
||||||
serverPlayerMove(data: any, playerId: string) {
|
serverPlayerMove(data: any, playerId: string) {
|
||||||
|
168
src/game/GameSummayView.ts
Normal file
168
src/game/GameSummayView.ts
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
import { createButton, createContainer } from '@/common/helpers'
|
||||||
|
import type { GameSummary, MatchSessionDto } from '@/common/interfaces'
|
||||||
|
import { EventEmitter, type Application, type Container } from 'pixi.js'
|
||||||
|
import { createText, whiteStyle, yellowStyle } from './utilities/fonts'
|
||||||
|
|
||||||
|
export class GameSummayView extends EventEmitter {
|
||||||
|
public width: number
|
||||||
|
public height: number
|
||||||
|
container!: Container
|
||||||
|
layer!: Container
|
||||||
|
gameSummary!: GameSummary
|
||||||
|
matchState!: MatchSessionDto
|
||||||
|
type: 'round' | 'match' = 'round'
|
||||||
|
|
||||||
|
constructor(app: Application) {
|
||||||
|
super()
|
||||||
|
this.width = 500
|
||||||
|
this.height = 400
|
||||||
|
this.container = createContainer({
|
||||||
|
width: this.width,
|
||||||
|
height: this.height,
|
||||||
|
x: app.canvas.width / 2 - this.width / 2,
|
||||||
|
y: app.canvas.height / 2 - this.height / 2,
|
||||||
|
parent: app.stage,
|
||||||
|
alpha: 0.7,
|
||||||
|
color: 0x121212,
|
||||||
|
})
|
||||||
|
this.layer = createContainer({
|
||||||
|
width: this.width,
|
||||||
|
height: this.height,
|
||||||
|
parent: this.container,
|
||||||
|
})
|
||||||
|
console.log('GameSummaryView created!')
|
||||||
|
|
||||||
|
this.container.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
setGameSummary(data: any, type: 'round' | 'match') {
|
||||||
|
this.type = type
|
||||||
|
this.matchState = data.sessionState
|
||||||
|
this.gameSummary = data.lastGame
|
||||||
|
this.render()
|
||||||
|
this.container.visible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTitle(y: number = 20, title: string): number {
|
||||||
|
const text = createText({
|
||||||
|
text: title,
|
||||||
|
x: this.width / 2,
|
||||||
|
y,
|
||||||
|
style: yellowStyle(24),
|
||||||
|
})
|
||||||
|
this.layer.addChild(text)
|
||||||
|
return y + 24
|
||||||
|
}
|
||||||
|
|
||||||
|
renderWinner(y: number): number {
|
||||||
|
let line = y + 12
|
||||||
|
this.layer.addChild(
|
||||||
|
createText({
|
||||||
|
text: `Winner: ${this.gameSummary.winner.name}`,
|
||||||
|
x: this.width / 2,
|
||||||
|
y: line,
|
||||||
|
style: whiteStyle(20),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
if (this.gameSummary.isBlocked) {
|
||||||
|
line += 30
|
||||||
|
this.container.addChild(
|
||||||
|
createText({
|
||||||
|
text: '(Blocked)',
|
||||||
|
x: this.width / 2,
|
||||||
|
y: line,
|
||||||
|
style: whiteStyle(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
line += 30
|
||||||
|
this.layer.addChild(
|
||||||
|
createText({
|
||||||
|
text: `Points this round: ${this.gameSummary.winner.score}`,
|
||||||
|
x: this.width / 2,
|
||||||
|
y: line,
|
||||||
|
style: whiteStyle(20),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
return line + 16
|
||||||
|
}
|
||||||
|
|
||||||
|
renderScores(y: number): number {
|
||||||
|
const scores = this.matchState.scoreboard
|
||||||
|
// this.type === 'round'
|
||||||
|
// ? this.gameSummary.score
|
||||||
|
// : this.matchState.scoreboard.map((d) => ({ name: d[0], score: d[1] }))
|
||||||
|
let line = y + 30
|
||||||
|
scores.forEach((score: any) => {
|
||||||
|
line = line + 30
|
||||||
|
this.layer.addChild(
|
||||||
|
createText({
|
||||||
|
text: `${score.name}:`,
|
||||||
|
x: 130,
|
||||||
|
y: line,
|
||||||
|
style: whiteStyle(18),
|
||||||
|
align: 'left',
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
this.layer.addChild(
|
||||||
|
createText({
|
||||||
|
text: `${score.score}`,
|
||||||
|
x: 330,
|
||||||
|
y: line,
|
||||||
|
style: whiteStyle(18),
|
||||||
|
align: 'right',
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
|
||||||
|
renderButtons() {
|
||||||
|
if (this.type === 'round') {
|
||||||
|
this.layer.addChild(
|
||||||
|
createButton({
|
||||||
|
text: 'Next',
|
||||||
|
dimension: {
|
||||||
|
x: this.width / 2 - 25,
|
||||||
|
y: this.height - 50,
|
||||||
|
width: 60,
|
||||||
|
height: 25,
|
||||||
|
},
|
||||||
|
action: () => {
|
||||||
|
this.emit('nextClick', { sessionState: this.matchState })
|
||||||
|
this.container.visible = false
|
||||||
|
},
|
||||||
|
parent: this.layer,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
this.layer.addChild(
|
||||||
|
createButton({
|
||||||
|
text: 'Finish',
|
||||||
|
dimension: {
|
||||||
|
x: this.width / 2 - 25,
|
||||||
|
y: this.height - 50,
|
||||||
|
width: 60,
|
||||||
|
height: 25,
|
||||||
|
},
|
||||||
|
action: () => {
|
||||||
|
this.emit('finishClick', this.gameSummary)
|
||||||
|
this.container.visible = false
|
||||||
|
},
|
||||||
|
parent: this.layer,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const title: string = this.type === 'round' ? 'Round Summary' : 'Match Finished!'
|
||||||
|
this.layer.removeChildren()
|
||||||
|
let y = this.renderTitle(30, title.toUpperCase())
|
||||||
|
y = this.renderWinner(y)
|
||||||
|
this.renderScores(y)
|
||||||
|
this.renderButtons()
|
||||||
|
}
|
||||||
|
}
|
@ -11,7 +11,6 @@ export class Hand extends EventEmitter {
|
|||||||
tiles: Tile[] = []
|
tiles: Tile[] = []
|
||||||
container: Container = new Container()
|
container: Container = new Container()
|
||||||
buttonPass: Container = new Container()
|
buttonPass: Container = new Container()
|
||||||
buttonNext: Container = new Container()
|
|
||||||
height: number
|
height: number
|
||||||
width: number
|
width: number
|
||||||
ticker: Ticker
|
ticker: Ticker
|
||||||
@ -27,6 +26,7 @@ export class Hand extends EventEmitter {
|
|||||||
availableTiles: Tile[] = []
|
availableTiles: Tile[] = []
|
||||||
tilesLayer!: Container
|
tilesLayer!: Container
|
||||||
interactionsLayer!: Container
|
interactionsLayer!: Container
|
||||||
|
score: number = 0
|
||||||
|
|
||||||
constructor(app: Application) {
|
constructor(app: Application) {
|
||||||
super()
|
super()
|
||||||
@ -49,14 +49,14 @@ export class Hand extends EventEmitter {
|
|||||||
height: this.height,
|
height: this.height,
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
parent: this.container
|
parent: this.container,
|
||||||
})
|
})
|
||||||
this.interactionsLayer = createContainer({
|
this.interactionsLayer = createContainer({
|
||||||
width: this.width,
|
width: this.width,
|
||||||
height: this.height,
|
height: this.height,
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
parent: this.container
|
parent: this.container,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,16 +65,6 @@ export class Hand extends EventEmitter {
|
|||||||
this.tiles = []
|
this.tiles = []
|
||||||
|
|
||||||
this.initialized = false
|
this.initialized = false
|
||||||
this.buttonNext = createButton(
|
|
||||||
'NEXT',
|
|
||||||
{ x: this.width / 2 - 25, y: this.height / 2, width: 50, height: 20 },
|
|
||||||
() => {
|
|
||||||
this.tilesLayer.removeChildren()
|
|
||||||
this.interactionsLayer.removeChild(this.buttonNext)
|
|
||||||
this.emit('nextClick')
|
|
||||||
},
|
|
||||||
this.interactionsLayer
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get canMove() {
|
get canMove() {
|
||||||
@ -98,7 +88,7 @@ export class Hand extends EventEmitter {
|
|||||||
this.availableTiles.forEach((tile) => {
|
this.availableTiles.forEach((tile) => {
|
||||||
tile.animateTo({
|
tile.animateTo({
|
||||||
x: tile.x,
|
x: tile.x,
|
||||||
y: tile.y - 10
|
y: tile.y - 10,
|
||||||
})
|
})
|
||||||
tile.interactive = true
|
tile.interactive = true
|
||||||
})
|
})
|
||||||
@ -108,7 +98,7 @@ export class Hand extends EventEmitter {
|
|||||||
this.availableTiles.forEach((tile) => {
|
this.availableTiles.forEach((tile) => {
|
||||||
tile.animateTo({
|
tile.animateTo({
|
||||||
x: tile.x,
|
x: tile.x,
|
||||||
y: tile.y + 10
|
y: tile.y + 10,
|
||||||
})
|
})
|
||||||
tile.setPosition(tile.x, tile.y + 10)
|
tile.setPosition(tile.x, tile.y + 10)
|
||||||
tile.interactive = false
|
tile.interactive = false
|
||||||
@ -128,7 +118,7 @@ export class Hand extends EventEmitter {
|
|||||||
initialize(playerState: PlayerDto) {
|
initialize(playerState: PlayerDto) {
|
||||||
this.tiles = this.createTiles(playerState)
|
this.tiles = this.createTiles(playerState)
|
||||||
this.initialized = this.tiles.length > 0
|
this.initialized = this.tiles.length > 0
|
||||||
this.renderTiles()
|
this.render()
|
||||||
this.emit('hand-updated', this.tiles)
|
this.emit('hand-updated', this.tiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,31 +177,32 @@ export class Hand extends EventEmitter {
|
|||||||
private createPassButton() {
|
private createPassButton() {
|
||||||
const lastTile = this.tiles[this.tiles.length - 1]
|
const lastTile = this.tiles[this.tiles.length - 1]
|
||||||
const x = lastTile ? lastTile.x + lastTile.width : this.scaleX(0)
|
const x = lastTile ? lastTile.x + lastTile.width : this.scaleX(0)
|
||||||
this.buttonPass = createButton(
|
this.buttonPass = createButton({
|
||||||
'PASS',
|
text: 'PASS',
|
||||||
{ x, y: this.height / 2, width: 50, height: 20 },
|
dimension: { x, y: this.height / 2, width: 50, height: 20 },
|
||||||
() => {
|
action: () => {
|
||||||
this.interactionsLayer.removeChild(this.buttonPass)
|
this.interactionsLayer.removeChild(this.buttonPass)
|
||||||
this.emit('game:button-pass-click')
|
this.emit('game:button-pass-click')
|
||||||
},
|
},
|
||||||
this.interactionsLayer
|
parent: this.interactionsLayer,
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
update(playerState: PlayerDto) {
|
update(playerState: PlayerDto) {
|
||||||
|
this.tilesLayer.removeChildren()
|
||||||
if (!this.initialized) {
|
if (!this.initialized) {
|
||||||
this.initialize(playerState)
|
this.initialize(playerState)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const missing: Tile | undefined = this.tiles.find(
|
const missing: Tile | undefined = this.tiles.find(
|
||||||
(tile: Tile) => !playerState.hand.find((t) => t.id === tile.id)
|
(tile: Tile) => !playerState.hand.find((t) => t.id === tile.id),
|
||||||
)
|
)
|
||||||
if (missing) {
|
if (missing) {
|
||||||
this.tilesLayer.removeChild(missing.getSprite())
|
this.tilesLayer.removeChild(missing.getSprite())
|
||||||
this.tiles = this.tiles.filter((tile) => tile.id !== missing.id)
|
this.tiles = this.tiles.filter((tile) => tile.id !== missing.id)
|
||||||
this.emit('hand-updated', this.tiles)
|
this.emit('hand-updated', this.tiles)
|
||||||
}
|
}
|
||||||
this.renderTiles()
|
this.render()
|
||||||
}
|
}
|
||||||
|
|
||||||
private createTiles(playerState: PlayerDto) {
|
private createTiles(playerState: PlayerDto) {
|
||||||
@ -230,8 +221,8 @@ export class Hand extends EventEmitter {
|
|||||||
outerStrength: 2,
|
outerStrength: 2,
|
||||||
innerStrength: 1,
|
innerStrength: 1,
|
||||||
color: 0xffffff,
|
color: 0xffffff,
|
||||||
quality: 0.5
|
quality: 0.5,
|
||||||
})
|
}),
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
newTile.on('pointerout', () => {
|
newTile.on('pointerout', () => {
|
||||||
@ -251,4 +242,13 @@ export class Hand extends EventEmitter {
|
|||||||
tile.setPosition(deltaX + tile.width / 2 + i * (tile.width + 5), tile.height / 2 + 20)
|
tile.setPosition(deltaX + tile.width / 2 + i * (tile.width + 5), tile.height / 2 + 20)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderScore() {
|
||||||
|
//this.scoreLayer.removeChildren()
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
this.renderTiles()
|
||||||
|
this.renderScore()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import { Scale, type ScaleFunction } from './utilities/scale'
|
|||||||
import { Tile } from './Tile'
|
import { Tile } from './Tile'
|
||||||
import type { Movement, PlayerDto, TileDto } from '@/common/interfaces'
|
import type { Movement, PlayerDto, TileDto } from '@/common/interfaces'
|
||||||
import { createContainer } from '@/common/helpers'
|
import { createContainer } from '@/common/helpers'
|
||||||
import { createText, playerNameText } from './utilities/fonts'
|
import { createText, playerNameText, scoreText } from './utilities/fonts'
|
||||||
|
|
||||||
export class OtherHand {
|
export class OtherHand {
|
||||||
tilesInitialNumber: number = 7
|
tilesInitialNumber: number = 7
|
||||||
@ -22,10 +22,12 @@ export class OtherHand {
|
|||||||
logger: LoggingService = new LoggingService()
|
logger: LoggingService = new LoggingService()
|
||||||
tilesLayer!: Container
|
tilesLayer!: Container
|
||||||
interactionsLayer!: Container
|
interactionsLayer!: Container
|
||||||
|
scoreLayer: Container = new Container()
|
||||||
|
score: number = 0
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private app: Application,
|
private app: Application,
|
||||||
public position: 'left' | 'right' | 'top' = 'left'
|
public position: 'left' | 'right' | 'top' = 'left',
|
||||||
) {
|
) {
|
||||||
this.height = 100
|
this.height = 100
|
||||||
this.width = 300
|
this.width = 300
|
||||||
@ -37,11 +39,23 @@ export class OtherHand {
|
|||||||
this.container.y = y
|
this.container.y = y
|
||||||
this.calculateScale()
|
this.calculateScale()
|
||||||
this.initLayers()
|
this.initLayers()
|
||||||
|
this.render()
|
||||||
}
|
}
|
||||||
|
|
||||||
setPlayer(player: PlayerDto) {
|
setPlayer(player: PlayerDto) {
|
||||||
this.player = player
|
this.player = player
|
||||||
this.container.addChild(createText(`${player.name}`, this.width / 2, 12, playerNameText))
|
this.container.addChild(
|
||||||
|
createText({
|
||||||
|
text: `${player.name}`,
|
||||||
|
x: this.width / 2,
|
||||||
|
y: 12,
|
||||||
|
style: playerNameText,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
setScore(score: number) {
|
||||||
|
this.score = score
|
||||||
}
|
}
|
||||||
|
|
||||||
setHand(tiles: TileDto[]) {
|
setHand(tiles: TileDto[]) {
|
||||||
@ -54,7 +68,19 @@ export class OtherHand {
|
|||||||
this.render()
|
this.render()
|
||||||
}
|
}
|
||||||
|
|
||||||
private render() {
|
private renderScore() {
|
||||||
|
this.scoreLayer.removeChildren()
|
||||||
|
const text = createText({
|
||||||
|
text: `${this.score}`,
|
||||||
|
x: this.width - 5,
|
||||||
|
y: 50,
|
||||||
|
style: scoreText,
|
||||||
|
})
|
||||||
|
text.anchor.set(1, 0.5)
|
||||||
|
this.scoreLayer.addChild(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderTiles() {
|
||||||
this.tilesLayer.removeChildren()
|
this.tilesLayer.removeChildren()
|
||||||
const x = -9
|
const x = -9
|
||||||
this.hand.forEach((tile, index) => {
|
this.hand.forEach((tile, index) => {
|
||||||
@ -63,6 +89,11 @@ export class OtherHand {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private render() {
|
||||||
|
this.renderTiles()
|
||||||
|
this.renderScore()
|
||||||
|
}
|
||||||
|
|
||||||
private addBg() {
|
private addBg() {
|
||||||
const bg = new Sprite(Texture.WHITE)
|
const bg = new Sprite(Texture.WHITE)
|
||||||
bg.alpha = 0.08
|
bg.alpha = 0.08
|
||||||
@ -96,17 +127,17 @@ export class OtherHand {
|
|||||||
height: this.height,
|
height: this.height,
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
parent: this.container
|
parent: this.container,
|
||||||
})
|
})
|
||||||
this.interactionsLayer = createContainer({
|
this.interactionsLayer = createContainer({
|
||||||
width: this.width,
|
width: this.width,
|
||||||
height: this.height,
|
height: this.height,
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
parent: this.container
|
parent: this.container,
|
||||||
})
|
})
|
||||||
this.container.addChild(this.tilesLayer)
|
// this.container.addChild(this.tilesLayer)
|
||||||
this.container.addChild(this.interactionsLayer)
|
this.container.addChild(this.scoreLayer)
|
||||||
}
|
}
|
||||||
|
|
||||||
private calculateScale() {
|
private calculateScale() {
|
||||||
|
@ -27,10 +27,16 @@ import tile6_3 from '@/assets/images/tiles/6-3.png'
|
|||||||
import tile6_4 from '@/assets/images/tiles/6-4.png'
|
import tile6_4 from '@/assets/images/tiles/6-4.png'
|
||||||
import tile6_5 from '@/assets/images/tiles/6-5.png'
|
import tile6_5 from '@/assets/images/tiles/6-5.png'
|
||||||
import tile6_6 from '@/assets/images/tiles/6-6.png'
|
import tile6_6 from '@/assets/images/tiles/6-6.png'
|
||||||
import dot from '@/assets/images/circle.png'
|
|
||||||
import bgWood_1 from '@/assets/images/backgrounds/wood-1.jpg'
|
import bgWood_1 from '@/assets/images/backgrounds/wood-1.jpg'
|
||||||
import bg_1 from '@/assets/images/backgrounds/bg-1.png'
|
import bg_1 from '@/assets/images/backgrounds/bg-1.png'
|
||||||
import bg_green from '@/assets/images/backgrounds/bg-green.png'
|
import bg_green from '@/assets/images/backgrounds/bg-green.png'
|
||||||
|
import bg_red from '@/assets/images/backgrounds/bg-red.png'
|
||||||
|
import bg_yellow from '@/assets/images/backgrounds/bg-yellow.png'
|
||||||
|
import snd_move_1 from '@/assets/sounds/move-1.mp3'
|
||||||
|
import snd_move_2 from '@/assets/sounds/move-2.mp3'
|
||||||
|
import snd_move_3 from '@/assets/sounds/move-3.mp3'
|
||||||
|
import snd_move_4 from '@/assets/sounds/move-4.mp3'
|
||||||
|
import snd_intro from '@/assets/sounds/intro.mp3'
|
||||||
|
|
||||||
export const assets = [
|
export const assets = [
|
||||||
{ alias: 'tile-back', src: tileBack },
|
{ alias: 'tile-back', src: tileBack },
|
||||||
@ -62,8 +68,14 @@ export const assets = [
|
|||||||
{ alias: 'tile-6_4', src: tile6_4 },
|
{ alias: 'tile-6_4', src: tile6_4 },
|
||||||
{ alias: 'tile-6_5', src: tile6_5 },
|
{ alias: 'tile-6_5', src: tile6_5 },
|
||||||
{ alias: 'tile-6_6', src: tile6_6 },
|
{ alias: 'tile-6_6', src: tile6_6 },
|
||||||
{ alias: 'dot', src: dot },
|
|
||||||
{ alias: 'bg-wood-1', src: bgWood_1 },
|
{ alias: 'bg-wood-1', src: bgWood_1 },
|
||||||
{ alias: 'bg-1', src: bg_1 },
|
{ alias: 'bg-gray', src: bg_1 },
|
||||||
{ alias: 'bg-green', src: bg_green }
|
{ alias: 'bg-green', src: bg_green },
|
||||||
|
{ alias: 'bg-red', src: bg_red },
|
||||||
|
{ alias: 'bg-yellow', src: bg_yellow },
|
||||||
|
{ alias: 'snd-move-1', src: snd_move_1 },
|
||||||
|
{ alias: 'snd-move-2', src: snd_move_2 },
|
||||||
|
{ alias: 'snd-move-3', src: snd_move_3 },
|
||||||
|
{ alias: 'snd-move-4', src: snd_move_4 },
|
||||||
|
{ alias: 'snd-intro', src: snd_intro },
|
||||||
]
|
]
|
||||||
|
@ -1,19 +1,27 @@
|
|||||||
import { Text, TextStyle } from 'pixi.js'
|
import {
|
||||||
|
Container,
|
||||||
|
Text,
|
||||||
|
TextStyle,
|
||||||
|
type TextStyleAlign,
|
||||||
|
type TextStyleFontStyle,
|
||||||
|
type TextStyleFontWeight,
|
||||||
|
type TextStyleOptions,
|
||||||
|
} from 'pixi.js'
|
||||||
|
|
||||||
export const dropShadowStyle = {
|
export const dropShadowStyle = {
|
||||||
alpha: 0.5,
|
alpha: 0.5,
|
||||||
angle: 0.3,
|
angle: 0.3,
|
||||||
blur: 5,
|
blur: 5,
|
||||||
distance: 4
|
distance: 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mainText = new TextStyle({
|
export const mainText = new TextStyle({
|
||||||
dropShadow: dropShadowStyle,
|
dropShadow: dropShadowStyle,
|
||||||
fill: '#b71a1a',
|
fill: '#aaaaaa',
|
||||||
fontFamily: 'Arial, Helvetica, sans-serif',
|
fontFamily: 'Arial, Helvetica, sans-serif',
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
letterSpacing: 1,
|
letterSpacing: 1,
|
||||||
stroke: '#658f56'
|
stroke: '#565656',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const playerNameText = new TextStyle({
|
export const playerNameText = new TextStyle({
|
||||||
@ -23,12 +31,104 @@ export const playerNameText = new TextStyle({
|
|||||||
letterSpacing: 1,
|
letterSpacing: 1,
|
||||||
stroke: '#565656',
|
stroke: '#565656',
|
||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
fontWeight: 'bold'
|
fontWeight: 'bold',
|
||||||
})
|
})
|
||||||
|
|
||||||
export function createText(str: string, x: number, y: number, style: TextStyle = mainText) {
|
export const summaryTitle = new TextStyle({
|
||||||
|
dropShadow: dropShadowStyle,
|
||||||
|
fill: '#a2a2a2',
|
||||||
|
fontFamily: 'Arial, Helvetica, sans-serif',
|
||||||
|
letterSpacing: 1,
|
||||||
|
stroke: '#565656',
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const scoreText = new TextStyle({
|
||||||
|
dropShadow: dropShadowStyle,
|
||||||
|
fill: '#aaaaaa',
|
||||||
|
fontFamily: 'Arial, Helvetica, sans-serif',
|
||||||
|
letterSpacing: 1,
|
||||||
|
stroke: '#565656',
|
||||||
|
fontSize: 32,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
})
|
||||||
|
|
||||||
|
function getStyle(styleOptions: TextStyleOptions = {}) {
|
||||||
|
const {
|
||||||
|
fill = 0xa2a2a2,
|
||||||
|
stroke = 0x565656,
|
||||||
|
fontSize = 15,
|
||||||
|
fontFamily = 'Arial, Helvetica, sans-serif',
|
||||||
|
fontWeight = 'normal',
|
||||||
|
fontStyle = 'normal',
|
||||||
|
dropShadow,
|
||||||
|
letterSpacing = 1,
|
||||||
|
} = styleOptions
|
||||||
|
const style = new TextStyle({
|
||||||
|
fill,
|
||||||
|
fontFamily,
|
||||||
|
letterSpacing,
|
||||||
|
stroke,
|
||||||
|
fontSize,
|
||||||
|
fontStyle,
|
||||||
|
fontWeight: fontWeight as any,
|
||||||
|
dropShadow: dropShadow ? dropShadowStyle : undefined,
|
||||||
|
})
|
||||||
|
return style
|
||||||
|
}
|
||||||
|
|
||||||
|
export const whiteStyle = (
|
||||||
|
fontSize: number = 15,
|
||||||
|
fontWeight: TextStyleFontWeight = 'normal',
|
||||||
|
dropShadow: boolean = true,
|
||||||
|
) =>
|
||||||
|
getStyle({
|
||||||
|
fontSize,
|
||||||
|
fontWeight,
|
||||||
|
dropShadow,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const yellowStyle = (
|
||||||
|
fontSize: number = 15,
|
||||||
|
fontWeight: TextStyleFontWeight = 'normal',
|
||||||
|
dropShadow: boolean = true,
|
||||||
|
) =>
|
||||||
|
getStyle({
|
||||||
|
fill: 0xffff00,
|
||||||
|
fontSize,
|
||||||
|
fontWeight,
|
||||||
|
dropShadow,
|
||||||
|
})
|
||||||
|
|
||||||
|
interface TextOptions {
|
||||||
|
text: string
|
||||||
|
x: number
|
||||||
|
y: number
|
||||||
|
style?: TextStyle
|
||||||
|
container?: Container
|
||||||
|
align?: 'left' | 'center' | 'right'
|
||||||
|
fontStyle?: TextStyleFontStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createText(textOptions: TextOptions) {
|
||||||
|
const defaultOptions = { style: whiteStyle(), align: 'center' }
|
||||||
|
const { text: str, x, y, style, container, align } = { ...defaultOptions, ...textOptions }
|
||||||
const text = new Text({ text: str, style })
|
const text = new Text({ text: str, style })
|
||||||
text.anchor.set(0.5, 0.5)
|
|
||||||
|
switch (align) {
|
||||||
|
case 'center':
|
||||||
|
text.anchor.set(0.5, 0.5)
|
||||||
|
break
|
||||||
|
case 'left':
|
||||||
|
text.anchor.set(0, 0.5)
|
||||||
|
break
|
||||||
|
case 'right':
|
||||||
|
text.anchor.set(1, 0.5)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if (container) container.addChild(text)
|
||||||
text.x = x
|
text.x = x
|
||||||
text.y = y
|
text.y = y
|
||||||
return text
|
return text
|
||||||
|
@ -23,8 +23,8 @@ export class SocketIoClientService extends ServiceBase {
|
|||||||
}
|
}
|
||||||
this.socket = io(this.url, {
|
this.socket = io(this.url, {
|
||||||
auth: {
|
auth: {
|
||||||
token: jwt.value
|
token: jwt.value,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
this.socket.on('connect', () => {
|
this.socket.on('connect', () => {
|
||||||
if (this.socket && this.socket.recovered) {
|
if (this.socket && this.socket.recovered) {
|
||||||
@ -62,14 +62,6 @@ export class SocketIoClientService extends ServiceBase {
|
|||||||
|
|
||||||
// Custom events
|
// Custom events
|
||||||
|
|
||||||
// this.socket.on('makeMove', async (data: any, callback: any) => {
|
|
||||||
// callback(await this.gameEventManager.handleCanMakeMoveEvent(data))
|
|
||||||
// })
|
|
||||||
|
|
||||||
// this.socket.on('chooseTile', async (data: any, callback: any) => {
|
|
||||||
// callback(await this.gameEventManager.handleCanSelectTileEvent())
|
|
||||||
// })
|
|
||||||
|
|
||||||
this.socket.on('server:game-event', (data: any) => {
|
this.socket.on('server:game-event', (data: any) => {
|
||||||
this.gameEventManager.handleGameEvent(data)
|
this.gameEventManager.handleGameEvent(data)
|
||||||
})
|
})
|
||||||
@ -77,6 +69,13 @@ export class SocketIoClientService extends ServiceBase {
|
|||||||
this.socket.on('server:game-event-ack', async (data: any, callback: any) => {
|
this.socket.on('server:game-event-ack', async (data: any, callback: any) => {
|
||||||
await this.gameEventManager.handleGameEventAck(data, callback)
|
await this.gameEventManager.handleGameEventAck(data, callback)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.socket.onAny((eventName, eventData) => {
|
||||||
|
if (eventName === 'server:game-event' || eventName === 'server:game-event-ack') {
|
||||||
|
const { event, data } = eventData
|
||||||
|
this.logger.debug(`Received event: ${event}`, data)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMessage(event: string, data: any): void {
|
sendMessage(event: string, data: any): void {
|
||||||
|
9
src/stores/gameOptions.ts
Normal file
9
src/stores/gameOptions.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import type { GameOptions } from '@/common/interfaces'
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
export const useGameOptionsStore = defineStore('gameOptions', () => {
|
||||||
|
const gameOptions = ref<GameOptions>()
|
||||||
|
|
||||||
|
return { gameOptions }
|
||||||
|
})
|
@ -40,20 +40,16 @@ function copySeed() {
|
|||||||
<template>
|
<template>
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<section class="block info">
|
<section class="block info">
|
||||||
<p>
|
<p>Running: {{ sessionState?.sessionInProgress }}</p>
|
||||||
Running: {{ sessionState?.sessionInProgress }} Seed: {{ sessionState?.seed }}
|
<p>Seed: {{ sessionState?.seed }}</p>
|
||||||
<button @click="copySeed">Copy!</button>
|
|
||||||
</p>
|
|
||||||
<p>
|
<p>
|
||||||
FreeEnds: {{ gameState?.boardFreeEnds }} - Current Player:{{
|
FreeEnds: {{ gameState?.boardFreeEnds }} - Current Player:{{
|
||||||
gameState?.currentPlayer?.name
|
gameState?.currentPlayer?.name
|
||||||
}}
|
}}
|
||||||
- Score: {{ sessionState?.scoreboard }}
|
|
||||||
</p>
|
|
||||||
<p v-if="sessionState?.id">
|
|
||||||
SessionID: {{ sessionState.id }} PlayerID: {{ playerState?.id }} - canMakeMove
|
|
||||||
{{ canMakeMove }}
|
|
||||||
</p>
|
</p>
|
||||||
|
<p>Score: {{ sessionState?.scoreboard }}</p>
|
||||||
|
<p v-if="sessionState?.id">SessionID: {{ sessionState.id }}</p>
|
||||||
|
<p>PlayerID: {{ playerState?.id }}</p>
|
||||||
</section>
|
</section>
|
||||||
<section class="block">
|
<section class="block">
|
||||||
<div class="game-container">
|
<div class="game-container">
|
||||||
@ -107,9 +103,12 @@ function copySeed() {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
.info {
|
.info {
|
||||||
position: absolute;
|
color: white;
|
||||||
top: 0;
|
opacity: 0.1;
|
||||||
left: 0;
|
position: fixed;
|
||||||
|
top: 200px;
|
||||||
|
left: 10px;
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -9,25 +9,27 @@ import type { MatchSessionDto } from '@/common/interfaces'
|
|||||||
import { useEventBusStore } from '@/stores/eventBus'
|
import { useEventBusStore } from '@/stores/eventBus'
|
||||||
import { useAuthStore } from '@/stores/auth'
|
import { useAuthStore } from '@/stores/auth'
|
||||||
import { copyToclipboard } from '@/common/helpers'
|
import { copyToclipboard } from '@/common/helpers'
|
||||||
|
import { useGameOptionsStore } from '@/stores/gameOptions'
|
||||||
|
|
||||||
|
let background = ref<string>('green')
|
||||||
|
let teamed = ref<boolean>(false)
|
||||||
let seed = ref<string>('')
|
let seed = ref<string>('')
|
||||||
let sessionName = ref('Test Value')
|
let sessionName = ref('Test Value')
|
||||||
let sessionId = ref('')
|
|
||||||
let matchSessions = ref<MatchSessionDto[]>([])
|
let matchSessions = ref<MatchSessionDto[]>([])
|
||||||
let dataInterval: any
|
let dataInterval: any
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const gameStore = useGameStore()
|
const gameStore = useGameStore()
|
||||||
const auth = useAuthStore()
|
const auth = useAuthStore()
|
||||||
|
const gameOptionsStore = useGameOptionsStore()
|
||||||
|
|
||||||
const socketService: any = inject('socket')
|
const socketService: any = inject('socket')
|
||||||
const gameService: GameService = inject<GameService>('game') as GameService
|
const gameService: GameService = inject<GameService>('game') as GameService
|
||||||
const logger: LoggingService = inject<LoggingService>('logger') as LoggingService
|
const logger: LoggingService = inject<LoggingService>('logger') as LoggingService
|
||||||
|
|
||||||
const { readyForStart, sessionState, isSessionStarted, playerState, amIHost } =
|
const { sessionState, isSessionStarted, playerState, amIHost } = storeToRefs(gameStore)
|
||||||
storeToRefs(gameStore)
|
|
||||||
const { updateSessionState, updatePlayerState, updateGameState } = gameStore
|
|
||||||
const { user } = storeToRefs(auth)
|
const { user } = storeToRefs(auth)
|
||||||
|
const { gameOptions } = storeToRefs(gameOptionsStore)
|
||||||
|
|
||||||
// function setPlayerReady() {
|
// function setPlayerReady() {
|
||||||
// logger.debug('Starting game')
|
// logger.debug('Starting game')
|
||||||
@ -53,26 +55,12 @@ eventBus.subscribe('window-before-unload', () => {
|
|||||||
async function createMatch() {
|
async function createMatch() {
|
||||||
logger.debug('Creating match')
|
logger.debug('Creating match')
|
||||||
await socketService.connect()
|
await socketService.connect()
|
||||||
|
gameOptions.value = { background: background.value }
|
||||||
const id = await gameService.createMatchSession(sessionName.value, seed.value)
|
const id = await gameService.createMatchSession(sessionName.value, seed.value)
|
||||||
logger.debug('Match created successfully')
|
logger.debug('Match created successfully')
|
||||||
router.push({ name: 'match', params: { id } })
|
router.push({ name: 'match', params: { id } })
|
||||||
}
|
}
|
||||||
|
|
||||||
async function cancelMatch() {
|
|
||||||
logger.debug('Cancelling match')
|
|
||||||
await gameService.cancelMatchSession(sessionId.value)
|
|
||||||
await socketService.disconnect()
|
|
||||||
sessionId.value = ''
|
|
||||||
seed.value = ''
|
|
||||||
sessionName.value = ''
|
|
||||||
updateSessionState(undefined)
|
|
||||||
updatePlayerState(undefined)
|
|
||||||
updateGameState(undefined)
|
|
||||||
|
|
||||||
logger.debug('Match cancelled successfully')
|
|
||||||
loadData()
|
|
||||||
}
|
|
||||||
|
|
||||||
async function joinMatch(id: string) {
|
async function joinMatch(id: string) {
|
||||||
if (id) {
|
if (id) {
|
||||||
await socketService.connect()
|
await socketService.connect()
|
||||||
@ -90,19 +78,16 @@ async function deleteMatch(id: string) {
|
|||||||
|
|
||||||
async function loadData() {
|
async function loadData() {
|
||||||
const listResponse = await gameService.listMatchSessions()
|
const listResponse = await gameService.listMatchSessions()
|
||||||
console.log('listResponse :>> ', listResponse)
|
|
||||||
matchSessions.value = listResponse.data
|
matchSessions.value = listResponse.data
|
||||||
sessionName.value = `Test #${listResponse.pagination.total + 1}`
|
sessionName.value = `Test #${listResponse.pagination.total + 1}`
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
logger.debug('Home view mounted')
|
|
||||||
loadData()
|
loadData()
|
||||||
dataInterval = setInterval(loadData, 5000)
|
dataInterval = setInterval(loadData, 5000)
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
logger.debug('Home view unmounted')
|
|
||||||
clearInterval(dataInterval)
|
clearInterval(dataInterval)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -117,32 +102,58 @@ function copy(sessionSeed: string) {
|
|||||||
<section class="section">
|
<section class="section">
|
||||||
<h1 class="title is-2">Welcome to the {{ user.username }}'s Home Page</h1>
|
<h1 class="title is-2">Welcome to the {{ user.username }}'s Home Page</h1>
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<p>This is a protected route.</p>
|
<div class="field">
|
||||||
<p>{{ sessionState || 'No session' }}</p>
|
<label class="label">Name</label>
|
||||||
<p>{{ playerState || 'No player state' }}</p>
|
<div class="control">
|
||||||
<p>Session started: {{ isSessionStarted }}</p>
|
<input type="text" class="input" v-model="sessionName" placeholder="Session Name" />
|
||||||
<p>Host: {{ amIHost }}</p>
|
|
||||||
</div>
|
|
||||||
<div class="block" v-if="!isSessionStarted">
|
|
||||||
<div class="grid">
|
|
||||||
<div class="cell">
|
|
||||||
<input
|
|
||||||
class="input"
|
|
||||||
style="margin-bottom: 0"
|
|
||||||
v-model="sessionName"
|
|
||||||
placeholder="Session Name"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="cell">
|
|
||||||
<input class="input" style="margin-bottom: 0" v-model="seed" placeholder="Seed" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">Seed</label>
|
||||||
|
<div class="control">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="input"
|
||||||
|
style="margin-bottom: 0"
|
||||||
|
v-model="seed"
|
||||||
|
placeholder="Type the session seed here!"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<div class="cell">
|
||||||
|
<div class="field">
|
||||||
|
<label for="background" class="label">Background color</label>
|
||||||
|
<div class="control">
|
||||||
|
<div class="select">
|
||||||
|
<select v-model="background" name="background">
|
||||||
|
<option value="green">Green Fabric</option>
|
||||||
|
<option value="gray">Gray Fabric</option>
|
||||||
|
<option value="blue">Blue Fabric</option>
|
||||||
|
<option value="yellow">Yellow Fabric</option>
|
||||||
|
<option value="red">Red Fabric</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<div class="control">
|
||||||
|
<label for="teamed" class="checkbox">
|
||||||
|
<input v-model="teamed" name="teamed" type="checkbox" />
|
||||||
|
Crossed game ({{ teamed }})
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="button" @click="createMatch" v-if="!isSessionStarted">
|
<div class="block" v-if="!isSessionStarted"></div>
|
||||||
Create Match Session
|
|
||||||
</button>
|
<button class="button is-primary" @click.once="createMatch">Create Match Session</button>
|
||||||
</section>
|
</section>
|
||||||
<section class="section available-sessions" v-if="!isSessionStarted">
|
<section class="section available-sessions">
|
||||||
<h2 class="title is-4">Available Sessions</h2>
|
<h2 class="title is-4">Available Sessions</h2>
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<div v-if="matchSessions.length === 0">
|
<div v-if="matchSessions.length === 0">
|
||||||
@ -150,16 +161,27 @@ function copy(sessionSeed: string) {
|
|||||||
</div>
|
</div>
|
||||||
<div v-else class="grid is-col-min-12">
|
<div v-else class="grid is-col-min-12">
|
||||||
<div class="cell" v-for="session in matchSessions" :key="session.id">
|
<div class="cell" v-for="session in matchSessions" :key="session.id">
|
||||||
<p class="title is-6">{{ session.name }}</p>
|
<div class="card">
|
||||||
<p>ID: {{ session._id }}</p>
|
<div class="card-content">
|
||||||
<p>Players: {{ session.players.length }}</p>
|
<p class="title is-6">{{ session.name }}</p>
|
||||||
<p>
|
<p>ID: {{ session._id }}</p>
|
||||||
Seed: {{ session.seed }}
|
<p>Players: {{ session.players.length }}</p>
|
||||||
<button @click="() => copy(session.seed)">Copy</button>
|
<p>
|
||||||
</p>
|
Seed: {{ session.seed }}
|
||||||
<p>Status: {{ session.status }}</p>
|
<button class="button is-small" @click="() => copy(session.seed)">Copy</button>
|
||||||
<button class="button" @click="() => joinMatch(session._id)">Join</button>
|
</p>
|
||||||
<button class="button" @click="() => deleteMatch(session._id)">Delete</button>
|
<p>Status: {{ session.status }}</p>
|
||||||
|
<div class="buttons is-centered mt-4"></div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<p class="card-footer-item">
|
||||||
|
<a href="#" @click.once.prevent="() => joinMatch(session._id)"> Join </a>
|
||||||
|
</p>
|
||||||
|
<p class="card-footer-item">
|
||||||
|
<a href="#" @click.once.prevent="() => deleteMatch(session._id)"> Delete </a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,6 +4,7 @@ import type { GameService } from '@/services/GameService'
|
|||||||
import type { LoggingService } from '@/services/LoggingService'
|
import type { LoggingService } from '@/services/LoggingService'
|
||||||
import { useEventBusStore } from '@/stores/eventBus'
|
import { useEventBusStore } from '@/stores/eventBus'
|
||||||
import { useGameStore } from '@/stores/game'
|
import { useGameStore } from '@/stores/game'
|
||||||
|
import { useGameOptionsStore } from '@/stores/gameOptions'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { inject, onBeforeMount, ref } from 'vue'
|
import { inject, onBeforeMount, ref } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
@ -12,6 +13,7 @@ const route = useRoute()
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const gameStore = useGameStore()
|
const gameStore = useGameStore()
|
||||||
const eventBus = useEventBusStore()
|
const eventBus = useEventBusStore()
|
||||||
|
const gameOptionsStore = useGameOptionsStore()
|
||||||
const socketService: any = inject('socket')
|
const socketService: any = inject('socket')
|
||||||
const gameService: GameService = inject<GameService>('game') as GameService
|
const gameService: GameService = inject<GameService>('game') as GameService
|
||||||
const logger: LoggingService = inject<LoggingService>('logger') as LoggingService
|
const logger: LoggingService = inject<LoggingService>('logger') as LoggingService
|
||||||
@ -22,6 +24,7 @@ let matchSession = ref<MatchSessionDto | undefined>(undefined)
|
|||||||
const { readyForStart, sessionState, isSessionStarted, playerState, amIHost } =
|
const { readyForStart, sessionState, isSessionStarted, playerState, amIHost } =
|
||||||
storeToRefs(gameStore)
|
storeToRefs(gameStore)
|
||||||
const { updateSessionState, updatePlayerState, updateGameState } = gameStore
|
const { updateSessionState, updatePlayerState, updateGameState } = gameStore
|
||||||
|
const { gameOptions } = storeToRefs(gameOptionsStore)
|
||||||
|
|
||||||
async function setPlayerReady() {
|
async function setPlayerReady() {
|
||||||
logger.debug('Starting game')
|
logger.debug('Starting game')
|
||||||
@ -35,7 +38,7 @@ async function setPlayerReady() {
|
|||||||
}
|
}
|
||||||
await socketService.sendMessage('client:set-player-ready', {
|
await socketService.sendMessage('client:set-player-ready', {
|
||||||
userId: playerState.value.id,
|
userId: playerState.value.id,
|
||||||
sessionId: sessionState.value.id
|
sessionId: sessionState.value.id,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +48,7 @@ async function startMatch() {
|
|||||||
if (sessionId) {
|
if (sessionId) {
|
||||||
await socketService.sendMessageWithAck('client:start-session', {
|
await socketService.sendMessageWithAck('client:start-session', {
|
||||||
sessionId: sessionId,
|
sessionId: sessionId,
|
||||||
playerId: playerId
|
playerId: playerId,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,7 +92,7 @@ onBeforeMount(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h1 class="title is-2">Match Page</h1>
|
<h1 class="title is-2">Match Page {{ isSessionStarted }}</h1>
|
||||||
<div class="block" v-if="matchSession">
|
<div class="block" v-if="matchSession">
|
||||||
<p>Session ID: {{ matchSession._id }}</p>
|
<p>Session ID: {{ matchSession._id }}</p>
|
||||||
<p>Session Name: {{ matchSession.name }}</p>
|
<p>Session Name: {{ matchSession.name }}</p>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user