我的第一个项目(十一) :飞机大战分包完成(简单阐述分包思路以及过程)
好家伙,代码已开源
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行,这,没人想维护的,复制粘贴都嫌累
(再看一眼就要爆炸)
我们要实现一个这样的效果(事实上也实现了)
而事实上,就是三行代码:
<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.clientX;
62 // let y = e.touches.clinetY;
63 let x = e.touches.pageX;
64 let y = e.touches.pageY;
65 // let x = e.touches.screenX;
66 // let y = e.touches.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.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.hit(hero)) {
104 //将敌机和英雄的destory属性改为true
105 enemies.collide();
106 hero.collide();
107 }
108 for (let j = 0; j < hero.bulletList.length; j++) {
109 enemies.hit(hero.bulletList);
110 //检测子弹是否撞到敌机
111 if (enemies.hit(hero.bulletList)) {
112 //将敌机和子弹的destory属性改为true
113 enemies.collide();
114 hero.bulletList.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.move();
142 }
143 for (let i = 0; i < enemies.length; i++) {
144 enemies.move();
145 }
146 for (let i = 0; i < awards.length; i++) {
147 awards.move();
148 }
149 }
150 // 全局函数 来绘制所有的子弹/敌人组件 绘制score&life面板
151 function paintComponent() {
152 for (let i = 0; i < hero.bulletList.length; i++) {
153 hero.bulletList.paint(context);
154 }
155 for (let i = 0; i < enemies.length; i++) {
156 enemies.paint(context);
157 }
158 for (let i = 0; i < awards.length; i++) {
159 awards.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.outOfBounds() || hero.bulletList.destory) {
184 hero.bulletList.splice(i, 1);
185 }
186 }
187 for (let i = 0; i < enemies.length; i++) {
188 if (enemies.outOfBounds() || enemies.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】 我们会及时删除侵权内容,谢谢合作!
页:
[1]