我的第一个项目(十一) :飞机大战分包完成(简单阐述分包思路以及过程)
好家伙,
(相关资料图)
代码已开源
Git:
https://gitee.com/tang-and-han-dynasties/panghu-planebattle-esm.git
NPM:
panghu-planebattle-esm - npm (npmjs.com)现在,比如说,我用Vue写好了个人博客主页的前端
我想在这个主页里面加点东西,让我的博客更缤纷多彩一点
我想在他的主页里面塞个小游戏,他会怎么做
1.思考步骤如下:
第一步:去网上找个小游戏的资源,将这个包下载到本地,
诶,正好发现有个飞机大战 panghu-planebattle-modular小游戏开发好了
我可以直接下载,或者通过npm安装
npm install panghu-planebattle-modular
第二步:导入到某个.vue文件或html文件
通过import导入
第三步:划一个区域 剩下的他就不用管了 大概是这么个过程,然后我们按着这个思路,反向去分我们这个包 先来看看原先的完整代码: 完整代码 一看,738行,这,没人想维护的,复制粘贴都嫌累 (再看一眼就要爆炸) 我们要实现一个这样的效果(事实上也实现了) 而事实上,就是三行代码: 让使用者操作的部分由738行代码变成3行代码 将程序主要分成下面几个需要处理的部分 1、静态的:图片,图片地址,配置项 2、六个小类:Enemy、Hero、Loading、Sky、Award、Bullet 3、主启动类:Main 4、全局方法,全局变量 5、入口(对外导出的对象) 项目目录结构如下: 1.图片 2.配置项 首先是配置项config.js 我们将所有的配置项文件都放在这里,全局变量也放在这里 3.其中六个小类,我把他们"独立"分开 比如Bullet(子弹类) 这里需要提一嘴的是,类的导出必须带 default,否则会报错 4.主启动类main 我们将所有曾经的全局方法,还有定时器都封装到这个类中 最后新建一个实例,并导出 5.包的入口 首先看一眼package.json 看main,(这个可以自己调的) 由上图可知,这个包的入口就是index.js了 config.js中的canvas main.js中的main 在这里,用上我们前几天学的语法(嘿嘿) 分包完成
Helloworld.vue欢迎来到主页面
//从包中导入canvas,main_1import { canvas, main_1 } from "panghu-planebattle-modular"//dom操作添加canvasthis.$refs.stage.appendChild(canvas); //调用main_1的maingame方法main_1.maingame();
//初始化一个子弹类class Bullet { constructor(config, x, y) { this.img = config.img; this.width = config.width; this.height = config.height; this.x = x; this.y = y; this.destory = false; } //子弹绘制方法 paint(context) { context.drawImage(this.img, this.x, this.y); } //移动子弹 this.y-- move() { this.y -= 8; } outOfBounds() { //如果返回的是真的话 那么我们应该销毁掉这个子弹 return this.y < -this.height; } collide() { //让这颗子弹变成可销毁状态 this.destory = true; }}export default Bullet
export default Bullet
1 import Enemy from "./enemy" 2 import Hero from "./hero" 3 import Loading from "./loading" 4 import Sky from "./sky" 5 import Award from "./award" 6 7 import { START, STARTING, RUNNING, PAUSE, END } from "./config" 8 import { SKY, LOADING, HERO, E1, E2, E3, C1 } from "./config" 9 import { bg, copyright, pause } from "./config" 10 import { canvas, context } from "./config" 11 12 class Main { 13 //以下全为全局变量或方法 (全局的!!) 14 //初始化一个天空实例 15 //主启动方法 16 maingame() { 17 const sky = new Sky(SKY); 18 //初始化一个飞机界面加载实例 19 const loading = new Loading(LOADING); 20 //初始化一个英雄实例 英雄是会变的 21 let hero = new Hero(HERO); 22 //该变量中有所有的敌机实例 23 let enemies = []; 24 //该变量中存放所有的奖励实例 25 let awards = []; 26 //敌机产生的速率 27 let ENEMY_CREATE_INTERVAL = 800; 28 let ENEMY_LASTTIME = new Date().getTime(); 29 30 function stateControl() { 31 //为canvas绑定一个点击事件 且他如果是START状态的时候需要修改成STARTING状态 32 canvas.addEventListener("click", () => { 33 if (state === START) { 34 state = STARTING; 35 } 36 }); 37 // 为canvas绑定一个鼠标移动事件 鼠标正好在飞机图片的正中心 38 canvas.addEventListener("mousemove", (e) => { 39 let x = e.offsetX; 40 let y = e.offsetY; 41 hero.x = x - hero.width / 2; 42 hero.y = y - hero.height / 2; 43 }); 44 // 为canvas绑定一个鼠标离开事件 鼠标离开时 RUNNING -> PAUSE 45 canvas.addEventListener("mouseleave", () => { 46 if (state === RUNNING) { 47 state = PAUSE; 48 } 49 }); 50 // 为canvas绑定一个鼠标进入事件 鼠标进入时 PAUSE => RUNNING 51 canvas.addEventListener("mouseenter", () => { 52 if (state === PAUSE) { 53 state = RUNNING; 54 } 55 }); 56 //为canvas绑定一个屏幕移动触摸点事件 触碰点正好在飞机图片的正中心 57 canvas.addEventListener("touchmove", (e) => { 58 // let x = e.pageX; 59 // let y = e.pageY; 60 console.log(e); 61 // let x = e.touches[0].clientX; 62 // let y = e.touches[0].clinetY; 63 let x = e.touches[0].pageX; 64 let y = e.touches[0].pageY; 65 // let x = e.touches[0].screenX; 66 // let y = e.touches[0].screenY; 67 let write1 = (document.body.clientWidth - 480) / 2; 68 let write2 = (document.body.clientHeight - 650) / 2; 69 hero.x = x - write1 - hero.width / 2; 70 hero.y = y - write2 - hero.height / 2; 71 72 // hero.x = x - hero.width / 2; 73 // hero.y = y - hero.height / 2; 74 console.log(x, y); 75 console.log(document.body.clientWidth, document.body.clientHeight); 76 e.preventDefault(); // 阻止屏幕滚动的默认行为 77 78 }) 79 } 80 stateControl(); 81 // 碰撞检测函数 82 //此处的碰撞检测包括 83 //1.子弹与敌机的碰撞 84 //2.英雄与敌机的碰撞 85 //3.英雄与随机奖励的碰撞 86 function checkHit() { 87 // 遍历所有的敌机 88 for (let i = 0; i < awards.length; i++) { 89 //检测英雄是否碰到奖励类 90 if (awards[i].hit(hero)) { 91 //当然了,这个随机奖励的样式也要删了 92 awards.splice(i, 1); 93 //清除所有的敌机 94 // for (let i = 0; i < enemies.length; i++) { 95 // enemies.splice(i, 1); 96 // } 97 enemies.length = 0; 98 99 }100 }101 for (let i = 0; i < enemies.length; i++) {102 //检测英雄是否撞到敌机103 if (enemies[i].hit(hero)) {104 //将敌机和英雄的destory属性改为true105 enemies[i].collide();106 hero.collide();107 }108 for (let j = 0; j < hero.bulletList.length; j++) {109 enemies[i].hit(hero.bulletList[j]);110 //检测子弹是否撞到敌机111 if (enemies[i].hit(hero.bulletList[j])) {112 //将敌机和子弹的destory属性改为true113 enemies[i].collide();114 hero.bulletList[j].collide();115 }116 }117 }118 }119 // 全局函数 隔一段时间就来初始化一架敌机/奖励120 function createComponent() {121 const currentTime = new Date().getTime();122 if (currentTime - ENEMY_LASTTIME >= ENEMY_CREATE_INTERVAL) {123 let ran = Math.floor(Math.random() * 100);124 if (ran < 55) {125 enemies.push(new Enemy(E1));126 } else if (ran < 85 && ran > 55) {127 enemies.push(new Enemy(E2));128 } else if (ran < 95 && ran > 85) {129 enemies.push(new Enemy(E3));130 } else if (ran > 95) {131 awards.push(new Award(C1));132 133 }134 135 ENEMY_LASTTIME = currentTime;136 }137 }138 // 全局函数 来判断所有的子弹/敌人组件 "负责移动"139 function judgeComponent() {140 for (let i = 0; i < hero.bulletList.length; i++) {141 hero.bulletList[i].move();142 }143 for (let i = 0; i < enemies.length; i++) {144 enemies[i].move();145 }146 for (let i = 0; i < awards.length; i++) {147 awards[i].move();148 }149 }150 // 全局函数 来绘制所有的子弹/敌人组件 绘制score&life面板151 function paintComponent() {152 for (let i = 0; i < hero.bulletList.length; i++) {153 hero.bulletList[i].paint(context);154 }155 for (let i = 0; i < enemies.length; i++) {156 enemies[i].paint(context);157 }158 for (let i = 0; i < awards.length; i++) {159 awards[i].paint(context);160 }161 context.font = "20px 微软雅黑";162 context.fillStyle = "green";163 context.textAlign = "left";164 context.fillText("score: " + score, 10, 20);165 context.textAlign = "right";166 context.fillText("life: " + life, 480 - 10, 20);167 //重置样式168 context.fillStyle = "black";169 context.textAlign = "left";170 }171 // 全局函数 来销毁所有的子弹/敌人组件 销毁掉英雄172 function deleteComponent() {173 if (hero.destory) {174 life--;175 hero.destory = false;176 if (life === 0) {177 state = END;178 } else {179 hero = new Hero(HERO);180 }181 }182 for (let i = 0; i < hero.bulletList.length; i++) {183 if (hero.bulletList[i].outOfBounds() || hero.bulletList[i].destory) {184 hero.bulletList.splice(i, 1);185 }186 }187 for (let i = 0; i < enemies.length; i++) {188 if (enemies[i].outOfBounds() || enemies[i].destory) {189 enemies.splice(i, 1);190 }191 }192 }193 194 //当图片加载完毕时,需要做某些事情195 bg.addEventListener("load", () => {196 setInterval(() => {197 switch (state) {198 case START:199 sky.judge();200 sky.paint(context);201 let logo_x = (480 - copyright.naturalWidth) / 2;202 let logo_y = (650 - copyright.naturalHeight) / 2;203 context.drawImage(copyright, logo_x, logo_y);204 break;205 case STARTING:206 sky.judge();207 sky.paint(context);208 loading.judge();209 loading.paint(context);210 break;211 case RUNNING:212 sky.judge();213 sky.paint(context);214 hero.judge();215 hero.paint(context);216 hero.shoot(context);217 createComponent();218 judgeComponent();219 deleteComponent();220 paintComponent();221 checkHit();222 break;223 case PAUSE:224 let pause_x = (480 - pause.naturalWidth) / 2;225 let pause_y = (650 - pause.naturalHeight) / 2;226 context.drawImage(pause, pause_x, pause_y);227 break;228 case END:229 //给我的画笔设置一个字的样式230 //后面写出来的字都是这个样式的231 context.font = "bold 24px 微软雅黑";232 context.textAlign = "center";233 context.textBaseline = "middle";234 context.fillText("GAME_OVER", 480 / 2, 650 / 2);235 break;236 }237 }, 10);238 });239 240 241 //背景切换方法242 // function changebg() {243 // console.log("changebg方法被触发")244 // bg.src = "img/background.png"245 // }246 }247 }248 export let main_1 = new Main()249 // export default Main
main.js//index.jsexport { canvas } from "./config"export { main_1 } from "./main"
export let canvas = document.createElement("canvas");canvas.width = 480;canvas.height = 650;canvas.ref = canvas;canvas.style = "border: 1px solid red;"
export let main_1 = new Main()