|
好家伙,
代码已开源
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安装- <strong>npm install panghu-planebattle-modular</strong>
复制代码
第二步:导入到某个.vue文件或html文件
通过import导入
第三步:划一个区域给这个包去渲染游戏
剩下的他就不用管了
大概是这么个过程,然后我们按着这个思路,反向去分我们这个包
先来看看原先的完整代码:
完整代码
- <strong><template>
-
- <h1>欢迎来到主页面</h1>
-
-
- </template>
-
-
-
-
-
- </strong>
复制代码 Helloworld.vue
一看,738行,这,没人想维护的,复制粘贴都嫌累
(再看一眼就要爆炸)
我们要实现一个这样的效果(事实上也实现了)- [/code][b] [/b]
- [b]而事实上,就是三行代码:[/b]
- [code]<strong>//从包中导入canvas,main_1
- import { canvas, main_1 } from "panghu-planebattle-modular"
- //dom操作添加canvas
- this.$refs.stage.appendChild(canvas);
-
- //调用main_1的maingame方法
- main_1.maingame();</strong>
复制代码
让使用者操作的部分由738行代码变成3行代码
2.开始分包
将程序主要分成下面几个需要处理的部分
1、静态的:图片,图片地址,配置项
2、六个小类:Enemy、Hero、Loading、Sky、Award、Bullet
3、主启动类:Main
4、全局方法,全局变量
5、入口(对外导出的对象)
项目目录结构如下:
1.图片
2.配置项
首先是配置项config.js
我们将所有的配置项文件都放在这里,全局变量也放在这里
如果将来我们要调参数,比如说,改改图片,改改子弹的速度之类,就直接在这个文件里改就行了
3.其中六个小类,我把他们"独立"分开
比如Bullet(子弹类)- <strong>//初始化一个子弹类
- 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 </strong>
复制代码
这里需要提一嘴的是,类的导出必须带 default,否则会报错- <strong>export default Bullet </strong>
复制代码
4.主启动类main
我们将所有曾经的全局方法,还有定时器都封装到这个类中
最后新建一个实例,并导出
- <strong> 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属性改为true
- 105 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属性改为true
- 113 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 </strong>
复制代码 main.js
5.包的入口
首先看一眼package.json
看main,(这个可以自己调的)
由上图可知,这个包的入口就是index.js了
- <strong>//index.js
- export { canvas } from "./config"
- export { main_1 } from "./main"</strong>
复制代码 config.js中的canvas- <strong>export let canvas = document.createElement('canvas');
- canvas.width = 480;
- canvas.height = 650;
- canvas.ref = canvas;
- canvas.style = "border: 1px solid red;"</strong>
复制代码 main.js中的main- <strong>export let main_1 = new Main()</strong>
复制代码
在这里,用上我们前几天学的语法(嘿嘿)
分包完成
来源:https://www.cnblogs.com/FatTiger4399/p/17322997.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|