Shooting / index.html
KaiShin1885's picture
Update index.html
763e3f3 verified
<!DOCTYPE html>
<html>
<head>
<title>FPS Game</title>
<style>
body { margin: 0; overflow: hidden; }
#gameCanvas { width: 100vw; height: 100vh; }
.ui {
position: fixed;
color: white;
font-family: Arial;
pointer-events: none;
text-shadow: 1px 1px 2px black;
}
#health {
top: 20px;
left: 20px;
width: 200px;
height: 20px;
background: rgba(255,0,0,0.3);
border: 2px solid red;
}
#healthBar {
position: absolute;
bottom: 20px;
left: 20px;
width: 400px;
height: 30px;
background: rgba(0,20,0,0.7);
border: 2px solid #0f0;
z-index: 1001;
border-radius: 15px;
overflow: hidden;
}
#ammo {
top: 50px;
left: 20px;
font-size: 24px;
}
#enemies {
top: 80px;
left: 20px;
font-size: 20px;
}
#crosshair {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 24px;
}
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0,0,0,0.9);
padding: 30px;
border-radius: 10px;
text-align: center;
color: white;
border: 2px solid white;
min-width: 300px;
}
.button {
margin: 10px;
padding: 15px 30px;
font-size: 18px;
cursor: pointer;
background: #4CAF50;
border: none;
color: white;
border-radius: 5px;
transition: background 0.3s;
}
.button:hover {
background: #45a049;
}
.modal h1 {
color: #4CAF50;
margin-bottom: 20px;
}
</style>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<div class="ui">
<div id="health"><div id="healthBar"></div></div>
<div id="ammo">90/90</div>
<div id="enemies">Enemies: 3</div>
<div id="crosshair">+</div>
</div>
<div id="menuModal" class="modal">
<h1>FPS Game</h1>
<h2>Select Difficulty</h2>
<button class="button" onclick="startGame(1)">Level 1 (3 Enemies)</button>
<button class="button" onclick="startGame(2)">Level 2 (5 Enemies)</button>
<button class="button" onclick="startGame(3)">Level 3 (7 Enemies)</button>
<button class="button" onclick="startGame(4)">Level 4 (9 Enemies)</button>
<button class="button" onclick="startGame(5)">Level 5 (12 Enemies)</button>
</div>
<div id="gameOverModal" class="modal" style="display:none;">
<h1>Game Over</h1>
<p>Your health reached 0!</p>
<button class="button" onclick="showMenu()">Try Again</button>
</div>
<div id="victoryModal" class="modal" style="display:none;">
<h1>Victory!</h1>
<p>All enemies eliminated!</p>
<button class="button" onclick="showMenu()">Play Again</button>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
const GAME_CONFIG = {
PLAYER: {
HEALTH: 200,
AMMO: 90,
DAMAGE: 5,
SPEED: 0.15,
FIRE_RATE: 100
},
ENEMY: {
HEALTH: 30,
DAMAGE: 10,
FIRE_RATE: 1000,
GROUP_DISTANCE: 10,
SPEED: 0.05
},
LEVELS: {
1: { enemies: 3, obstacles: 5, mapSize: 100 },
2: { enemies: 5, obstacles: 8, mapSize: 150 },
3: { enemies: 7, obstacles: 12, mapSize: 200 },
4: { enemies: 9, obstacles: 16, mapSize: 250 },
5: { enemies: 12, obstacles: 20, mapSize: 300 }
}
};
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({canvas: document.getElementById('gameCanvas')});
renderer.setSize(window.innerWidth, window.innerHeight);
let gameState = {
player: {
health: GAME_CONFIG.PLAYER.HEALTH,
ammo: GAME_CONFIG.PLAYER.AMMO,
lastShot: 0
},
enemies: [],
bullets: [],
enemyBullets: [],
isShooting: false,
isPlaying: false,
level: 1
};
const keys = { w: false, s: false, a: false, d: false };
document.addEventListener('keydown', e => {
if(keys.hasOwnProperty(e.key.toLowerCase())) {
keys[e.key.toLowerCase()] = true;
}
});
document.addEventListener('keyup', e => {
if(keys.hasOwnProperty(e.key.toLowerCase())) {
keys[e.key.toLowerCase()] = false;
}
});
document.addEventListener('mousedown', e => {
if(e.button === 0) gameState.isShooting = true;
});
document.addEventListener('mouseup', e => {
if(e.button === 0) gameState.isShooting = false;
});
document.addEventListener('mousemove', e => {
if(document.pointerLockElement === document.body) {
camera.rotation.y -= e.movementX * 0.002;
}
});
function startGame(level) {
gameState = {
player: {
health: GAME_CONFIG.PLAYER.HEALTH,
ammo: GAME_CONFIG.PLAYER.AMMO,
lastShot: 0
},
enemies: [],
bullets: [],
enemyBullets: [],
isShooting: false,
isPlaying: true,
level: level
};
hideAllModals();
document.body.requestPointerLock();
createLevel(level);
gameLoop();
}
function hideAllModals() {
document.getElementById('menuModal').style.display = 'none';
document.getElementById('gameOverModal').style.display = 'none';
document.getElementById('victoryModal').style.display = 'none';
}
function showMenu() {
hideAllModals();
document.getElementById('menuModal').style.display = 'block';
}
function gameOver() {
gameState.isPlaying = false;
document.exitPointerLock();
hideAllModals();
document.getElementById('gameOverModal').style.display = 'block';
}
function victory() {
gameState.isPlaying = false;
document.exitPointerLock();
hideAllModals();
document.getElementById('victoryModal').style.display = 'block';
}
function createLevel(level) {
while(scene.children.length > 0) {
scene.remove(scene.children[0]);
}
const config = GAME_CONFIG.LEVELS[level];
// Ground
const ground = new THREE.Mesh(
new THREE.PlaneGeometry(config.mapSize, config.mapSize),
new THREE.MeshBasicMaterial({color: 0x444444})
);
ground.rotation.x = -Math.PI/2;
scene.add(ground);
// Obstacles
for(let i = 0; i < config.obstacles; i++) {
const obstacle = new THREE.Mesh(
new THREE.BoxGeometry(5, 10, 5),
new THREE.MeshBasicMaterial({color: 0x666666})
);
obstacle.position.set(
(Math.random() - 0.5) * config.mapSize * 0.8,
5,
(Math.random() - 0.5) * config.mapSize * 0.8
);
scene.add(obstacle);
}
// Enemies
for(let i = 0; i < config.enemies; i++) {
const enemy = new THREE.Mesh(
new THREE.BoxGeometry(2, 4, 2),
new THREE.MeshBasicMaterial({color: 0xff0000})
);
const angle = (Math.PI * 2 / config.enemies) * i;
const radius = config.mapSize * 0.4;
enemy.position.set(
Math.cos(angle) * radius,
2,
Math.sin(angle) * radius
);
enemy.health = GAME_CONFIG.ENEMY.HEALTH;
enemy.lastShot = 0;
scene.add(enemy);
gameState.enemies.push(enemy);
}
camera.position.set(0, 2, 0);
camera.rotation.set(0, 0, 0);
updateUI();
}
function movePlayer() {
const moveVector = new THREE.Vector3();
if(keys.w) moveVector.z -= GAME_CONFIG.PLAYER.SPEED;
if(keys.s) moveVector.z += GAME_CONFIG.PLAYER.SPEED;
if(keys.a) moveVector.x -= GAME_CONFIG.PLAYER.SPEED;
if(keys.d) moveVector.x += GAME_CONFIG.PLAYER.SPEED;
moveVector.applyAxisAngle(new THREE.Vector3(0, 1, 0), camera.rotation.y);
camera.position.add(moveVector);
}
function shoot() {
if(gameState.player.ammo <= 0 ||
Date.now() - gameState.player.lastShot < GAME_CONFIG.PLAYER.FIRE_RATE) return;
gameState.player.ammo--;
gameState.player.lastShot = Date.now();
const bullet = new THREE.Mesh(
new THREE.SphereGeometry(0.2),
new THREE.MeshBasicMaterial({color: 0xffff00})
);
bullet.position.copy(camera.position);
const direction = new THREE.Vector3(0, 0, -1);
direction.applyQuaternion(camera.quaternion);
bullet.velocity = direction.multiplyScalar(2);
scene.add(bullet);
gameState.bullets.push(bullet);
updateUI();
}
function updateBullets() {
// Player bullets
for(let i = gameState.bullets.length - 1; i >= 0; i--) {
const bullet = gameState.bullets[i];
bullet.position.add(bullet.velocity);
gameState.enemies.forEach((enemy, enemyIndex) => {
if(bullet.position.distanceTo(enemy.position) < 2) {
enemy.health -= GAME_CONFIG.PLAYER.DAMAGE;
scene.remove(bullet);
gameState.bullets.splice(i, 1);
if(enemy.health <= 0) {
scene.remove(enemy);
gameState.enemies.splice(enemyIndex, 1);
gameState.player.ammo += 30;
updateUI();
if(gameState.enemies.length === 0) {
victory();
}
}
}
});
}
// Enemy bullets
for(let i = gameState.enemyBullets.length - 1; i >= 0; i--) {
const bullet = gameState.enemyBullets[i];
bullet.position.add(bullet.velocity);
if(bullet.position.distanceTo(camera.position) < 1) {
gameState.player.health -= GAME_CONFIG.ENEMY.DAMAGE;
scene.remove(bullet);
gameState.enemyBullets.splice(i, 1);
updateUI();
if(gameState.player.health <= 0) {
gameOver();
}
}
}
}
function updateEnemies() {
gameState.enemies.forEach(enemy => {
// Movement with group avoidance
const toPlayer = new THREE.Vector3()
.subVectors(camera.position, enemy.position)
.normalize();
const avoidance = new THREE.Vector3();
gameState.enemies.forEach(other => {
if(other !== enemy) {
const dist = enemy.position.distanceTo(other.position);
if(dist < GAME_CONFIG.ENEMY.GROUP_DISTANCE) {
const away = new THREE.Vector3()
.subVectors(enemy.position, other.position)
.normalize()
.multiplyScalar(1/dist);
avoidance.add(away);
}
}
});
const movement = toPlayer.add(avoidance.multiplyScalar(0.5))
.normalize()
.multiplyScalar(GAME_CONFIG.ENEMY.SPEED);
enemy.position.add(movement);
// Shooting
if(Date.now() - enemy.lastShot > GAME_CONFIG.ENEMY.FIRE_RATE) {
enemy.lastShot = Date.now();
const bullet = new THREE.Mesh(
new THREE.SphereGeometry(0.2),
new THREE.MeshBasicMaterial({color: 0xff0000})
);
bullet.position.copy(enemy.position);
bullet.velocity = toPlayer.normalize().multiplyScalar(0.5);
scene.add(bullet);
gameState.enemyBullets.push(bullet);
}
});
}
function updateUI() {
document.getElementById('healthBar').style.width =
(gameState.player.health / GAME_CONFIG.PLAYER.HEALTH * 100) + '%';
document.getElementById('ammo').textContent =
`Ammo: ${gameState.player.ammo}/${GAME_CONFIG.PLAYER.AMMO}`;
document.getElementById('enemies').textContent =
`Enemies: ${gameState.enemies.length}`;
}
function gameLoop() {
if(!gameState.isPlaying) return;
requestAnimationFrame(gameLoop);
if(gameState.isShooting) shoot();
movePlayer();
updateEnemies();
updateBullets();
renderer.render(scene, camera);
}
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// Initialize game
updateUI();
</script>
</body>
</html>