This commit is contained in:
2026-05-16 11:35:29 +01:00
parent 222bd6fe97
commit 7cdc7c1426
2 changed files with 164 additions and 103 deletions
+76 -56
View File
@@ -192,6 +192,81 @@ const LEAF_COLORS = ['', '#ed5145', '#fdb068', '#fee5cd'];
export const TRUNK_TOP_CSS = (H - 150) + 10;
let cachedTreeCanvas: HTMLCanvasElement | null = null;
function renderTreeCanvas() {
if (cachedTreeCanvas) return cachedTreeCanvas;
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d")!;
canvas.width = W * PX;
canvas.height = H * PX;
ctx.clearRect(0, 0, canvas.width, canvas.height);
const { woodGrid, leafGrid } = buildTree(55);
for (let y = 0; y < H; y++)
for (let x = 0; x < W; x++) {
const v = woodGrid[y * W + x];
if (v) {
ctx.fillStyle = WOOD_COLORS[v] ?? '#321901';
ctx.fillRect(x * PX, y * PX, PX, PX);
}
}
for (let y = 0; y < H; y++)
for (let x = 0; x < W; x++) {
const v = leafGrid[y * W + x];
if (v) {
ctx.fillStyle = LEAF_COLORS[v];
ctx.fillRect(x * PX, y * PX, PX, PX);
}
}
const GROUND_Y = H - 50;
const groundColors = ['#fee5cd', '#fdca9b', '#fdb068'];
const grassColors = ['#ed5145', '#fb7b04', '#c96303', '#f17c74'];
let gs = 12345;
function grassRand() {
gs = (gs * 16807 + 0) % 2147483647;
return (gs & 0x7fffffff) / 0x7fffffff;
}
for (let x = 0; x < W; x++) {
const wave = Math.sin(x * 0.05) * 3 + Math.sin(x * 0.12) * 2;
const groundTop = Math.round(GROUND_Y + wave);
for (let y = groundTop; y < H; y++) {
const depth = (y - groundTop) / (H - groundTop);
const ci = depth < 0.3 ? 0 : depth < 0.7 ? 1 : 2;
ctx.fillStyle = groundColors[ci];
ctx.fillRect(x * PX, y * PX, PX, PX);
}
}
for (let x = 0; x < W; x++) {
if (grassRand() > 0.35) continue;
const wave = Math.sin(x * 0.05) * 3 + Math.sin(x * 0.12) * 2;
const surfaceY = Math.round(GROUND_Y + wave);
const bladeH = Math.floor(grassRand() * 4) + 2;
const color = grassColors[Math.floor(grassRand() * grassColors.length)];
ctx.fillStyle = color;
for (let b = 0; b < bladeH; b++) {
ctx.fillRect(x * PX, (surfaceY - b - 1) * PX, PX, PX);
}
if (grassRand() > 0.6 && x + 1 < W) {
ctx.fillRect((x + 1) * PX, (surfaceY - 1) * PX, PX, PX);
}
}
cachedTreeCanvas = canvas;
return canvas;
}
export function prewarmTreeCanvas() {
renderTreeCanvas();
}
const Tree = forwardRef<HTMLCanvasElement>(function Tree(_, ref) {
const internalRef = useRef<HTMLCanvasElement>(null);
const canvasRef = (ref as React.RefObject<HTMLCanvasElement>) ?? internalRef;
@@ -202,62 +277,7 @@ const Tree = forwardRef<HTMLCanvasElement>(function Tree(_, ref) {
canvas.width = W * PX;
canvas.height = H * PX;
ctx.clearRect(0, 0, canvas.width, canvas.height);
const { woodGrid, leafGrid } = buildTree(55);
for (let y = 0; y < H; y++)
for (let x = 0; x < W; x++) {
const v = woodGrid[y * W + x];
if (v) {
ctx.fillStyle = WOOD_COLORS[v] ?? '#321901';
ctx.fillRect(x * PX, y * PX, PX, PX);
}
}
for (let y = 0; y < H; y++)
for (let x = 0; x < W; x++) {
const v = leafGrid[y * W + x];
if (v) {
ctx.fillStyle = LEAF_COLORS[v];
ctx.fillRect(x * PX, y * PX, PX, PX);
}
}
const GROUND_Y = H - 50;
const groundColors = ['#fee5cd', '#fdca9b', '#fdb068'];
const grassColors = ['#ed5145', '#fb7b04', '#c96303', '#f17c74'];
let gs = 12345;
function grassRand() {
gs = (gs * 16807 + 0) % 2147483647;
return (gs & 0x7fffffff) / 0x7fffffff;
}
for (let x = 0; x < W; x++) {
const wave = Math.sin(x * 0.05) * 3 + Math.sin(x * 0.12) * 2;
const groundTop = Math.round(GROUND_Y + wave);
for (let y = groundTop; y < H; y++) {
const depth = (y - groundTop) / (H - groundTop);
const ci = depth < 0.3 ? 0 : depth < 0.7 ? 1 : 2;
ctx.fillStyle = groundColors[ci];
ctx.fillRect(x * PX, y * PX, PX, PX);
}
}
for (let x = 0; x < W; x++) {
if (grassRand() > 0.35) continue;
const wave = Math.sin(x * 0.05) * 3 + Math.sin(x * 0.12) * 2;
const surfaceY = Math.round(GROUND_Y + wave);
const bladeH = Math.floor(grassRand() * 4) + 2;
const color = grassColors[Math.floor(grassRand() * grassColors.length)];
ctx.fillStyle = color;
for (let b = 0; b < bladeH; b++) {
ctx.fillRect(x * PX, (surfaceY - b - 1) * PX, PX, PX);
}
if (grassRand() > 0.6 && x + 1 < W) {
ctx.fillRect((x + 1) * PX, (surfaceY - 1) * PX, PX, PX);
}
}
ctx.drawImage(renderTreeCanvas(), 0, 0);
}, []);
return (