小时候我们有个熟悉的游戏叫小蜜蜂。本文教大家在鸿蒙上学做这个小蜜蜂游戏。
开发实战
①HAP 应用建立
前面我们介绍了简单的 Hap 应用的开发以及基础控件的介绍,这里我们就不赘述 Hap 项目的建立过程,以下就是基础的 Hap 的 page 文件:index.ets。
build() { Row() { Column() { Canvas(this.context) .width('100%') .height('100%') .onClick((ev: ClickEvent) => { console.info("click!!") this.doClick() }) .onReady(() =>{ this.context.imageSmoothingEnabled = false this.drawall() }) } .width('100%') } .height('100%') .backgroundColor("#000000") }build 是基础页面的构造函数,用于界面的元素构造,其他的页面的生命周期函数如下:
declare class CustomComponent { /** * Customize the pop-up content constructor. * @since 7 */ build(): void; /** * aboutToAppear Method * @since 7 */ aboutToAppear?(): void; /** * aboutToDisappear Method * @since 7 */ aboutToDisappear?(): void; /** * onPageShow Method * @since 7 */ onPageShow?(): void; /** * onPageHide Method * @since 7 */ onPageHide?(): void; /** * onBackPress Method * @since 7 */ onBackPress?(): void; }
②Canvas 介绍
canvas 是画布组件用于自定义绘制图形,具体的 API 页面如下:
https://developer.harmonyos.com/cn/docs/documentation/doc-references/ts-components-canvas-canvas-0000001333641081页面显示前会调用 aboutToAppear() 函数,此函数为页面生命周期函数。 canvas 组件初始化完毕后会调用 onReady() 函数,函数内部实现小游戏的初始页面的绘制。
初始化页面数据:
drawall() { this.context.clearRect(0,0,this.context.width,this.context.height) this.drawFj(); this.drawEn(); this.drawBullet(); this.drawScore(); }绘制飞机:
drawFj() { this.context.drawImage( this.fjImg, this.fjStartX, this.fjslotY,this.birdH,this.birdW) }绘制害虫:
drawEn() { for (let line=0; line < this.enemylist.length; line++) { for (let row=0; row < this.enemylist[line].length; row++) { if (this.enemylist[line][row] == 1) { if (line == 0) { this.context.drawImage( this.en1Img, this.en1slotX+row*this.birdW,this.en1slotY-line*this.birdH,this.birdH,this.birdW); } else if (line == 1) { this.context.drawImage( this.en2Img, this.en1slotX+row*this.birdW,this.en1slotY-line*this.birdH,this.birdH,this.birdW); } else if (line == 2) { this.context.drawImage( this.en3Img, this.en1slotX+row*this.birdW,this.en1slotY-line*this.birdH,this.birdH,this.birdW); } } } } }
不同行的害虫长相不同,分值不同。
③游戏逻辑
简单的小游戏主体游戏逻辑为:点击鼠标移动飞机,飞机发射子弹,命中害虫,计算分数:
doClick() { if (this.en1slotX <= 50) { this.en1slotX += this.birdW } else { this.en1slotX -= this.birdW } console.log("doclick----") this.moveFj(); }
④完整逻辑
@Entry @Component struct Index { @State message: string = 'Hello World' private settings: RenderingContextSettings = new RenderingContextSettings(true); private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings); private blockType: number = 0 private blockSize: number = 30 private en1Img:ImageBitmap = new ImageBitmap("common/images/mf1.png") private en2Img:ImageBitmap = new ImageBitmap("common/images/mf2.png") private en3Img:ImageBitmap = new ImageBitmap("common/images/mf3.png") private fjImg:ImageBitmap = new ImageBitmap("common/images/fj.png") private startX = 30; private startY = 100; private enStartY = 140; private fjStartX = 50; private fjStartY = 610; private fjslotX = 50; private fjslotY = this.fjStartY; private en1slotX = 50; private en1slotY = this.enStartY; private en2slotX = 50; private en2slotY = this.enStartY; private bulletX = 65; private bulletY = 550; private birdH = 40; private birdW = 40; private score = 0; private fjDirection = 1; private enemylist = [ [1,1,1,1,1], [1,1,1,1,1], [1,1,1,1,1], ] moveFj() { this.fjStartX = this.fjStartX + this.fjDirection * this.birdW if (this.fjStartX >= 210) { this.fjDirection = -1 } else if (this.fjStartX <= 50) { this.fjDirection = 1 } } drawFj() { this.context.drawImage( this.fjImg, this.fjStartX, this.fjslotY,this.birdH,this.birdW) } drawEn() { for (let line=0; line < this.enemylist.length; line++) { for (let row=0; row < this.enemylist[line].length; row++) { if (this.enemylist[line][row] == 1) { if (line == 0) { this.context.drawImage( this.en1Img, this.en1slotX+row*this.birdW,this.en1slotY-line*this.birdH,this.birdH,this.birdW); } else if (line == 1) { this.context.drawImage( this.en2Img, this.en1slotX+row*this.birdW,this.en1slotY-line*this.birdH,this.birdH,this.birdW); } else if (line == 2) { this.context.drawImage( this.en3Img, this.en1slotX+row*this.birdW,this.en1slotY-line*this.birdH,this.birdH,this.birdW); } } } } } drawBullet() { let isfind = false this.context.fillStyle = 'rgb(250,250,250)' this.context.font = '80px sans-serif' this.bulletX = this.fjStartX + 20 this.context.fillText(":", this.fjStartX+20, this.bulletY) for (let line=0; line < this.enemylist.length; line++) { if (Math.abs(this.bulletY - (this.en1slotY-line*this.birdH)) <= this.birdH) { console.log("find line: "+line) for (let row = 0; row < this.enemylist[line].length; row++) { let matchsize = Math.abs(this.bulletX - (this.en1slotX+row*this.birdW)) // console.log("find szie: "+matchsize.toString()+" row:"+row.toString()+" line:"+line.toString()+" bulletX:"+this.bulletX.toString()+" bulletY:"+ // this.bulletY.toString()+" en1slotX"+this.en1slotX.toString()+" en1slotY"+this.en1slotY.toString()) if (matchsize <= this.birdW) { if (this.enemylist[line][row] == 1) { console.log("row:"+row.toString()+" line:"+line.toString()+" bulletX:"+this.bulletX.toString()+" bulletY:"+ this.bulletY.toString()+" en1slotX"+this.en1slotX.toString()+" en1slotY"+this.en1slotY.toString()); this.enemylist[line][row] = 0 isfind = true switch (line) { case 0: this.score += 1; break; case 1: this.score += 2; break; case 2: this.score += 3; break; default: break; } //console.log("score: "+this.score.toString()) break } } } if (isfind) { break; } } } if (this.bulletY <= 100 || isfind == true) { this.bulletY = 550 } else { this.bulletY -= 50; } } drawScore() { this.context.fillStyle = 'rgb(250,250,250)' this.context.font = '80px sans-serif' this.context.fillText("Score:"+this.score.toString(), 20, 750) // this.context.fillText(":", 65, 550) } drawall() { this.context.clearRect(0,0,this.context.width,this.context.height) this.drawFj(); this.drawEn(); this.drawBullet(); this.drawScore(); } async sleep(ms: number) { var that = this; return new Promise((r) => { setInterval(() => { if (that.en1slotX <= 50) { that.en1slotX += that.birdW } else { that.en1slotX -= that.birdW } console.log(that.en1slotX.toString()) that.drawall() }, ms) }) } doClick() { if (this.en1slotX <= 50) { this.en1slotX += this.birdW } else { this.en1slotX -= this.birdW } console.log("doclick----") this.moveFj(); } aboutToAppear() { this.sleep(1000) } build() { Row() { Column() { Canvas(this.context) .width('100%') .height('100%') .onClick((ev: ClickEvent) => { console.info("click!!") this.doClick() }) .onReady(() =>{ this.context.imageSmoothingEnabled = false this.drawall() }) } .width('100%') } .height('100%') .backgroundColor("#000000") } }遗留问题:
飞机的子弹可以多发
害虫可以攻击飞机
游戏声音问题:目前 ohos 不支持音频播放资源音频,看之后版本是否支持
DevEco 用 setInterval 重绘 canvas 会导致 ide 崩溃
总结
本文主要介绍了小游戏的开发,画布功能的使用,获取源码请通过“阅读原文”下载附件。
作者:王石
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !