我正在参加掘金社区游戏创意投稿大赛团队赛,详情请看:游戏创意投稿大赛
由大帅 带队,鹏飞 参与开发《1945年柏林的夜空》史诗型飞机游戏。正值刚学习vue3,又赶上了掘金的游戏创意大赛,因为不太熟悉游戏引擎,所以就使用 uni-app 的 vue3-vite-ts 脚手架通过在canvas上自由画图的方式撸了这版游戏。本文为代码实现篇,主要讲解项目各个模块是怎么运行起来的。
说实话参加项目是偶然的,而且最近公司项目比较紧急,已经连续4天加班到转钟了,不过还是坚持下来了,同时也感谢大帅和鹏飞两位大佬的支持。废话不多说,show code
因为我们是飞机大战,所以我从--战斗机、子弹、碰撞几个方面说下: 因为使用的是ts,我们先来先创建基础飞机类、我方、敌方、子弹包括定位、宽高、开火方法、移动方法:
interface planeIf {
x: number
y: number
index: number
life: number
width: number
height: number
}
interface heroIf extends planeIf {
count: number
hCount: number
eCount: number
n: number
draw: (ctx: any, changeState: (arg0: StateEnum) => void, hullets: hulletIf[], score: number, liveEnemy: enemyIf[]) => void
hit: (liveEnemy: enemyIf[]) => void
}
interface enemyIf extends planeIf {
speed: number
n: number
enemy: null | {}
removable: boolean
die: boolean
draw: (ctx: any, canvasHeight: number, canvasWidth: number,hullets: hulletIf[],gameScore:number ,changeScore: (arg0: number) => void) => void
hit: (ullets: hulletIf[],gameScore:number ,changeScore: (arg0: number) => void) => void
}
interface hulletIf {
n: number
mx: number
my: number
width: number
height: number
removable: boolean
draw: (ctx: any) => void
}
好的,现在所有类型都定义好了,还要完善基类的方法,例如:1.我方战斗机的飞行、子弹逻辑、开火逻辑、碰撞逻辑;2.敌方战斗机的飞行、开火逻辑、碰撞逻辑;3.子弹位置、轨迹。下面就写一个我方战斗机的逻辑示例:
class Hero implements heroIf {
x: number
y: number
index: number
count: number
hCount: number
eCount: number
n: number
life: number
width: number
height: number
constructor(width: number, height: number) {
// this.x = (width - heroImg[0].width) / 2 // hero的坐标
// this.y = height - heroImg[0].height
this.x = (width - 100) / 2 // hero的坐标
this.y = height - 200
this.index = 0 // 用于切换hero的图片
this.count = 0 // 用于控制hero图片切换的频率
this.hCount = 0 // 用于控制子弹发射的频率
this.eCount = 0 // 用于控制敌机出现的频率
this.n = 0
this.life = 3
this.width = 0
this.height = 0
uni.getImageInfo({
src: `/static/img/${heroArr[this.index]}`,
success: (res)=>{
this.width = res.width; // 子弹的宽和高
this.height = res.height;
this.x =(width - res.width) / 2 // hero的坐标
this.y = height - res.height
}
})
}
draw(ctx: any, changePhase: (arg0: StateEnum) => void, hullets: hulletIf[], score: number, liveEnemy: enemyIf[]) {
this.count++
this.hit(liveEnemy)
if (this.index > 4) {
changePhase(StateEnum.OVER)
this.index = 5
}
if (this.count % 3 == 0 && this.index <= 1) {
// 切换hero的图片
this.index = this.index == 0 ? 1 : 0
this.count = 0
}
ctx.drawImage(`/static/img/${heroArr[this.index]}`, this.x, this.y)
ctx.draw(true)
this.hCount++
if (this.hCount % 3 == 0) {
// 同时生成三颗子弹
this.n == 32 && (this.n = 0)
hullets.push(new Hullet(this.n, this.x, this.y, this.width))
this.n == 0 && (this.n = -32)
hullets.push(new Hullet(this.n, this.x, this.y, this.width))
this.n == -32 && (this.n = 32)
hullets.push(new Hullet(this.n, this.x, this.y, this.width))
this.hCount = 0
}
this.eCount++
if (this.eCount % 8 == 0) {
//生成敌机
liveEnemy.push(new Enemy())
this.eCount = 0
}
}
hit(liveEnemy: enemyIf[]) {
// 判断是自己是否被击中
for (var i = 0; i < liveEnemy.length; i++) {
var d = liveEnemy[i]
// 敌机与自己的碰撞检测
var px, py
px = this.x <= d.x ? d.x : this.x
py = this.y <= d.y ? d.y : this.y
// 判断点
if (
px >= this.x &&
px <= this.x + this.width &&
py >= this.y &&
py <= this.y + this.height &&
px >= d.x &&
px <= d.x + d.width &&
py >= d.y &&
py <= d.y + d.height
) {
this.life--
if (this.life < 2) {
if (this.index <= 2) {
this.index = 3
}
this.index++
}
}
}
}
}
现在一切就绪,准备 setup 画背景、画敌机、画我方战斗机、操作逻辑、开始、暂停、结束、主引擎等代码的完善,感兴趣可以去git上提点提点。
通过参加这次比赛,学习巩固了uniapp + vue3 + ts + vite的实战,在我看来vue3不论是现在还是未来都有很大的前景,在国内认可度,普及度都是极高的,不光是vue3的composition-api,Reactivity、还是proxy双向数据绑定,对ts都高度支持,配合vite,谁用谁酸爽。
飞机动起来:传送门-上篇
好了,本文就给大家介绍到这里,感觉有帮助的,留下个赞或评论再走吧!谢啦~ 💐