game flow

This commit is contained in:
Jose Conde
2024-07-06 20:28:48 +02:00
parent c40dcd74db
commit 9a6f430e4d
22 changed files with 937 additions and 260 deletions

View File

@ -14,10 +14,13 @@ import { Tile } from '@/game/Tile'
import { DIRECTIONS, createContainer, isTilePair } from '@/common/helpers'
import { createText } from '@/game/utilities/fonts'
import { Dot } from '@/game/Dot'
import { LoggingService } from '@/services/LoggingService'
import { inject } from 'vue'
export class Board extends EventEmitter {
private _scale: number = 1
private _canMove: boolean = false
private logger = inject<LoggingService>('logger')!
ticker: Ticker
height: number
@ -25,7 +28,7 @@ export class Board extends EventEmitter {
grain: number = 25
scaleY: ScaleFunction
scaleX: ScaleFunction
state: GameState | undefined
state?: GameState
container!: Container
initialContainer!: Container
tilesContainer!: Container
@ -45,7 +48,7 @@ export class Board extends EventEmitter {
leftDirection: string = 'west'
rightDirection: string = 'east'
playerHand: Tile[] = []
firstTile: Tile | undefined
firstTile?: Tile
constructor(app: Application) {
super()
@ -63,8 +66,8 @@ export class Board extends EventEmitter {
})
const background = new Sprite(Assets.get('bg-1'))
background.width = this.width
background.height = this.height
// background.width = this.width
// background.height = this.height
this.container.addChild(background)
this.initialContainer = createContainer({
@ -102,7 +105,13 @@ export class Board extends EventEmitter {
this.tilesContainer.addChild(verticalLine)
this.tilesContainer.addChild(horizontalLine)
this.createTexts()
this.textContainer = createContainer({
width: this.width,
height: this.height,
parent: this.container
})
this.showText('Starting game...')
}
private calculateScale() {
@ -138,20 +147,17 @@ export class Board extends EventEmitter {
this.playerHand = tiles
}
createTexts() {
this.textContainer = new Container()
this.textWaitForPlayers = createText('Waiting for players', this.scaleX(0), 100)
this.textYourTurn = createText('Your turn!', this.scaleX(0), 100)
this.container.addChild(this.textContainer)
this.textContainer.addChild(this.textWaitForPlayers)
this.textContainer.addChild(this.textYourTurn)
this.textYourTurn.visible = false
showText(text: string) {
this.textContainer.removeChildren()
this.textContainer.addChild(createText(text, this.scaleX(0), 100))
}
private updateCanMoveText() {
this.textWaitForPlayers.visible = !this.canMove
this.textYourTurn.visible = this.canMove
if (this.canMove) {
this.showText('Your turn!')
} else {
this.showText('Waiting for players')
}
}
setState(state: GameState, playerId: string) {
@ -161,7 +167,6 @@ export class Board extends EventEmitter {
if (lastMove === null) {
return
}
console.log('lastMove :>> ', lastMove)
if (
lastMove !== null &&
lastMove.tile !== undefined &&
@ -319,7 +324,6 @@ export class Board extends EventEmitter {
y += isEndVertical && !isNextVertical ? 0 : 1
}
}
console.log('position::>>', tile.pips, x, y)
tile.setPosition(this.scaleX(x), this.scaleY(y))
tile.setOrientation(orientation)
tile.reScale(this.scale)
@ -386,7 +390,7 @@ export class Board extends EventEmitter {
this.addTile(tile, move)
this.setFreeEnd(move)
} catch (error) {
console.log('error :>> ', error)
this.logger.error(error, 'Error updating board')
}
}
@ -395,7 +399,6 @@ export class Board extends EventEmitter {
}
setValidEnds(values: boolean[], tile: TileDto) {
console.log('validEnds')
if (this.count === 0) {
this.createInteractionsII('right', [[0, 0], undefined, undefined, undefined])
return
@ -405,15 +408,12 @@ export class Board extends EventEmitter {
const side = 'left'
const validInteractions = this.nextTileValidMoves(tile, side)
const validPoints = this.nextTileValidPoints(tile, side, validInteractions)
console.log('validInteractions :>> ', validInteractions)
// this.createInteractions(side, tile)
this.createInteractionsII(side, validPoints)
}
if (values[1]) {
const side = 'right'
const validInteractions = this.nextTileValidMoves(tile, side)
const validPoints = this.nextTileValidPoints(tile, side, validInteractions)
console.log('validInteractions :>> ', validInteractions)
this.createInteractionsII(side, validPoints)
}
}
@ -501,7 +501,6 @@ export class Board extends EventEmitter {
dot.alpha = 0.5
dot.interactive = true
dot.on('pointerdown', () => {
console.log('direction :>> ', direction)
this.emit(`${side}Click`, direction && { direction, x, y })
this.cleanInteractions()
})
@ -567,4 +566,21 @@ export class Board extends EventEmitter {
}
return [canPlayNorth, canPlayEast, canPlaySouth, canPlayWest]
}
gameFinished() {
this.tiles = []
this.boneyard = []
this.movements = []
this.playerHand = []
this.freeEnds = undefined
this.leftTile = undefined
this.rightTile = undefined
this.nextTile = undefined
this.leftDirection = 'west'
this.rightDirection = 'east'
this.firstTile = undefined
this.tilesContainer.removeChildren()
this.interactionContainer.removeChildren()
this.showText('Game finished')
}
}

View File

@ -4,6 +4,7 @@ import { assets } from '@/game/utilities/assets'
import { Tile } from '@/game/Tile'
import { Hand } from '@/game/Hand'
import type { Movement, TileDto } from '@/common/interfaces'
import type { SocketIoClientService } from '@/services/SocketIoClientService'
export class Game {
public board!: Board
@ -19,7 +20,9 @@ export class Game {
height: 650
},
private emit: any,
private props: any
private socketService: SocketIoClientService,
private playerId: string,
private sessionId: string
) {}
async setup(): Promise<HTMLCanvasElement> {
@ -66,11 +69,18 @@ export class Game {
const move: Movement = {
id: '',
type: 'pass',
playerId: this.props.playerId ?? ''
playerId: this.playerId
}
this.emit('move', move)
this.board.updateBoard(move)
})
this.hand.on('nextClick', async () => {
await this.socketService.sendMessageWithAck('playerReady', {
user: this.playerId,
sessionId: this.sessionId
})
})
}
getMoves(tile: any): [boolean, boolean] {
@ -101,7 +111,7 @@ export class Game {
const move: Movement = {
tile: this.selectedTile,
type: 'left',
playerId: this.props.playerId ?? '',
playerId: this.playerId,
...data
}
this.emit('move', move)
@ -115,7 +125,7 @@ export class Game {
const move: Movement = {
tile: this.selectedTile,
type: 'right',
playerId: this.props.playerId ?? '',
playerId: this.playerId,
...data
}
this.emit('move', move)
@ -124,6 +134,11 @@ export class Game {
})
}
gameFinished() {
this.hand.gameFinished()
this.board.gameFinished()
}
private removeBoardEvents() {
this.board.off('leftClick')
this.board.off('rightClick')

View File

@ -9,13 +9,16 @@ import {
Ticker
} from 'pixi.js'
import { Tile } from '@/game/Tile'
import type { PlayerState, TileDto } from '@/common/interfaces'
import type { Dimension, PlayerDto, TileDto } from '@/common/interfaces'
import { GlowFilter } from 'pixi-filters'
import { Scale, type ScaleFunction } from './utilities/scale'
import { LoggingService } from '@/services/LoggingService'
export class Hand extends EventEmitter {
tiles: Tile[] = []
container: Container = new Container()
buttonPassContainer: Container = new Container()
buttonPass: Container = new Container()
buttonNext: Container = new Container()
height: number
width: number
ticker: Ticker
@ -24,6 +27,10 @@ export class Hand extends EventEmitter {
initialized: boolean = false
_canMove: boolean = false
scale: number = 1
scaleY!: ScaleFunction
scaleX!: ScaleFunction
grain: number = 25
logger: LoggingService = new LoggingService()
constructor(app: Application) {
super()
@ -34,24 +41,47 @@ export class Hand extends EventEmitter {
this.container.y = app.canvas.height - this.height
this.container.width = this.width
this.container.height = this.height
this.calculateScale()
this.addBg()
this.createPassButton()
}
gameFinished() {
this.logger.debug('gameFinished')
this.tiles = []
this.container.removeChildren()
this.initialized = false
this.buttonNext = this.createButton(
'NEXT',
{ x: this.width / 2 - 25, y: this.height / 2, width: 50, height: 20 },
'nextClick'
)
}
get canMove() {
return this._canMove
}
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])
}
set canMove(value: boolean) {
this._canMove = value
this.buttonPassContainer.eventMode = value ? 'static' : 'none'
this.buttonPassContainer.cursor = value ? 'pointer' : 'default'
if (value) {
this.createPassButton()
} else {
this.container.removeChild(this.buttonPass)
}
this.tiles.forEach((tile) => {
tile.interactive = value
})
}
initialize(playerState: PlayerState) {
initialize(playerState: PlayerDto) {
this.tiles = this.createTiles(playerState)
this.emit('handUpdated', this.tiles)
this.initialized = this.tiles.length > 0
@ -106,11 +136,15 @@ export class Hand extends EventEmitter {
tile.off('pointerout')
}
private createPassButton() {
const rectangle = new Graphics().roundRect(0, 0, 80, 30, 10).fill(0xffff00)
private createButton(
textStr: string,
dimension: Dimension,
action: string | Function
): Container {
const { x, y, width, height } = dimension
const rectangle = new Graphics().roundRect(x, y, width + 4, height + 4, 5).fill(0xffff00)
const text = new Text({
text: 'PASS',
text: textStr,
style: {
fontFamily: 'Arial',
fontSize: 12,
@ -120,38 +154,45 @@ export class Hand extends EventEmitter {
}
})
text.anchor = 0.5
const container = new Container()
container.addChild(rectangle)
container.addChild(text)
this.buttonPassContainer = new Container()
text.y = y + height / 2
text.x = x + width / 2
this.buttonPassContainer.addChild(rectangle)
this.buttonPassContainer.addChild(text)
text.y = this.buttonPassContainer.height / 2 - 4
text.x = this.buttonPassContainer.width / 2 - 8
this.buttonPassContainer.eventMode = 'none'
this.buttonPassContainer.cursor = 'default'
this.buttonPassContainer.x = 20
this.buttonPassContainer.y = this.height / 2 - 10
container.eventMode = 'static'
container.cursor = 'pointer'
rectangle.alpha = 0.7
text.alpha = 0.7
this.buttonPassContainer.on('pointerdown', () => {
this.emit('passClick')
container.on('pointerdown', () => {
action instanceof Function ? action() : this.emit(action)
})
this.buttonPassContainer.on('pointerover', () => {
container.on('pointerover', () => {
rectangle.alpha = 1
text.alpha = 1
})
this.buttonPassContainer.on('pointerout', () => {
container.on('pointerout', () => {
rectangle.alpha = 0.7
text.alpha = 0.7
})
this.container.addChild(this.buttonPassContainer)
this.container.addChild(container)
return container
}
update(playerState: PlayerState) {
private createPassButton() {
const lastTile = this.tiles[this.tiles.length - 1]
const x = lastTile ? lastTile.x + lastTile.width : this.scaleX(0)
this.buttonPass = this.createButton(
'PASS',
{ x, y: this.height / 2, width: 50, height: 20 },
'passClick'
)
}
update(playerState: PlayerDto) {
if (!this.initialized) {
this.initialize(playerState)
return
@ -167,7 +208,7 @@ export class Hand extends EventEmitter {
this.renderTiles()
}
private createTiles(playerState: PlayerState) {
private createTiles(playerState: PlayerDto) {
return playerState.hand.map((tile) => {
const newTile: Tile = new Tile(tile.id, this.ticker, tile.pips, this.scale)
newTile.alpha = 0.7