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

This commit is contained in:
2026-02-25 16:07:16 +01:00
parent 858082e151
commit 7b4d4dec66

View File

@@ -289,29 +289,99 @@ onRender((ctx) => {
}
} else {
// food
const foodPos = cellToBoardPos(food);
ctx.fillStyle = "#ff2020";
ctx.fillRect(
cellToBoardPos(food).x + 1,
cellToBoardPos(food).y + 1,
CELL_SIZE,
CELL_SIZE,
);
ctx.fillRect(foodPos.x + 1, foodPos.y + 1, CELL_SIZE, CELL_SIZE);
// snake
for (const part of tail) {
ctx.fillStyle = state.value === "dead" ? "#991010" : "#20ff20";
ctx.fillRect(
cellToBoardPos(part).x + 1,
cellToBoardPos(part).y + 1,
CELL_SIZE,
CELL_SIZE,
);
const snakeParts = [...tail, position];
const dead = state.value === "dead";
const FILL = dead ? "#b84800" : "#ff8c00";
const FILL_DIM = dead ? "#8c3600" : "#cc7000";
const connectedTo = (i: number, dx: number, dy: number) => {
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);
}
assets.user.snakeHead.draw(
ctx,
cellToBoardPos(position).x + 1,
cellToBoardPos(position).y,
);
if (connectedTo(i, 0, 1)) {
ctx.fillRect(px, py + CELL_SIZE, CELL_SIZE, CELL_PADDING);
}
}
// outlines
ctx.fillStyle = "#ffffff";
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();
@@ -353,7 +423,7 @@ useKeyDown(({ key }) => {
break;
}
if (newDirection.clone().dot(direction) === 0) {
if (newDirection.dot(direction) === 0) {
nextDirection.copy(newDirection);
atlas.audio.type.play(0.35);
}