diff options
author | elioat <elioat@tilde.institute> | 2024-01-05 20:59:39 -0500 |
---|---|---|
committer | elioat <elioat@tilde.institute> | 2024-01-05 20:59:39 -0500 |
commit | 166a055a3df448839cc5564e20fc7e37205d875e (patch) | |
tree | 87e3f73809afe48557f3342547e6bbcb11993080 /js | |
parent | 92b42b5a86fcacdb479e54e99fe045d72f337ff9 (diff) | |
download | tour-166a055a3df448839cc5564e20fc7e37205d875e.tar.gz |
8
Diffstat (limited to 'js')
-rw-r--r-- | js/ship-game/game.js | 340 | ||||
-rw-r--r-- | js/ship-game/index.html | 1 |
2 files changed, 223 insertions, 118 deletions
diff --git a/js/ship-game/game.js b/js/ship-game/game.js index e50814c..072561f 100644 --- a/js/ship-game/game.js +++ b/js/ship-game/game.js @@ -1,147 +1,251 @@ -const canvas = document.getElementById('gameCanvas'); -const ctx = canvas.getContext('2d'); -canvas.style.display = "block"; -canvas.width = window.innerWidth - 100; -canvas.height = window.innerHeight - 200; +// this code is terrible. it currently doesn't run at a smooth rate, the rate at which it runs seems to be linked to the mouse moving around +(() => { + const canvas = document.getElementById('gameCanvas'); + const ctx = canvas.getContext('2d'); -let audio = new Audio('./zap.wav'); -audio.preload = 'auto'; + canvas.style.display = "block"; + canvas.width = window.innerWidth - 100; + canvas.height = window.innerHeight - 200; -let audioLoaded = false; + const audio = new Audio('./zap.wav'); + audio.preload = 'auto'; -audio.addEventListener('canplaythrough', function() { - audioLoaded = true; -}); + let audioLoaded = false; -audio.addEventListener('error', function() { - console.error('Error loading audio file'); -}); + const getRandomColor = () => { + const letters = '0123456789ABCDEF'; + return Array.from({ length: 6 }, () => letters[Math.floor(Math.random() * 16)]).join(''); + }; + + const createTargets = () => { + const numTargets = 5; + const minDistance = 100; + + const targets = Array.from({ length: numTargets }).reduce((acc) => { + let isRound = Math.random() < 0.5; + let sides = isRound ? 0 : Math.floor(Math.random() * 5) + 3; + let radius = Math.random() * 50 + 20; + let x, y, validPosition; -const createTargets = () => { - let targets = []; + do { + validPosition = true; + x = Math.random() * (canvas.width - 2 * radius - 120) + radius + 60; + y = Math.random() * (canvas.height - 2 * radius - 120) + radius + 60; - for(let i = 0; i < 10; i++) { - let radius = Math.random() * 50 + 20; - let x = Math.random() * (canvas.width - 2 * radius - 120) + radius + 60; - let y = Math.random() * (canvas.height - 2 * radius - 120) + radius + 60; - let vx = (Math.random() - 0.5) * 10; - let vy = (Math.random() - 0.5) * 10; + validPosition = !acc.some((otherTarget) => { + const dx = otherTarget.x - x; + const dy = otherTarget.y - y; + const distance = Math.sqrt(dx * dx + dy * dy); - targets.push({x, y, vx, vy, radius}); - } + return distance < minDistance; + }); + } while (!validPosition); - return targets; -} + let vx = (Math.random() - 0.5) * 5; + let vy = (Math.random() - 0.5) * 5; + let color = getRandomColor(); -let score = 0; -const drawScore = () => { - ctx.font = '20px Arial'; - ctx.fillStyle = 'white'; - ctx.fillText('Score: ' + score, 10, 30); -}; + while (color === canvas.style.backgroundColor) { + color = getRandomColor(); + } + acc.push({ x, y, vx, vy, radius, sides, color }); + return acc; + }, []); + + return targets; + }; -let showHelp = true; -const drawHelp = () => { - if(showHelp) { + const drawScore = () => { ctx.font = '20px Arial'; ctx.fillStyle = 'white'; - ctx.fillText('Click to shoot. Press R to respawn targets. Press H to toggle help text.', 10, 50); - } -} + ctx.fillText('Score: ' + score, 10, 30); + }; -const drawLine = (line) => { - if (line && Date.now() - line.time < 500) { - ctx.beginPath(); - ctx.moveTo(line.startX, line.startY); - ctx.lineTo(line.endX, line.endY); - ctx.strokeStyle = 'red'; - ctx.lineWidth = 4; - ctx.stroke(); - } -}; - -const drawTargets = (targets) => { - for (let target of targets) { - target.x += target.vx; - target.y += target.vy; - - if (target.x - target.radius < 0 || target.x + target.radius > canvas.width) { - target.vx = -target.vx; + const drawHelp = () => { + if (showHelp) { + ctx.font = '20px Arial'; + ctx.fillStyle = 'white'; + ctx.fillText('Click to shoot. Press R to respawn targets. Press H to toggle help text.', 10, 50); + } + }; + + const drawLine = (line) => { + if (line && Date.now() - line.time < 500) { + ctx.beginPath(); + ctx.moveTo(canvas.width, canvas.height); + ctx.lineTo(line.endX, line.endY); + ctx.strokeStyle = 'red'; + ctx.lineWidth = 4; + ctx.stroke(); } - if (target.y - target.radius < 0 || target.y + target.radius > canvas.height) { - target.vy = -target.vy; + }; + + const detectCollision = (target, otherTarget) => { + const dx = otherTarget.x - target.x; + const dy = otherTarget.y - target.y; + const distance = Math.sqrt(dx * dx + dy * dy); + + if (distance < target.radius + otherTarget.radius) { + const normalX = dx / distance; + const normalY = dy / distance; + const tangentX = -normalY; + const tangentY = normalX; + + const dotProductTarget = target.vx * normalX + target.vy * normalY; + const dotProductOtherTarget = otherTarget.vx * normalX + otherTarget.vy * normalY; + + const targetVxAfterCollision = dotProductOtherTarget * normalX + dotProductTarget * tangentX; + const targetVyAfterCollision = dotProductOtherTarget * normalY + dotProductTarget * tangentY; + const otherTargetVxAfterCollision = dotProductTarget * normalX + dotProductOtherTarget * tangentX; + const otherTargetVyAfterCollision = dotProductTarget * normalY + dotProductOtherTarget * tangentY; + + target.vx = targetVxAfterCollision; + target.vy = targetVyAfterCollision; + otherTarget.vx = otherTargetVxAfterCollision; + otherTarget.vy = otherTargetVyAfterCollision; } + }; + + const drawTargets = (targets) => { + targets.forEach((target, index) => { + target.x += target.vx; + target.y += target.vy; + + if (target.x - target.radius < 0 || target.x + target.radius > canvas.width) { + target.vx = -target.vx; + } + if (target.y - target.radius < 0 || target.y + target.radius > canvas.height) { + target.vy = -target.vy; + } + + targets.forEach((target, index) => { + const otherTargets = targets.slice(index + 1); + otherTargets.forEach((otherTarget) => { + detectCollision(target, otherTarget); + }); + }); + + ctx.beginPath(); + if (target.sides === 0) { + ctx.arc(target.x, target.y, target.radius, 0, 2 * Math.PI); + } else if (target.sides === 3) { + ctx.moveTo(target.x + target.radius * Math.cos(0), target.y + target.radius * Math.sin(0)); + for (let i = 1; i <= target.sides; i++) { + ctx.lineTo(target.x + target.radius * Math.cos(i * 2 * Math.PI / target.sides), target.y + target.radius * Math.sin(i * 2 * Math.PI / target.sides)); + } + } else if (target.sides === 4) { + ctx.rect(target.x - target.radius, target.y - target.radius, target.radius * 2, target.radius * 2); + } else { + ctx.moveTo(target.x + target.radius, target.y); + for (let i = 1; i <= target.sides; i++) { + ctx.lineTo(target.x + target.radius * Math.cos(i * 2 * Math.PI / target.sides), target.y + target.radius * Math.sin(i * 2 * Math.PI / target.sides)); + } + } + ctx.fillStyle = target.color; + ctx.fill(); + }); + }; + + let score = 0; + let showHelp = true; + let line = null; + let targets = createTargets(); + + let mousePos = { x: 0, y: 0 }; + let prevMousePos = { x: 0, y: 0 }; + + canvas.addEventListener('mousemove', (e) => { + const rect = canvas.getBoundingClientRect(); + prevMousePos.x = mousePos.x; + prevMousePos.y = mousePos.y; + mousePos.x = e.clientX - rect.left; + mousePos.y = e.clientY - rect.top; + }); + + const drawMouseCircle = () => { + if (mousePos.x !== prevMousePos.x || mousePos.y !== prevMousePos.y) { + ctx.clearRect(0, 0, canvas.width, canvas.height); + drawScore(); + drawHelp(); + drawLine(line); + drawTargets(targets); + } + + ctx.beginPath(); + ctx.arc(mousePos.x, mousePos.y, 10, 0, Math.PI * 2); + ctx.fillStyle = 'white'; + ctx.fill(); ctx.beginPath(); - ctx.arc(target.x, target.y, target.radius, 0, Math.PI * 2); - ctx.fillStyle = '#aaa'; + ctx.arc(mousePos.x, mousePos.y, 5, 0, Math.PI * 2); + ctx.fillStyle = 'black'; ctx.fill(); - } -}; + }; -const gameLoop = () => { - ctx.clearRect(0, 0, canvas.width, canvas.height); + const gameLoop = () => { + ctx.clearRect(0, 0, canvas.width, canvas.height); - drawScore(); - drawHelp(); - drawLine(line); - drawTargets(targets); + drawScore(); + drawHelp(); + drawLine(line); + drawTargets(targets); + drawMouseCircle(); - requestAnimationFrame(gameLoop); -}; + requestAnimationFrame(gameLoop); + }; -let line = null; + audio.addEventListener('canplaythrough', function () { + audioLoaded = true; + }); -canvas.addEventListener('click', (e) => { - const rect = canvas.getBoundingClientRect(); - const x = e.clientX - rect.left; - const y = e.clientY - rect.top; + audio.addEventListener('error', function () { + console.error('Error loading audio file'); + }); - if (audioLoaded) { - audio.play().catch((error) => { - console.error('Error playing audio:', error); + canvas.addEventListener('click', (e) => { + const rect = canvas.getBoundingClientRect(); + const x = e.clientX - rect.left; + const y = e.clientY - rect.top; + + if (audioLoaded) { + audio.play().catch((error) => { + console.error('Error playing audio:', error); + }); + } + + line = { + startX: 0, + startY: canvas.height, + endX: x, + endY: y, + time: Date.now() + }; + + targets = targets.filter((target) => { + const dx = target.x - x; + const dy = target.y - y; + if (dx * dx + dy * dy <= target.radius * target.radius) { + score++; + return false; + } + return true; }); - } - - line = { - startX: 0, - startY: canvas.height, - endX: x, - endY: y, - time: Date.now() - }; + }); - targets = targets.filter((target) => { - const dx = target.x - x; - const dy = target.y - y; - if (dx * dx + dy * dy <= target.radius * target.radius) { - score++; - return false; + window.addEventListener('resize', () => { + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + }); + + window.addEventListener('keydown', (e) => { + if (e.key === 'r' || e.key === 'R') { + targets = createTargets(); + } + if (e.key === 'h' || e.key === 'H') { + showHelp = !showHelp; } - return true; }); -}); - -window.addEventListener('resize', () => { - canvas.width = window.innerWidth; - canvas.height = window.innerHeight; -}); - -window.addEventListener('keydown', (e) => { - if (e.key === 'r' || e.key === 'R') { - targets = createTargets(); - } -}); - -window.addEventListener('keydown', (e) => { - if (e.key === 'h' || e.key === 'H') { - showHelp = !showHelp; - } else if (e.key === 'r' || e.key === 'R') { - targets = createTargets(); - } -}); - -let targets = createTargets(); - -gameLoop(); \ No newline at end of file + + gameLoop(); +})(); diff --git a/js/ship-game/index.html b/js/ship-game/index.html index 8c46ae7..4b8ada6 100644 --- a/js/ship-game/index.html +++ b/js/ship-game/index.html @@ -10,6 +10,7 @@ canvas { background-color: rgb(5, 10, 94); border: 1px solid black; + cursor: none; } body, canvas { padding: 1em; |