270 lines
8.6 KiB
HTML
270 lines
8.6 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Wireframe Flight Background</title>
|
|
<style>
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
overflow: hidden;
|
|
background: #000;
|
|
color: #ff0000;
|
|
font-family: monospace;
|
|
}
|
|
|
|
canvas {
|
|
display: block;
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
}
|
|
|
|
#log {
|
|
position: fixed;
|
|
top: 10px;
|
|
left: 10px;
|
|
z-index: 100;
|
|
font-size: 12px;
|
|
max-width: 90%;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<canvas id="bgCanvas"></canvas>
|
|
<div id="log"></div>
|
|
<script>
|
|
const log = document.getElementById('log');
|
|
function addLog(msg) {
|
|
const div = document.createElement('div');
|
|
div.textContent = msg;
|
|
log.appendChild(div);
|
|
}
|
|
|
|
window.addEventListener('error', function(e) {
|
|
addLog('ERROR: ' + e.message + ' at line ' + e.lineno);
|
|
});
|
|
|
|
addLog('Script start');
|
|
|
|
const canvas = document.getElementById('bgCanvas');
|
|
const ctx = canvas.getContext('2d');
|
|
|
|
let width, height;
|
|
|
|
function resize() {
|
|
width = canvas.width = window.innerWidth;
|
|
height = canvas.height = window.innerHeight;
|
|
}
|
|
|
|
window.addEventListener('resize', resize);
|
|
resize();
|
|
|
|
const camera = { fov: 800 };
|
|
|
|
class Point3D {
|
|
constructor(x, y, z) {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.z = z;
|
|
}
|
|
|
|
project() {
|
|
const scale = camera.fov / (camera.fov + this.z);
|
|
const xIso = this.x - this.z;
|
|
const yIso = (this.x + this.z) * 0.5 - this.y;
|
|
const x2d = xIso * scale + width / 2;
|
|
const y2d = yIso * scale + height / 2;
|
|
return { x: x2d, y: y2d };
|
|
}
|
|
}
|
|
|
|
class Landscape {
|
|
constructor() {
|
|
this.gridSize = 120;
|
|
this.gridRange = 20;
|
|
this.offsetX = 0;
|
|
this.offsetZ = 0;
|
|
this.triangles = [];
|
|
this.waterLevel = 20;
|
|
}
|
|
|
|
generateHeight(x, z) {
|
|
const nx = x / 300;
|
|
const nz = z / 300;
|
|
let y = 0;
|
|
y += Math.sin(nx * 0.7) * 60;
|
|
y += Math.cos(nz * 0.7) * 60;
|
|
y += Math.sin(nx * 1.5 + nz * 0.3) * 30;
|
|
y += Math.cos(nz * 1.5 - nx * 0.4) * 25;
|
|
return y;
|
|
}
|
|
|
|
isWater(y) {
|
|
return y < this.waterLevel;
|
|
}
|
|
|
|
update() {
|
|
this.offsetX -= 1.5;
|
|
this.offsetZ -= 0.7;
|
|
this.generateTriangles();
|
|
}
|
|
|
|
getPoint(x, z) {
|
|
const worldX = x * this.gridSize + this.offsetX;
|
|
const worldZ = z * this.gridSize + this.offsetZ;
|
|
const y = this.generateHeight(worldX, worldZ);
|
|
return new Point3D(worldX, y, worldZ);
|
|
}
|
|
|
|
generateTriangles() {
|
|
this.triangles = [];
|
|
for (let x = -this.gridRange; x <= this.gridRange; x++) {
|
|
for (let z = -this.gridRange; z <= this.gridRange; z++) {
|
|
const p1 = this.getPoint(x, z);
|
|
const p2 = this.getPoint(x + 1, z);
|
|
const p3 = this.getPoint(x + 1, z + 1);
|
|
const p4 = this.getPoint(x, z + 1);
|
|
|
|
const w1 = this.isWater(p1.y);
|
|
const w2 = this.isWater(p2.y);
|
|
const w3 = this.isWater(p3.y);
|
|
const w4 = this.isWater(p4.y);
|
|
|
|
this.triangles.push({ p1, p2, p3, isWater: w1 || w2 || w3, depth: (p1.z + p2.z + p3.z) / 3 });
|
|
this.triangles.push({ p1, p3, p4, isWater: w1 || w3 || w4, depth: (p1.z + p3.z + p4.z) / 3 });
|
|
}
|
|
}
|
|
}
|
|
|
|
draw() {
|
|
this.triangles.sort((a, b) => b.depth - a.depth);
|
|
this.triangles.forEach(tri => {
|
|
const proj1 = tri.p1.project();
|
|
const proj2 = tri.p2.project();
|
|
const proj3 = tri.p3.project();
|
|
|
|
const v1 = { x: tri.p2.x - tri.p1.x, y: tri.p2.y - tri.p1.y, z: tri.p2.z - tri.p1.z };
|
|
const v2 = { x: tri.p3.x - tri.p1.x, y: tri.p3.y - tri.p1.y, z: tri.p3.z - tri.p1.z };
|
|
const crossZ = v1.x * v2.y - v1.y * v2.x;
|
|
if (crossZ >= 0) return;
|
|
|
|
const baseColor = tri.isWater ? 'rgba(0, 150, 220, 0.7)' : 'rgba(0, 200, 0, 0.7)';
|
|
ctx.fillStyle = baseColor;
|
|
ctx.beginPath();
|
|
ctx.moveTo(proj1.x, proj1.y);
|
|
ctx.lineTo(proj2.x, proj2.y);
|
|
ctx.lineTo(proj3.x, proj3.y);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
|
|
ctx.strokeStyle = tri.isWater ? '#00ccff' : '#00ff66';
|
|
ctx.lineWidth = 1;
|
|
ctx.stroke();
|
|
});
|
|
}
|
|
}
|
|
|
|
class Airplane {
|
|
constructor() {
|
|
this.vertices = [];
|
|
this.init();
|
|
}
|
|
|
|
init() {
|
|
const segments = 8;
|
|
const fuselageLength = 80;
|
|
const fuselageRadius = 8;
|
|
|
|
for (let i = 0; i < segments; i++) {
|
|
const angle = (i / segments) * Math.PI * 2;
|
|
this.vertices.push(new Point3D(
|
|
Math.cos(angle) * fuselageRadius,
|
|
Math.sin(angle) * fuselageRadius,
|
|
0
|
|
));
|
|
}
|
|
|
|
for (let i = 0; i < segments; i++) {
|
|
const angle = (i / segments) * Math.PI * 2;
|
|
this.vertices.push(new Point3D(
|
|
Math.cos(angle) * fuselageRadius,
|
|
Math.sin(angle) * fuselageRadius,
|
|
fuselageLength
|
|
));
|
|
}
|
|
|
|
const wingSpan = 100;
|
|
const wingY = -2;
|
|
this.vertices.push(new Point3D(-wingSpan / 2, wingY, 10));
|
|
this.vertices.push(new Point3D(-wingSpan / 2 + 5, wingY, 35));
|
|
this.vertices.push(new Point3D(wingSpan / 2 - 5, wingY, 35));
|
|
this.vertices.push(new Point3D(wingSpan / 2, wingY, 10));
|
|
}
|
|
|
|
update() {
|
|
this.yaw = Math.sin(Date.now() / 1000) * 0.15;
|
|
this.roll = Math.sin(Date.now() / 600) * 0.2;
|
|
this.pitch = Math.cos(Date.now() / 800) * 0.15;
|
|
}
|
|
|
|
render() {
|
|
ctx.strokeStyle = '#ff0000';
|
|
ctx.lineWidth = 2;
|
|
ctx.shadowBlur = 15;
|
|
ctx.shadowColor = '#ff0000';
|
|
|
|
this.vertices.forEach(v => {
|
|
const proj = v.project();
|
|
ctx.beginPath();
|
|
ctx.arc(proj.x, proj.y, 3, 0, Math.PI * 2);
|
|
ctx.fillStyle = '#ff0000';
|
|
ctx.fill();
|
|
});
|
|
|
|
for (let i = 0; i < this.vertices.length - 1; i++) {
|
|
if (i === 7) continue;
|
|
const p1 = this.vertices[i].project();
|
|
const p2 = this.vertices[i + 1].project();
|
|
ctx.beginPath();
|
|
ctx.moveTo(p1.x, p1.y);
|
|
ctx.lineTo(p2.x, p2.y);
|
|
ctx.stroke();
|
|
}
|
|
|
|
ctx.shadowBlur = 0;
|
|
}
|
|
}
|
|
|
|
try {
|
|
const landscape = new Landscape();
|
|
const airplane = new Airplane();
|
|
addLog('Objects created');
|
|
|
|
function animate() {
|
|
ctx.fillStyle = '#000';
|
|
ctx.fillRect(0, 0, width, height);
|
|
|
|
landscape.update();
|
|
landscape.draw();
|
|
|
|
airplane.update();
|
|
airplane.render();
|
|
|
|
requestAnimationFrame(animate);
|
|
}
|
|
|
|
animate();
|
|
addLog('Animation started');
|
|
} catch (e) {
|
|
addLog('CATCH: ' + e.message);
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|