working flow

This commit is contained in:
Jose Conde 2024-07-14 21:35:03 +02:00
parent 1b058db6c0
commit 3755f2857a
13 changed files with 375 additions and 214 deletions

View File

@ -1,6 +1,7 @@
import { Graphics, Container, Text } from 'pixi.js'
import type { ContainerOptions, Dimension, TileDto } from './interfaces'
import { DEFAULT_CONTAINER_OPTIONS } from './constants'
import useClipboard from 'vue-clipboard3'
export function getColorBackground(container: Container, colorName: string, alpha: number = 0.5) {
const graphics = new Graphics()
@ -22,6 +23,10 @@ export function createContainer(options: ContainerOptions) {
if (opts.color) {
rect.fill(opts.color)
}
if (opts.alpha) {
rect.alpha = opts.alpha
}
rect.visible = opts.visible
container.addChild(rect)
if (opts.parent) {
@ -78,6 +83,15 @@ export function createButton(
return container
}
export function createCrosshair(container: Container, color: number = 0xff0000, d: Dimension) {
const verticalLine = new Graphics().moveTo(d.x, 0).lineTo(d.x, d.height).stroke(color)
const horizontalLine = new Graphics().moveTo(0, d.y).lineTo(d.width, d.y).stroke(color)
verticalLine.alpha = 0.2
horizontalLine.alpha = 0.2
container.addChild(verticalLine)
container.addChild(horizontalLine)
}
export async function wait(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms))
}
@ -91,3 +105,8 @@ export function isTilePair(tile: TileDto): boolean {
export function isTileVertical(tile: TileDto): boolean {
return tile.orientation === 'north' || tile.orientation === 'south'
}
export function copyToclipboard(value: string) {
const { toClipboard } = useClipboard()
toClipboard(value)
}

View File

@ -74,6 +74,7 @@ export interface ContainerOptions {
color?: number
visible?: boolean
parent?: Container
alpha?: number
}
export interface Dimension {

View File

@ -1,31 +1,38 @@
<script setup lang="ts">
import type { MatchSessionDto, GameDto, PlayerDto } from '@/common/interfaces'
import { onMounted, onUnmounted, ref, watch, inject } from 'vue'
import type { GameDto, PlayerDto } from '@/common/interfaces'
import { onMounted, onUnmounted, ref, inject, toRaw } from 'vue'
import { Game } from '@/game/Game'
import { useGameStore } from '@/stores/game'
import { useEventBusStore } from '@/stores/eventBus'
import type { LoggingService } from '@/services/LoggingService'
import { storeToRefs } from 'pinia'
const logger: LoggingService = inject<LoggingService>('logger') as LoggingService
const emit = defineEmits(['move'])
const socketService: any = inject('socket')
const gameStore = useGameStore()
const eventBus = useEventBusStore()
const { playerState, sessionState, canMakeMove } = storeToRefs(gameStore)
const { updateSessionState, updatePlayerState, updateGameState } = gameStore
const { playerState, sessionState } = storeToRefs(gameStore)
const { updateGameState } = gameStore
const minScreenWidth = 800
const minScreenHeight = 700
let screenWidth = window.innerWidth - 10
let screenHeight = window.innerHeight - 10
if (screenWidth < minScreenWidth) screenWidth = minScreenWidth
if (screenHeight < minScreenHeight) screenHeight = minScreenHeight
const boardScale = screenWidth > 1200 ? 0.8 : screenWidth > 1200 ? 0.7 : 0.6
let appEl = ref<HTMLElement | null>(null)
const game = new Game(
{
width: 1200,
height: 650,
boardScale: 0.7,
width: screenWidth,
height: screenHeight,
boardScale,
handScale: 1
},
emit,
socketService,
playerState.value?.id || '',
sessionState.value?.id || ''
@ -61,36 +68,31 @@ onMounted(async () => {
const canvas = await game.setup()
appEl.value.appendChild(canvas)
await game.preload()
await game.start()
await game.start(sessionState?.value?.players)
eventBus.subscribe('server:game-finished', (data) => {
console.log('server:game-finished :>> ', data)
game.gameFinished(data)
})
eventBus.subscribe('server:server-player-move', (data) => {
console.log('server:player-move :>> ', data)
game.serverPlayerMove(data, playerState.value?.id ?? '')
})
eventBus.subscribe('game:player-turn-started', (data: any) => {
console.log('game:player-turn-started :>> ', data)
// game.setCanMakeMove(true)
})
eventBus.subscribe('server:hand-dealt', (playerState: PlayerDto) => {
console.log('server:hand-dealt :>> ', playerState)
game.hand.update(playerState)
eventBus.subscribe('server:hand-dealt', (data: { player: PlayerDto; gameState: GameDto }) => {
game.hand.update(data.player)
game.updateOtherHands(data.gameState)
})
eventBus.subscribe('server:next-turn', (gameState: GameDto) => {
console.log('server:next-turn :>> ', gameState)
updateGameState(gameState)
game.setNextPlayer(gameState)
})
eventBus.subscribe('server:match-finished', (data) => {
console.log('server:match-finished :>> ', data)
game.matchFinished(data)
})
@ -115,7 +117,7 @@ onMounted(async () => {
})
onUnmounted(() => {
game.destroy()
//game.destroy()
})
</script>

View File

@ -1,27 +1,18 @@
import {
Application,
Assets,
Container,
EventEmitter,
Graphics,
Sprite,
Text,
Ticker
} from 'pixi.js'
import { Application, Assets, Container, EventEmitter, Sprite, Text, Ticker } from 'pixi.js'
import { Scale, type ScaleFunction } from '@/game/utilities/scale'
import type { AnimationOptions, Movement, PlayerDto, TileDto } from '@/common/interfaces'
import { Tile } from '@/game/Tile'
import { DIRECTIONS, createContainer, isTilePair } from '@/common/helpers'
import { DIRECTIONS, createContainer, createCrosshair, isTilePair } from '@/common/helpers'
import { createText } from '@/game/utilities/fonts'
import { LoggingService } from '@/services/LoggingService'
import { inject } from 'vue'
import { GlowFilter } from 'pixi-filters'
import { ORIENTATION_ANGLES } from '@/common/constants'
import type { OtherHand } from './OtherHand'
export class Board extends EventEmitter {
private _scale: number = 1
private _canMove: boolean = false
private logger = inject<LoggingService>('logger')!
private logger: LoggingService = new LoggingService()
ticker: Ticker
height: number
@ -50,6 +41,7 @@ export class Board extends EventEmitter {
playerHand: Tile[] = []
firstTile?: Tile
currentPlayer!: PlayerDto
otherPlayerHands: OtherHand[] = []
constructor(app: Application) {
super()
@ -93,18 +85,19 @@ export class Board extends EventEmitter {
visible: false
})
const verticalLine = new Graphics()
.moveTo(this.scaleX(0), 0)
.lineTo(this.scaleX(0), this.height)
.stroke(0xff0000)
const horizontalLine = new Graphics()
.moveTo(0, this.scaleY(0))
.lineTo(this.width, this.scaleY(0))
.stroke(0xff0000)
verticalLine.alpha = 0.2
horizontalLine.alpha = 0.2
this.tilesContainer.addChild(verticalLine)
this.tilesContainer.addChild(horizontalLine)
createCrosshair(this.tilesContainer, 0xff0000, {
width: this.width,
height: this.height,
x: this.scaleX(0),
y: this.scaleY(0)
})
createCrosshair(this.interactionContainer, 0xffff00, {
width: this.width,
height: this.height,
x: this.scaleX(0),
y: this.scaleY(0)
})
this.textContainer = createContainer({
width: this.width,
@ -135,15 +128,6 @@ export class Board extends EventEmitter {
this.calculateScale()
}
get canMove() {
return this._canMove
}
set canMove(value: boolean) {
this._canMove = value
this.updateCanMoveText()
}
setPlayerHand(tiles: Tile[]) {
this.playerHand = tiles
}
@ -153,12 +137,8 @@ export class Board extends EventEmitter {
this.textContainer.addChild(createText(text, this.scaleX(0), 100))
}
private updateCanMoveText() {
if (this.canMove) {
async setPlayerTurn(player: PlayerDto) {
this.showText('Your turn!')
} else {
this.showText('Waiting for players')
}
}
async setServerPlayerTurn(currentPlayer: PlayerDto) {
@ -168,6 +148,9 @@ export class Board extends EventEmitter {
async playerMove(move: any, playerId: string) {
const { move: lastMove } = move
if (lastMove === null) {
setTimeout(() => {
this.emit('game:tile-animation-ended')
}, 500)
return
}
if (
@ -252,21 +235,46 @@ export class Board extends EventEmitter {
tile.reScale(this.scale)
this.tiles.push(tile)
await this.animateTile(tile, x, y, orientation, move)
this.emit('game:tile-animation-ended', tile.toPlain())
}
async animateTile(tile: Tile, x: number, y: number, orientation: string, move: Movement) {
const targetX = this.scaleX(x)
const targetY = this.scaleY(y)
const animation: AnimationOptions = {
x: this.scaleX(x),
y: this.scaleY(y),
x: targetX,
y: targetY,
rotation: ORIENTATION_ANGLES[orientation],
duration: 20
}
tile.setPosition(this.scaleX(x), this.scaleY(y))
const tempAlpha = tile.alpha
tile.alpha = 0
const clonedTile = tile.clone()
clonedTile.addTo(this.tilesContainer)
const pos = this.getAnimationInitialPoosition(move)
clonedTile.setPosition(this.scaleX(pos.x), this.scaleY(pos.y))
await clonedTile.animateTo(animation)
clonedTile.removeFromParent()
tile.setOrientation(orientation)
tile.setPosition(targetX, targetY)
tile.alpha = tempAlpha
}
// tile.setPosition(this.scaleX(0), this.height + tile.height / 2)
// console.log('going to animate', tile.pips)
// await tile.animateTo(animation)
// console.log('animated', tile.pips)
this.emit('game:tile-animation-ended', tile.toPlain())
getAnimationInitialPoosition(move: Movement): { x: number; y: number } {
const otherHand = this.otherPlayerHands.find((h) => h.player?.id === move.playerId)
if (otherHand === undefined) {
return { x: 0, y: this.scaleY.inverse(this.height + 50) }
}
const position = otherHand.position
switch (position) {
case 'left':
return { x: this.scaleX.inverse(100), y: this.scaleY.inverse(100) }
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) }
}
}
getPlayedTile(id: string): Tile | undefined {
@ -315,16 +323,14 @@ export class Board extends EventEmitter {
}
}
async updateBoard(move: Movement) {
async updateBoard(move: Movement, tile: Tile | undefined) {
try {
const { tile: tileDto } = move
const tile = this.getTileInHand(tileDto?.id ?? '')
// const { tileDto: tileDto } = move
// const tile = this.getTileInHand(tileDto?.id ?? '')
this.movements.push(move)
if (tile === undefined) {
return
}
this.movements.push(move)
await this.addTile(tile, move)
this.setFreeEnd(move)
} catch (error) {

View File

@ -5,17 +5,17 @@ import { Tile } from '@/game/Tile'
import { Hand } from '@/game/Hand'
import type { GameDto, Movement, PlayerDto, TileDto } from '@/common/interfaces'
import type { SocketIoClientService } from '@/services/SocketIoClientService'
import { useEventBusStore } from '@/stores/eventBus'
import { wait } from '@/common/helpers'
import { Actions } from 'pixi-actions'
import { OtherHand } from './OtherHand'
export class Game {
public board!: Board
public hand!: Hand
private app: Application = new Application()
private selectedTile: TileDto | undefined
private eventBus: any = useEventBusStore()
private currentMove: Movement | undefined
private otherHands: OtherHand[] = []
constructor(
private options: { boardScale: number; handScale: number; width: number; height: number } = {
@ -24,24 +24,29 @@ export class Game {
width: 1200,
height: 800
},
private emit: any,
private socketService: SocketIoClientService,
private playerId: string,
private sessionId: string
) {}
async setup(): Promise<HTMLCanvasElement> {
const width = 1200
const height = 800
const width = this.options.width || 1200
const height = this.options.height || 800
await this.app.init({ width, height })
this.app.ticker.add((tick) => Actions.tick(tick.deltaTime / 60))
return this.app.canvas
}
async start() {
async start(players: PlayerDto[] = []) {
this.board = new Board(this.app)
this.hand = new Hand(this.app)
this.otherHands = [
new OtherHand(this.app, 'left'),
new OtherHand(this.app, 'top'),
new OtherHand(this.app, 'right')
]
this.initOtherHands(players)
this.hand.scale = this.options.handScale
this.board.scale = this.options.boardScale
this.setBoardEvents()
@ -54,6 +59,32 @@ export class Game {
})
}
initOtherHands(players: PlayerDto[]) {
const myIndex = players.findIndex((player) => player.id === this.playerId)
const copy = [...players]
const cut = copy.splice(myIndex)
cut.shift()
const final = cut.concat(copy)
for (let i = 0; i < final.length; i++) {
const hand = this.otherHands[i]
hand.setPlayer(final[i])
}
this.board.otherPlayerHands = this.otherHands
}
updateOtherHands(gameState: GameDto) {
const players = gameState.players
players.forEach((player) => {
const hand = this.otherHands.find((hand) => hand.player?.id === player.id)
if (hand) {
hand.setHand(player.hand)
}
})
}
async preload() {
await Assets.load(assets)
}
@ -82,11 +113,11 @@ export class Game {
sessionId: this.sessionId,
move: move
})
await this.board.updateBoard(move)
await this.board.updateBoard(move, undefined)
})
this.hand.on('nextClick', () => {
this.socketService.sendMessage('client:set-player-ready', {
this.socketService.sendMessage('client:set-client-ready-for-next-game', {
userId: this.playerId,
sessionId: this.sessionId
})
@ -120,24 +151,18 @@ export class Game {
return validEnds
}
public setCanMakeMove(value: boolean) {
this.hand.setCanMove(value, this.board.count === 0, this.board.freeEnds)
this.board.canMove = value
}
async setNextPlayer(state: GameDto) {
const currentPlayer = state?.currentPlayer!
if (currentPlayer.id !== this.playerId) {
this.setCanMakeMove(false)
this.board.setServerPlayerTurn(currentPlayer)
if (currentPlayer.id === this.playerId) {
this.hand.prepareForMove(this.board.count === 0, this.board.freeEnds)
this.board.setPlayerTurn(currentPlayer)
} else {
this.setCanMakeMove(true)
this.board.setServerPlayerTurn(currentPlayer)
}
}
private setBoardEvents() {
this.board.on('game:board-left-action-click', async (data) => {
console.log('left data :>> ', data)
if (this.selectedTile === undefined) return
const move: Movement = {
tile: this.selectedTile,
@ -146,12 +171,11 @@ export class Game {
...data
}
this.currentMove = move
this.hand.tileMoved(this.selectedTile)
await this.board.updateBoard({ ...move, tile: this.selectedTile })
const tile = this.hand.tileMoved(this.selectedTile)
await this.board.updateBoard({ ...move, tile: this.selectedTile }, tile)
})
this.board.on('game:board-right-action-click', async (data) => {
console.log('right data :>> ', data)
if (this.selectedTile === undefined) return
const move: Movement = {
tile: this.selectedTile,
@ -160,31 +184,25 @@ export class Game {
...data
}
this.currentMove = move
this.hand.tileMoved(this.selectedTile)
await this.board.updateBoard({ ...move, tile: this.selectedTile })
const tile = this.hand.tileMoved(this.selectedTile)
await this.board.updateBoard({ ...move, tile: this.selectedTile }, tile)
})
this.board.on('game:tile-animation-ended', async (tile) => {
console.log('animation ended', tile)
if (tile.playerId === this.playerId) {
if (tile !== null && tile !== undefined && tile.playerId === this.playerId) {
this.socketService.sendMessage('client:player-move', {
sessionId: this.sessionId,
move: this.currentMove
})
} else {
this.socketService.sendMessage('client:animation-ended', {
sessionId: this.sessionId,
userId: this.playerId
})
}
})
}
// sendMoveEvent(move: Movement) {
// this.board.on('game:tile-animation-ended', async (tile) => {
// this.eventBus.publish('game:tile-animation-ended', tile)
// // this.socketService.sendMessageWithAck('client:tile-animation-ended', {
// // sessionId: this.sessionId,
// // tile
// // })
// })
// }
gameFinished(data: any) {
this.hand.gameFinished()
this.board.gameFinished(data)
@ -197,6 +215,13 @@ export class Game {
serverPlayerMove(data: any, playerId: string) {
this.board.playerMove(data, playerId)
if (!(data.move === undefined || data.move === null)) {
const otherHand = this.otherHands.find((hand) => hand.player?.id === data.move.playerId)
if (otherHand) {
otherHand.update(data.move)
}
}
}
private removeBoardEvents() {

View File

@ -88,30 +88,31 @@ export class Hand extends EventEmitter {
this.scaleY = Scale([-scaleYSteps, scaleYSteps], [0, this.height])
}
setCanMove(value: boolean, isFirstMove: boolean, freeEnds?: [number, number]) {
console.log('this.tiles :>> ', this.tiles.length)
this.availableTiles =
!value || isFirstMove
prepareForMove(isFirstMove: boolean, freeEnds?: [number, number]) {
this.availableTiles = isFirstMove
? this.tiles
: this.tiles.filter((tile) => this.hasMoves(tile.toPlain(), freeEnds))
console.log('this.availableTiles :>> ', this.availableTiles.length)
if (value && this.availableTiles.length === 0) {
if (this.availableTiles.length === 0) {
this.createPassButton()
} else {
this.interactionsLayer.removeChild(this.buttonPass)
}
this.availableTiles.forEach((tile) => {
if (value) {
tile.animateTo({
x: tile.x,
y: tile.y - 10
})
// const action: Action = Actions.moveTo(tile.getSprite(), tile.x, tile.y - 10, 1,).play()
}
tile.interactive = value
tile.interactive = true
})
}
afterMove() {
this.availableTiles.forEach((tile) => {
tile.animateTo({
x: tile.x,
y: tile.y + 10
})
tile.setPosition(tile.x, tile.y + 10)
tile.interactive = false
})
this._canMove = value
}
hasMoves(tile: TileDto, freeEnds?: [number, number]): boolean {
@ -166,20 +167,12 @@ export class Hand extends EventEmitter {
selected.alpha = 0.7
}
public tileMoved(tileDto: TileDto) {
public tileMoved(tileDto: TileDto): Tile | undefined {
const tile = this.tiles.find((t) => t.id === tileDto.id)
if (!tile) return
this.availableTiles
.filter((t) => t.id !== tileDto.id)
.forEach((t) => {
t.animateTo({
x: t.x,
y: t.y + 10
})
})
this.afterMove()
this.tiles = this.tiles.filter((t) => t.id !== tileDto.id)
tile.interactive = false
@ -187,6 +180,8 @@ export class Hand extends EventEmitter {
tile.off('pointerdown')
tile.off('pointerover')
tile.off('pointerout')
this.tilesLayer.removeChild(tile.getSprite())
return tile
}
private createPassButton() {
@ -195,7 +190,10 @@ export class Hand extends EventEmitter {
this.buttonPass = createButton(
'PASS',
{ x, y: this.height / 2, width: 50, height: 20 },
() => this.emit('game:button-pass-click'),
() => {
this.interactionsLayer.removeChild(this.buttonPass)
this.emit('game:button-pass-click')
},
this.interactionsLayer
)
}

118
src/game/OtherHand.ts Normal file
View File

@ -0,0 +1,118 @@
import { LoggingService } from '@/services/LoggingService'
import { Application, Container, Sprite, Texture } from 'pixi.js'
import { Scale, type ScaleFunction } from './utilities/scale'
import { Tile } from './Tile'
import type { Movement, PlayerDto, TileDto } from '@/common/interfaces'
import { createContainer } from '@/common/helpers'
import { createText, playerNameText } from './utilities/fonts'
export class OtherHand {
tilesInitialNumber: number = 7
player?: PlayerDto
hand: Tile[] = []
container: Container = new Container()
height: number
width: number
scale: number = 0.5
scaleY!: ScaleFunction
scaleX!: ScaleFunction
x: number = 0
y: number = 0
grain: number = 25
logger: LoggingService = new LoggingService()
tilesLayer!: Container
interactionsLayer!: Container
constructor(
private app: Application,
public position: 'left' | 'right' | 'top' = 'left'
) {
this.height = 100
this.width = 300
app.stage.addChild(this.container)
const { x, y } = this.getPosition()
this.container.width = this.width
this.container.height = this.height
this.container.x = x
this.container.y = y
this.calculateScale()
this.initLayers()
}
setPlayer(player: PlayerDto) {
this.player = player
this.container.addChild(createText(`${player.name}`, this.width / 2, 12, playerNameText))
}
setHand(tiles: TileDto[]) {
this.hand = tiles.map((tile) => new Tile(tile.id, this.app.ticker, undefined, this.scale))
this.render()
}
update(move: Movement) {
this.hand = this.hand.filter((tile) => tile.id !== move?.tile?.id)
this.render()
}
private render() {
this.tilesLayer.removeChildren()
const x = -9
this.hand.forEach((tile, index) => {
tile.setPosition(this.scaleX(x + index * 2), this.height / 2)
this.tilesLayer.addChild(tile.getSprite())
})
}
private addBg() {
const bg = new Sprite(Texture.WHITE)
bg.alpha = 0.08
bg.width = this.width
bg.height = this.height
this.container.addChild(bg)
}
private getPosition() {
let x = 0
let y = 0
if (this.position === 'left') {
x = 0
y = 30
} else if (this.position === 'right') {
x = this.app.canvas.width - this.width
y = 30
} else {
x = (this.app.canvas.width - this.width) / 2
y = 0
}
return { x, y }
}
private initLayers() {
this.container.removeChildren()
this.addBg()
this.tilesLayer = createContainer({
width: this.width,
height: this.height,
x: 0,
y: 0,
parent: this.container
})
this.interactionsLayer = createContainer({
width: this.width,
height: this.height,
x: 0,
y: 0,
parent: this.container
})
this.container.addChild(this.tilesLayer)
this.container.addChild(this.interactionsLayer)
}
private calculateScale() {
const scaleXSteps = Math.floor(this.width / (this.grain * this.scale)) / 2
const scaleYSteps = Math.floor(this.height / (this.grain * this.scale)) / 2
this.scaleX = Scale([-scaleXSteps, scaleXSteps], [0, this.width])
this.scaleY = Scale([-scaleYSteps, scaleYSteps], [0, this.height])
}
}

View File

@ -1,10 +1,11 @@
import type { AnimationOptions } from '@/common/interfaces'
import { Sprite, Texture, Ticker } from 'pixi.js'
import { Container, Sprite, Texture, Ticker } from 'pixi.js'
import { Tile } from './Tile'
export abstract class SpriteBase {
private _interactive: boolean = false
protected sprite: Sprite = new Sprite()
private container?: Container
constructor(
protected ticker?: Ticker,
@ -136,6 +137,11 @@ export abstract class SpriteBase {
}
addTo(container: any) {
this.container = container
container.addChild(this.sprite)
}
removeFromParent() {
this.container?.removeChild(this.sprite)
}
}

View File

@ -86,4 +86,11 @@ export class Tile extends SpriteBase {
}
this.orientation = value
}
clone(): Tile {
const copy = new Tile(this.id, this.ticker, this.pips, this.scale, this.playerId)
copy.selected = this.selected
copy.orientation = this.orientation
return copy
}
}

View File

@ -16,6 +16,16 @@ export const mainText = new TextStyle({
stroke: '#658f56'
})
export const playerNameText = new TextStyle({
dropShadow: dropShadowStyle,
fill: '#a2a2a2',
fontFamily: 'Arial, Helvetica, sans-serif',
letterSpacing: 1,
stroke: '#565656',
fontSize: 15,
fontWeight: 'bold'
})
export function createText(str: string, x: number, y: number, style: TextStyle = mainText) {
const text = new Text({ text: str, style })
text.anchor.set(0.5, 0.5)

View File

@ -31,13 +31,15 @@ onBeforeUnmount(() => {
})
function copySeed() {
if (sessionState?.value?.seed) toClipboard(sessionState.value.seed)
if (sessionState?.value?.seed) {
toClipboard(sessionState.value.seed)
}
}
</script>
<template>
<div class="block">
<section class="block">
<section class="block info">
<p>
Running: {{ sessionState?.sessionInProgress }} Seed: {{ sessionState?.seed }}
<button @click="copySeed">Copy!</button>
@ -99,56 +101,15 @@ function copySeed() {
* {
box-sizing: border-box;
}
.action-select {
display: flex;
gap: 16px;
align-items: start;
justify-items: center;
}
.game-container {
display: flex;
align-items: start;
justify-content: center;
}
.control {
padding: 8px;
margin-right: 4px;
}
textarea {
width: 100%;
height: 110px;
resize: none;
}
#response,
#status {
height: 180px;
}
.tiles-container {
display: flex;
gap: 4px;
flex-flow: row wrap;
align-content: flex-start;
}
.board-container {
.info {
position: absolute;
height: 600px;
padding: 10px;
width: calc(50% - 50px);
background-color: var(--pico-form-element-background-color);
}
.hand-container {
position: fixed;
bottom: 0;
height: 200px;
padding: 10px;
width: calc(50% - 50px);
background-color: var(--pico-form-element-background-color);
top: 0;
left: 0;
z-index: 20;
}
</style>

View File

@ -8,8 +8,9 @@ import type { GameService } from '@/services/GameService'
import type { MatchSessionDto } from '@/common/interfaces'
import { useEventBusStore } from '@/stores/eventBus'
import { useAuthStore } from '@/stores/auth'
import { copyToclipboard } from '@/common/helpers'
let seed = ref('')
let seed = ref<string>('')
let sessionName = ref('Test Value')
let sessionId = ref('')
let matchSessions = ref<MatchSessionDto[]>([])
@ -79,16 +80,19 @@ async function joinMatch(id: string) {
router.push({ name: 'match', params: { id } })
}
}
async function startMatch() {
if (sessionState.value && sessionState.value.id) {
router.push({ name: 'game' })
async function deleteMatch(id: string) {
if (id) {
await socketService.connect()
await gameService.cancelMatchSession(id)
loadData()
}
}
async function loadData() {
matchSessions.value = await gameService.listMatchSessions()
sessionName.value = `Test #${matchSessions.value.length + 1}`
const listResponse = await gameService.listMatchSessions()
console.log('listResponse :>> ', listResponse)
matchSessions.value = listResponse.data
sessionName.value = `Test #${listResponse.pagination.total + 1}`
}
onMounted(() => {
@ -101,6 +105,11 @@ onUnmounted(() => {
logger.debug('Home view unmounted')
clearInterval(dataInterval)
})
function copy(sessionSeed: string) {
seed.value = sessionSeed
copyToclipboard(sessionSeed)
}
</script>
<template>
@ -132,16 +141,6 @@ onUnmounted(() => {
<button class="button" @click="createMatch" v-if="!isSessionStarted">
Create Match Session
</button>
<!-- <button class="button" @click="setPlayerReady" v-if="isSessionStarted">
<span v-if="!readyForStart">Ready</span><span v-else>Unready</span>
</button> -->
<!-- <button class="button" @click="startMatch" v-if="readyForStart">
<span>Start</span>
</button>
<button class="button" @click="cancelMatch" v-if="isSessionStarted">
<span>Cancel</span>
</button> -->
</section>
<section class="section available-sessions" v-if="!isSessionStarted">
<h2 class="title is-4">Available Sessions</h2>
@ -149,12 +148,19 @@ onUnmounted(() => {
<div v-if="matchSessions.length === 0">
<p>No sessions available</p>
</div>
<div v-else v-for="session in matchSessions" :key="session.id">
<p>{{ session.name }}</p>
<p>{{ session }}</p>
<button class="button" @click="() => joinMatch(session._id)">
Join ({{ session._id }})
</button>
<div v-else class="grid is-col-min-12">
<div class="cell" v-for="session in matchSessions" :key="session.id">
<p class="title is-6">{{ session.name }}</p>
<p>ID: {{ session._id }}</p>
<p>Players: {{ session.players.length }}</p>
<p>
Seed: {{ session.seed }}
<button @click="() => copy(session.seed)">Copy</button>
</p>
<p>Status: {{ session.status }}</p>
<button class="button" @click="() => joinMatch(session._id)">Join</button>
<button class="button" @click="() => deleteMatch(session._id)">Delete</button>
</div>
</div>
</div>
</section>

View File

@ -70,7 +70,9 @@ eventBus.subscribe('window-before-unload', async () => {
await cancelMatch()
})
eventBus.subscribe('server:match-starting', () => {
eventBus.subscribe('server:match-starting', (data) => {
const session = data.sessionState as MatchSessionDto
updateSessionState(session)
logger.debug('Match starting')
router.push({ name: 'game' })
})