game flow
This commit is contained in:
		@@ -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')
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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')
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user