Files
Hoya26/frontend/src/lib/ts/parallax/scenes/forest.ts
2026-01-24 21:30:08 +00:00

169 lines
5.9 KiB
TypeScript

import type { DrawContext } from '../types';
import { getSceneColors } from '../colors';
export function drawForestTrees(dc: DrawContext): void {
const { ctx, width, height, state } = dc;
const colors = getSceneColors(state);
const parallax = state.mouseX * 0.8 + state.scrollY * 0.5;
const drawPineTree = (x: number, y: number, scale: number, dark: boolean) => {
ctx.fillStyle = dark ? '#3E2723' : '#5D4037';
ctx.fillRect(x - 6 * scale + parallax, y, 12 * scale, 35 * scale);
const foliageColor = dark ? colors.treeDark : colors.treeLight;
ctx.fillStyle = foliageColor;
for (let layer = 0; layer < 4; layer++) {
const layerY = y + 5 * scale - layer * 22 * scale;
const layerWidth = (35 - layer * 5) * scale;
ctx.beginPath();
ctx.moveTo(x + parallax, layerY - 25 * scale);
ctx.lineTo(x - layerWidth + parallax, layerY);
ctx.lineTo(x + layerWidth + parallax, layerY);
ctx.closePath();
ctx.fill();
}
};
const treePositions = [
{ x: width * 0.05, y: height * 0.68, scale: 0.7, dark: true },
{ x: width * 0.15, y: height * 0.66, scale: 0.8, dark: true },
{ x: width * 0.28, y: height * 0.67, scale: 0.6, dark: true },
{ x: width * 0.42, y: height * 0.65, scale: 0.75, dark: true },
{ x: width * 0.58, y: height * 0.68, scale: 0.65, dark: true },
{ x: width * 0.72, y: height * 0.66, scale: 0.7, dark: true },
{ x: width * 0.88, y: height * 0.67, scale: 0.8, dark: true },
{ x: width * 0.95, y: height * 0.68, scale: 0.6, dark: true },
{ x: width * 0.08, y: height * 0.76, scale: 1.4, dark: false },
{ x: width * 0.22, y: height * 0.78, scale: 1.2, dark: false },
{ x: width * 0.38, y: height * 0.74, scale: 1.6, dark: false },
{ x: width * 0.52, y: height * 0.77, scale: 1.3, dark: false },
{ x: width * 0.68, y: height * 0.75, scale: 1.5, dark: false },
{ x: width * 0.82, y: height * 0.78, scale: 1.1, dark: false },
{ x: width * 0.94, y: height * 0.76, scale: 1.4, dark: false },
];
treePositions.forEach((t) => drawPineTree(t.x, t.y, t.scale, t.dark));
}
export function drawMushrooms(dc: DrawContext): void {
const { ctx, width, height, state } = dc;
const parallax = state.mouseX * 0.9 + state.scrollY * 0.6;
const drawMushroom = (x: number, y: number, scale: number, isRed: boolean) => {
ctx.fillStyle = '#F5F5DC';
ctx.beginPath();
ctx.ellipse(x + parallax, y + 8 * scale, 6 * scale, 10 * scale, 0, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = isRed ? '#D32F2F' : '#8D6E63';
ctx.beginPath();
ctx.ellipse(x + parallax, y - 2 * scale, 12 * scale, 8 * scale, 0, Math.PI, Math.PI * 2);
ctx.fill();
if (isRed) {
ctx.fillStyle = '#FFFFFF';
ctx.beginPath();
ctx.arc(x + parallax - 4, y - 4 * scale, 2 * scale, 0, Math.PI * 2);
ctx.arc(x + parallax + 5, y - 3 * scale, 1.5 * scale, 0, Math.PI * 2);
ctx.fill();
}
};
drawMushroom(width * 0.15, height * 0.84, 1.0, true);
drawMushroom(width * 0.35, height * 0.86, 0.8, false);
drawMushroom(width * 0.52, height * 0.83, 1.2, true);
drawMushroom(width * 0.78, height * 0.85, 0.9, false);
drawMushroom(width * 0.88, height * 0.84, 1.1, true);
}
export function drawDeer(dc: DrawContext): void {
const { ctx, width, height, state } = dc;
const time = Date.now() * 0.001;
const parallax = state.mouseX * 0.5;
const x = width * 0.6 + parallax;
const y = height * 0.72;
const headBob = Math.sin(time * 2) * 3;
ctx.fillStyle = '#8D6E63';
ctx.beginPath();
ctx.ellipse(x, y, 35, 25, 0, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#6D4C41';
ctx.fillRect(x - 20, y + 15, 8, 30);
ctx.fillRect(x - 5, y + 18, 8, 28);
ctx.fillRect(x + 10, y + 15, 8, 30);
ctx.fillRect(x + 25, y + 18, 8, 28);
ctx.fillStyle = '#8D6E63';
ctx.beginPath();
ctx.ellipse(x + 40, y - 15 + headBob, 12, 18, 0.3, 0, Math.PI * 2);
ctx.fill();
ctx.beginPath();
ctx.ellipse(x + 55, y - 25 + headBob, 10, 12, 0.2, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = '#5D4037';
ctx.lineWidth = 3;
ctx.lineCap = 'round';
ctx.beginPath();
ctx.moveTo(x + 50, y - 35 + headBob);
ctx.lineTo(x + 45, y - 50 + headBob);
ctx.lineTo(x + 40, y - 45 + headBob);
ctx.moveTo(x + 45, y - 50 + headBob);
ctx.lineTo(x + 50, y - 55 + headBob);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(x + 60, y - 35 + headBob);
ctx.lineTo(x + 65, y - 50 + headBob);
ctx.lineTo(x + 70, y - 45 + headBob);
ctx.moveTo(x + 65, y - 50 + headBob);
ctx.lineTo(x + 60, y - 55 + headBob);
ctx.stroke();
ctx.fillStyle = '#1a1a1a';
ctx.beginPath();
ctx.arc(x + 60, y - 25 + headBob, 3, 0, Math.PI * 2);
ctx.fill();
}
export function drawLightRays(dc: DrawContext): void {
const { ctx, width, height, state } = dc;
const time = Date.now() * 0.0005;
ctx.save();
ctx.globalAlpha = 0.15 + Math.sin(time) * 0.05;
const gradient = ctx.createLinearGradient(width * 0.7, 0, width * 0.5, height * 0.7);
gradient.addColorStop(0, 'rgba(255, 255, 200, 0.8)');
gradient.addColorStop(1, 'rgba(255, 255, 200, 0)');
ctx.fillStyle = gradient;
ctx.beginPath();
ctx.moveTo(width * 0.75, 0);
ctx.lineTo(width * 0.85, 0);
ctx.lineTo(width * 0.55, height * 0.7);
ctx.lineTo(width * 0.45, height * 0.7);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.moveTo(width * 0.55, 0);
ctx.lineTo(width * 0.62, 0);
ctx.lineTo(width * 0.35, height * 0.65);
ctx.lineTo(width * 0.28, height * 0.65);
ctx.closePath();
ctx.fill();
ctx.restore();
}
export function drawForestScene(dc: DrawContext): void {
drawLightRays(dc);
drawForestTrees(dc);
drawMushrooms(dc);
drawDeer(dc);
}