|
|
你好!我帮你写了一个更漂亮、更刺激的飞机大战小游戏,支持计分和排名(排行榜会保存在浏览器里),这样你每次玩都能看到自己的分数排第几哦。下面是完整代码,你可以直接保存为`plane_game.html`打开玩。
---
- <!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <title>超级飞机大战 - 带排行榜</title>
- <style>
- /* 背景渐变和中心游戏区 */
- body, html {
- margin: 0; padding: 0; height: 100%;
- background: linear-gradient(to bottom, #00111f, #000);
- font-family: "微软雅黑", sans-serif;
- overflow: hidden;
- user-select: none;
- }
- #game {
- position: relative;
- width: 400px;
- height: 600px;
- margin: 20px auto;
- background: linear-gradient(to bottom, #002240, #000010);
- border-radius: 15px;
- box-shadow: 0 0 20px #0af;
- overflow: hidden;
- }
- /* 飞机 */
- #player {
- position: absolute;
- width: 50px;
- height: 50px;
- bottom: 15px;
- left: 175px;
- background: url('https://cdn-icons-png.flaticon.com/512/6326/6326193.png') no-repeat center / contain;
- filter: drop-shadow(0 0 5px #0ff);
- transition: filter 0.2s;
- z-index: 10;
- }
- #player.damaged {
- filter: drop-shadow(0 0 13px red);
- }
- /* 子弹 */
- .bullet {
- position: absolute;
- width: 10px;
- height: 20px;
- background: linear-gradient(90deg, #00ffff, #006677);
- border-radius: 5px;
- filter: drop-shadow(0 0 6px #0ff);
- z-index: 9;
- }
- /* 敌机 */
- .enemy {
- position: absolute;
- width: 50px;
- height: 50px;
- background: url('https://cdn-icons-png.flaticon.com/512/616/616489.png') no-repeat center / contain;
- filter: drop-shadow(0 0 7px #f44);
- transition: transform 0.15s ease;
- z-index: 8;
- }
- .enemy.damaged {
- transform: scale(1.2);
- }
- /* 爆炸动画 */
- .explosion {
- position: absolute;
- width: 60px;
- height: 60px;
- background: url('https://i.ibb.co/1rvdWgF/explosion.png') no-repeat center / contain;
- animation: explode 0.5s ease forwards;
- pointer-events: none;
- z-index: 20;
- }
- @keyframes explode {
- 0% {opacity: 1; transform: scale(1);}
- 100% {opacity: 0; transform: scale(1.8);}
- }
- /* 顶部状态栏 */
- #infoBar {
- color: #0ff;
- text-align: center;
- font-size: 20px;
- letter-spacing: 2px;
- margin-top: 10px;
- user-select:none;
- }
- #hp {
- color: #f44;
- font-weight: bold;
- margin-left: 20px;
- }
- /* 排行榜弹窗 */
- #rankOverlay {
- display: none;
- position: fixed;
- top: 0; left: 0; right: 0; bottom: 0;
- background: rgba(0,0,0,0.75);
- z-index: 50;
- justify-content: center;
- align-items: center;
- }
- #rankBox {
- background: #002a4e;
- padding: 20px 30px;
- border-radius: 12px;
- width: 320px;
- max-height: 80vh;
- overflow-y: auto;
- color: #0ff;
- }
- #rankBox h2 {
- margin-top: 0;
- text-align: center;
- }
- #rankList {
- margin-top: 10px;
- }
- #rankList li {
- line-height: 1.6em;
- font-size: 18px;
- }
- #closeRankBtn {
- display: block;
- margin: 15px auto 0;
- background: #0ff;
- border: none;
- padding: 10px 20px;
- border-radius: 8px;
- cursor: pointer;
- font-weight: bold;
- color: #002a4e;
- transition: background-color 0.3s;
- }
- #closeRankBtn:hover {
- background: #06e;
- color: white;
- }
- /* 提示文字 */
- #tip {
- text-align: center;
- color: #08f;
- font-size: 14px;
- margin-bottom: 4px;
- }
- </style>
- </head>
- <body>
- <div id="tip">左右方向键或A/D移动,空格发射子弹</div>
- <div id="game" tabindex="0">
- <div id="player"></div>
- </div>
- <div id="infoBar">得分: 0 <span id="hp">❤❤❤</span></div>
- <!-- 排行榜弹窗 -->
- <div id="rankOverlay">
- <div id="rankBox">
- <h2>排行榜 Top 10</h2>
- <ol id="rankList"></ol>
- <button id="closeRankBtn">关闭</button>
- </div>
- </div>
- <script>
- (() => {
- const game = document.getElementById('game');
- const player = document.getElementById('player');
- const scoreBoard = document.getElementById('infoBar');
- const hpDisplay = document.getElementById('hp');
- const rankOverlay = document.getElementById('rankOverlay');
- const rankList = document.getElementById('rankList');
- const closeRankBtn = document.getElementById('closeRankBtn');
- const gameWidth = game.clientWidth;
- const gameHeight = game.clientHeight;
- let playerX = (gameWidth - player.clientWidth) / 2;
- const playerWidth = player.clientWidth;
- const playerHeight = player.clientHeight;
- let bullets = [];
- let enemies = [];
- let score = 0;
- let hp = 3;
- let isGameOver = false;
- // 敌机速度和生成间隔随分数增长
- let enemySpeedBase = 2.5;
- let enemySpawnInterval = 1300;
- // 控制发射频率,避免按着空格连发太快
- let lastShootTime = 0;
- const shootCooldown = 250;
- // 控制玩家移动状态
- let movingLeft = false;
- let movingRight = false;
- // 初始化位置
- player.style.left = playerX + 'px';
- // 键盘事件监听
- window.addEventListener('keydown', (e) => {
- if (isGameOver) return;
- if (e.code === "ArrowLeft" || e.key.toLowerCase() === 'a') {
- movingLeft = true;
- } else if (e.code === "ArrowRight" || e.key.toLowerCase() === 'd') {
- movingRight = true;
- } else if (e.code === "Space") {
- e.preventDefault();
- shootBullet();
- }
- });
- window.addEventListener('keyup', (e) => {
- if (e.code === "ArrowLeft" || e.key.toLowerCase() === 'a') {
- movingLeft = false;
- } else if (e.code === "ArrowRight" || e.key.toLowerCase() === 'd') {
- movingRight = false;
- }
- });
- // 发射子弹
- function shootBullet(){
- if(isGameOver) return;
- const now = Date.now();
- if(now - lastShootTime < shootCooldown) return;
- lastShootTime = now;
- const bullet = document.createElement('div');
- bullet.className = 'bullet';
- const startX = playerX + playerWidth/2 - 5;
- const startY = playerHeight + 15;
- bullet.style.left = startX + 'px';
- bullet.style.bottom = startY + 'px';
- game.appendChild(bullet);
- bullets.push({
- el: bullet,
- x: startX,
- y: startY,
- width: 10,
- height: 20,
- speed: 10
- });
- }
- // 创建敌机,随机横向
- function createEnemy() {
- if(isGameOver) return;
- const enemy = document.createElement('div');
- enemy.className = 'enemy';
- const x = Math.random() * (gameWidth - 50);
- enemy.style.left = x + 'px';
- enemy.style.top = '-50px';
- game.appendChild(enemy);
- enemies.push({
- el: enemy,
- x: x,
- y: -50,
- width: 50,
- height: 50,
- speed: enemySpeedBase + Math.random() * 1.5
- });
- }
- // 爆炸动画效果
- function showExplosion(x, y) {
- const exp = document.createElement('div');
- exp.className = 'explosion';
- exp.style.left = (x - 5) + 'px';
- exp.style.top = (y - 5) + 'px';
- game.appendChild(exp);
- setTimeout(() => {
- exp.remove();
- }, 500);
- }
- // 分数增加后调整敌机速度和生成频率
- function levelUp() {
- enemySpeedBase = 2.5 + score*0.1;
- enemySpawnInterval = Math.max(600, 1300 - score*15);
- }
- // 矩形碰撞检测
- function rectCollide(a, b){
- return !(
- a.x > b.x + b.width ||
- a.x + a.width < b.x ||
- a.y > b.y + b.height ||
- a.y + a.height < b.y
- );
- }
- // 玩家受伤处理
- function playerHit() {
- if (isGameOver) return;
- hp--;
- updateHpDisplay();
- // 加个红色闪烁提示
- player.classList.add('damaged');
- setTimeout(() => player.classList.remove('damaged'), 300);
- if (hp <= 0) {
- gameOver();
- }
- }
- // 更新生命显示
- function updateHpDisplay(){
- hpDisplay.textContent = '❤'.repeat(hp) + '♡'.repeat(3 - hp);
- }
- // 游戏结束:弹出输入名字界面并展示排行榜
- function gameOver(){
- isGameOver = true;
- setTimeout(() => {
- const name = prompt("游戏结束!你的得分:" + score + "\n请输入你的名字(不超过10字):", "玩家");
- if(name!==null){
- saveScore(name.trim().substring(0,10), score);
- }
- showRanking();
- }, 100);
- }
- // 保存分数到本地localStorage里
- function saveScore(name, score){
- const rankData = JSON.parse(localStorage.getItem('planeRank') || '[]');
- rankData.push({name, score});
- // 按分数倒序排序
- rankData.sort((a,b) => b.score - a.score);
- // 只保留前20条
- localStorage.setItem('planeRank', JSON.stringify(rankData.slice(0,20)));
- }
- // 显示排行榜弹窗
- function showRanking(){
- rankList.innerHTML = '';
- const rankData = JSON.parse(localStorage.getItem('planeRank') || '[]');
- const len = Math.min(10, rankData.length);
- if(len === 0){
- rankList.innerHTML = '<li>暂无排名数据</li>';
- } else {
- for(let i=0; i<len; i++){
- const r = rankData[i];
- const li = document.createElement('li');
- li.textContent = `${i+1}. ${r.name} — ${r.score}分`;
- rankList.appendChild(li);
- }
- }
- rankOverlay.style.display = 'flex';
- }
- closeRankBtn.addEventListener('click', () => {
- rankOverlay.style.display = 'none';
- restartGame();
- });
- // 重置游戏数据,重新开始
- function restartGame(){
- // 清除所有敌机和子弹
- bullets.forEach(b => b.el.remove());
- enemies.forEach(e => e.el.remove());
- bullets = [];
- enemies = [];
- score = 0;
- hp = 3;
- isGameOver = false;
- updateHpDisplay();
- updateScoreDisplay();
- playerX = (gameWidth - playerWidth)/2;
- player.style.left = playerX + 'px';
- enemySpeedBase = 2.5;
- enemySpawnInterval = 1300;
- }
- // 更新分数显示
- function updateScoreDisplay(){
- scoreBoard.childNodes[0].textContent = '得分: ' + score + ' ';
- }
- // 游戏主循环
- let lastSpawnTime = 0;
- function gameLoop(time=0){
- if(isGameOver){
- requestAnimationFrame(gameLoop);
- return;
- }
- // 移动玩家
- if(movingLeft){
- playerX -= 6;
- if(playerX < 0) playerX = 0;
- }
- if(movingRight){
- playerX += 6;
- if(playerX > gameWidth - playerWidth) playerX = gameWidth - playerWidth;
- }
- player.style.left = playerX + 'px';
- // 移动子弹
- for(let i=bullets.length-1; i>=0; i--){
- let b = bullets[i];
- b.y += b.speed;
- if(b.y > gameHeight){
- b.el.remove();
- bullets.splice(i, 1);
- continue;
- }
- b.el.style.bottom = b.y + 'px';
- }
- // 移动敌机
- for(let i=enemies.length-1; i>=0; i--){
- let en = enemies[i];
- en.y += en.speed;
- if(en.y > gameHeight){
- // 到底部后对玩家造成伤害
- playerHit();
- en.el.remove();
- enemies.splice(i, 1);
- continue;
- }
- en.el.style.top = en.y + 'px';
- }
- // 碰撞检测:子弹和敌机
- for(let i=enemies.length-1; i>=0; i--){
- const en = enemies[i];
- for(let j=bullets.length-1; j>=0; j--){
- const b = bullets[j];
- // 注意坐标系:敌机用top定位,y是距离上边;子弹用bottom定位,y是距离底部
- // 为了简化,我们用相对于容器顶端的坐标计算,子弹y换算:
- const bulletTop = gameHeight - b.y - b.height;
- if(rectCollide(
- {x: en.x, y: en.y, width: en.width, height: en.height},
- {x: b.x, y: bulletTop, width: b.width, height: b.height}
- )){
- // 击中敌机
- showExplosion(en.x, en.y);
- en.el.remove();
- b.el.remove();
- enemies.splice(i, 1);
- bullets.splice(j, 1);
- score++;
- updateScoreDisplay();
- levelUp();
- break;
- }
- }
- }
- // 碰撞检测:敌机和玩家
- for(let i=enemies.length-1; i>=0; i--){
- const en = enemies[i];
- const playerTop = gameHeight - playerHeight - 15;
- if(rectCollide(
- {x: en.x, y: en.y, width: en.width, height: en.height},
- {x: playerX, y: playerTop, width: playerWidth, height: playerHeight}
- )){
- playerHit();
- showExplosion(en.x, en.y);
- en.el.remove();
- enemies.splice(i, 1);
- break;
- }
- }
- // 生成新敌机
- if(time - lastSpawnTime > enemySpawnInterval){
- createEnemy();
- lastSpawnTime = time;
- }
- requestAnimationFrame(gameLoop);
- }
- // 入口:开始游戏
- updateHpDisplay();
- updateScoreDisplay();
- game.focus();
- requestAnimationFrame(gameLoop);
- })();
- </script>
- </body>
- </html>
复制代码
---
### 玩法说明:
- 用 **左右箭头** 或者 **A、D 键** 控制飞机左右移动。
- 按空格键发射子弹。
- 敌机会从顶部出现,往下飞。
- 子弹击中敌机得分,得分越高,敌机飞得越快,出现越频繁。
- 敌机撞到飞机或到达底部会扣一颗❤,生命值耗尽游戏结束。
- 游戏结束时会弹出输入框让你输名字保存分数,并显示排行榜前十名。
- 你可以关闭排行榜继续游戏,或者刷新页面重新开始。
---
### 图片说明:
- 飞机和敌机用的是高清PNG图标,带光影和投影效果,看起来更立体好看。
- 爆炸是一个小动画图片,让战斗过程更有感觉。
---
这个程序纯前端,不需要服务器,可以保存多次游戏分数,用浏览器本地存储保持排行榜。如果打开沙盒限制导致无法保存,可以换成Chrome或其他现代浏览器试试看。
有什么想改进的,随时告诉我,帮你优化!祝你游戏开心,打败所有敌机吧!✈️???????? |
|