我的第一个项目(十一) :飞机大战分包完成(简单阐述分包思路以及过程)
好家伙,
代码已开源
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导入
第三步:划一个区域<div>给这个包去渲染游戏
剩下的他就不用管了
大概是这么个过程,然后我们按着这个思路,反向去分我们这个包
先来看看原先的完整代码:
完整代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<template>
<div>
<h1>欢迎来到主页面</h1>
<div ref="stage"></div>
</div>
</template>
<script>
export default {
mounted() {
//canvas初始化
console.log("我被执行啦")
let canvas = document.createElement('canvas');
this.$refs.stage.appendChild(canvas);
canvas.width = 480;
canvas.height = 650;
canvas.ref = canvas;
canvas.style = "border: 1px solid red;"
const context = canvas.getContext("2d");
//图片初始化方法
function createImage(src) {
let img;
if (typeof src === "string") {
img = new Image();
img.src = require('./img/' + src);
} else {
img = [];
for (let i = 0; i < src.length; i++) {
img[i] = new Image();
img[i].src = require('./img/' + src[i]);
}
}
return img;
}
//createImage()方法测试样例
// let bg = createImage("4.jpg")
// bg.onload = function () {
// console.log("img加载完毕")
// context.drawImage(bg, 0, 0, 480, 650)
// }
const IMAGES = {
b: "bullet1.png",
bg: "4.png",
copyright: "shoot_copyright.png",
pause: "game_pause.png",
loading_frame: ["game_loading1.png", "game_loading2.png", "game_loading3.png",
"game_loading4.png"
],
hero_frame_live: ["hero1.png", "hero2.png"],
hero_frame_death: ["hero_blowup_n1.png", "hero_blowup_n2.png", "hero_blowup_n3.png",
"hero_blowup_n4.png"
],
e1_live: ["enemy1.png"],
e1_death: ["enemy1_down1.png", "enemy1_down2.png", "enemy1_down3.png", "enemy1_down4.png"],
e2_live: ["enemy2.png"],
e2_death: ["enemy2_down1.png", "enemy2_down2.png", "enemy2_down3.png", "enemy2_down4.png"],
e3_live: ["enemy3_n1.png", "enemy3_n2.png"],
e3_death: ["enemy3_down1.png", "enemy3_down2.png", "enemy3_down3.png", "enemy3_down4.png",
"enemy3_down5.png", "enemy3_down6.png"
],
c1: "lanqiu.png"
};
//初始化各个图片
const b = createImage(IMAGES.b);
const bg = createImage(IMAGES.bg);
const copyright = createImage(IMAGES.copyright);
const pause = createImage(IMAGES.pause);
const loading_frame = createImage(IMAGES.loading_frame);
const hero_frame = {
live: createImage(IMAGES.hero_frame_live),
death: createImage(IMAGES.hero_frame_death),
};
const e1 = {
live: createImage(IMAGES.e1_live),
death: createImage(IMAGES.e1_death),
};
const e2 = {
live: createImage(IMAGES.e2_live),
death: createImage(IMAGES.e2_death),
};
const e3 = {
live: createImage(IMAGES.e3_live),
death: createImage(IMAGES.e3_death),
};
const c1 = createImage(IMAGES.c1);
//配置项:
// 定义游戏的状态
// 开始
const START = 0;
// 开始时
const STARTING = 1;
// 运行时
const RUNNING = 2;
// 暂停时
const PAUSE = 3;
// 结束时
const END = 4;
// 加载中
const LOADINGING = 5;
//state表示游戏的状态 取值必须是以上的五种状态
let state = LOADINGING;
// hero_frame.addEventListener("load", () => {
// state = START;
// })
pause.onload = function () {
state = START;
console.log(state)
}
//score 分数变量 life 变量
let score = 0;
let life = 3;
//天空类的配置项
const SKY = {
bg: bg,
width: 480,
height: 650,
speed: 10,
};
// 飞机加载界面的配置项
const LOADING = {
frame: loading_frame,
width: 186,
height: 38,
x: 0,
y: 650 - 38,
speed: 400,
};
// 英雄配置项
const HERO = {
frame: hero_frame,
width: 99,
height: 124,
speed: 100,
};
// 子弹配置项
const BULLET = {
img: b,
width: 9,
height: 21,
};
//小敌机配置项
const E1 = {
type: 1,
width: 57,
height: 51,
life: 10,
score: 1,
frame: e1,
minSpeed: 20,
maxSpeed: 10
};
//中敌机配置项
const E2 = {
type: 2,
width: 69,
height: 95,
life: 50,
score: 5,
frame: e2,
minSpeed: 50,
maxSpeed: 20
};
//打敌机配置项
const E3 = {
type: 3,
width: 169,
height: 258,
life: 100,
score: 20,
frame: e3,
minSpeed: 100,
maxSpeed: 100
};
//奖励类配置项
const C1 = {
type: 4,
width: 75,
height: 75,
life: 1,
score: 1,
img: c1,
minSpeed: 5,
maxSpeed: 10
};
//正式代码
//初始化奖励类
class Award {
constructor(config) {
this.type = config.type;
this.width = config.width;
this.height = config.height;
this.x = Math.floor(Math.random() * (480 - config.width));
this.y = -config.height;
this.life = config.life;
this.score = config.score;
this.img = config.img;
this.live = true;
this.speed = Math.floor(Math.random() * (config.minSpeed - config.maxSpeed + 1)) + config.maxSpeed;
this.lastTime = new Date().getTime();
this.deathIndex = 0;
this.destory = false;
}
move() {
const currentTime = new Date().getTime();
if (currentTime - this.lastTime >= this.speed) {
if (this.live) {
this.y = this.y + 6;
this.lastTime = currentTime;
} else {
this.destory = true;
}
}
}
paint(context) {
context.drawImage(this.img, this.x, this.y, this.width, this.height);
}
outOfBounds() {
if (this.y > 650) {
return true;
}
}
hit(o) {
let ol = o.x;
let or = o.x + o.width;
let ot = o.y;
let ob = o.y + o.height;
let el = this.x;
let er = this.x + this.width;
let et = this.y;
let eb = this.y + this.height;
if (ol > er || or < el || ot > eb || ob < et) {
return false;
} else {
return true;
}
}
// collide() {
// this.life--;
// if (this.life === 0) {
// this.live = false;
// score += this.score;
// }
// }
}
//
//初始化一个子弹类
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;
}
}
//
// 初始化一个敌机类
class Enemy {
constructor(config) {
this.type = config.type;
this.width = config.width;
this.height = config.height;
this.x = Math.floor(Math.random() * (480 - config.width));
this.y = -config.height;
this.life = config.life;
this.score = config.score;
this.frame = config.frame;
this.img = this.frame.live[0];
this.live = true;
this.speed = Math.floor(Math.random() * (config.minSpeed - config.maxSpeed + 1)) + config.maxSpeed;
this.lastTime = new Date().getTime();
this.deathIndex = 0;
this.destory = false;
}
move() {
const currentTime = new Date().getTime();
if (currentTime - this.lastTime >= this.speed) {
if (this.live) {
this.img = this.frame.live[0];
this.y++;
this.lastTime = currentTime;
} else {
this.img = this.frame.death[this.deathIndex++];
if (this.deathIndex === this.frame.death.length) {
this.destory = true;
}
}
}
}
paint(context) {
context.drawImage(this.img, this.x, this.y);
}
outOfBounds() {
if (this.y > 650) {
return true;
}
}
hit(o) {
let ol = o.x;
let or = o.x + o.width;
let ot = o.y;
let ob = o.y + o.height;
let el = this.x;
let er = this.x + this.width;
let et = this.y;
let eb = this.y + this.height;
if (ol > er || or < el || ot > eb || ob < et) {
return false;
} else {
return true;
}
}
collide() {
this.life--;
if (this.life === 0) {
this.live = false;
score += this.score;
}
}
}
//
// 初始化一个英雄类
class Hero {
constructor(config) {
this.width = config.width;
this.height = config.height;
this.x = (480 - config.width) / 2;
this.y = 650 - config.height;
this.frame = config.frame;
this.frameLiveIndex = 0;
this.frameDeathIndex = 0;
this.lastTime = new Date().getTime();
this.speed = config.speed;
//当前展示的图片
this.img = null;
this.live = true;
//子弹上次射击的时间
this.lastShootTime = new Date().getTime();
//子弹射击的间隔
this.shootInterval = 50;
//子弹夹数组
this.bulletList = [];
this.destory = false;
}
judge() {
const currentTime = new Date().getTime();
if (currentTime - this.lastTime > this.speed) {
if (this.live) {
this.img = this.frame.live[this.frameLiveIndex++ % this.frame.live.length];
} else {
//0 1 2 3 4
this.img = this.frame.death[this.frameDeathIndex++];
//到4的时候英雄死了
if (this.frameDeathIndex === this.frame.death.length) {
this.destory = true;
}
}
this.lastTime = currentTime;
}
}
paint(context) {
context.drawImage(this.img, this.x, this.y, this.width, this.height);
}
//英雄可以射击子弹
shoot() {
//获取当前时间
const currentTime = new Date().getTime();
//飞机的位置
if (currentTime - this.lastShootTime > this.shootInterval) {
//在飞机的头部初始化一个子弹对象
let bullet = new Bullet(BULLET, this.x + this.width / 2 - BULLET.width / 2, this.y - BULLET.height);
//英雄飞机要认领这个子弹
this.bulletList.push(bullet);
//在网页上绘制一个子弹对象
bullet.paint(context);
//更新英雄射击时间
this.lastShootTime = currentTime;
}
}
collide() {
//将活着标识符切换为false
//活着 -> 爆炸中 -> 死亡(销毁)
this.live = false;
}
}
//
// 初始化一个飞机界面加载类
class Loading {
constructor(config) {
this.frame = config.frame;
this.frameIndex = 0;
this.width = config.width;
this.height = config.height;
this.x = config.x;
this.y = config.y;
this.speed = config.speed;
this.lastTime = new Date().getTime();
}
judge() {
const currentTime = new Date().getTime();
if (currentTime - this.lastTime > this.speed) {
this.frameIndex++;
if (this.frameIndex === 4) {
state = RUNNING;
}
this.lastTime = currentTime;
}
}
paint(context) {
context.drawImage(this.frame[this.frameIndex], this.x, this.y);
}
}
class Main {
//一下全为全局变量或方法 (全局的!!)
//初始化一个天空实例
//主启动方法
maingame() {
const sky = new Sky(SKY);
//初始化一个飞机界面加载实例
const loading = new Loading(LOADING);
//初始化一个英雄实例 英雄是会变的
let hero = new Hero(HERO);
//该变量中有所有的敌机实例
let enemies = [];
//该变量中存放所有的奖励实例
let awards = [];
//敌机产生的速率
let ENEMY_CREATE_INTERVAL = 800;
let ENEMY_LASTTIME = new Date().getTime();
function stateControl() {
//为canvas绑定一个点击事件 且他如果是START状态的时候需要修改成STARTING状态
canvas.addEventListener("click", () => {
if (state === START) {
state = STARTING;
}
});
// 为canvas绑定一个鼠标移动事件 鼠标正好在飞机图片的正中心
canvas.addEventListener("mousemove", (e) => {
let x = e.offsetX;
let y = e.offsetY;
hero.x = x - hero.width / 2;
hero.y = y - hero.height / 2;
});
// 为canvas绑定一个鼠标离开事件 鼠标离开时 RUNNING -> PAUSE
canvas.addEventListener("mouseleave", () => {
if (state === RUNNING) {
state = PAUSE;
}
});
// 为canvas绑定一个鼠标进入事件 鼠标进入时 PAUSE => RUNNING
canvas.addEventListener("mouseenter", () => {
if (state === PAUSE) {
state = RUNNING;
}
});
//为canvas绑定一个屏幕移动触摸点事件 触碰点正好在飞机图片的正中心
canvas.addEventListener("touchmove", (e) => {
// let x = e.pageX;
// let y = e.pageY;
console.log(e);
// let x = e.touches[0].clientX;
// let y = e.touches[0].clinetY;
let x = e.touches[0].pageX;
let y = e.touches[0].pageY;
// let x = e.touches[0].screenX;
// let y = e.touches[0].screenY;
let write1 = (document.body.clientWidth - 480) / 2;
let write2 = (document.body.clientHeight - 650) / 2;
hero.x = x - write1 - hero.width / 2;
hero.y = y - write2 - hero.height / 2;
// hero.x = x - hero.width / 2;
// hero.y = y - hero.height / 2;
console.log(x, y);
console.log(document.body.clientWidth, document.body.clientHeight);
e.preventDefault(); // 阻止屏幕滚动的默认行为
})
}
stateControl();
// 碰撞检测函数
//此处的碰撞检测包括
//1.子弹与敌机的碰撞
//2.英雄与敌机的碰撞
//3.英雄与随机奖励的碰撞
function checkHit() {
// 遍历所有的敌机
for (let i = 0; i < awards.length; i++) {
//检测英雄是否碰到奖励类
if (awards[i].hit(hero)) {
//当然了,这个随机奖励的样式也要删了
awards.splice(i, 1);
//清除所有的敌机
// for (let i = 0; i < enemies.length; i++) {
// enemies.splice(i, 1);
// }
enemies.length = 0;
}
}
for (let i = 0; i < enemies.length; i++) {
//检测英雄是否撞到敌机
if (enemies[i].hit(hero)) {
//将敌机和英雄的destory属性改为true
enemies[i].collide();
hero.collide();
}
for (let j = 0; j < hero.bulletList.length; j++) {
enemies[i].hit(hero.bulletList[j]);
//检测子弹是否撞到敌机
if (enemies[i].hit(hero.bulletList[j])) {
//将敌机和子弹的destory属性改为true
enemies[i].collide();
hero.bulletList[j].collide();
}
}
}
}
// 全局函数 隔一段时间就来初始化一架敌机/奖励
function createComponent() {
const currentTime = new Date().getTime();
if (currentTime - ENEMY_LASTTIME >= ENEMY_CREATE_INTERVAL) {
let ran = Math.floor(Math.random() * 100);
if (ran < 55) {
enemies.push(new Enemy(E1));
} else if (ran < 85 && ran > 55) {
enemies.push(new Enemy(E2));
} else if (ran < 95 && ran > 85) {
enemies.push(new Enemy(E3));
} else if (ran > 95) {
awards.push(new award(C1));
}
ENEMY_LASTTIME = currentTime;
}
}
// 全局函数 来判断所有的子弹/敌人组件 "负责移动"
function judgeComponent() {
for (let i = 0; i < hero.bulletList.length; i++) {
hero.bulletList[i].move();
}
for (let i = 0; i < enemies.length; i++) {
enemies[i].move();
}
for (let i = 0; i < awards.length; i++) {
awards[i].move();
}
}
// 全局函数 来绘制所有的子弹/敌人组件 绘制score&life面板
function paintComponent() {
for (let i = 0; i < hero.bulletList.length; i++) {
hero.bulletList[i].paint(context);
}
for (let i = 0; i < enemies.length; i++) {
enemies[i].paint(context);
}
for (let i = 0; i < awards.length; i++) {
awards[i].paint(context);
}
context.font = "20px 微软雅黑";
context.fillStyle = "green";
context.textAlign = "left";
context.fillText("score: " + score, 10, 20);
context.textAlign = "right";
context.fillText("life: " + life, 480 - 10, 20);
//重置样式
context.fillStyle = "black";
context.textAlign = "left";
}
// 全局函数 来销毁所有的子弹/敌人组件 销毁掉英雄
function deleteComponent() {
if (hero.destory) {
life--;
hero.destory = false;
if (life === 0) {
state = END;
} else {
hero = new Hero(HERO);
}
}
for (let i = 0; i < hero.bulletList.length; i++) {
if (hero.bulletList[i].outOfBounds() || hero.bulletList[i].destory) {
hero.bulletList.splice(i, 1);
}
}
for (let i = 0; i < enemies.length; i++) {
if (enemies[i].outOfBounds() || enemies[i].destory) {
enemies.splice(i, 1);
}
}
}
//当图片加载完毕时,需要做某些事情
bg.addEventListener("load", () => {
setInterval(() => {
switch (state) {
case START:
sky.judge();
sky.paint(context);
let logo_x = (480 - copyright.naturalWidth) / 2;
let logo_y = (650 - copyright.naturalHeight) / 2;
context.drawImage(copyright, logo_x, logo_y);
break;
case STARTING:
sky.judge();
sky.paint(context);
loading.judge();
loading.paint(context);
break;
case RUNNING:
sky.judge();
sky.paint(context);
hero.judge();
hero.paint(context);
hero.shoot();
createComponent();
judgeComponent();
deleteComponent();
paintComponent();
checkHit();
break;
case PAUSE:
let pause_x = (480 - pause.naturalWidth) / 2;
let pause_y = (650 - pause.naturalHeight) / 2;
context.drawImage(pause, pause_x, pause_y);
break;
case END:
//给我的画笔设置一个字的样式
//后面写出来的字都是这个样式的
context.font = "bold 24px 微软雅黑";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText("GAME_OVER", 480 / 2, 650 / 2);
break;
}
}, 10);
});
//背景切换方法
// function changebg() {
// console.log("changebg方法被触发")
// bg.src = "img/background.png"
// }
}
}
//
//初始化一个天空类
class Sky {
constructor(config) {
this.bg = config.bg;
this.width = config.width;
this.height = config.height;
this.x1 = 0;
this.y1 = 0;
this.x2 = 0;
this.y2 = -this.height;
this.speed = config.speed;
this.lastTime = new Date().getTime();
}
//判断方法
judge() {
let currentTime = new Date().getTime();
if (currentTime - this.lastTime > this.speed) {
this.y1++;
this.y2++;
this.lastTime = currentTime;
}
if (this.y2 === 0) {
this.y1 = 0;
this.y2 = -this.height;
}
}
//绘图方法
paint(context) {
context.drawImage(this.bg, this.x1, this.y1, this.width, this.height);
context.drawImage(this.bg, this.x2, this.y2, this.width, this.height);
}
}
let main_1 = new Main()
main_1.maingame();
}
}
</script>
<style>
#stage {
width: 480px;
height: 650px;
margin: 0 auto;
}
</style>
一看,738行,这,没人想维护的,复制粘贴都嫌累
(再看一眼就要爆炸)
我们要实现一个这样的效果(事实上也实现了)
<template>
<div>
<div ref="stage"></div>
</div>
</template>
<script>
import { canvas, main_1 } from "panghu-planebattle-modular"
export default {
mounted() {
this.$refs.stage.appendChild(canvas);
main_1.maingame();
}
}
</script>
<style>
#stage {
width: 480px;
height: 650px;
margin: 0 auto;
}
</style>
而事实上,就是三行代码:
//从包中导入canvas,main_1
import { canvas, main_1 } from "panghu-planebattle-modular"
//dom操作添加canvas
this.$refs.stage.appendChild(canvas);
//调用main_1的maingame方法
main_1.maingame();
让使用者操作的部分由738行代码变成3行代码
2.开始分包
将程序主要分成下面几个需要处理的部分
1、静态的:图片,图片地址,配置项
2、六个小类:Enemy、Hero、Loading、Sky、Award、Bullet
3、主启动类:Main
4、全局方法,全局变量
5、入口(对外导出的对象)
项目目录结构如下:
1.图片
2.配置项
首先是配置项config.js
我们将所有的配置项文件都放在这里,全局变量也放在这里
3.其中六个小类,我把他们"独立"分开
比如Bullet(子弹类)
//初始化一个子弹类
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
这里需要提一嘴的是,类的导出必须带 default,否则会报错
export default Bullet
4.主启动类main
我们将所有曾经的全局方法,还有定时器都封装到这个类中
最后新建一个实例,并导出
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
5.包的入口
首先看一眼package.json
看main,(这个可以自己调的)
由上图可知,这个包的入口就是index.js了
//index.js
export { canvas } from "./config"
export { main_1 } from "./main"
config.js中的canvas
export let canvas = document.createElement('canvas');
canvas.width = 480;
canvas.height = 650;
canvas.ref = canvas;
canvas.style = "border: 1px solid red;"
main.js中的main
export let main_1 = new Main()
在这里,用上我们前几天学的语法(嘿嘿)
分包完成