好家伙,
我继续尝试着将我的飞机大战使用ES6模块化分离开来,出了点问题
edge,chrome等一系列浏览器,会为了安全,禁止你跨域访问
目录如下:
主程序
index.html
main_1.js
main.js
完整代码如下:
1 /* //plane封装成类 2 //实例化后使用 3 //plane方法有: 4 // cteate 5 config 6 start 7 stop 8 pause 9 10 11 */ 12 let plane = { 13 create(dom) { 14 let canvas = document.createElement('canvas'); 15 dom.appendChild(canvas); 16 canvas.width = 480; 17 canvas.height = 650; 18 19 // 初始化画布对象 20 // const canvas = document.getElementById("canvas"); 21 const context = canvas.getContext("2d"); 22 23 // 定义游戏的状态 24 // 开始 25 const START = 0; 26 // 开始时 27 const STARTING = 1; 28 // 运行时 29 const RUNNING = 2; 30 // 暂停时 31 const PAUSE = 3; 32 // 结束时 33 const END = 4; 34 35 //创建一个配置文件 收藏所有的图片路径 36 const IMAGES = { 37 b: "img/bullet1.png", 38 bg: "img/4.jpg", 39 copyright: "img/shoot_copyright.png", 40 pause: "img/game_pause.png", 41 loading_frame: ["img/game_loading1.png", "img/game_loading2.png", "img/game_loading3.png", 42 "img/game_loading4.png" 43 ], 44 hero_frame_live: ["img/hero1.png", "img/hero2.png"], 45 hero_frame_death: ["img/hero_blowup_n1.png", "img/hero_blowup_n2.png", "img/hero_blowup_n3.png", 46 "img/hero_blowup_n4.png" 47 ], 48 e1_live: ["img/enemy1.png"], 49 e1_death: ["img/enemy1_down1.png", "img/enemy1_down2.png", "img/enemy1_down3.png", "img/enemy1_down4.png"], 50 e2_live: ["img/enemy2.png"], 51 e2_death: ["img/enemy2_down1.png", "img/enemy2_down2.png", "img/enemy2_down3.png", "img/enemy2_down4.png"], 52 e3_live: ["img/enemy3_n1.png", "img/enemy3_n2.png"], 53 e3_death: ["img/enemy3_down1.png", "img/enemy3_down2.png", "img/enemy3_down3.png", "img/enemy3_down4.png", 54 "img/enemy3_down5.png", "img/enemy3_down6.png" 55 ], 56 c1: "img/lanqiu.jpg" 57 }; 58 //初始化各个图片 59 const b = createImage(IMAGES.b); 60 const bg = createImage(IMAGES.bg); 61 const copyright = createImage(IMAGES.copyright); 62 const pause = createImage(IMAGES.pause); 63 const loading_frame = createImage(IMAGES.loading_frame); 64 const hero_frame = { 65 live: createImage(IMAGES.hero_frame_live), 66 death: createImage(IMAGES.hero_frame_death), 67 }; 68 const e1 = { 69 live: createImage(IMAGES.e1_live), 70 death: createImage(IMAGES.e1_death), 71 }; 72 const e2 = { 73 live: createImage(IMAGES.e2_live), 74 death: createImage(IMAGES.e2_death), 75 }; 76 const e3 = { 77 live: createImage(IMAGES.e3_live), 78 death: createImage(IMAGES.e3_death), 79 }; 80 const c1 = createImage(IMAGES.c1); 81 82 function createImage(src) { 83 let img; 84 if (typeof src === "string") { 85 img = new Image(); 86 img.src = src; 87 } else { 88 img = []; 89 for (let i = 0; i < src.length; i++) { 90 img[i] = new Image(); 91 img[i].src = src[i]; 92 } 93 } 94 return img; 95 } 96 97 //天空类的配置项 98 const SKY = { 99 bg: bg, 100 width: 480, 101 height: 650, 102 speed: 10, 103 }; 104 105 // 飞机加载界面的配置项 106 const LOADING = { 107 frame: loading_frame, 108 width: 186, 109 height: 38, 110 x: 0, 111 y: 650 - 38, 112 speed: 400, 113 }; 114 115 // 英雄配置项 116 const HERO = { 117 frame: hero_frame, 118 width: 99, 119 height: 124, 120 speed: 100, 121 }; 122 123 // 子弹配置项 124 const BULLET = { 125 img: b, 126 width: 9, 127 height: 21, 128 }; 129 130 //小敌机配置项 131 const E1 = { 132 type: 1, 133 width: 57, 134 height: 51, 135 life: 10, 136 score: 1, 137 frame: e1, 138 minSpeed: 20, 139 maxSpeed: 10 140 }; 141 //中敌机配置项 142 const E2 = { 143 type: 2, 144 width: 69, 145 height: 95, 146 life: 50, 147 score: 5, 148 frame: e2, 149 minSpeed: 50, 150 maxSpeed: 20 151 }; 152 //打敌机配置项 153 const E3 = { 154 type: 3, 155 width: 169, 156 height: 258, 157 life: 100, 158 score: 20, 159 frame: e3, 160 minSpeed: 100, 161 maxSpeed: 100 162 }; 163 //奖励类配置项 164 const C1 = { 165 type: 4, 166 width: 75, 167 height: 75, 168 life: 1, 169 score: 1, 170 img: c1, 171 minSpeed: 5, 172 maxSpeed: 10 173 }; 174 175 //初始化一个天空类 176 class Sky { 177 constructor(config) { 178 this.bg = config.bg; 179 this.width = config.width; 180 this.height = config.height; 181 this.x1 = 0; 182 this.y1 = 0; 183 this.x2 = 0; 184 this.y2 = -this.height; 185 this.speed = config.speed; 186 this.lastTime = new Date().getTime(); 187 } 188 judge() { 189 let currentTime = new Date().getTime(); 190 if (currentTime - this.lastTime > this.speed) { 191 this.y1++; 192 this.y2++; 193 this.lastTime = currentTime; 194 } 195 if (this.y2 === 0) { 196 this.y1 = 0; 197 this.y2 = -this.height; 198 } 199 } 200 paint(context) { 201 context.drawImage(this.bg, this.x1, this.y1, this.width, this.height); 202 context.drawImage(this.bg, this.x2, this.y2, this.width, this.height); 203 } 204 } 205 206 // 初始化一个飞机界面加载类 207 class Loading { 208 constructor(config) { 209 this.frame = config.frame; 210 this.frameIndex = 0; 211 this.width = config.width; 212 this.height = config.height; 213 this.x = config.x; 214 this.y = config.y; 215 this.speed = config.speed; 216 this.lastTime = new Date().getTime(); 217 } 218 judge() { 219 const currentTime = new Date().getTime(); 220 if (currentTime - this.lastTime > this.speed) { 221 this.frameIndex++; 222 if (this.frameIndex === 4) { 223 state = RUNNING; 224 } 225 this.lastTime = currentTime; 226 } 227 } 228 paint(context) { 229 context.drawImage(this.frame[this.frameIndex], this.x, this.y); 230 } 231 } 232 233 // 初始化一个英雄类 234 class Hero { 235 constructor(config) { 236 this.width = config.width; 237 this.height = config.height; 238 this.x = (480 - config.width) / 2; 239 this.y = 650 - config.height; 240 this.frame = config.frame; 241 this.frameLiveIndex = 0; 242 this.frameDeathIndex = 0; 243 this.lastTime = new Date().getTime(); 244 this.speed = config.speed; 245 this.img = null; 246 this.live = true; 247 this.lastShootTime = new Date().getTime(); 248 this.shootInterval = 50; //直接控制子弹刷新速率 249 this.bulletList = []; 250 this.destory = false; 251 } 252 judge() { 253 const currentTime = new Date().getTime(); 254 if (currentTime - this.lastTime > this.speed) { 255 if (this.live) { 256 this.img = this.frame.live[this.frameLiveIndex++ % this.frame.live.length]; 257 } else { 258 this.img = this.frame.death[this.frameDeathIndex++]; 259 if (this.frameDeathIndex === this.frame.death.length) { 260 this.destory = true; 261 } 262 } 263 this.lastTime = currentTime; 264 } 265 } 266 paint(context) { 267 context.drawImage(this.img, this.x, this.y, this.width, this.height); 268 } 269 shoot() { 270 const currentTime = new Date().getTime(); 271 if (currentTime - this.lastShootTime > this.shootInterval) { 272 let bullet = new Bullet(BULLET, this.x + this.width / 2 - BULLET.width / 2, this.y - BULLET.height); 273 this.bulletList.push(bullet); 274 bullet.paint(context); 275 this.lastShootTime = currentTime; 276 } 277 } 278 collide() { 279 this.live = false; 280 } 281 } 282 283 //初始化一个子弹类 284 class Bullet { 285 constructor(config, x, y) { 286 this.img = config.img; 287 this.width = config.width; 288 this.height = config.height; 289 this.x = x; 290 this.y = y; 291 this.destory = false; 292 } 293 paint(context) { 294 context.drawImage(this.img, this.x, this.y); 295 } 296 move() { 297 this.y -= 8; 298 } 299 outOfBounds() { 300 return this.y < -this.height; 301 } 302 collide() { 303 this.destory = true; 304 } 305 } 306 307 // 初始化一个敌机类 308 class Enemy { 309 constructor(config) { 310 this.type = config.type; 311 this.width = config.width; 312 this.height = config.height; 313 this.x = Math.floor(Math.random() * (480 - config.width)); 314 this.y = -config.height; 315 this.life = config.life; 316 this.score = config.score; 317 this.frame = config.frame; 318 this.img = this.frame.live[0]; 319 this.live = true; 320 this.speed = Math.floor(Math.random() * (config.minSpeed - config.maxSpeed + 1)) + config.maxSpeed; 321 this.lastTime = new Date().getTime(); 322 this.deathIndex = 0; 323 this.destory = false; 324 } 325 move() { 326 const currentTime = new Date().getTime(); 327 if (currentTime - this.lastTime >= this.speed) { 328 if (this.live) { 329 this.img = this.frame.live[0]; 330 this.y++; 331 this.lastTime = currentTime; 332 } else { 333 this.img = this.frame.death[this.deathIndex++]; 334 if (this.deathIndex === this.frame.death.length) { 335 this.destory = true; 336 } 337 } 338 } 339 } 340 paint(context) { 341 context.drawImage(this.img, this.x, this.y); 342 } 343 outOfBounds() { 344 if (this.y > 650) { 345 return true; 346 } 347 } 348 hit(o) { 349 let ol = o.x; 350 let or = o.x + o.width; 351 let ot = o.y; 352 let ob = o.y + o.height; 353 let el = this.x; 354 let er = this.x + this.width; 355 let et = this.y; 356 let eb = this.y + this.height; 357 if (ol > er || or < el || ot > eb || ob < et) { 358 return false; 359 } else { 360 return true; 361 } 362 } 363 collide() { 364 this.life--; 365 if (this.life === 0) { 366 this.live = false; 367 score += this.score; 368 } 369 } 370 } 371 //初始化奖励类 372 class award { 373 constructor(config) { 374 this.type = config.type; 375 this.width = config.width; 376 this.height = config.height; 377 this.x = Math.floor(Math.random() * (480 - config.width)); 378 this.y = -config.height; 379 this.life = config.life; 380 this.score = config.score; 381 this.img = config.img; 382 this.live = true; 383 this.speed = Math.floor(Math.random() * (config.minSpeed - config.maxSpeed + 1)) + config.maxSpeed; 384 this.lastTime = new Date().getTime(); 385 this.deathIndex = 0; 386 this.destory = false; 387 } 388 move() { 389 const currentTime = new Date().getTime(); 390 if (currentTime - this.lastTime >= this.speed) { 391 if (this.live) { 392 this.y = this.y + 6; 393 this.lastTime = currentTime; 394 } else { 395 this.destory = true; 396 397 } 398 } 399 } 400 paint(context) { 401 context.drawImage(this.img, this.x, this.y, this.width, this.height); 402 } 403 outOfBounds() { 404 if (this.y > 650) { 405 return true; 406 } 407 } 408 hit(o) { 409 let ol = o.x; 410 let or = o.x + o.width; 411 let ot = o.y; 412 let ob = o.y + o.height; 413 let el = this.x; 414 let er = this.x + this.width; 415 let et = this.y; 416 let eb = this.y + this.height; 417 if (ol > er || or < el || ot > eb || ob < et) { 418 return false; 419 } else { 420 return true; 421 } 422 } 423 // collide() { 424 // this.life--; 425 // if (this.life === 0) { 426 // this.live = false; 427 // score += this.score; 428 // } 429 // } 430 } 431 //初始化一个天空实例 432 const sky = new Sky(SKY); 433 //初始化一个飞机界面加载实例 434 const loading = new Loading(LOADING); 435 //初始化一个英雄实例 英雄是会变的 436 let hero = new Hero(HERO); 437 //state表示游戏的状态 取值必须是以上的五种状态 438 let state = START; 439 //score 分数变量 life 变量 440 let score = 0; 441 let life = 3; 442 //为canvas绑定一个点击事件 且他如果是START状态的时候需要修改成STARTING状态 443 canvas.addEventListener("click", () => { 444 if (state === START) { 445 state = STARTING; 446 } 447 }); 448 // 为canvas绑定一个鼠标移动事件 鼠标正好在飞机图片的正中心 449 canvas.addEventListener("mousemove", (e) => { 450 let x = e.offsetX; 451 let y = e.offsetY; 452 hero.x = x - hero.width / 2; 453 hero.y = y - hero.height / 2; 454 }); 455 456 // //为canvas绑定一个屏幕触碰事件 触碰点正好在飞机图片的正中心 457 // canvas.addEventListener("touchstart",(e)=>{ 458 // let x = e.offsetX; 459 // let y = e.offsetY; 460 // hero.x = x - hero.width / 2; 461 // hero.y = y - hero.height / 2; 462 // }) 463 //为canvas绑定一个屏幕移动触摸点事件 触碰点正好在飞机图片的正中心 464 canvas.addEventListener("touchmove", (e) => { 465 // let x = e.pageX; 466 // let y = e.pageY; 467 console.log(e); 468 // let x = e.touches[0].clientX; 469 // let y = e.touches[0].clinetY; 470 let x = e.touches[0].pageX; 471 let y = e.touches[0].pageY; 472 // let x = e.touches[0].screenX; 473 // let y = e.touches[0].screenY; 474 let write1 = (document.body.clientWidth - 480) / 2; 475 let write2 = (document.body.clientHeight - 650) / 2; 476 hero.x = x - write1 - hero.width / 2; 477 hero.y = y - write2 - hero.height / 2; 478 479 // hero.x = x - hero.width / 2; 480 // hero.y = y - hero.height / 2; 481 console.log(x, y); 482 console.log(document.body.clientWidth, document.body.clientHeight); 483 e.preventDefault(); // 阻止屏幕滚动的默认行为 484 485 }) 486 // 为canvas绑定一个鼠标离开事件 鼠标离开时 RUNNING -> PAUSE 487 canvas.addEventListener("mouseleave", () => { 488 if (state === RUNNING) { 489 state = PAUSE; 490 } 491 }); 492 493 // 为canvas绑定一个鼠标进入事件 鼠标进入时 PAUSE => RUNNING 494 canvas.addEventListener("mouseenter", () => { 495 if (state === PAUSE) { 496 state = RUNNING; 497 } 498 }); 499 // 碰撞检测函数 500 //此处的碰撞检测包括 501 //1.子弹与敌机的碰撞 502 //2.英雄与敌机的碰撞 503 //3.英雄与随机奖励的碰撞 504 function checkHit() { 505 // 遍历所有的敌机 506 for (let i = 0; i < awards.length; i++) { 507 //检测英雄是否碰到奖励类 508 if (awards[i].hit(hero)) { 509 //当然了,这个随机奖励的样式也要删了 510 awards.splice(i, 1); 511 //清除所有的敌机 512 // for (let i = 0; i < enemies.length; i++) { 513 // enemies.splice(i, 1); 514 // } 515 enemies.length = 0; 516 517 } 518 } 519 for (let i = 0; i < enemies.length; i++) { 520 //检测英雄是否撞到敌机 521 if (enemies[i].hit(hero)) { 522 //将敌机和英雄的destory属性改为true 523 enemies[i].collide(); 524 hero.collide(); 525 } 526 for (let j = 0; j < hero.bulletList.length; j++) { 527 enemies[i].hit(hero.bulletList[j]); 528 //检测子弹是否撞到敌机 529 if (enemies[i].hit(hero.bulletList[j])) { 530 //将敌机和子弹的destory属性改为true 531 enemies[i].collide(); 532 hero.bulletList[j].collide(); 533 } 534 } 535 } 536 } 537 //该变量中有所有的敌机实例 538 let enemies = []; 539 //该变量中存放所有的奖励实例 540 let awards = []; 541 //敌机产生的速率 542 let ENEMY_CREATE_INTERVAL = 800; 543 let ENEMY_LASTTIME = new Date().getTime(); 544 // 全局函数 隔一段时间就来初始化一架敌机/奖励 545 function createComponent() { 546 const currentTime = new Date().getTime(); 547 if (currentTime - ENEMY_LASTTIME >= ENEMY_CREATE_INTERVAL) { 548 let ran = Math.floor(Math.random() * 100); 549 if (ran < 55) { 550 enemies.push(new Enemy(E1)); 551 } else if (ran < 85 && ran > 55) { 552 enemies.push(new Enemy(E2)); 553 } else if (ran < 95 && ran > 85) { 554 enemies.push(new Enemy(E3)); 555 } else if (ran > 95) { 556 awards.push(new award(C1)); 557 558 } 559 560 ENEMY_LASTTIME = currentTime; 561 } 562 } 563 // 全局函数 来判断所有的子弹/敌人组件 "负责移动" 564 function judgeComponent() { 565 for (let i = 0; i < hero.bulletList.length; i++) { 566 hero.bulletList[i].move(); 567 } 568 for (let i = 0; i < enemies.length; i++) { 569 enemies[i].move(); 570 } 571 for (let i = 0; i < awards.length; i++) { 572 awards[i].move(); 573 } 574 } 575 // 全局函数 来绘制所有的子弹/敌人组件 绘制score&life面板 576 function paintComponent() { 577 for (let i = 0; i < hero.bulletList.length; i++) { 578 hero.bulletList[i].paint(context); 579 } 580 for (let i = 0; i < enemies.length; i++) { 581 enemies[i].paint(context); 582 } 583 for (let i = 0; i < awards.length; i++) { 584 awards[i].paint(context); 585 } 586 context.font = "20px 微软雅黑"; 587 context.fillStyle = "green"; 588 context.textAlign = "left"; 589 context.fillText("score: " + score, 10, 20); 590 context.textAlign = "right"; 591 context.fillText("life: " + life, 480 - 10, 20); 592 //重置样式 593 context.fillStyle = "black"; 594 context.textAlign = "left"; 595 } 596 // 全局函数 来销毁所有的子弹/敌人组件 销毁掉英雄 597 function deleteComponent() { 598 if (hero.destory) { 599 life--; 600 hero.destory = false; 601 if (life === 0) { 602 state = END; 603 } else { 604 hero = new Hero(HERO); 605 } 606 } 607 for (let i = 0; i < hero.bulletList.length; i++) { 608 if (hero.bulletList[i].outOfBounds() || hero.bulletList[i].destory) { 609 hero.bulletList.splice(i, 1); 610 } 611 } 612 for (let i = 0; i < enemies.length; i++) { 613 if (enemies[i].outOfBounds() || enemies[i].destory) { 614 enemies.splice(i, 1); 615 } 616 } 617 } 618 619 620 621 622 //当图片加载完毕时,需要做某些事情 623 bg.addEventListener("load", () => { 624 setInterval(() => { 625 switch (state) { 626 case START: 627 sky.judge(); 628 sky.paint(context); 629 let logo_x = (480 - copyright.naturalWidth) / 2; 630 let logo_y = (650 - copyright.naturalHeight) / 2; 631 context.drawImage(copyright, logo_x, logo_y); 632 break; 633 case STARTING: 634 sky.judge(); 635 sky.paint(context); 636 loading.judge(); 637 loading.paint(context); 638 break; 639 case RUNNING: 640 sky.judge(); 641 sky.paint(context); 642 hero.judge(); 643 hero.paint(context); 644 hero.shoot(); 645 createComponent(); 646 judgeComponent(); 647 deleteComponent(); 648 paintComponent(); 649 checkHit(); 650 break; 651 case PAUSE: 652 let pause_x = (480 - pause.naturalWidth) / 2; 653 let pause_y = (650 - pause.naturalHeight) / 2; 654 context.drawImage(pause, pause_x, pause_y); 655 break; 656 case END: 657 //给我的画笔设置一个字的样式 658 //后面写出来的字都是这个样式的 659 context.font = "bold 24px 微软雅黑"; 660 context.textAlign = "center"; 661 context.textBaseline = "middle"; 662 context.fillText("GAME_OVER", 480 / 2, 650 / 2); 663 break; 664 } 665 }, 10); 666 }); 667 668 //背景切换方法 669 function changebg() { 670 console.log("changebg方法被触发") 671 bg.src = "img/background.png" 672 } 673 674 } 675 }; 676 677 678 export { 679 plane 680 };复制
然后打开index.html
直接报错,跨域问题
网上搜了一大片问题解决方案:
方案一:使用npm模块 anywhere
anywhere可以将你的当前目录变成一个静态文件服务器的根目录。
全局安装:
npm install anywhere -g复制
在index.html目录下;
anywhere复制
随后自动打开网页,不再报错
方案二:
使用Live Server插件
安装后,直接在右下角启动服务
方案三:
买个服务器,部署到服务器上
.....