|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<title>Tank Battle</title> |
|
<style> |
|
body { |
|
margin: 0; |
|
overflow: hidden; |
|
background: #333; |
|
font-family: Arial; |
|
} |
|
#gameCanvas { |
|
background-repeat: repeat; |
|
} |
|
#instructions { |
|
position: fixed; |
|
top: 10px; |
|
right: 10px; |
|
color: white; |
|
background: rgba(0,0,0,0.7); |
|
padding: 10px; |
|
border-radius: 5px; |
|
z-index: 1000; |
|
} |
|
#weaponInfo { |
|
position: fixed; |
|
top: 150px; |
|
right: 10px; |
|
color: white; |
|
background: rgba(0,0,0,0.7); |
|
padding: 10px; |
|
border-radius: 5px; |
|
z-index: 1000; |
|
font-size: 18px; |
|
} |
|
.button { |
|
position: fixed; |
|
top: 50%; |
|
left: 50%; |
|
transform: translate(-50%, -50%); |
|
padding: 20px 40px; |
|
font-size: 24px; |
|
background: #4CAF50; |
|
color: white; |
|
border: none; |
|
border-radius: 5px; |
|
cursor: pointer; |
|
display: none; |
|
z-index: 1000; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<div id="instructions"> |
|
Controls:<br> |
|
WASD - Move tank<br> |
|
Mouse - Aim<br> |
|
Space - Fire<br> |
|
C - Switch Weapon |
|
</div> |
|
<div id="weaponInfo">Current Weapon: Cannon</div> |
|
<button id="nextRound" class="button">Next Round</button> |
|
<button id="restart" class="button">Restart Game</button> |
|
<canvas id="gameCanvas"></canvas> |
|
|
|
<script> |
|
const canvas = document.getElementById('gameCanvas'); |
|
const ctx = canvas.getContext('2d'); |
|
const nextRoundBtn = document.getElementById('nextRound'); |
|
const restartBtn = document.getElementById('restart'); |
|
const weaponInfo = document.getElementById('weaponInfo'); |
|
|
|
canvas.width = window.innerWidth; |
|
canvas.height = window.innerHeight; |
|
|
|
|
|
const backgroundImg = new Image(); |
|
backgroundImg.src = 'city.png'; |
|
|
|
const playerImg = new Image(); |
|
playerImg.src = 'player.png'; |
|
|
|
const enemyImg = new Image(); |
|
enemyImg.src = 'enemy.png'; |
|
|
|
|
|
const cannonSound = new Audio('firemn.ogg'); |
|
const machinegunSound = new Audio('firemg.ogg'); |
|
const enemyFireSound = new Audio('firemg.ogg'); |
|
|
|
|
|
let currentRound = 1; |
|
let gameOver = false; |
|
let currentWeapon = 'cannon'; |
|
let enemies = []; |
|
let bullets = []; |
|
let items = []; |
|
let lastShot = 0; |
|
|
|
const weapons = { |
|
cannon: { |
|
fireRate: 1000, |
|
damage: 0.25, |
|
bulletSize: 5, |
|
sound: cannonSound |
|
}, |
|
machinegun: { |
|
fireRate: 200, |
|
damage: 0.05, |
|
bulletSize: 2, |
|
sound: machinegunSound |
|
} |
|
}; |
|
|
|
|
|
const player = { |
|
x: canvas.width/2, |
|
y: canvas.height/2, |
|
speed: 5, |
|
angle: 0, |
|
width: 100, |
|
height: 45, |
|
health: 1000, |
|
maxHealth: 1000 |
|
}; |
|
|
|
class Enemy { |
|
constructor() { |
|
this.x = Math.random() * canvas.width; |
|
this.y = Math.random() * canvas.height; |
|
this.health = 1000; |
|
this.maxHealth = 1000; |
|
this.speed = 2; |
|
this.lastShot = 0; |
|
this.shootInterval = 333; |
|
this.angle = 0; |
|
this.moveAngle = Math.random() * Math.PI * 2; |
|
this.width = 100; |
|
this.height = 45; |
|
} |
|
|
|
update() { |
|
this.x += Math.cos(this.moveAngle) * this.speed; |
|
this.y += Math.sin(this.moveAngle) * this.speed; |
|
|
|
if(this.x < 0 || this.x > canvas.width) this.moveAngle = Math.PI - this.moveAngle; |
|
if(this.y < 0 || this.y > canvas.height) this.moveAngle = -this.moveAngle; |
|
|
|
if(Math.random() < 0.02) { |
|
this.moveAngle = Math.random() * Math.PI * 2; |
|
} |
|
|
|
this.angle = Math.atan2(player.y - this.y, player.x - this.x); |
|
|
|
const now = Date.now(); |
|
if (now - this.lastShot > this.shootInterval) { |
|
this.shoot(); |
|
this.lastShot = now; |
|
} |
|
} |
|
|
|
shoot() { |
|
enemyFireSound.cloneNode().play(); |
|
bullets.push({ |
|
x: this.x, |
|
y: this.y, |
|
angle: this.angle, |
|
speed: 5, |
|
isEnemy: true, |
|
size: 3 |
|
}); |
|
} |
|
} |
|
|
|
function drawBackground() { |
|
const pattern = ctx.createPattern(backgroundImg, 'repeat'); |
|
ctx.fillStyle = pattern; |
|
ctx.fillRect(0, 0, canvas.width, canvas.height); |
|
} |
|
|
|
function initRound() { |
|
enemies = []; |
|
for(let i = 0; i < 5 * currentRound; i++) { |
|
enemies.push(new Enemy()); |
|
} |
|
player.health = player.maxHealth; |
|
bullets = []; |
|
items = []; |
|
} |
|
|
|
document.addEventListener('keydown', (e) => { |
|
if(e.key.toLowerCase() === 'c') { |
|
currentWeapon = currentWeapon === 'cannon' ? 'machinegun' : 'cannon'; |
|
weaponInfo.textContent = `Current Weapon: ${currentWeapon.charAt(0).toUpperCase() + currentWeapon.slice(1)}`; |
|
} |
|
}); |
|
|
|
canvas.addEventListener('mousemove', (e) => { |
|
player.angle = Math.atan2(e.clientY - player.y, e.clientX - player.x); |
|
}); |
|
|
|
function fireBullet() { |
|
const weapon = weapons[currentWeapon]; |
|
const now = Date.now(); |
|
if (keys[' '] && now - lastShot > weapon.fireRate) { |
|
weapon.sound.cloneNode().play(); |
|
bullets.push({ |
|
x: player.x + Math.cos(player.angle) * 30, |
|
y: player.y + Math.sin(player.angle) * 30, |
|
angle: player.angle, |
|
speed: 10, |
|
isEnemy: false, |
|
damage: weapon.damage, |
|
size: weapon.bulletSize |
|
}); |
|
lastShot = now; |
|
} |
|
} |
|
|
|
const keys = {}; |
|
document.addEventListener('keydown', e => keys[e.key] = true); |
|
document.addEventListener('keyup', e => keys[e.key] = false); |
|
|
|
function updateGame() { |
|
if(gameOver) return; |
|
|
|
if(keys['w']) player.y -= player.speed; |
|
if(keys['s']) player.y += player.speed; |
|
if(keys['a']) player.x -= player.speed; |
|
if(keys['d']) player.x += player.speed; |
|
|
|
player.x = Math.max(player.width/2, Math.min(canvas.width - player.width/2, player.x)); |
|
player.y = Math.max(player.height/2, Math.min(canvas.height - player.height/2, player.y)); |
|
|
|
fireBullet(); |
|
|
|
enemies.forEach(enemy => enemy.update()); |
|
|
|
bullets = bullets.filter(bullet => { |
|
bullet.x += Math.cos(bullet.angle) * bullet.speed; |
|
bullet.y += Math.sin(bullet.angle) * bullet.speed; |
|
|
|
if(!bullet.isEnemy) { |
|
enemies = enemies.filter(enemy => { |
|
const dist = Math.hypot(bullet.x - enemy.x, bullet.y - enemy.y); |
|
if(dist < 30) { |
|
enemy.health -= enemy.maxHealth * bullet.damage; |
|
if(enemy.health <= 0) { |
|
spawnHealthItem(enemy.x, enemy.y); |
|
return false; |
|
} |
|
return true; |
|
} |
|
return true; |
|
}); |
|
} else { |
|
const dist = Math.hypot(bullet.x - player.x, bullet.y - player.y); |
|
if(dist < 30) { |
|
player.health -= 100; |
|
if(player.health <= 0) { |
|
gameOver = true; |
|
restartBtn.style.display = 'block'; |
|
} |
|
return false; |
|
} |
|
} |
|
|
|
return bullet.x >= 0 && bullet.x <= canvas.width && |
|
bullet.y >= 0 && bullet.y <= canvas.height; |
|
}); |
|
|
|
items = items.filter(item => { |
|
const dist = Math.hypot(item.x - player.x, item.y - player.y); |
|
if(dist < 30) { |
|
player.health = Math.min(player.health + 200, player.maxHealth); |
|
return false; |
|
} |
|
return true; |
|
}); |
|
|
|
if(enemies.length === 0) { |
|
if(currentRound < 10) { |
|
nextRoundBtn.style.display = 'block'; |
|
} else { |
|
gameOver = true; |
|
restartBtn.style.display = 'block'; |
|
} |
|
} |
|
} |
|
|
|
function spawnHealthItem(x, y) { |
|
items.push({x, y}); |
|
} |
|
|
|
function drawHealthBar(x, y, health, maxHealth, width, height, color) { |
|
ctx.fillStyle = '#333'; |
|
ctx.fillRect(x - width/2, y - height/2, width, height); |
|
ctx.fillStyle = color; |
|
ctx.fillRect(x - width/2, y - height/2, width * (health/maxHealth), height); |
|
} |
|
|
|
function drawGame() { |
|
drawBackground(); |
|
|
|
ctx.save(); |
|
ctx.translate(player.x, player.y); |
|
ctx.rotate(player.angle); |
|
ctx.drawImage(playerImg, -player.width/2, -player.height/2, player.width, player.height); |
|
ctx.restore(); |
|
|
|
drawHealthBar(canvas.width/2, 30, player.health, player.maxHealth, 200, 20, 'green'); |
|
|
|
enemies.forEach(enemy => { |
|
ctx.save(); |
|
ctx.translate(enemy.x, enemy.y); |
|
ctx.rotate(enemy.angle); |
|
ctx.drawImage(enemyImg, -enemy.width/2, -enemy.height/2, enemy.width, enemy.height); |
|
ctx.restore(); |
|
drawHealthBar(enemy.x, enemy.y - 40, enemy.health, enemy.maxHealth, 60, 5, 'red'); |
|
}); |
|
|
|
bullets.forEach(bullet => { |
|
ctx.beginPath(); |
|
ctx.fillStyle = bullet.isEnemy ? 'red' : 'yellow'; |
|
ctx.arc(bullet.x, bullet.y, bullet.size, 0, Math.PI * 2); |
|
ctx.fill(); |
|
}); |
|
|
|
ctx.fillStyle = 'green'; |
|
items.forEach(item => { |
|
ctx.beginPath(); |
|
ctx.arc(item.x, item.y, 10, 0, Math.PI * 2); |
|
ctx.fill(); |
|
}); |
|
|
|
ctx.fillStyle = 'white'; |
|
ctx.font = '24px Arial'; |
|
ctx.fillText(`Round ${currentRound}/10`, 10, 30); |
|
} |
|
|
|
function gameLoop() { |
|
updateGame(); |
|
drawGame(); |
|
requestAnimationFrame(gameLoop); |
|
} |
|
|
|
nextRoundBtn.addEventListener('click', () => { |
|
currentRound++; |
|
nextRoundBtn.style.display = 'none'; |
|
initRound(); |
|
}); |
|
|
|
restartBtn.addEventListener('click', () => { |
|
currentRound = 1; |
|
gameOver = false; |
|
restartBtn.style.display = 'none'; |
|
initRound(); |
|
}); |
|
|
|
Promise.all([ |
|
new Promise(resolve => backgroundImg.onload = resolve), |
|
new Promise(resolve => playerImg.onload = resolve), |
|
new Promise(resolve => enemyImg.onload = resolve) |
|
]).then(() => { |
|
initRound(); |
|
gameLoop(); |
|
}); |
|
|
|
window.addEventListener('resize', () => { |
|
canvas.width = window.innerWidth; |
|
canvas.height = window.innerHeight; |
|
}); |
|
</script> |
|
</body> |
|
</html> |