progress
This commit is contained in:
@ -8,6 +8,7 @@ import { LoggingService } from '@/services/LoggingService'
|
||||
import { GlowFilter } from 'pixi-filters'
|
||||
import { ORIENTATION_ANGLES } from '@/common/constants'
|
||||
import type { OtherHand } from './OtherHand'
|
||||
import { sound } from '@pixi/sound'
|
||||
|
||||
export class Board extends EventEmitter {
|
||||
private _scale: number = 1
|
||||
@ -46,63 +47,61 @@ export class Board extends EventEmitter {
|
||||
constructor(app: Application) {
|
||||
super()
|
||||
this.ticker = app.ticker
|
||||
this.height = app.canvas.height - 130
|
||||
this.height = app.canvas.height - 130 - 130
|
||||
this.width = app.canvas.width
|
||||
this.scaleX = Scale([0, this.width], [0, this.width])
|
||||
this.scaleY = Scale([0, this.height], [0, this.height])
|
||||
this.calculateScale()
|
||||
|
||||
this.container = createContainer({
|
||||
y: 130,
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
parent: app.stage
|
||||
parent: app.stage,
|
||||
})
|
||||
|
||||
const background = new Sprite(Assets.get('bg-green'))
|
||||
// background.width = this.width
|
||||
// background.height = this.height
|
||||
this.container.addChild(background)
|
||||
// this.container.y = 130
|
||||
|
||||
this.initialContainer = createContainer({
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
// color: 0x1e2f23,
|
||||
visible: false,
|
||||
parent: this.container
|
||||
parent: this.container,
|
||||
})
|
||||
|
||||
this.tilesContainer = createContainer({
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
// color: 0x1e2f23,
|
||||
parent: this.container
|
||||
parent: this.container,
|
||||
})
|
||||
|
||||
this.interactionContainer = createContainer({
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
parent: this.container,
|
||||
visible: false
|
||||
visible: false,
|
||||
})
|
||||
|
||||
createCrosshair(this.tilesContainer, 0xff0000, {
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
x: this.scaleX(0),
|
||||
y: this.scaleY(0)
|
||||
y: this.scaleY(0),
|
||||
})
|
||||
|
||||
createCrosshair(this.interactionContainer, 0xffff00, {
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
x: this.scaleX(0),
|
||||
y: this.scaleY(0)
|
||||
y: this.scaleY(0),
|
||||
})
|
||||
|
||||
this.textContainer = createContainer({
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
parent: this.container
|
||||
parent: this.container,
|
||||
})
|
||||
|
||||
this.showText('Starting game...')
|
||||
@ -134,7 +133,13 @@ export class Board extends EventEmitter {
|
||||
|
||||
showText(text: string) {
|
||||
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) {
|
||||
@ -169,7 +174,6 @@ export class Board extends EventEmitter {
|
||||
}
|
||||
|
||||
async addTile(tile: Tile, move: Movement) {
|
||||
console.log('adding tile', tile.pips)
|
||||
let orientation = ''
|
||||
let x: number =
|
||||
move.type === 'left'
|
||||
@ -234,11 +238,18 @@ export class Board extends EventEmitter {
|
||||
tile.addTo(this.tilesContainer)
|
||||
tile.reScale(this.scale)
|
||||
this.tiles.push(tile)
|
||||
|
||||
const moveSound = this.getRandomClickSound()
|
||||
await this.animateTile(tile, x, y, orientation, move)
|
||||
sound.play(moveSound)
|
||||
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) {
|
||||
const targetX = this.scaleX(x)
|
||||
const targetY = this.scaleY(y)
|
||||
@ -246,13 +257,13 @@ export class Board extends EventEmitter {
|
||||
x: targetX,
|
||||
y: targetY,
|
||||
rotation: ORIENTATION_ANGLES[orientation],
|
||||
duration: 20
|
||||
duration: 20,
|
||||
}
|
||||
const tempAlpha = tile.alpha
|
||||
tile.alpha = 0
|
||||
const clonedTile = tile.clone()
|
||||
clonedTile.addTo(this.tilesContainer)
|
||||
const pos = this.getAnimationInitialPoosition(move)
|
||||
const pos = this.getAnimationInitialPosition(move)
|
||||
clonedTile.setPosition(this.scaleX(pos.x), this.scaleY(pos.y))
|
||||
await clonedTile.animateTo(animation)
|
||||
clonedTile.removeFromParent()
|
||||
@ -261,7 +272,7 @@ export class Board extends EventEmitter {
|
||||
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)
|
||||
if (otherHand === undefined) {
|
||||
return { x: 0, y: this.scaleY.inverse(this.height + 50) }
|
||||
@ -271,9 +282,9 @@ export class Board extends EventEmitter {
|
||||
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) }
|
||||
case 'top':
|
||||
return { x: 0, y: this.scaleY.inverse(100) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -365,7 +376,7 @@ export class Board extends EventEmitter {
|
||||
nextTileValidPoints(
|
||||
tile: TileDto,
|
||||
side: string,
|
||||
validMoves: boolean[]
|
||||
validMoves: boolean[],
|
||||
): ([number, number] | undefined)[] {
|
||||
const isLeft = side === 'left'
|
||||
const end = isLeft ? this.leftTile : this.rightTile
|
||||
@ -450,8 +461,8 @@ export class Board extends EventEmitter {
|
||||
outerStrength: 1,
|
||||
innerStrength: 0,
|
||||
color: 0xffffff,
|
||||
quality: 0.5
|
||||
})
|
||||
quality: 0.5,
|
||||
}),
|
||||
])
|
||||
dot.setOrientation(direction ?? 'north')
|
||||
// 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 { assets } from '@/game/utilities/assets'
|
||||
import { Tile } from '@/game/Tile'
|
||||
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 { wait } from '@/common/helpers'
|
||||
import { Actions } from 'pixi-actions'
|
||||
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 {
|
||||
public board!: Board
|
||||
@ -16,17 +33,20 @@ export class Game {
|
||||
private selectedTile: TileDto | undefined
|
||||
private currentMove: Movement | undefined
|
||||
private otherHands: OtherHand[] = []
|
||||
private backgroundLayer: Container = new Container()
|
||||
private gameSummaryView!: GameSummayView
|
||||
|
||||
constructor(
|
||||
private options: { boardScale: number; handScale: number; width: number; height: number } = {
|
||||
private options: GameOptions = {
|
||||
boardScale: 1,
|
||||
handScale: 1,
|
||||
width: 1200,
|
||||
height: 800
|
||||
height: 800,
|
||||
background: 'bg-green',
|
||||
},
|
||||
private socketService: SocketIoClientService,
|
||||
private playerId: string,
|
||||
private sessionId: string
|
||||
private sessionId: string,
|
||||
) {}
|
||||
|
||||
async setup(): Promise<HTMLCanvasElement> {
|
||||
@ -39,14 +59,16 @@ export class Game {
|
||||
}
|
||||
|
||||
async start(players: PlayerDto[] = []) {
|
||||
this.iniialStuff(this.app)
|
||||
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')
|
||||
new OtherHand(this.app, 'right'),
|
||||
]
|
||||
this.initOtherHands(players)
|
||||
this.gameSummaryView = new GameSummayView(this.app)
|
||||
this.hand.scale = this.options.handScale
|
||||
this.board.scale = this.options.boardScale
|
||||
this.setBoardEvents()
|
||||
@ -55,10 +77,18 @@ export class Game {
|
||||
wait(3000)
|
||||
this.socketService.sendMessage('client:set-client-ready', {
|
||||
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[]) {
|
||||
const myIndex = players.findIndex((player) => player.id === this.playerId)
|
||||
const copy = [...players]
|
||||
@ -107,25 +137,36 @@ export class Game {
|
||||
const move: Movement = {
|
||||
id: '',
|
||||
type: 'pass',
|
||||
playerId: this.playerId
|
||||
playerId: this.playerId,
|
||||
}
|
||||
this.socketService.sendMessage('client:player-move', {
|
||||
sessionId: this.sessionId,
|
||||
move: move
|
||||
move: move,
|
||||
})
|
||||
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', {
|
||||
userId: this.playerId,
|
||||
sessionId: this.sessionId
|
||||
sessionId: this.sessionId,
|
||||
})
|
||||
})
|
||||
|
||||
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) {
|
||||
this.selectedTile = tile
|
||||
if (tile !== undefined) {
|
||||
@ -168,7 +209,7 @@ export class Game {
|
||||
tile: this.selectedTile,
|
||||
type: 'left',
|
||||
playerId: this.playerId,
|
||||
...data
|
||||
...data,
|
||||
}
|
||||
this.currentMove = move
|
||||
const tile = this.hand.tileMoved(this.selectedTile)
|
||||
@ -181,7 +222,7 @@ export class Game {
|
||||
tile: this.selectedTile,
|
||||
type: 'right',
|
||||
playerId: this.playerId,
|
||||
...data
|
||||
...data,
|
||||
}
|
||||
this.currentMove = move
|
||||
const tile = this.hand.tileMoved(this.selectedTile)
|
||||
@ -192,12 +233,12 @@ export class Game {
|
||||
if (tile !== null && tile !== undefined && tile.playerId === this.playerId) {
|
||||
this.socketService.sendMessage('client:player-move', {
|
||||
sessionId: this.sessionId,
|
||||
move: this.currentMove
|
||||
move: this.currentMove,
|
||||
})
|
||||
} else {
|
||||
this.socketService.sendMessage('client:animation-ended', {
|
||||
sessionId: this.sessionId,
|
||||
userId: this.playerId
|
||||
userId: this.playerId,
|
||||
})
|
||||
}
|
||||
})
|
||||
@ -206,11 +247,13 @@ export class Game {
|
||||
gameFinished(data: any) {
|
||||
this.hand.gameFinished()
|
||||
this.board.gameFinished(data)
|
||||
this.gameSummaryView.setGameSummary(data, 'round')
|
||||
}
|
||||
|
||||
matchFinished(data: any) {
|
||||
// this.hand.matchFinished()
|
||||
this.board.matchFinished(data)
|
||||
this.gameSummaryView.setGameSummary(data, 'match')
|
||||
}
|
||||
|
||||
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[] = []
|
||||
container: Container = new Container()
|
||||
buttonPass: Container = new Container()
|
||||
buttonNext: Container = new Container()
|
||||
height: number
|
||||
width: number
|
||||
ticker: Ticker
|
||||
@ -27,6 +26,7 @@ export class Hand extends EventEmitter {
|
||||
availableTiles: Tile[] = []
|
||||
tilesLayer!: Container
|
||||
interactionsLayer!: Container
|
||||
score: number = 0
|
||||
|
||||
constructor(app: Application) {
|
||||
super()
|
||||
@ -49,14 +49,14 @@ export class Hand extends EventEmitter {
|
||||
height: this.height,
|
||||
x: 0,
|
||||
y: 0,
|
||||
parent: this.container
|
||||
parent: this.container,
|
||||
})
|
||||
this.interactionsLayer = createContainer({
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
x: 0,
|
||||
y: 0,
|
||||
parent: this.container
|
||||
parent: this.container,
|
||||
})
|
||||
}
|
||||
|
||||
@ -65,16 +65,6 @@ export class Hand extends EventEmitter {
|
||||
this.tiles = []
|
||||
|
||||
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() {
|
||||
@ -98,7 +88,7 @@ export class Hand extends EventEmitter {
|
||||
this.availableTiles.forEach((tile) => {
|
||||
tile.animateTo({
|
||||
x: tile.x,
|
||||
y: tile.y - 10
|
||||
y: tile.y - 10,
|
||||
})
|
||||
tile.interactive = true
|
||||
})
|
||||
@ -108,7 +98,7 @@ export class Hand extends EventEmitter {
|
||||
this.availableTiles.forEach((tile) => {
|
||||
tile.animateTo({
|
||||
x: tile.x,
|
||||
y: tile.y + 10
|
||||
y: tile.y + 10,
|
||||
})
|
||||
tile.setPosition(tile.x, tile.y + 10)
|
||||
tile.interactive = false
|
||||
@ -128,7 +118,7 @@ export class Hand extends EventEmitter {
|
||||
initialize(playerState: PlayerDto) {
|
||||
this.tiles = this.createTiles(playerState)
|
||||
this.initialized = this.tiles.length > 0
|
||||
this.renderTiles()
|
||||
this.render()
|
||||
this.emit('hand-updated', this.tiles)
|
||||
}
|
||||
|
||||
@ -187,31 +177,32 @@ export class Hand extends EventEmitter {
|
||||
private createPassButton() {
|
||||
const lastTile = this.tiles[this.tiles.length - 1]
|
||||
const x = lastTile ? lastTile.x + lastTile.width : this.scaleX(0)
|
||||
this.buttonPass = createButton(
|
||||
'PASS',
|
||||
{ x, y: this.height / 2, width: 50, height: 20 },
|
||||
() => {
|
||||
this.buttonPass = createButton({
|
||||
text: 'PASS',
|
||||
dimension: { x, y: this.height / 2, width: 50, height: 20 },
|
||||
action: () => {
|
||||
this.interactionsLayer.removeChild(this.buttonPass)
|
||||
this.emit('game:button-pass-click')
|
||||
},
|
||||
this.interactionsLayer
|
||||
)
|
||||
parent: this.interactionsLayer,
|
||||
})
|
||||
}
|
||||
|
||||
update(playerState: PlayerDto) {
|
||||
this.tilesLayer.removeChildren()
|
||||
if (!this.initialized) {
|
||||
this.initialize(playerState)
|
||||
return
|
||||
}
|
||||
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) {
|
||||
this.tilesLayer.removeChild(missing.getSprite())
|
||||
this.tiles = this.tiles.filter((tile) => tile.id !== missing.id)
|
||||
this.emit('hand-updated', this.tiles)
|
||||
}
|
||||
this.renderTiles()
|
||||
this.render()
|
||||
}
|
||||
|
||||
private createTiles(playerState: PlayerDto) {
|
||||
@ -230,8 +221,8 @@ export class Hand extends EventEmitter {
|
||||
outerStrength: 2,
|
||||
innerStrength: 1,
|
||||
color: 0xffffff,
|
||||
quality: 0.5
|
||||
})
|
||||
quality: 0.5,
|
||||
}),
|
||||
])
|
||||
})
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
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 type { Movement, PlayerDto, TileDto } from '@/common/interfaces'
|
||||
import { createContainer } from '@/common/helpers'
|
||||
import { createText, playerNameText } from './utilities/fonts'
|
||||
import { createText, playerNameText, scoreText } from './utilities/fonts'
|
||||
|
||||
export class OtherHand {
|
||||
tilesInitialNumber: number = 7
|
||||
@ -22,10 +22,12 @@ export class OtherHand {
|
||||
logger: LoggingService = new LoggingService()
|
||||
tilesLayer!: Container
|
||||
interactionsLayer!: Container
|
||||
scoreLayer: Container = new Container()
|
||||
score: number = 0
|
||||
|
||||
constructor(
|
||||
private app: Application,
|
||||
public position: 'left' | 'right' | 'top' = 'left'
|
||||
public position: 'left' | 'right' | 'top' = 'left',
|
||||
) {
|
||||
this.height = 100
|
||||
this.width = 300
|
||||
@ -37,11 +39,23 @@ export class OtherHand {
|
||||
this.container.y = y
|
||||
this.calculateScale()
|
||||
this.initLayers()
|
||||
this.render()
|
||||
}
|
||||
|
||||
setPlayer(player: PlayerDto) {
|
||||
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[]) {
|
||||
@ -54,7 +68,19 @@ export class OtherHand {
|
||||
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()
|
||||
const x = -9
|
||||
this.hand.forEach((tile, index) => {
|
||||
@ -63,6 +89,11 @@ export class OtherHand {
|
||||
})
|
||||
}
|
||||
|
||||
private render() {
|
||||
this.renderTiles()
|
||||
this.renderScore()
|
||||
}
|
||||
|
||||
private addBg() {
|
||||
const bg = new Sprite(Texture.WHITE)
|
||||
bg.alpha = 0.08
|
||||
@ -96,17 +127,17 @@ export class OtherHand {
|
||||
height: this.height,
|
||||
x: 0,
|
||||
y: 0,
|
||||
parent: this.container
|
||||
parent: this.container,
|
||||
})
|
||||
this.interactionsLayer = createContainer({
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
x: 0,
|
||||
y: 0,
|
||||
parent: this.container
|
||||
parent: this.container,
|
||||
})
|
||||
this.container.addChild(this.tilesLayer)
|
||||
this.container.addChild(this.interactionsLayer)
|
||||
// this.container.addChild(this.tilesLayer)
|
||||
this.container.addChild(this.scoreLayer)
|
||||
}
|
||||
|
||||
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_5 from '@/assets/images/tiles/6-5.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 bg_1 from '@/assets/images/backgrounds/bg-1.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 = [
|
||||
{ alias: 'tile-back', src: tileBack },
|
||||
@ -62,8 +68,14 @@ export const assets = [
|
||||
{ alias: 'tile-6_4', src: tile6_4 },
|
||||
{ alias: 'tile-6_5', src: tile6_5 },
|
||||
{ alias: 'tile-6_6', src: tile6_6 },
|
||||
{ alias: 'dot', src: dot },
|
||||
{ alias: 'bg-wood-1', src: bgWood_1 },
|
||||
{ alias: 'bg-1', src: bg_1 },
|
||||
{ alias: 'bg-green', src: bg_green }
|
||||
{ alias: 'bg-gray', src: bg_1 },
|
||||
{ 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 = {
|
||||
alpha: 0.5,
|
||||
angle: 0.3,
|
||||
blur: 5,
|
||||
distance: 4
|
||||
distance: 4,
|
||||
}
|
||||
|
||||
export const mainText = new TextStyle({
|
||||
dropShadow: dropShadowStyle,
|
||||
fill: '#b71a1a',
|
||||
fill: '#aaaaaa',
|
||||
fontFamily: 'Arial, Helvetica, sans-serif',
|
||||
fontWeight: 'bold',
|
||||
letterSpacing: 1,
|
||||
stroke: '#658f56'
|
||||
stroke: '#565656',
|
||||
})
|
||||
|
||||
export const playerNameText = new TextStyle({
|
||||
@ -23,12 +31,104 @@ export const playerNameText = new TextStyle({
|
||||
letterSpacing: 1,
|
||||
stroke: '#565656',
|
||||
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 })
|
||||
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.y = y
|
||||
return text
|
||||
|
Reference in New Issue
Block a user