feat(settings/user/snake): improve snake design

This commit is contained in:
2026-02-25 16:07:16 +01:00
parent bbe20150ed
commit a265180a79

View File

@@ -289,29 +289,99 @@ onRender((ctx) => {
} }
} else { } else {
// food // food
const foodPos = cellToBoardPos(food);
ctx.fillStyle = "#ff2020"; ctx.fillStyle = "#ff2020";
ctx.fillRect( ctx.fillRect(foodPos.x + 1, foodPos.y + 1, CELL_SIZE, CELL_SIZE);
cellToBoardPos(food).x + 1,
cellToBoardPos(food).y + 1,
CELL_SIZE,
CELL_SIZE,
);
// snake // snake
for (const part of tail) { const snakeParts = [...tail, position];
ctx.fillStyle = state.value === "dead" ? "#991010" : "#20ff20"; const dead = state.value === "dead";
ctx.fillRect( const FILL = dead ? "#b84800" : "#ff8c00";
cellToBoardPos(part).x + 1, const FILL_DIM = dead ? "#8c3600" : "#cc7000";
cellToBoardPos(part).y + 1,
CELL_SIZE, const connectedTo = (i: number, dx: number, dy: number) => {
CELL_SIZE, const part = snakeParts[i]!;
); const neighbor = new THREE.Vector2(part.x + dx, part.y + dy);
const prev = snakeParts[i - 1];
const next = snakeParts[i + 1];
return (prev && prev.equals(neighbor)) || (next && next.equals(neighbor));
};
// fills
for (let i = 0; i < snakeParts.length; i++) {
const part = snakeParts[i]!;
const { x, y } = cellToBoardPos(part);
const px = x + 1;
const py = y + 1;
ctx.fillStyle = i === snakeParts.length - 1 ? FILL : FILL_DIM;
ctx.fillRect(px, py, CELL_SIZE, CELL_SIZE);
if (connectedTo(i, 1, 0)) {
ctx.fillRect(px + CELL_SIZE, py, CELL_PADDING, CELL_SIZE);
}
if (connectedTo(i, 0, 1)) {
ctx.fillRect(px, py + CELL_SIZE, CELL_SIZE, CELL_PADDING);
}
} }
assets.user.snakeHead.draw(
ctx, // outlines
cellToBoardPos(position).x + 1, ctx.fillStyle = "#ffffff";
cellToBoardPos(position).y, for (let i = 0; i < snakeParts.length; i++) {
); const part = snakeParts[i]!;
const { x, y } = cellToBoardPos(part);
const px = x + 1;
const py = y + 1;
if (!connectedTo(i, 0, -1)) {
ctx.fillRect(px, py, CELL_SIZE, 1);
}
if (!connectedTo(i, 0, 1)) {
ctx.fillRect(px, py + CELL_SIZE - 1, CELL_SIZE, 1);
}
if (!connectedTo(i, -1, 0)) {
ctx.fillRect(px, py, 1, CELL_SIZE);
}
if (!connectedTo(i, 1, 0)) {
ctx.fillRect(px + CELL_SIZE - 1, py, 1, CELL_SIZE);
}
}
const EYE_SIZE = 2;
const EYE_MARGIN = 3;
const eyeFar = CELL_SIZE - EYE_MARGIN - EYE_SIZE;
const head = snakeParts[snakeParts.length - 1]!;
const { x: headCellX, y: headCellY } = cellToBoardPos(head);
const headX = headCellX + 1;
const headY = headCellY + 1;
let eye1x: number, eye1y: number, eye2x: number, eye2y: number;
if (direction.x === 1) {
eye1x = headX + eyeFar;
eye1y = headY + EYE_MARGIN;
eye2x = headX + eyeFar;
eye2y = headY + eyeFar;
} else if (direction.x === -1) {
eye1x = headX + EYE_MARGIN;
eye1y = headY + EYE_MARGIN;
eye2x = headX + EYE_MARGIN;
eye2y = headY + eyeFar;
} else if (direction.y === 1) {
eye1x = headX + EYE_MARGIN;
eye1y = headY + eyeFar;
eye2x = headX + eyeFar;
eye2y = headY + eyeFar;
} else {
eye1x = headX + EYE_MARGIN;
eye1y = headY + EYE_MARGIN;
eye2x = headX + eyeFar;
eye2y = headY + EYE_MARGIN;
}
ctx.fillStyle = dead ? "#3d1500" : "#7a3800";
ctx.fillRect(eye1x, eye1y, EYE_SIZE, EYE_SIZE);
ctx.fillRect(eye2x, eye2y, EYE_SIZE, EYE_SIZE);
} }
ctx.restore(); ctx.restore();
@@ -353,7 +423,7 @@ useKeyDown(({ key }) => {
break; break;
} }
if (newDirection.clone().dot(direction) === 0) { if (newDirection.dot(direction) === 0) {
nextDirection.copy(newDirection); nextDirection.copy(newDirection);
atlas.audio.type.play(0.35); atlas.audio.type.play(0.35);
} }