70 lines
1.9 KiB
Svelte
70 lines
1.9 KiB
Svelte
<script lang="ts">
|
|
import { boardSize, type Point } from '#lib/games/snake';
|
|
import { themeState } from '#lib/theme/theme.svelte';
|
|
|
|
let { snake, food, size }: { snake: Point[]; food: Point | null; size: number } = $props();
|
|
|
|
const emptyCellOpacity = 0.06;
|
|
|
|
let canvasElement = $state<HTMLCanvasElement>();
|
|
let pixelRatio = $state(1);
|
|
|
|
const canvasSize = $derived(Math.round(size * pixelRatio));
|
|
|
|
function themeColor(name: string): string {
|
|
return getComputedStyle(canvasElement!).getPropertyValue(name).trim();
|
|
}
|
|
|
|
function drawBoard(context: CanvasRenderingContext2D) {
|
|
const gap = Math.max(1, Math.round(pixelRatio));
|
|
const cellSpan = (canvasSize - gap) / boardSize;
|
|
|
|
const fillCell = (point: Point) => {
|
|
const left = gap + Math.round(point.x * cellSpan);
|
|
const top = gap + Math.round(point.y * cellSpan);
|
|
const right = Math.round((point.x + 1) * cellSpan);
|
|
const bottom = Math.round((point.y + 1) * cellSpan);
|
|
context.fillRect(left, top, right - left, bottom - top);
|
|
};
|
|
|
|
context.clearRect(0, 0, canvasSize, canvasSize);
|
|
|
|
context.globalAlpha = emptyCellOpacity;
|
|
context.fillStyle = themeColor('--foreground');
|
|
for (let y = 0; y < boardSize; y++) {
|
|
for (let x = 0; x < boardSize; x++) fillCell({ x, y });
|
|
}
|
|
context.globalAlpha = 1;
|
|
|
|
if (food) {
|
|
context.fillStyle = themeColor('--red');
|
|
fillCell(food);
|
|
}
|
|
|
|
context.fillStyle = themeColor('--green');
|
|
snake.slice(1).forEach(fillCell);
|
|
|
|
context.fillStyle = themeColor('--accent');
|
|
if (snake[0]) fillCell(snake[0]);
|
|
}
|
|
|
|
$effect(() => {
|
|
size;
|
|
pixelRatio = window.devicePixelRatio || 1;
|
|
});
|
|
|
|
$effect(() => {
|
|
themeState.currentId;
|
|
const context = canvasElement?.getContext('2d');
|
|
if (context && canvasSize > 0) drawBoard(context);
|
|
});
|
|
</script>
|
|
|
|
<canvas bind:this={canvasElement} width={canvasSize} height={canvasSize} style="width: {size}px; height: {size}px"></canvas>
|
|
|
|
<style>
|
|
canvas {
|
|
display: block;
|
|
}
|
|
</style>
|