Пост #32
19.07.2025 15:16
<!DOCTYPE html>
<html>
<head>
<title>Tank Battle - Fixed Controls</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<meta charset="UTF-8">
<style>
body { margin: 0; overflow: hidden; background: #222; font-family: Arial, sans-serif; }
canvas { display: block; }
/* UI элементы */
#ui {
position: absolute;
top: 15px;
left: 15px;
color: white;
font-size: 18px;
text-shadow: 1px 1px 2px black;
background: rgba(0,0,0,0.5);
padding: 8px 12px;
border-radius: 10px;
}
#start-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.9);
display: flex;
justify-content: center;
align-items: center;
z-index: 100;
}
#start-form {
background: #333;
padding: 30px;
border-radius: 15px;
text-align: center;
color: white;
max-width: 300px;
width: 80%;
}
#nickname-input {
padding: 12px;
font-size: 18px;
margin: 15px 0;
width: 100%;
box-sizing: border-box;
border-radius: 8px;
border: none;
}
.mode-btn {
padding: 12px 25px;
font-size: 18px;
background: #3498db;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
margin: 5px;
width: 100%;
}
.controls-info {
color: white;
background: rgba(0,0,0,0.5);
padding: 10px;
border-radius: 5px;
margin-top: 15px;
font-size: 14px;
}
</style>
</head>
<body>
<div id="ui">Убито: <span id="score">0</span></div>
<div id="start-modal">
<div id="start-form">
<h2 style="margin-top: 0;">Танковый бой</h2>
<input type="text" id="nickname-input" maxlength="12" placeholder="Танкист">
<button onclick="startGame()" class="mode-btn">Начать игру</button>
<div class="controls-info">
Управление:<br>
WASD - движение<br>
Стрелки - поворот башни<br>
Пробел - стрельба
</div>
</div>
</div>
<script>
// === ИНИЦИАЛИЗАЦИЯ ===
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.insertBefore(canvas, document.body.firstChild);
// Игровые объекты
const players = [];
const enemies = [];
const bullets = [];
const walls = [];
let score = 0;
let playerNickname = "Игрок";
let gameRunning = false;
let lastUpdateTime = 0;
// Управление
const controls = {
move: { up: false, left: false, right: false, down: false },
turret: { left: false, right: false },
shoot: false
};
// === ИГРОВЫЕ ФУНКЦИИ ===
function startGame() {
playerNickname = document.getElementById('nickname-input').value.trim() || "Танкист";
document.getElementById('start-modal').style.display = 'none';
// Создаем игрока
players.push({
x: canvas.width/2,
y: canvas.height/2,
angle: 0,
turretAngle: 0,
speed: 3,
color: '#3498db',
turretColor: '#2980b9',
name: playerNickname,
health: 100
});
generateMap();
spawnEnemies(1);
gameRunning = true;
lastUpdateTime = Date.now();
gameLoop();
}
function generateMap() {
walls.length = 0;
// Границы карты
walls.push({x: 0, y: 0, width: canvas.width, height: 20});
walls.push({x: 0, y: 0, width: 20, height: canvas.height});
walls.push({x: canvas.width-20, y: 0, width: 20, height: canvas.height});
walls.push({x: 0, y: canvas.height-20, width: canvas.width, height: 20});
// Случайные стены
for (let i = 0; i < 15; i++) {
walls.push({
x: Math.random() * (canvas.width - 100) + 50,
y: Math.random() * (canvas.height - 100) + 50,
width: 40 + Math.random() * 60,
height: 40 + Math.random() * 60
});
}
}
function spawnEnemies(count) {
for (let i = 0; i < count; i++) {
enemies.push({
x: Math.random() * (canvas.width - 100) + 50,
y: Math.random() * (canvas.height - 100) + 50,
angle: Math.random() * Math.PI * 2,
turretAngle: Math.random() * Math.PI * 2,
speed: 1.5,
color: '#e74c3c',
turretColor: '#c0392b',
health: 100,
aiTimer: 0
});
}
}
function drawTank(x, y, angle, turretAngle, color, turretColor, name, health) {
ctx.save();
ctx.translate(x, y);
// Корпус
ctx.rotate(angle);
ctx.fillStyle = color;
ctx.beginPath();
ctx.moveTo(0, -20);
ctx.lineTo(25, 0);
ctx.lineTo(0, 20);
ctx.lineTo(-25, 0);
ctx.closePath();
ctx.fill();
ctx.rotate(-angle);
// Башня
ctx.rotate(turretAngle);
ctx.fillStyle = turretColor;
ctx.beginPath();
ctx.arc(0, 0, 12, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#333';
ctx.fillRect(12, -3, 25, 6);
ctx.restore();
// Ник
if (name) {
ctx.fillStyle = 'white';
ctx.font = 'bold 14px Arial';
ctx.textAlign = 'center';
ctx.fillText(name, x, y - 30);
}
// Полоска здоровья
if (health !== undefined) {
ctx.fillStyle = 'red';
ctx.fillRect(x - 20, y - 40, 40, 5);
ctx.fillStyle = 'lime';
ctx.fillRect(x - 20, y - 40, 40 * (health / 100), 5);
}
}
function updateEnemies(deltaTime) {
enemies.forEach(enemy => {
if (players.length === 0) return;
// Находим ближайшего игрока
const player = players[0];
const angleToPlayer = Math.atan2(player.y - enemy.y, player.x - enemy.x);
// Поворот башни к игроку
const turretAngleDiff = ((angleToPlayer - enemy.turretAngle + Math.PI * 3) % (Math.PI * 2)) - Math.PI;
enemy.turretAngle += Math.sign(turretAngleDiff) * 0.05 * deltaTime * 60;
// Движение
const angleDiff = ((angleToPlayer - enemy.angle + Math.PI * 3) % (Math.PI * 2)) - Math.PI;
enemy.angle += Math.sign(angleDiff) * 0.03 * deltaTime * 60;
// Движение вперед
const newX = enemy.x + Math.cos(enemy.angle) * enemy.speed * deltaTime * 60;
const newY = enemy.y + Math.sin(enemy.angle) * enemy.speed * deltaTime * 60;
if (!checkWallCollision(newX, newY, 20)) {
enemy.x = newX;
enemy.y = newY;
}
// Стрельба
enemy.aiTimer += deltaTime * 60;
if (enemy.aiTimer > 90) {
bullets.push({
x: enemy.x,
y: enemy.y,
angle: enemy.turretAngle,
speed: 5,
isEnemy: true
});
enemy.aiTimer = 0;
}
});
}
function checkWallCollision(x, y, radius) {
for (const wall of walls) {
const closestX = Math.max(wall.x, Math.min(x, wall.x + wall.width));
const closestY = Math.max(wall.y, Math.min(y, wall.y + wall.height));
const distance = Math.hypot(x - closestX, y - closestY);
if (distance < radius + 5) { // 5 - отступ для коллизии
return true;
}
}
return false;
}
function updateBullets(deltaTime) {
for (let i = bullets.length - 1; i >= 0; i--) {
const bullet = bullets[i];
bullet.x += Math.cos(bullet.angle) * bullet.speed * deltaTime * 60;
bullet.y += Math.sin(bullet.angle) * bullet.speed * deltaTime * 60;
// Удаление за пределами экрана
if (bullet.x < 0 || bullet.x > canvas.width || bullet.y < 0 || bullet.y > canvas.height) {
bullets.splice(i, 1);
continue;
}
// Проверка столкновения со стенами
if (checkWallCollision(bullet.x, bullet.y, 4)) {
bullets.splice(i, 1);
}
}
}
function checkCollisions() {
const player = players[0];
if (!player) return;
// Пули с врагами
for (let i = bullets.length - 1; i >= 0; i--) {
const bullet = bullets[i];
// Пуля игрока попадает во врага
if (!bullet.isEnemy) {
for (let j = enemies.length - 1; j >= 0; j--) {
const enemy = enemies[j];
const dist = Math.hypot(bullet.x - enemy.x, bullet.y - enemy.y);
if (dist < 25) {
enemies.splice(j, 1);
bullets.splice(i, 1);
score++;
document.getElementById('score').textContent = score;
// Спавним нового врага
setTimeout(() => spawnEnemies(1), 1000);
break;
}
}
}
// Пуля врага попадает в игрока
else {
const dist = Math.hypot(bullet.x - player.x, bullet.y - player.y);
if (dist < 25) {
player.health -= 20;
bullets.splice(i, 1);
if (player.health <= 0) {
gameOver();
}
break;
}
}
}
}
function gameOver() {
gameRunning = false;
setTimeout(() => {
alert(`Игра окончена!\nВаш счет: ${score}`);
document.location.reload();
}, 500);
}
function gameLoop() {
if (!gameRunning) return;
const now = Date.now();
const deltaTime = (now - lastUpdateTime) / 1000;
lastUpdateTime = now;
update(deltaTime);
render();
requestAnimationFrame(gameLoop);
}
function update(deltaTime) {
const player = players[0];
if (!player) return;
// Управление движением
if (controls.move.up) {
const newX = player.x + Math.cos(player.angle) * player.speed * deltaTime * 60;
const newY = player.y + Math.sin(player.angle) * player.speed * deltaTime * 60;
if (!checkWallCollision(newX, newY, 20)) {
player.x = newX;
player.y = newY;
}
}
if (controls.move.left) player.angle -= 0.05 * deltaTime * 60;
if (controls.move.right) player.angle += 0.05 * deltaTime * 60;
// Управление башней
if (controls.turret.left) player.turretAngle -= 0.05 * deltaTime * 60;
if (controls.turret.right) player.turretAngle += 0.05 * deltaTime * 60;
// Обработка стрельбы
if (controls.shoot) {
controls.shoot = false;
bullets.push({
x: player.x,
y: player.y,
angle: player.turretAngle,
speed: 7,
isEnemy: false
});
}
updateEnemies(deltaTime);
updateBullets(deltaTime);
checkCollisions();
}
function render() {
// Очистка
ctx.fillStyle = '#222';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Стены
ctx.fillStyle = '#555';
walls.forEach(wall => {
ctx.fillRect(wall.x, wall.y, wall.width, wall.height);
});
// Игрок
players.forEach(player => {
drawTank(
player.x, player.y,
player.angle, player.turretAngle,
player.color, player.turretColor,
player.name,
player.health
);
});
// Враги
enemies.forEach(enemy => {
drawTank(
enemy.x, enemy.y,
enemy.angle, enemy.turretAngle,
enemy.color, enemy.turretColor,
"Бот",
enemy.health
);
});
// Пули
ctx.fillStyle = '#f1c40f';
bullets.forEach(bullet => {
ctx.beginPath();
ctx.arc(bullet.x, bullet.y, 4, 0, Math.PI * 2);
ctx.fill();
});
}
// === ОБРАБОТЧИКИ СОБЫТИЙ ===
document.addEventListener('keydown', (e) => {
if (!gameRunning) return;
switch (e.key.toLowerCase()) {
case 'w':
controls.move.up = true;
break;
case 'a':
controls.move.left = true;
break;
case 'd':
controls.move.right = true;
break;
case 'arrowleft':
controls.turret.left = true;
break;
case 'arrowright':
controls.turret.right = true;
break;
case ' ':
controls.shoot = true;
break;
}
});
document.addEventListener('keyup', (e) => {
switch (e.key.toLowerCase()) {
case 'w':
controls.move.up = false;
break;
case 'a':
controls.move.left = false;
break;
case 'd':
controls.move.right = false;
break;
case 'arrowleft':
controls.turret.left = false;
break;
case 'arrowright':
controls.turret.right = false;
break;
}
});
window.addEventListener('resize', () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
if (gameRunning) {
generateMap();
}
});
// Автофокус на поле ввода
window.onload = () => {
document.getElementById('nickname-input').focus();
};
</script>
</body>
</html>
<html>
<head>
<title>Tank Battle - Fixed Controls</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<meta charset="UTF-8">
<style>
body { margin: 0; overflow: hidden; background: #222; font-family: Arial, sans-serif; }
canvas { display: block; }
/* UI элементы */
#ui {
position: absolute;
top: 15px;
left: 15px;
color: white;
font-size: 18px;
text-shadow: 1px 1px 2px black;
background: rgba(0,0,0,0.5);
padding: 8px 12px;
border-radius: 10px;
}
#start-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.9);
display: flex;
justify-content: center;
align-items: center;
z-index: 100;
}
#start-form {
background: #333;
padding: 30px;
border-radius: 15px;
text-align: center;
color: white;
max-width: 300px;
width: 80%;
}
#nickname-input {
padding: 12px;
font-size: 18px;
margin: 15px 0;
width: 100%;
box-sizing: border-box;
border-radius: 8px;
border: none;
}
.mode-btn {
padding: 12px 25px;
font-size: 18px;
background: #3498db;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
margin: 5px;
width: 100%;
}
.controls-info {
color: white;
background: rgba(0,0,0,0.5);
padding: 10px;
border-radius: 5px;
margin-top: 15px;
font-size: 14px;
}
</style>
</head>
<body>
<div id="ui">Убито: <span id="score">0</span></div>
<div id="start-modal">
<div id="start-form">
<h2 style="margin-top: 0;">Танковый бой</h2>
<input type="text" id="nickname-input" maxlength="12" placeholder="Танкист">
<button onclick="startGame()" class="mode-btn">Начать игру</button>
<div class="controls-info">
Управление:<br>
WASD - движение<br>
Стрелки - поворот башни<br>
Пробел - стрельба
</div>
</div>
</div>
<script>
// === ИНИЦИАЛИЗАЦИЯ ===
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.insertBefore(canvas, document.body.firstChild);
// Игровые объекты
const players = [];
const enemies = [];
const bullets = [];
const walls = [];
let score = 0;
let playerNickname = "Игрок";
let gameRunning = false;
let lastUpdateTime = 0;
// Управление
const controls = {
move: { up: false, left: false, right: false, down: false },
turret: { left: false, right: false },
shoot: false
};
// === ИГРОВЫЕ ФУНКЦИИ ===
function startGame() {
playerNickname = document.getElementById('nickname-input').value.trim() || "Танкист";
document.getElementById('start-modal').style.display = 'none';
// Создаем игрока
players.push({
x: canvas.width/2,
y: canvas.height/2,
angle: 0,
turretAngle: 0,
speed: 3,
color: '#3498db',
turretColor: '#2980b9',
name: playerNickname,
health: 100
});
generateMap();
spawnEnemies(1);
gameRunning = true;
lastUpdateTime = Date.now();
gameLoop();
}
function generateMap() {
walls.length = 0;
// Границы карты
walls.push({x: 0, y: 0, width: canvas.width, height: 20});
walls.push({x: 0, y: 0, width: 20, height: canvas.height});
walls.push({x: canvas.width-20, y: 0, width: 20, height: canvas.height});
walls.push({x: 0, y: canvas.height-20, width: canvas.width, height: 20});
// Случайные стены
for (let i = 0; i < 15; i++) {
walls.push({
x: Math.random() * (canvas.width - 100) + 50,
y: Math.random() * (canvas.height - 100) + 50,
width: 40 + Math.random() * 60,
height: 40 + Math.random() * 60
});
}
}
function spawnEnemies(count) {
for (let i = 0; i < count; i++) {
enemies.push({
x: Math.random() * (canvas.width - 100) + 50,
y: Math.random() * (canvas.height - 100) + 50,
angle: Math.random() * Math.PI * 2,
turretAngle: Math.random() * Math.PI * 2,
speed: 1.5,
color: '#e74c3c',
turretColor: '#c0392b',
health: 100,
aiTimer: 0
});
}
}
function drawTank(x, y, angle, turretAngle, color, turretColor, name, health) {
ctx.save();
ctx.translate(x, y);
// Корпус
ctx.rotate(angle);
ctx.fillStyle = color;
ctx.beginPath();
ctx.moveTo(0, -20);
ctx.lineTo(25, 0);
ctx.lineTo(0, 20);
ctx.lineTo(-25, 0);
ctx.closePath();
ctx.fill();
ctx.rotate(-angle);
// Башня
ctx.rotate(turretAngle);
ctx.fillStyle = turretColor;
ctx.beginPath();
ctx.arc(0, 0, 12, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#333';
ctx.fillRect(12, -3, 25, 6);
ctx.restore();
// Ник
if (name) {
ctx.fillStyle = 'white';
ctx.font = 'bold 14px Arial';
ctx.textAlign = 'center';
ctx.fillText(name, x, y - 30);
}
// Полоска здоровья
if (health !== undefined) {
ctx.fillStyle = 'red';
ctx.fillRect(x - 20, y - 40, 40, 5);
ctx.fillStyle = 'lime';
ctx.fillRect(x - 20, y - 40, 40 * (health / 100), 5);
}
}
function updateEnemies(deltaTime) {
enemies.forEach(enemy => {
if (players.length === 0) return;
// Находим ближайшего игрока
const player = players[0];
const angleToPlayer = Math.atan2(player.y - enemy.y, player.x - enemy.x);
// Поворот башни к игроку
const turretAngleDiff = ((angleToPlayer - enemy.turretAngle + Math.PI * 3) % (Math.PI * 2)) - Math.PI;
enemy.turretAngle += Math.sign(turretAngleDiff) * 0.05 * deltaTime * 60;
// Движение
const angleDiff = ((angleToPlayer - enemy.angle + Math.PI * 3) % (Math.PI * 2)) - Math.PI;
enemy.angle += Math.sign(angleDiff) * 0.03 * deltaTime * 60;
// Движение вперед
const newX = enemy.x + Math.cos(enemy.angle) * enemy.speed * deltaTime * 60;
const newY = enemy.y + Math.sin(enemy.angle) * enemy.speed * deltaTime * 60;
if (!checkWallCollision(newX, newY, 20)) {
enemy.x = newX;
enemy.y = newY;
}
// Стрельба
enemy.aiTimer += deltaTime * 60;
if (enemy.aiTimer > 90) {
bullets.push({
x: enemy.x,
y: enemy.y,
angle: enemy.turretAngle,
speed: 5,
isEnemy: true
});
enemy.aiTimer = 0;
}
});
}
function checkWallCollision(x, y, radius) {
for (const wall of walls) {
const closestX = Math.max(wall.x, Math.min(x, wall.x + wall.width));
const closestY = Math.max(wall.y, Math.min(y, wall.y + wall.height));
const distance = Math.hypot(x - closestX, y - closestY);
if (distance < radius + 5) { // 5 - отступ для коллизии
return true;
}
}
return false;
}
function updateBullets(deltaTime) {
for (let i = bullets.length - 1; i >= 0; i--) {
const bullet = bullets[i];
bullet.x += Math.cos(bullet.angle) * bullet.speed * deltaTime * 60;
bullet.y += Math.sin(bullet.angle) * bullet.speed * deltaTime * 60;
// Удаление за пределами экрана
if (bullet.x < 0 || bullet.x > canvas.width || bullet.y < 0 || bullet.y > canvas.height) {
bullets.splice(i, 1);
continue;
}
// Проверка столкновения со стенами
if (checkWallCollision(bullet.x, bullet.y, 4)) {
bullets.splice(i, 1);
}
}
}
function checkCollisions() {
const player = players[0];
if (!player) return;
// Пули с врагами
for (let i = bullets.length - 1; i >= 0; i--) {
const bullet = bullets[i];
// Пуля игрока попадает во врага
if (!bullet.isEnemy) {
for (let j = enemies.length - 1; j >= 0; j--) {
const enemy = enemies[j];
const dist = Math.hypot(bullet.x - enemy.x, bullet.y - enemy.y);
if (dist < 25) {
enemies.splice(j, 1);
bullets.splice(i, 1);
score++;
document.getElementById('score').textContent = score;
// Спавним нового врага
setTimeout(() => spawnEnemies(1), 1000);
break;
}
}
}
// Пуля врага попадает в игрока
else {
const dist = Math.hypot(bullet.x - player.x, bullet.y - player.y);
if (dist < 25) {
player.health -= 20;
bullets.splice(i, 1);
if (player.health <= 0) {
gameOver();
}
break;
}
}
}
}
function gameOver() {
gameRunning = false;
setTimeout(() => {
alert(`Игра окончена!\nВаш счет: ${score}`);
document.location.reload();
}, 500);
}
function gameLoop() {
if (!gameRunning) return;
const now = Date.now();
const deltaTime = (now - lastUpdateTime) / 1000;
lastUpdateTime = now;
update(deltaTime);
render();
requestAnimationFrame(gameLoop);
}
function update(deltaTime) {
const player = players[0];
if (!player) return;
// Управление движением
if (controls.move.up) {
const newX = player.x + Math.cos(player.angle) * player.speed * deltaTime * 60;
const newY = player.y + Math.sin(player.angle) * player.speed * deltaTime * 60;
if (!checkWallCollision(newX, newY, 20)) {
player.x = newX;
player.y = newY;
}
}
if (controls.move.left) player.angle -= 0.05 * deltaTime * 60;
if (controls.move.right) player.angle += 0.05 * deltaTime * 60;
// Управление башней
if (controls.turret.left) player.turretAngle -= 0.05 * deltaTime * 60;
if (controls.turret.right) player.turretAngle += 0.05 * deltaTime * 60;
// Обработка стрельбы
if (controls.shoot) {
controls.shoot = false;
bullets.push({
x: player.x,
y: player.y,
angle: player.turretAngle,
speed: 7,
isEnemy: false
});
}
updateEnemies(deltaTime);
updateBullets(deltaTime);
checkCollisions();
}
function render() {
// Очистка
ctx.fillStyle = '#222';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Стены
ctx.fillStyle = '#555';
walls.forEach(wall => {
ctx.fillRect(wall.x, wall.y, wall.width, wall.height);
});
// Игрок
players.forEach(player => {
drawTank(
player.x, player.y,
player.angle, player.turretAngle,
player.color, player.turretColor,
player.name,
player.health
);
});
// Враги
enemies.forEach(enemy => {
drawTank(
enemy.x, enemy.y,
enemy.angle, enemy.turretAngle,
enemy.color, enemy.turretColor,
"Бот",
enemy.health
);
});
// Пули
ctx.fillStyle = '#f1c40f';
bullets.forEach(bullet => {
ctx.beginPath();
ctx.arc(bullet.x, bullet.y, 4, 0, Math.PI * 2);
ctx.fill();
});
}
// === ОБРАБОТЧИКИ СОБЫТИЙ ===
document.addEventListener('keydown', (e) => {
if (!gameRunning) return;
switch (e.key.toLowerCase()) {
case 'w':
controls.move.up = true;
break;
case 'a':
controls.move.left = true;
break;
case 'd':
controls.move.right = true;
break;
case 'arrowleft':
controls.turret.left = true;
break;
case 'arrowright':
controls.turret.right = true;
break;
case ' ':
controls.shoot = true;
break;
}
});
document.addEventListener('keyup', (e) => {
switch (e.key.toLowerCase()) {
case 'w':
controls.move.up = false;
break;
case 'a':
controls.move.left = false;
break;
case 'd':
controls.move.right = false;
break;
case 'arrowleft':
controls.turret.left = false;
break;
case 'arrowright':
controls.turret.right = false;
break;
}
});
window.addEventListener('resize', () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
if (gameRunning) {
generateMap();
}
});
// Автофокус на поле ввода
window.onload = () => {
document.getElementById('nickname-input').focus();
};
</script>
</body>
</html>
Автор:
Anonymous