diff options
Diffstat (limited to 'js/ship-game/game.js')
-rw-r--r-- | js/ship-game/game.js | 411 |
1 files changed, 176 insertions, 235 deletions
diff --git a/js/ship-game/game.js b/js/ship-game/game.js index 412288c..44a5df0 100644 --- a/js/ship-game/game.js +++ b/js/ship-game/game.js @@ -1,256 +1,197 @@ -(() => { - const canvas = document.getElementById('gameCanvas'); - const ctx = canvas.getContext('2d'); - - canvas.style.display = "block"; - canvas.width = window.innerWidth - 100; - canvas.height = window.innerHeight - 200; - - const audio = new Audio('./zap.wav'); - audio.preload = 'auto'; - - let audioLoaded = false; - - 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; - - do { - validPosition = true; - x = Math.random() * (canvas.width - 2 * radius - 120) + radius + 60; - y = Math.random() * (canvas.height - 2 * radius - 120) + radius + 60; - - validPosition = !acc.some((otherTarget) => { - const dx = otherTarget.x - x; - const dy = otherTarget.y - y; - const distance = Math.sqrt(dx * dx + dy * dy); - - return distance < minDistance; - }); - } while (!validPosition); - - let vx = (Math.random() - 0.5) * 5; - let vy = (Math.random() - 0.5) * 5; - let color = getRandomColor(); - - while (color === canvas.style.backgroundColor) { - color = getRandomColor(); - } - - acc.push({ x, y, vx, vy, radius, sides, color }); - return acc; - }, []); - - return targets; - }; - - const drawScore = () => { +const canvas = document.getElementById('gameCanvas'); +const ctx = canvas.getContext('2d'); +canvas.style.display = "block"; +canvas.width = window.innerWidth; +canvas.height = window.innerHeight; + +let audio = new Audio('./zap.wav'); +audio.preload = 'auto'; + +let audioLoaded = false; + +audio.addEventListener('canplaythrough', function() { + audioLoaded = true; +}); + +audio.addEventListener('error', function() { + console.error('Error loading audio file'); +}); + +const createTargets = () => { + let targets = []; + + for(let i = 0; i < 10; i++) { + let shape = getRandomShape(); + 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; + + targets.push({x, y, vx, vy, radius, shape}); + } + + return targets; +} + +const getRandomShape = () => { + const shapes = ['circle', 'pentagon', 'triangle', 'square']; + const randomIndex = Math.floor(Math.random() * shapes.length); + return shapes[randomIndex]; +} + +let score = 0; +const drawScore = () => { + ctx.font = '20px Arial'; + ctx.fillStyle = 'white'; + ctx.fillText('Score: ' + score, 10, 30); +}; + +let level = 1; +const drawLevel = () => { + ctx.font = '20px Arial'; + ctx.fillStyle = 'white'; + ctx.fillText('Level: ' + level, 10, 60); +} + + +let showHelp = false; +const drawHelp = () => { + if(showHelp) { ctx.font = '20px Arial'; ctx.fillStyle = 'white'; - ctx.fillText('Score: ' + score, 10, 30); - }; - - 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); - } - }; + 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 = 5; - ctx.shadowColor = 'rgba(255, 255, 0, 0.75)'; - ctx.shadowBlur = 50; - ctx.shadowOffsetX = 0; - ctx.shadowOffsetY = 0; - ctx.stroke(); - ctx.shadowColor = 'transparent'; - ctx.shadowBlur = 0; +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 colors = ['#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#FF00FF', '#00FFFF']; + +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 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; + if (target.y - target.radius < 0 || target.y + target.radius > canvas.height) { + target.vy = -target.vy; } - }; - 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; + ctx.beginPath(); + if (target.shape === 'circle') { + ctx.arc(target.x, target.y, target.radius, 0, Math.PI * 2); + } else if (target.shape === 'pentagon') { + ctx.moveTo(target.x + target.radius * Math.cos(0), target.y + target.radius * Math.sin(0)); + for (let i = 1; i <= 5; i++) { + ctx.lineTo(target.x + target.radius * Math.cos(i * (Math.PI * 2) / 5), target.y + target.radius * Math.sin(i * (Math.PI * 2) / 5)); } - if (target.y - target.radius < 0 || target.y + target.radius > canvas.height) { - target.vy = -target.vy; + } else if (target.shape === 'triangle') { + ctx.moveTo(target.x + target.radius * Math.cos(0), target.y + target.radius * Math.sin(0)); + for (let i = 1; i <= 3; i++) { + ctx.lineTo(target.x + target.radius * Math.cos(i * (Math.PI * 2) / 3), target.y + target.radius * Math.sin(i * (Math.PI * 2) / 3)); } - - 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); + } else if (target.shape === 'square') { + ctx.rect(target.x - target.radius, target.y - target.radius, target.radius * 2, target.radius * 2); } - - ctx.beginPath(); - ctx.arc(mousePos.x, mousePos.y, 10, 0, Math.PI * 2); - ctx.fillStyle = 'white'; + + const randomColor = colors[Math.floor(Math.random() * colors.length)]; + ctx.fillStyle = randomColor; ctx.fill(); + } +}; - ctx.beginPath(); - 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(); + drawLevel(); + drawHelp(); + drawLine(line); + drawTargets(targets); - drawScore(); - drawHelp(); - drawLine(line); - drawTargets(targets); - drawMouseCircle(); + requestAnimationFrame(gameLoop); - requestAnimationFrame(gameLoop); - }; - - audio.addEventListener('canplaythrough', function () { - audioLoaded = true; - }); + if (targets.length === 0) { + level++; + targets = createTargets(); + } +}; - audio.addEventListener('error', function () { - console.error('Error loading audio file'); - }); +let line = null; - canvas.addEventListener('click', (e) => { - const rect = canvas.getBoundingClientRect(); - const x = e.clientX - rect.left; - const y = e.clientY - rect.top; +const handleInteraction = (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; + if (audioLoaded) { + audio.play().catch((error) => { + console.error('Error playing audio:', error); }); - }); - - window.addEventListener('resize', () => { - canvas.width = window.innerWidth; - canvas.height = window.innerHeight; - }); + } + + line = { + startX: 0, + startY: canvas.height, + endX: x, + endY: y, + time: Date.now() + }; - window.addEventListener('keydown', (e) => { - if (e.key === 'r' || e.key === 'R') { - targets = createTargets(); - } - if (e.key === 'h' || e.key === 'H') { - showHelp = !showHelp; + 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; }); - - gameLoop(); -})(); +}; + +canvas.addEventListener('click', handleInteraction); +canvas.addEventListener('touchstart', function(e) { + // Prevent the window from scrolling + e.preventDefault(); + + // A touch event can have multiple touches so we just get the first one + e.clientX = e.touches[0].clientX; + e.clientY = e.touches[0].clientY; + + handleInteraction(e); +}, { passive: 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(); + } +}); + +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 |