本教程將完整講解如何開發一款和平精英風格的HTML射擊游戲,涵蓋核心設計理念、代碼架構與關鍵實現細節。
核心設計架構
游戲機制系統
- 角色控制系統:通過鍵盤實現玩家移動
- 戰斗系統:子彈發射與碰撞檢測
- 道具系統:武器、彈藥和醫療包收集
- 敵人系統:AI行為與傷害機制
- 界面系統:實時狀態顯示與游戲信息
技術選型
- HTML:構建游戲基礎結構
- CSS:實現視覺效果與動畫
- JavaScript:處理游戲邏輯與交互
代碼實現詳解
游戲HTML框架
<!DOCTYPE html>
<html>
<head><!-- 元數據與樣式引入 -->
</head>
<body><div class="header">游戲信息顯示</div><div class="game-container"><div class="game-area"><div class="player"></div><div class="enemy"></div><div class="item"></div><div class="bullet"></div></div><div class="stats-panel"><!-- 狀態顯示與操作控件 --></div></div>
</body>
</html>
樣式設計要點
- 采用Flexbox/Grid現代化布局方案
- 運用CSS漸變與陰影效果
- 實現關鍵幀動畫效果
- 響應式設計適配不同設備
JavaScript功能模塊
- 游戲初始化模塊
- 玩家控制模塊
- 敵人生成與AI模塊
- 道具系統模塊
- 碰撞檢測模塊
- 界面更新模塊
核心代碼實現
游戲初始化
function initGame() {// 設置玩家初始位置playerX = gameArea.offsetWidth / 2;playerY = gameArea.offsetHeight / 2;resetGameElements();generateEnemies(5);generateItems(5);startMainLoop();initEventListeners();
}
敵人生成機制
function generateEnemies(count) {for (let i = 0; i < count; i++) {const safeDistance = 50;const x = safeDistance + Math.random() * (gameArea.offsetWidth - 2 * safeDistance);const y = safeDistance + Math.random() * (gameArea.offsetHeight - 2 * safeDistance);const enemy = document.createElement('div');enemy.className = 'enemy';enemy.style.left = `${x}px`;enemy.style.top = `${y}px`;gameArea.appendChild(enemy);enemies.push({element: enemy,position: {x, y},health: 30,speed: 1 + Math.random() * 2});}
}
碰撞檢測系統
function detectCollisions() {// 玩家與敵人碰撞enemies.forEach(enemy => {const distance = calculateDistance(playerX, playerY, enemy.position.x, enemy.position.y);if (distance < 45) {health -= 2;updateHUD();if (health <= 0) endGame();}});// 子彈碰撞檢測bullets.forEach((bullet, bIndex) => {enemies.forEach((enemy, eIndex) => {const distance = calculateDistance(bullet.x, bullet.y, enemy.position.x, enemy.position.y);if (distance < 25) {enemy.health -= 10;destroyBullet(bIndex);if (enemy.health <= 0) {removeEnemy(eIndex);score += 100;updateHUD();if (!enemies.length) nextLevel();}}});});
}
游戲主循環
function mainGameLoop() {updateEnemyPositions();detectCollisions();checkItemCollection();
}function updateBullets() {bullets.forEach((bullet, index) => {bullet.x += bullet.velocityX;bullet.y += bullet.velocityY;if (isOutsideBounds(bullet)) {removeBullet(index);return;}bullet.element.style.transform = `translate(${bullet.x}px, ${bullet.y}px)`;});
}
關鍵優化點
道具生成邊界控制
// 確保道具在有效區域內生成
const margin = 40;
const x = margin + Math.random() * (gameArea.offsetWidth - 2 * margin);
const y = margin + Math.random() * (gameArea.offsetHeight - 2 * margin);
游戲元素清理
function resetGameElements() {[enemies, items, bullets].forEach(group => {group.forEach(item => {if (item.element?.parentNode) {gameArea.removeChild(item.element);}});group.length = 0;});
}
子彈系統優化
// 使用獨立計時器管理子彈運動
bulletUpdateInterval = setInterval(updateBullets, 50);
完整代碼
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>和平精英HTML</title><style>* {margin: 0;padding: 0;box-sizing: border-box;}body {font-family: 'Arial', sans-serif;background: linear-gradient(135deg, #0a2e36, #1a3e46);color: white;overflow: hidden;display: flex;flex-direction: column;height: 100vh;padding: 10px;}.header {text-align: center;padding: 10px;margin-bottom: 15px;background: rgba(0, 0, 0, 0.3);border-radius: 10px;box-shadow: 0 4px 15px rgba(0, 0, 0, 0.5);}.title {font-size: 28px;font-weight: bold;color: #ffcc00;text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);margin-bottom: 5px;}.game-container {display: flex;flex: 1;gap: 15px;margin-bottom: 15px;}.game-area {flex: 1;background-color: #1d4e5c;border-radius: 10px;position: relative;overflow: hidden;box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);background-image: radial-gradient(circle at 25% 25%, #2a5c6c 0%, #1d4e5c 20%, #0f3b48 100%);}.player {width: 40px;height: 40px;background: linear-gradient(135deg, #ff9d00, #ff6600);border: 3px solid #ffcc00;border-radius: 50%;position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);z-index: 100;transition: transform 0.2s;box-shadow: 0 0 10px rgba(255, 157, 0, 0.7);}.player::after {content: '';position: absolute;width: 10px;height: 10px;background: #ff3300;border-radius: 50%;top: 50%;left: 70%;transform: translateY(-50%);}.weapon {width: 25px;height: 10px;background: linear-gradient(135deg, #555, #333);position: absolute;top: 50%;left: 70%;transform: translateY(-50%);border-radius: 3px;}.bullet {position: absolute;width: 8px;height: 8px;background: radial-gradient(circle, #ffcc00, #ff6600);border-radius: 50%;z-index: 90;box-shadow: 0 0 5px #ffcc00;}.enemy {position: absolute;width: 35px;height: 35px;background: radial-gradient(circle at 30% 30%, #ff3c3c, #cc0000);border: 2px solid #ff0000;border-radius: 50%;display: flex;align-items: center;justify-content: center;color: white;font-weight: bold;z-index: 80;box-shadow: 0 0 10px rgba(255, 0, 0, 0.5);}.item {position: absolute;width: 30px;height: 30px;border-radius: 5px;display: flex;align-items: center;justify-content: center;color: white;font-weight: bold;font-size: 18px;z-index: 70;animation: pulse 2s infinite;box-shadow: 0 0 10px rgba(255, 255, 255, 0.5);border: 1px solid rgba(255, 255, 255, 0.3);}@keyframes pulse {0% { transform: scale(1) rotate(0deg); }50% { transform: scale(1.1) rotate(5deg); }100% { transform: scale(1) rotate(0deg); }}.weapon-item {background: linear-gradient(135deg, #7d5ba6, #5a3f80);}.health-item {background: linear-gradient(135deg, #29bf12, #1e8c0c);}.ammo-item {background: linear-gradient(135deg, #f2bb05, #d9a404);}.stats-panel {width: 250px;background: linear-gradient(135deg, #1d4e5c, #0f3b48);border-radius: 10px;padding: 15px;display: flex;flex-direction: column;gap: 15px;box-shadow: 0 0 15px rgba(0, 0, 0, 0.4);}.panel-title {font-size: 18px;color: #ffcc00;border-bottom: 2px solid #2a8c79;padding-bottom: 5px;margin-bottom: 10px;}.stat {display: flex;align-items: center;gap: 10px;}.stat-icon {width: 30px;height: 30px;border-radius: 5px;display: flex;align-items: center;justify-content: center;background: linear-gradient(135deg, #2a8c79, #1d6b5c);font-weight: bold;box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);}.stat-value {flex: 1;height: 20px;background-color: #0a2e36;border-radius: 5px;overflow: hidden;box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.5);}.stat-fill {height: 100%;border-radius: 5px;transition: width 0.3s;}.health-fill {background: linear-gradient(90deg, #29bf12, #8eff80);width: 100%;}.ammo-fill {background: linear-gradient(90deg, #f2bb05, #ffdd80);width: 100%;}.inventory {display: grid;grid-template-columns: repeat(2, 1fr);gap: 10px;margin-top: 10px;}.inventory-item {height: 60px;background: linear-gradient(135deg, #2a8c79, #1d6b5c);border-radius: 5px;display: flex;flex-direction: column;align-items: center;justify-content: center;gap: 5px;box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);border: 1px solid rgba(255, 255, 255, 0.1);}.inventory-icon {font-size: 20px;}.inventory-title {font-size: 12px;}.controls {display: flex;gap: 10px;margin-top: 15px;}.btn {flex: 1;padding: 12px;border: none;border-radius: 5px;background: linear-gradient(135deg, #2a8c79, #1d6b5c);color: white;font-weight: bold;cursor: pointer;transition: all 0.3s;box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);}.btn:hover {transform: translateY(-2px);box-shadow: 0 5px 10px rgba(0, 0, 0, 0.4);}.btn:active {transform: translateY(0);}.btn-fire {background: linear-gradient(135deg, #f21d44, #c50d2e);}.btn-fire:hover {background: linear-gradient(135deg, #ff3c60, #d91a3d);}.game-status {text-align: center;padding: 10px;background: linear-gradient(135deg, #1d4e5c, #0f3b48);border-radius: 10px;margin-bottom: 15px;box-shadow: 0 0 15px rgba(0, 0, 0, 0.4);}.score {font-size: 24px;font-weight: bold;color: #f2bb05;text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.5);}.message {position: absolute;top: 20px;left: 50%;transform: translateX(-50%);background-color: rgba(0, 0, 0, 0.7);padding: 10px 20px;border-radius: 5px;z-index: 200;opacity: 0;transition: opacity 0.5s;font-size: 14px;text-align: center;max-width: 80%;}.show {opacity: 1;}.instructions {background: rgba(0, 0, 0, 0.3);padding: 10px;border-radius: 5px;margin-top: 10px;font-size: 12px;}.key {display: inline-block;background: rgba(0, 0, 0, 0.5);padding: 2px 5px;border-radius: 3px;margin: 0 2px;border: 1px solid rgba(255, 255, 255, 0.2);}</style>
</head>
<body><div class="header"><div class="title">和平精英HTML版</div><div class="score">分數: <span id="score">0</span></div></div><div class="game-container"><div class="game-area" id="gameArea"><div class="player" id="player"><div class="weapon"></div></div><div class="message" id="message"></div><!-- 敵人和物品將由JavaScript動態生成 --></div><div class="stats-panel"><div class="panel-title">玩家狀態</div><div class="stat"><div class="stat-icon">??</div><div class="stat-value"><div class="stat-fill health-fill" id="healthBar"></div></div></div><div class="stat"><div class="stat-icon">🔫</div><div class="stat-value"><div class="stat-fill ammo-fill" id="ammoBar"></div></div></div><div class="panel-title">背包</div><div class="inventory"><div class="inventory-item"><div class="inventory-icon">🔫</div><div class="inventory-title" id="weaponName">無</div></div><div class="inventory-item"><div class="inventory-icon">??</div><div class="inventory-title" id="healthCount">0</div></div><div class="inventory-item"><div class="inventory-icon">📦</div><div class="inventory-title" id="ammoCount">0</div></div><div class="inventory-item"><div class="inventory-icon">?</div><div class="inventory-title" id="level">1</div></div></div><div class="controls"><button class="btn" id="btnReload">裝彈 (R)</button><button class="btn btn-fire" id="btnFire">開火 (F)</button></div><div class="instructions">移動: <span class="key">W</span> <span class="key">A</span> <span class="key">S</span> <span class="key">D</span>或方向鍵<br>開火: <span class="key">F</span> 或 點擊按鈕<br>裝彈: <span class="key">R</span><br>使用醫療包: <span class="key">H</span></div></div></div><script>// 游戲變量const player = document.getElementById('player');const gameArea = document.getElementById('gameArea');const message = document.getElementById('message');const scoreElement = document.getElementById('score');const healthBar = document.getElementById('healthBar');const ammoBar = document.getElementById('ammoBar');const weaponName = document.getElementById('weaponName');const healthCount = document.getElementById('healthCount');const ammoCount = document.getElementById('ammoCount');const levelElement = document.getElementById('level');const btnReload = document.getElementById('btnReload');const btnFire = document.getElementById('btnFire');let playerX = 400;let playerY = 300;let score = 0;let health = 100;let ammo = 30;let maxAmmo = 30;let playerLevel = 1;let playerWeapon = '無';let healthKits = 0;let ammoPacks = 0;let enemies = [];let items = [];let bullets = [];let gameInterval;let bulletInterval;// 初始化游戲function initGame() {// 設置玩家初始位置playerX = gameArea.offsetWidth / 2;playerY = gameArea.offsetHeight / 2;player.style.left = `${playerX}px`;player.style.top = `${playerY}px`;// 清除所有現有的敵人和物品clearGameElements();// 生成敵人和物品generateEnemies(5);generateItems(5);// 更新UIupdateUI();// 開始游戲循環startGameLoop();// 添加鍵盤事件監聽setupEventListeners();showMessage('游戲開始!收集裝備,消滅敵人!');}// 清除游戲元素function clearGameElements() {enemies.forEach(enemy => {if (enemy.element && enemy.element.parentNode) {gameArea.removeChild(enemy.element);}});items.forEach(item => {if (item.element && item.element.parentNode) {gameArea.removeChild(item.element);}});bullets.forEach(bullet => {if (bullet.element && bullet.element.parentNode) {gameArea.removeChild(bullet.element);}});// 重置數組enemies = [];items = [];bullets = [];}// 設置事件監聽器function setupEventListeners() {document.addEventListener('keydown', handleKeyPress);btnReload.addEventListener('click', reloadWeapon);btnFire.addEventListener('click', fireWeapon);}// 開始游戲循環function startGameLoop() {if (gameInterval) clearInterval(gameInterval);if (bulletInterval) clearInterval(bulletInterval);gameInterval = setInterval(gameLoop, 100);bulletInterval = setInterval(moveBullets, 50);}// 生成敵人function generateEnemies(count) {for (let i = 0; i < count; i++) {const enemy = document.createElement('div');enemy.className = 'enemy';// 確保敵人生成在游戲區域內const padding = 50;const x = padding + Math.random() * (gameArea.offsetWidth - 2 * padding);const y = padding + Math.random() * (gameArea.offsetHeight - 2 * padding);enemy.style.left = `${x}px`;enemy.style.top = `${y}px`;enemy.textContent = '??';gameArea.appendChild(enemy);enemies.push({element: enemy,x: x,y: y,health: 30,speed: 1 + Math.random() * 2});}}// 生成物品function generateItems(count) {const itemTypes = [{ class: 'weapon-item', symbol: '🔫', type: 'weapon' },{ class: 'health-item', symbol: '??', type: 'health' },{ class: 'ammo-item', symbol: '📦', type: 'ammo' }];for (let i = 0; i < count; i++) {const type = itemTypes[Math.floor(Math.random() * itemTypes.length)];const item = document.createElement('div');item.className = `item ${type.class}`;item.textContent = type.symbol;// 確保物品生成在游戲區域內const padding = 40;const x = padding + Math.random() * (gameArea.offsetWidth - 2 * padding);const y = padding + Math.random() * (gameArea.offsetHeight - 2 * padding);item.style.left = `${x}px`;item.style.top = `${y}px`;gameArea.appendChild(item);items.push({element: item,x: x,y: y,type: type.type});}}// 游戲主循環function gameLoop() {moveEnemies();checkCollisions();checkItemPickups();}// 移動敵人function moveEnemies() {enemies.forEach(enemy => {// 計算方向向量const dx = playerX - enemy.x;const dy = playerY - enemy.y;// 計算距離const distance = Math.sqrt(dx * dx + dy * dy);// 標準化并應用速度if (distance > 0) {enemy.x += (dx / distance) * enemy.speed;enemy.y += (dy / distance) * enemy.speed;}// 更新DOM位置enemy.element.style.left = `${enemy.x}px`;enemy.element.style.top = `${enemy.y}px`;});}// 移動子彈function moveBullets() {bullets.forEach((bullet, index) => {// 更新子彈位置bullet.x += bullet.speedX;bullet.y += bullet.speedY;// 檢查子彈是否超出游戲區域if (bullet.x < 0 || bullet.x > gameArea.offsetWidth || bullet.y < 0 || bullet.y > gameArea.offsetHeight) {if (bullet.element.parentNode) {gameArea.removeChild(bullet.element);}bullets.splice(index, 1);return;}// 更新DOM位置bullet.element.style.left = `${bullet.x}px`;bullet.element.style.top = `${bullet.y}px`;});}// 檢查碰撞function checkCollisions() {// 檢查敵人與玩家的碰撞enemies.forEach((enemy) => {const dx = playerX - enemy.x;const dy = playerY - enemy.y;const distance = Math.sqrt(dx * dx + dy * dy);if (distance < 45) {// 玩家受到傷害health -= 2;updateUI();if (health <= 0) {gameOver();}}});// 檢查子彈與敵人的碰撞bullets.forEach((bullet, bulletIndex) => {enemies.forEach((enemy, enemyIndex) => {const dx = bullet.x - enemy.x;const dy = bullet.y - enemy.y;const distance = Math.sqrt(dx * dx + dy * dy);if (distance < 25) {// 擊中敵人enemy.health -= 10;// 移除子彈if (bullet.element.parentNode) {gameArea.removeChild(bullet.element);}bullets.splice(bulletIndex, 1);// 檢查敵人是否被消滅if (enemy.health <= 0) {if (enemy.element.parentNode) {gameArea.removeChild(enemy.element);}enemies.splice(enemyIndex, 1);// 增加分數score += 100;updateUI();// 如果所有敵人都被消滅,生成新的敵人if (enemies.length === 0) {playerLevel++;generateEnemies(5 + playerLevel);generateItems(3);showMessage(`等級提升!當前等級: ${playerLevel}`);updateUI();}}}});});}// 檢查物品拾取function checkItemPickups() {items.forEach((item, index) => {const dx = playerX - item.x;const dy = playerY - item.y;const distance = Math.sqrt(dx * dx + dy * dy);if (distance < 35) {// 拾取物品if (item.element.parentNode) {gameArea.removeChild(item.element);}items.splice(index, 1);// 根據物品類型應用效果switch (item.type) {case 'weapon':playerWeapon = 'M416';maxAmmo = 30;ammo = maxAmmo;showMessage('獲得了 M416 步槍!');break;case 'health':healthKits += 1;showMessage('獲得了醫療包!');break;case 'ammo':ammoPacks += 1;showMessage('獲得了彈藥包!');break;}updateUI();}});}// 發射武器function fireWeapon() {if (playerWeapon === '無') {showMessage('沒有武器!');return;}if (ammo <= 0) {showMessage('需要裝彈!');return;}// 創建子彈const bullet = document.createElement('div');bullet.className = 'bullet';// 設置子彈初始位置(玩家前方)const bulletSize = 8;const bulletX = playerX + 30;const bulletY = playerY;bullet.style.left = `${bulletX}px`;bullet.style.top = `${bulletY}px`;gameArea.appendChild(bullet);// 設置子彈方向(向右移動)const speed = 5;// 添加子彈到數組bullets.push({element: bullet,x: bulletX,y: bulletY,speedX: speed,speedY: 0});// 減少彈藥ammo--;updateUI();}// 裝彈function reloadWeapon() {if (playerWeapon === '無') {showMessage('沒有武器!');return;}if (ammoPacks <= 0) {showMessage('沒有彈藥包!');return;}ammoPacks--;ammo = maxAmmo;showMessage('裝彈完成!');updateUI();}// 處理按鍵事件function handleKeyPress(e) {const speed = 10;switch (e.key.toLowerCase()) {case 'arrowup':case 'w':playerY = Math.max(20, playerY - speed);break;case 'arrowdown':case 's':playerY = Math.min(gameArea.offsetHeight - 20, playerY + speed);break;case 'arrowleft':case 'a':playerX = Math.max(20, playerX - speed);break;case 'arrowright':case 'd':playerX = Math.min(gameArea.offsetWidth - 20, playerX + speed);break;case 'f':fireWeapon();break;case 'r':reloadWeapon();break;case 'h':useHealthKit();break;}// 更新玩家位置player.style.left = `${playerX}px`;player.style.top = `${playerY}px`;}// 使用醫療包function useHealthKit() {if (healthKits <= 0) {showMessage('沒有醫療包!');return;}healthKits--;health = Math.min(100, health + 50);showMessage('使用了醫療包!');updateUI();}// 更新UIfunction updateUI() {scoreElement.textContent = score;healthBar.style.width = `${health}%`;ammoBar.style.width = `${(ammo / maxAmmo) * 100}%`;weaponName.textContent = playerWeapon;healthCount.textContent = healthKits;ammoCount.textContent = ammoPacks;levelElement.textContent = playerLevel;}// 顯示消息function showMessage(text) {message.textContent = text;message.classList.add('show');setTimeout(() => {message.classList.remove('show');}, 2000);}// 游戲結束function gameOver() {clearInterval(gameInterval);clearInterval(bulletInterval);showMessage(`游戲結束!最終得分: ${score}`);document.removeEventListener('keydown', handleKeyPress);// 3秒后重新開始游戲setTimeout(initGame, 3000);}// 啟動游戲window.onload = initGame;</script>
</body>
</html>