|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<meta charset="utf-8"> |
|
<title>A-Frame 3D Breakout Shooter Game (Enhanced Speed)</title> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/aframe/1.2.0/aframe.min.js"></script> |
|
<style> |
|
#hud { |
|
position: fixed; |
|
top: 10px; |
|
left: 10px; |
|
color: white; |
|
font-family: Arial, sans-serif; |
|
font-size: 16px; |
|
z-index: 999; |
|
} |
|
#instructions { |
|
position: fixed; |
|
bottom: 10px; |
|
left: 50%; |
|
transform: translateX(-50%); |
|
color: white; |
|
font-family: Arial, sans-serif; |
|
font-size: 14px; |
|
text-align: center; |
|
z-index: 999; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<div id="hud"> |
|
<div>Score: <span id="score">0</span></div> |
|
<div>Lives: <span id="lives">3</span></div> |
|
<div>Balls: <span id="ballCount">1</span></div> |
|
</div> |
|
<div id="instructions"> |
|
Move mouse to control paddle | Click to shoot | Press spacebar to launch new ball |
|
</div> |
|
|
|
<a-scene background="color: #87CEEB"> |
|
|
|
</a-scene> |
|
|
|
<script> |
|
|
|
|
|
const INITIAL_BALL_SPEED = 10; |
|
const MAX_BALL_SPEED = 25; |
|
const BULLET_SPEED = 30; |
|
|
|
function init() { |
|
|
|
} |
|
|
|
function createBlocks() { |
|
|
|
} |
|
|
|
function createBall() { |
|
const ball = document.createElement('a-sphere'); |
|
ball.setAttribute('class', 'ball collidable'); |
|
ball.setAttribute('radius', '0.2'); |
|
ball.setAttribute('material', 'color: #EF2D5E'); |
|
ball.setAttribute('position', {x: 0, y: -5, z: 0}); |
|
const angle = Math.random() * Math.PI / 2 - Math.PI / 4; |
|
ball.velocity = new THREE.Vector3( |
|
Math.sin(angle) * INITIAL_BALL_SPEED, |
|
Math.cos(angle) * INITIAL_BALL_SPEED, |
|
0 |
|
); |
|
ballsContainer.appendChild(ball); |
|
balls.push(ball); |
|
updateBallCount(); |
|
updatePaddleSize(); |
|
} |
|
|
|
function shootBullet() { |
|
const bullet = document.createElement('a-sphere'); |
|
bullet.setAttribute('class', 'bullet collidable'); |
|
bullet.setAttribute('radius', '0.1'); |
|
bullet.setAttribute('material', 'color: #FFFFFF'); |
|
const paddlePos = paddle.getAttribute('position'); |
|
bullet.setAttribute('position', {x: paddlePos.x, y: paddlePos.y + 0.5, z: 0}); |
|
bullet.velocity = new THREE.Vector3(0, BULLET_SPEED, 0); |
|
bulletsContainer.appendChild(bullet); |
|
bullets.push(bullet); |
|
} |
|
|
|
|
|
|
|
function update() { |
|
const currentTime = Date.now(); |
|
const deltaTime = (currentTime - lastUpdateTime) / 1000; |
|
lastUpdateTime = currentTime; |
|
|
|
balls.forEach((ball, ballIndex) => { |
|
const ballPos = ball.getAttribute('position'); |
|
ballPos.x += ball.velocity.x * deltaTime; |
|
ballPos.y += ball.velocity.y * deltaTime; |
|
|
|
|
|
if (ballPos.x <= -9.8 || ballPos.x >= 9.8) ball.velocity.x *= -1; |
|
if (ballPos.y >= 9.8) ball.velocity.y *= -1; |
|
|
|
|
|
const paddlePos = paddle.getAttribute('position'); |
|
const paddleWidth = paddle.getAttribute('geometry').width; |
|
if (ballPos.y <= paddlePos.y + 0.5 && ballPos.y >= paddlePos.y && |
|
ballPos.x >= paddlePos.x - paddleWidth/2 && ballPos.x <= paddlePos.x + paddleWidth/2) { |
|
|
|
|
|
ball.velocity.y = Math.abs(ball.velocity.y); |
|
ball.velocity.x += paddleVelocity.x * 0.5; |
|
const hitPosition = (ballPos.x - paddlePos.x) / (paddleWidth / 2); |
|
ball.velocity.x += hitPosition * 2; |
|
|
|
|
|
const speed = Math.sqrt(ball.velocity.x * ball.velocity.x + ball.velocity.y * ball.velocity.y); |
|
ball.velocity.x = (ball.velocity.x / speed) * INITIAL_BALL_SPEED; |
|
ball.velocity.y = (ball.velocity.y / speed) * INITIAL_BALL_SPEED; |
|
} |
|
|
|
|
|
const blocks = document.querySelectorAll('.block'); |
|
blocks.forEach(block => { |
|
const blockPos = block.getAttribute('position'); |
|
if (ballPos.x >= blockPos.x - 1 && ballPos.x <= blockPos.x + 1 && |
|
ballPos.y >= blockPos.y - 0.5 && ballPos.y <= blockPos.y + 0.5) { |
|
if (block.getAttribute('special') === 'true') { |
|
createBall(); |
|
} |
|
blocksContainer.removeChild(block); |
|
ball.velocity.y *= -1; |
|
updateScore(); |
|
} |
|
}); |
|
|
|
|
|
bullets.forEach((bullet, bulletIndex) => { |
|
const bulletPos = bullet.getAttribute('position'); |
|
const distance = new THREE.Vector3(bulletPos.x - ballPos.x, bulletPos.y - ballPos.y, 0).length(); |
|
if (distance < 0.3) { |
|
|
|
const bulletVelocity = bullet.velocity; |
|
ball.velocity.x = bulletVelocity.x; |
|
ball.velocity.y = bulletVelocity.y; |
|
|
|
|
|
bulletsContainer.removeChild(bullet); |
|
bullets.splice(bulletIndex, 1); |
|
} |
|
}); |
|
|
|
|
|
if (ballPos.y < -10) { |
|
ballsContainer.removeChild(ball); |
|
balls.splice(ballIndex, 1); |
|
updateBallCount(); |
|
updatePaddleSize(); |
|
if (balls.length === 0) { |
|
updateLives(); |
|
if (lives > 0) createBall(); |
|
} |
|
} else { |
|
ball.setAttribute('position', ballPos); |
|
} |
|
|
|
|
|
const speed = Math.sqrt(ball.velocity.x * ball.velocity.x + ball.velocity.y * ball.velocity.y); |
|
if (speed > MAX_BALL_SPEED) { |
|
ball.velocity.x = (ball.velocity.x / speed) * MAX_BALL_SPEED; |
|
ball.velocity.y = (ball.velocity.y / speed) * MAX_BALL_SPEED; |
|
} |
|
}); |
|
|
|
|
|
bullets.forEach((bullet, index) => { |
|
const bulletPos = bullet.getAttribute('position'); |
|
bulletPos.y += bullet.velocity.y * deltaTime; |
|
|
|
const blocks = document.querySelectorAll('.block'); |
|
blocks.forEach(block => { |
|
const blockPos = block.getAttribute('position'); |
|
if (bulletPos.x >= blockPos.x - 1 && bulletPos.x <= blockPos.x + 1 && |
|
bulletPos.y >= blockPos.y - 0.5 && bulletPos.y <= blockPos.y + 0.5) { |
|
if (block.getAttribute('special') === 'true') { |
|
createBall(); |
|
} |
|
blocksContainer.removeChild(block); |
|
bulletsContainer.removeChild(bullet); |
|
bullets.splice(index, 1); |
|
updateScore(); |
|
} |
|
}); |
|
|
|
if (bulletPos.y > 10) { |
|
bulletsContainer.removeChild(bullet); |
|
bullets.splice(index, 1); |
|
} else { |
|
bullet.setAttribute('position', bulletPos); |
|
} |
|
}); |
|
|
|
|
|
if (document.querySelectorAll('.block').length === 0) { |
|
clearInterval(paddleColorChangeInterval); |
|
alert('Congratulations! You won! Your score: ' + score); |
|
location.reload(); |
|
} |
|
|
|
requestAnimationFrame(update); |
|
} |
|
|
|
document.querySelector('a-scene').addEventListener('loaded', init); |
|
</script> |
|
</body> |
|
</html> |