飞机大战-小游戏实现
设计
目前会把整个游戏分成四个类
-
引擎
-
飞机
-
子弹
-
敌机
-
HTML代码
<div class="main"> <ul class="options"> <li>简单模式</li> <li>一般模式</li> <li>地狱模式</li> <li>春哥附体</li> </ul> </div> <div class="mask"></div>
-
CSS代码
*{ margin:0; padding:0; } html,body{ width:100%; height:100%; overflow: hidden; } .main{ margin: auto; height: 100%; background: url(images/bg.jpg) repeat-y; background-position-y: 0px; width: 480px; } .options{ position: absolute; list-style: none; margin: auto; left: 0; right: 0; top: 100px; width: 200px; height: 300px; } .options li{ border-radius: 5px; box-shadow: 0 0 2px 1px black; float: left; width: 200px; height: 75px; text-align: center; line-height: 75px; margin-bottom: 20px; background: #f40; color: white; font: "微软雅黑"; font-size: 28px; cursor: pointer; } .logo{ position: absolute; left: 0; right: 0; top: 25%; margin: auto; width: 428px; height: 104px; background: url(images/logo.png) no-repeat; } .loading{ position: absolute; left: 0; right: 0; top: 60%; margin: auto; width: 192px; height: 41px; background: url(images/loading1.png) no-repeat; } .my-warplane{ position: absolute; width: 98px; height: 122px; background: url(images/me.png) no-repeat; } .bullet{ position: absolute; width: 7px; height: 18px; background: url(images/bullet.png) no-repeat; } .bullet_die{ position: absolute; width: 41px; height: 39px; background: url(images/die1.png) no-repeat; margin-left: -17px; } .enemy-small{ position: absolute; width: 59px; height: 36px; background: url(images/plane1.png) no-repeat; } .enemy-middle{ position: absolute; width: 70px; height: 92px; background: url(images/plane2.png) no-repeat; } .enemy-large{ position: absolute; width:165px; height: 256px; background: url(images/plane3.png) no-repeat; } .mask{ width: 100%; height: 100%; position: fixed; top: 0; left: 0; z-index: -10; } .mask.active{ z-index: 999; animation:die 0.5s infinite; } @keyframes die{ 0%{ background-color: rgba(0, 0, 0, 0); } 50%{ background-color: rgba(0, 0, 0, 0.3); } 50%{ background-color: rgba(235, 0, 0, 0.3); } }
-
JavaScript代码
//引擎类 class Engine{ constructor(){ this.btns = document.querySelectorAll(".options li"); this.options = document.querySelector(".options"); this.main = document.querySelector(".main"); // 这个数据是给plane类用的; this.main_width = this.main.offsetWidth; // 选择的游戏难度等级; this.level = null; // 保存背景的位移位置; this.bgposition = 0; this.bindEvent(); } bindEvent() { this.btns.forEach((ele, index) => { ele.onclick = () => { this.level = index; this.showAnimate(); setTimeout(() => { this.hideAnimate(); this.bgAnaimte(); this.gameStart(); }, 1000) } }) } // 展示开场动画; showAnimate() { // 开场动画部分 : // 清场 : this.options.remove(); // 元素入场 : this.logo = createEle("logo"); this.loading = createEle("loading"); // 循环执行123的数值; // - 我们在javascript之中实现的所有动画效果其实不是对css属性的赋值就是对类名改变; // - 如果多个元素的动作行为组合在一起用定时器执行就是我们需要的动画效果; let num = 0; this.loading_t = setInterval(() => { this.loading.style.background = `url(images/loading${(++num % 3) + 1}.png) no-repeat`; }, 500) } // 隐藏开场动画; hideAnimate() { // 清场 : this.logo.remove(); this.loading.remove(); clearInterval(this.loading_t); } // 背景动画; bgAnaimte() { this.bg_t = setInterval(() => { this.bgposition += 40; this.main.style.backgroundPositionY = this.bgposition + "px"; }, 100) } // 游戏开启; gameStart() { this.plane = new Plane(); this.createEnemy(); } // 游戏暂停; pause() { clearInterval(this.bg_t); } // 游戏恢复 ; start() { this.bgAnaimte(); } createEnemy() { // 小飞机定时器; this.small_enemy_t = setInterval(function () { new Enemy; }, 2000) //中型飞机定时器 this.middle_enemy_t = setInterval(function () { new Enemy(1); }, 5000) //大型飞机定时器 this.middle_enemy_t = setInterval(function () { new Enemy(2); }, 15000) } } // 复用的组件我们单独提取并封装; function createEle(className) { var div = document.createElement("div"); div.className = className; document.body.appendChild(div); return div; } function getRandomInt(min, max) { return min + Math.round((max - min) * Math.random()) } let engine = new Engine; //飞机类 class Plane{ constructor() { this.plane = createEle("my-warplane"); this.plane_width = this.plane.offsetWidth; this.plane_height = this.plane.offsetHeight; // 求得飞机x和y的最大最小值; this.min_x = (innerWidth - engine.main_width) / 2; this.max_x = this.min_x + engine.main_width - this.plane_width; this.x = innerWidth / 2 - this.plane_width / 2; this.hp = 100; this.bullet_list = []; this.init(); this.bindEvent(); this.fire(); } init() { this.plane.style.bottom = 0; this.plane.style.left = this.x + "px"; } bindEvent() { document.addEventListener("mousemove", e => { this.move(e.clientX - this.plane_width / 2) }); window.addEventListener("resize", e => { this.min_x = (innerWidth - engine.main_width) / 2; this.max_x = this.min_x + engine.main_width - this.plane_width; }) } move(x) { // 边间检测 ; x = x < this.min_x ? this.min_x : x; x = x > this.max_x ? this.max_x : x; this.plane.style.left = x + "px"; this.x = x; } fire() { // 1. 发射子弹的频率是engine选择难度之后根据难度数据做出的逻辑; // 2. 每次都创建一个新的子弹对象,让子弹可以直接飞出去; // 3. 记录了当前子弹的实例对象; this.fire_t = setInterval(() => { this.bullet_list.push(new Bullet(this.x, this.plane_height, this.plane_width, this.bullet_list)); }, engine.level === 3 ? 50 : (engine.level + 1) * 200) } } //子弹类 class Bullet{ constructor(x, height, width, arr) { if (x === null) { return false; } this.bullet = createEle("bullet"); this.x = x + width / 2 - 3; this.y = innerHeight - height - 30; // 存放子弹的数组; this.arr = arr; this.init(); this.move(); } move() { this.t = setInterval(() => { this.y -= 18; this.bullet.style.top = this.y + "px"; if (this.y <= 0) { this.destory(); } }, 30) } destory() { this.bullet.className = "bullet_die"; clearInterval(this.t); this.arr.splice(this.arr.indexOf(this), 1); // 在飞机的数组之中删除掉对应的元素; setTimeout(() => { this.bullet.remove(); }, 200) } } //敌机类 // 敌机创建分成三个类别, 小飞机中飞机大飞机; // - 1. 类名; // - 2. 速度不一样; // - 3. hp差距; class Enemy{ constructor(type = 0, x) { this.mask = document.querySelector(".mask"); this.list = [ { className: "enemy-small", speed: 15, hp: 1, dieList: [ "plane1_die1.png", "plane1_die2.png", "plane1_die3.png", ], width: 59, height: 36 }, { className: "enemy-middle", speed: 8, hp: 5, dieList: [ "plane2_die1.png", "plane2_die2.png", "plane2_die3.png", "plane2_die4.png", ], width: 70, height: 92 }, { className: "enemy-large", speed: 2, hp: 20, dieList: [ "plane3_die1.png", "plane3_die2.png", "plane3_die3.png", "plane3_die4.png", "plane3_die5.png", "plane3_die6.png", ], width: 165, height: 256 } ] Object.assign(this, this.list[type]) this.y = 0; this.enemy = createEle(this.className); this.min_x = (innerWidth - engine.main_width) / 2; this.max_x = this.min_x + engine.main_width - this.enemy.offsetWidth; this.x = x || getRandomInt(this.min_x, this.max_x) this.init(); this.move(); } init() { this.enemy.style.top = this.y + "px"; this.enemy.style.left = this.x + "px"; } move() { this.enemy_t = setInterval(() => { this.y += this.speed; this.enemy.style.top = this.y + "px"; // 碰撞检测; this.collision() if (this.y >= innerHeight) { this.enemy.remove(); clearInterval(this.enemy_t); } }, 50) } destory() { clearInterval(this.enemy_t); // 动画效果; let die_t = setInterval(() => { var url = this.dieList.shift(); this.enemy.style.background = `url(images/${url}) no-repeat`; // 如果死亡动画列表已经播放结束我们就关闭定时器, 同时在100毫秒之后删除当前元素; if (this.dieList.length === 0) { clearInterval(die_t); setTimeout(() => { this.enemy.remove(); }, 100) } }, 200) } // 碰撞检测和边界检测一样; // 找极值 : left 的极值, top的极值; collision() { // this.x , this.y ; let { plane } = engine let { bullet_list } = plane; bullet_list.forEach(bullet => { // 原理见图片; if ((bullet.y >= this.y && bullet.y <= this.y + this.height + 20) && (bullet.x >= this.x && bullet.x <= this.x + this.width)) { bullet.destory(); // 碰撞之后飞机应该让hp-1; this.hp--; if (this.hp <= 0) { this.destory(); } } }) // 判定战机和敌机的状态; // 碰撞检测 ; if (this.y + this.height >= innerHeight - 122) { if (plane.x >= this.x - plane.plane_width && plane.x <= this.x + this.width) { plane.hp--; this.hp--; if (this.hp <= 0) { this.destory(); } if (plane.hp <= 0) { alert("游戏结束"); location.reload(); } this.mask.classList.add("active"); clearTimeout(this.collision_t); this.collision_t = setTimeout(() => { this.mask.classList.remove("active"); }, 2000) } } } }
原创不易,转载请注明出处。