Files
website/src/lib/components/games/BreakoutCanvas.svelte
T

74 lines
1.9 KiB
Svelte

<script lang="ts">
import {
ballRadius,
brickHeight,
brickWidth,
fieldWidth,
paddleHeight,
paddleWidth,
paddleY,
type Ball,
type Brick
} from '#lib/games/breakout';
import { themeState } from '#lib/theme/theme.svelte';
let {
paddleX,
ball,
bricks,
width,
height
}: { paddleX: number; ball: Ball; bricks: Brick[]; width: number; height: number } = $props();
const brickRowColors = ['--red', '--orange', '--yellow', '--green', '--cyan', '--blue'];
let canvasElement = $state<HTMLCanvasElement>();
let pixelRatio = $state(1);
const canvasWidth = $derived(Math.round(width * pixelRatio));
const canvasHeight = $derived(Math.round(height * pixelRatio));
function drawField(context: CanvasRenderingContext2D) {
const style = getComputedStyle(canvasElement!);
const themeColor = (name: string) => style.getPropertyValue(name).trim();
const scale = canvasWidth / fieldWidth;
context.setTransform(1, 0, 0, 1, 0, 0);
context.clearRect(0, 0, canvasWidth, canvasHeight);
context.setTransform(scale, 0, 0, scale, 0, 0);
bricks.forEach((brick) => {
if (brick.broken) return;
context.fillStyle = themeColor(brickRowColors[brick.row % brickRowColors.length]);
context.fillRect(brick.x, brick.y, brickWidth, brickHeight);
});
context.fillStyle = themeColor('--accent');
context.fillRect(paddleX, paddleY, paddleWidth, paddleHeight);
context.fillStyle = themeColor('--foreground');
context.beginPath();
context.arc(ball.x, ball.y, ballRadius, 0, Math.PI * 2);
context.fill();
}
$effect(() => {
width;
pixelRatio = window.devicePixelRatio || 1;
});
$effect(() => {
themeState.currentId;
const context = canvasElement?.getContext('2d');
if (context && canvasWidth > 0) drawField(context);
});
</script>
<canvas bind:this={canvasElement} width={canvasWidth} height={canvasHeight} style="width: {width}px; height: {height}px"></canvas>
<style>
canvas {
display: block;
}
</style>