diff options
Diffstat (limited to 'src/ui/render.ts')
-rw-r--r-- | src/ui/render.ts | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/src/ui/render.ts b/src/ui/render.ts new file mode 100644 index 0000000..95464dc --- /dev/null +++ b/src/ui/render.ts @@ -0,0 +1,113 @@ +import { SessionState, GAME_SIZE, PADDLE_WIDTH, GameState } from "../state"; +import readline from "node:readline"; +import { + clearTerminal, + getCurrentTerminalSize, + TERM_SIZE as RENDER_SIZE, +} from "./utils"; + +let lastTermSize: ReturnType<typeof getCurrentTerminalSize> | undefined; + +export const renderGameState = (gameState: GameState): string[] => { + let rows: string[] = []; + for (let row = -1; row < GAME_SIZE.rows + 1; row++) { + // let rowOut: string = " ".repeat(marginCols); + let rowOut: string = " "; + + if (row === -1) { + rowOut = rowOut.concat("--".repeat(GAME_SIZE.cols + 2)); + } else { + for (let col = -1; col < GAME_SIZE.cols + 1; col++) { + if (col === -1 || col === GAME_SIZE.cols) { + rowOut = rowOut.concat("||"); + } else { + const [paddleX, paddleY] = gameState.paddle.position; + const paddleXMin = paddleX; + const paddleXMax = paddleX + PADDLE_WIDTH; + + const ballPositions = gameState.balls.map(({ position }) => position); + + const brickPositions = gameState.bricks.map( + ({ position }) => position + ); + + const hasPaddle = + col >= paddleXMin && col <= paddleXMax && row === paddleY; + + const firstBall = ballPositions.find( + ([ballX, ballY]) => + col === Math.round(ballX) && row === Math.round(ballY) + ); + + const hasBrick = brickPositions.some( + ([brickX, brickY]) => col === brickX && row === brickY + ); + + if (hasPaddle) { + rowOut = rowOut.concat("##"); + } else if (firstBall) { + const fx = firstBall[0] - Math.round(firstBall[0]); + + let chars; + if (fx < 0) { + chars = "O "; + } else { + chars = " O"; + } + + rowOut = rowOut.concat(chars); + } else if (hasBrick) { + rowOut = rowOut.concat("▒▒"); + } else { + rowOut = rowOut.concat(" "); + } + } + } + } + + rows.push(rowOut); + } + return rows; +}; + +export const renderState = (sessionState: SessionState) => { + const rl = new readline.promises.Readline(process.stdout, { + autoCommit: true, + }); + + rl.cursorTo(0, 0); + + const termSize = getCurrentTerminalSize(); + if ( + lastTermSize && + (lastTermSize.cols !== termSize.cols || lastTermSize.rows !== termSize.rows) + ) { + clearTerminal(); + } + lastTermSize = termSize; + + if (termSize.cols < RENDER_SIZE.cols || termSize.rows < RENDER_SIZE.rows) { + process.stdout.write("Please increase the screen size"); + return; + } + + const marginCols = (termSize.cols - RENDER_SIZE.cols) / 2; + const marginRows = (termSize.rows - RENDER_SIZE.rows) / 2; + + let allOut: string = "\n".repeat(marginRows); + + const localDisplay = renderGameState(sessionState.localPlayerGameState); + const remoteDisplay = renderGameState(sessionState.remotePlayerGameState); + + localDisplay.forEach( + (row, i) => + (allOut = allOut + .concat(" ".repeat(marginCols / 2)) + .concat(row) + .concat(" ".repeat(marginCols / 2)) + .concat(remoteDisplay[i]) + .concat("\n")) + ); + + process.stdout.write(allOut); +}; |