From 15206406f82af1ae8bcb9bf247c5c598d6146f14 Mon Sep 17 00:00:00 2001 From: A-Larsen Date: Wed, 14 Oct 2026 21:20:15 -0400 Subject: [PATCH] first commit --- index.js | 268 ++++++++++++++----------------------------------------- 1 file changed, 65 insertions(+), 203 deletions(-) diff --git a/index.js b/index.js index 17f2870..c1018fd 100644 --- a/index.js +++ b/index.js @@ -1,229 +1,91 @@ - -/* ===================== SETUP ===================== */ -const game = document.getElementById("game"); -game.width = 800; -game.height = 800; -const ctx = game.getContext("2d"); - -const BACKGROUND = "#101010"; -const FOREGROUND = "#50FF50"; -const TEXT = "#FFFFFF"; - -const FPS = 60; -const NEAR = 0.1; - -/* ===================== GEOMETRY ===================== */ -const vertices = [ - {x: 0.25, y: 0.25, z: 0.25}, - {x: -0.25, y: 0.25, z: 0.25}, - {x: -0.25, y: -0.25, z: 0.25}, - {x: 0.25, y: -0.25, z: 0.25}, - {x: 0.25, y: 0.25, z: -0.25}, - {x: -0.25, y: 0.25, z: -0.25}, - {x: -0.25, y: -0.25, z: -0.25}, - {x: 0.25, y: -0.25, z: -0.25}, -]; - -const edges = [ - [0,1,2,3], - [4,5,6,7], - [0,4],[1,5],[2,6],[3,7] -]; - -/* ===================== OBJECT ===================== */ -let objectPos = { x: 0, y: 0, z: 2 }; -let angle = 0; - -const AXIS_MODES = [ - ["x"], ["y"], ["z"], - ["x","y"], ["y","z"], ["x","z"], - ["x","y","z"] -]; -let axisModeIndex = AXIS_MODES.length - 1; -let activeAxes = AXIS_MODES[axisModeIndex]; - -/* ===================== CAMERA ===================== */ -let camera = { - position: { x: 0, y: 0, z: 0 }, - rotation: [1,0,0,0], - speed: 0.05, - sensitivity: 0.002 -}; - -/* ===================== INPUT ===================== */ -const keys = {}; -window.addEventListener("keydown", e => keys[e.key.toLowerCase()] = true); -window.addEventListener("keyup", e => keys[e.key.toLowerCase()] = false); - -/* ===================== QUATERNIONS ===================== */ -function quatFromAxisAngle(axis, angle) { - const h = angle / 2; - const s = Math.sin(h); - return [Math.cos(h), axis.x*s, axis.y*s, axis.z*s]; -} - -function quatMultiply(a, b) { - const [w1,x1,y1,z1] = a; - const [w2,x2,y2,z2] = b; - return [ - w1*w2 - x1*x2 - y1*y2 - z1*z2, - w1*x2 + x1*w2 + y1*z2 - z1*y2, - w1*y2 - x1*z2 + y1*w2 + z1*x2, - w1*z2 + x1*y2 - y1*x2 + z1*w2 - ]; +const canvas = document.getElementById("game"); +canvas.width = 800; +canvas.height = 800; +const ctx = canvas.getContext("2d"); + +let objects = { + cube: { + vertices: [ + // front + {x: -0.5 , y: -0.5, z: 0.5}, // top left + {x: 0.5 , y: -0.5, z: 0.5}, // top right + {x: 0.5 , y: 0.5, z: 0.5}, // bottom right + {x: -0.5 , y: 0.5, z: 0.5}, // bottom left + + // back + {x: -0.5 , y: -0.5, z: -0.5}, // top left + {x: 0.5 , y: -0.5, z: -0.5}, // top right + {x: 0.5 , y: 0.5, z: -0.5}, // bottom right + {x: -0.5 , y: 0.5, z: -0.5}, // bottom left + ], + index_buffers: [ + [0, 1, 2, 3], + [4, 5, 6, 7], + [0, 4], + [1, 5], + [2, 6], + [3, 7], + ] + } } -function quatConjugate(q) { - return [q[0], -q[1], -q[2], -q[3]]; +function project({x, y, z}) { + return { + x: x/z, + y: y/z + } } -function quatRotateVector(q, v) { - const qv = [0, v.x, v.y, v.z]; - const r = quatMultiply(quatMultiply(q, qv), quatConjugate(q)); - return { x: r[1], y: r[2], z: r[3] }; -} +function screen({x, y}) { + //-1..1 -> 0..2 -> 0..1 -> 0..w/h + // p.y *= -1 + return { + x: (x + 1)/2 * canvas.width, + y: (1 -(y + 1)/2) * canvas.height -/* ===================== CAMERA VECTORS ===================== */ -function cameraForward() { - return quatRotateVector(camera.rotation, {x:0,y:0,z:1}); -} -function cameraRight() { - return quatRotateVector(camera.rotation, {x:1,y:0,z:0}); -} -function cameraUp() { - return quatRotateVector(camera.rotation, {x:0,y:1,z:0}); + } } -function applyCamera(p) { - const v = { - x: p.x - camera.position.x, - y: p.y - camera.position.y, - z: p.z - camera.position.z - }; - return quatRotateVector(quatConjugate(camera.rotation), v); +function clear() { + ctx.fillStyle = "#000000" + ctx.fillRect(0, 0, canvas.width, canvas.height); } -/* ===================== PROJECTION ===================== */ -function project(p) { - return { x: p.x / p.z, y: p.y / p.z }; -} -function screen(p) { - return { - x: (p.x + 1) * 0.5 * game.width, - y: (1 - (p.y + 1) * 0.5) * game.height - }; +function translateZ({x, y, z}, dz) { + return {x: x, y: y, z: z + dz}; } -/* ===================== DRAW ===================== */ -function clear() { - ctx.fillStyle = BACKGROUND; - ctx.fillRect(0,0,game.width,game.height); - - ctx.fillStyle = TEXT; - ctx.font = "14px monospace"; - ctx.fillText("WASD: move | QE: up/down", 10, 18); - ctx.fillText("Mouse: look | Click canvas to lock", 10, 36); - ctx.fillText("Click canvas again: change cube axes", 10, 54); - ctx.fillText("Cube axes: " + activeAxes.join(","), 10, 72); -} - -function line(a,b) { - ctx.strokeStyle = FOREGROUND; - ctx.lineWidth = 2; +function line(p1, p2) { + ctx.lineWidth = 3; + ctx.strokeStyle = "#FF0000"; ctx.beginPath(); - ctx.moveTo(a.x,a.y); - ctx.lineTo(b.x,b.y); + ctx.moveTo(p1.x, p1.y); + ctx.lineTo(p2.x, p2.y); ctx.stroke(); } -/* ===================== LOOP ===================== */ -function frame() { - angle += Math.PI / FPS; - - // --- cube rotation quaternion --- - let q = [1,0,0,0]; - for (const ax of activeAxes) { - if (ax==="x") q = quatMultiply(quatFromAxisAngle({x:1,y:0,z:0}, angle), q); - if (ax==="y") q = quatMultiply(quatFromAxisAngle({x:0,y:1,z:0}, angle), q); - if (ax==="z") q = quatMultiply(quatFromAxisAngle({x:0,y:0,z:1}, angle), q); - } - - // --- camera movement --- - if (keys["w"]) { - const f = cameraForward(); - camera.position.x += f.x * camera.speed; - camera.position.y += f.y * camera.speed; - camera.position.z += f.z * camera.speed; - } - if (keys["s"]) { - const f = cameraForward(); - camera.position.x -= f.x * camera.speed; - camera.position.y -= f.y * camera.speed; - camera.position.z -= f.z * camera.speed; - } - if (keys["a"]) { - const r = cameraRight(); - camera.position.x -= r.x * camera.speed; - camera.position.y -= r.y * camera.speed; - camera.position.z -= r.z * camera.speed; - } - if (keys["d"]) { - const r = cameraRight(); - camera.position.x += r.x * camera.speed; - camera.position.y += r.y * camera.speed; - camera.position.z += r.z * camera.speed; - } - if (keys["q"]) { - const u = cameraUp(); - camera.position.x -= u.x * camera.speed; - camera.position.y -= u.y * camera.speed; - camera.position.z -= u.z * camera.speed; - } - if (keys["e"]) { - const u = cameraUp(); - camera.position.x += u.x * camera.speed; - camera.position.y += u.y * camera.speed; - camera.position.z += u.z * camera.speed; - } +function frame() { clear(); + let dz = 1.5 - for (const e of edges) { - for (let i=0;i { - game.requestPointerLock(); - axisModeIndex = (axisModeIndex + 1) % AXIS_MODES.length; - activeAxes = AXIS_MODES[axisModeIndex]; -}; - -window.addEventListener("mousemove", e => { - if (document.pointerLockElement !== game) return; - - const yaw = quatFromAxisAngle({x:0,y:1,z:0}, -e.movementX * camera.sensitivity); - const pitch = quatFromAxisAngle({x:1,y:0,z:0}, -e.movementY * camera.sensitivity); - camera.rotation = quatMultiply(yaw, camera.rotation); - camera.rotation = quatMultiply(camera.rotation, pitch); -}); +frame() -- 2.43.0