翼度科技»论坛 编程开发 JavaScript 查看内容

我的第一个项目(十一) :飞机大战分包完成(简单阐述分包思路以及过程)

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
好家伙,

 
代码已开源
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安装
  1. <strong>npm install panghu-planebattle-modular</strong>
复制代码
 
第二步:导入到某个.vue文件或html文件
通过import导入
 
第三步:划一个区域给这个包去渲染游戏
 剩下的他就不用管了
大概是这么个过程,然后我们按着这个思路,反向去分我们这个包
 
先来看看原先的完整代码:
完整代码
  1. <strong><template>
  2.    
  3.     <h1>欢迎来到主页面</h1>
  4.       
  5.    
  6.   </template>
  7.   
  8.   
  9.   
  10.   
  11.   
  12.   </strong>
复制代码
Helloworld.vue

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

 看main,(这个可以自己调的)
由上图可知,这个包的入口就是index.js了
 
  1. <strong>//index.js
  2. export { canvas } from "./config"
  3. export { main_1 } from "./main"</strong>
复制代码
config.js中的canvas
  1. <strong>export let canvas = document.createElement('canvas');
  2. canvas.width = 480;
  3. canvas.height = 650;
  4. canvas.ref = canvas;
  5. canvas.style = "border: 1px solid red;"</strong>
复制代码
main.js中的main
  1. <strong>export let main_1 = new Main()</strong>
复制代码
 
在这里,用上我们前几天学的语法(嘿嘿)

 
分包完成
 
 

来源:https://www.cnblogs.com/FatTiger4399/p/17322997.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具