caro5 / client /src /game /GridRenderer.ts
Pedro de Carvalho
Fix vict music
2e13c62
Raw
History Blame Contribute Delete
5.44 kB
import { Container, Graphics, Text, TextStyle } from 'pixi.js'
import { CELL_SIZE } from 'shared/board.ts'
import { theme, getThemeBackgroundImage, getThemeMode } from '../theme.ts'
const GRID_WIDTH = 1
const GRID_MAJOR_WIDTH = 2
const BORDER_WIDTH = 2
const BOARD_PAD = 1.2
const p = (gx: number, gy: number) => ({
x: gx * CELL_SIZE,
y: gy * CELL_SIZE,
})
export class GridRenderer {
container: Container
private graphics: Graphics
private coordsContainer: Container
private coordLabels: Text[] = []
private lastBoardSize = 0
constructor() {
this.graphics = new Graphics()
this.coordsContainer = new Container()
this.coordsContainer.eventMode = 'none'
this.container = new Container()
this.container.addChild(this.graphics)
this.container.addChild(this.coordsContainer)
}
private ensureCoords(boardSize: number): void {
if (boardSize === this.lastBoardSize && this.coordLabels.length > 0) return
this.lastBoardSize = boardSize
this.coordsContainer.removeChildren()
this.coordLabels.length = 0
const style = new TextStyle({ fontFamily: 'monospace', fontSize: 9, fill: 0xc0b8e8 })
const cols = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
for (let c = 0; c < boardSize; c++) {
const cx = (c + 0.5) * CELL_SIZE
const tT = new Text({ text: cols[c], style }); tT.alpha = 0.15; tT.anchor.set(0.5, 1); tT.position.set(cx, -5); this.coordsContainer.addChild(tT); this.coordLabels.push(tT)
const tB = new Text({ text: cols[c], style }); tB.alpha = 0.15; tB.anchor.set(0.5, 0); tB.position.set(cx, boardSize * CELL_SIZE + 5); this.coordsContainer.addChild(tB); this.coordLabels.push(tB)
}
for (let r = 0; r < boardSize; r++) {
const cy = (r + 0.5) * CELL_SIZE
const tL = new Text({ text: String(r + 1), style }); tL.alpha = 0.15; tL.anchor.set(1, 0.5); tL.position.set(-7, cy); this.coordsContainer.addChild(tL); this.coordLabels.push(tL)
const tR = new Text({ text: String(r + 1), style }); tR.alpha = 0.15; tR.anchor.set(0, 0.5); tR.position.set(boardSize * CELL_SIZE + 7, cy); this.coordsContainer.addChild(tR); this.coordLabels.push(tR)
}
}
draw(boardSize: number = 15): void {
this.graphics.clear()
const isGarden = getThemeMode() === 'garden'
const hasThemeBackgroundImage = getThemeBackgroundImage() !== null
const cellFillAlpha = hasThemeBackgroundImage ? 0.58 : 0.95
const gridColor = theme.gridMinor
const gridMajorColor = theme.gridMajor
const borderColor = theme.gridBorder
const start = 0
const end = boardSize
// Board shadow
const pad = BOARD_PAD
const sTL = p(start - pad, start - pad)
const sBR = p(end + pad, end + pad)
const bw = sBR.x - sTL.x
const bh = sBR.y - sTL.y
for (let i = 0; i < 6; i += 2) {
this.graphics.rect(sTL.x + i, sTL.y + i, bw, bh)
this.graphics.fill({ color: 0x000000, alpha: 0.03 + i * 0.005 })
}
// Cell fills (alternating board pattern)
for (let r = start; r < end; r++) {
for (let c = start; c < end; c++) {
const idx = r * boardSize + c
const isOdd = idx % 2 === 1
const fill = isOdd ? theme.cellFillAlt : theme.cellFill
const a = p(c, r)
const b = p(c + 1, r + 1)
this.graphics.rect(a.x, a.y, b.x - a.x, b.y - a.y)
this.graphics.fill({ color: fill, alpha: cellFillAlpha })
}
}
// Floor cast shadow (garden theme — stacked ellipses below board)
if (isGarden) {
const boardBot = boardSize * CELL_SIZE
const boardCx = (boardSize / 2) * CELL_SIZE
const boardHalfW = (boardSize / 2) * CELL_SIZE
for (let i = 0; i < 6; i++) {
const t = i / 5
const rx = boardHalfW * (0.7 + t * 0.45)
const ry = 2 + t * 5
const alpha = 0.28 * (1 - t * 0.9)
const yOff = 2 + t * 7
this.graphics.ellipse(boardCx, boardBot + yOff, rx, ry)
this.graphics.fill({ color: 0x000000, alpha })
}
}
// Board base (3D edge — visible thickness at bottom)
const edgeH = 10
this.graphics.rect(sTL.x, sTL.y + edgeH, bw, bh)
this.graphics.fill({ color: 0x000000, alpha: 0.12 })
this.graphics.rect(sTL.x, sTL.y, bw, bh)
this.graphics.fill({ color: 0x000000, alpha: 0.06 })
// Grid lines — vertical
for (let col = start; col <= end; col++) {
const isMajor = col % 5 === 0
const a = p(col, start)
const b = p(col, end)
this.graphics.moveTo(a.x, a.y)
this.graphics.lineTo(b.x, b.y)
this.graphics.stroke({
width: isMajor ? GRID_MAJOR_WIDTH : GRID_WIDTH,
color: isMajor ? gridMajorColor : gridColor,
alpha: isMajor ? 1 : 0.6,
})
}
// Grid lines — horizontal
for (let row = start; row <= end; row++) {
const isMajor = row % 5 === 0
const a = p(start, row)
const b = p(end, row)
this.graphics.moveTo(a.x, a.y)
this.graphics.lineTo(b.x, b.y)
this.graphics.stroke({
width: isMajor ? GRID_MAJOR_WIDTH : GRID_WIDTH,
color: isMajor ? gridMajorColor : gridColor,
alpha: isMajor ? 1 : 0.6,
})
}
// Border
const border = p(start, start)
this.graphics.rect(border.x, border.y, (end - start) * CELL_SIZE, (end - start) * CELL_SIZE)
this.graphics.stroke({ width: BORDER_WIDTH, color: borderColor })
this.ensureCoords(boardSize)
this.coordsContainer.visible = isGarden
}
}