简介
小时候我们有个熟悉的游戏叫小蜜蜂。本文中引用的图片资源均来自与Github。
开发
1、HAP应用建立
《#跟着小白一起学鸿蒙#[六]如何编写一个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")
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
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;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
2、Canvas介绍
canvas是画布组件用于自定义绘制图形,具体的API页面如下:
https://developer.harmonyos.com/cn/docs/documentation/doc-references/ts-components-canvas-canvas-0000001333641081
页面显示前会调用aboutToAppear()函数,此函数为页面生命周期函数。
canvas组件初始化完毕后会调用onReady()函数,函数内部实现小游戏的初始页面的绘制。
(1)初始化页面数据
drawall() {
this.context.clearRect(0,0,this.context.width,this.context.height)
this.drawFj();
this.drawEn();
this.drawBullet();
this.drawScore();
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
(2)绘制飞机
drawFj() {
this.context.drawImage( this.fjImg, this.fjStartX, this.fjslotY,this.birdH,this.birdW)
}
- 1.
- 2.
- 3.
(3)绘制害虫
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);
}
}
}
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
不同行的害虫长相不同,分值不同。
3、游戏逻辑
简单的小游戏主体游戏逻辑为:点击鼠标移动飞机,飞机发射子弹,命中害虫,计算分数:
doClick() {
if (this.en1slotX <= 50) {
this.en1slotX += this.birdW
} else {
this.en1slotX -= this.birdW
}
console.log("doclick----")
this.moveFj();
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
4、完整逻辑
@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")
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
- 172.
- 173.
- 174.
- 175.
- 176.
- 177.
- 178.
- 179.
- 180.
- 181.
- 182.
遗留问题:
- 飞机的子弹可以多发
- 害虫可以攻击飞机
- 游戏声音问题:目前ohos不支持音频播放资源音频,看之后版本是否支持
- DevEco用setInterval重绘canvas会导致ide崩溃
5、获取源码
见附件:
https://ost.51cto.com/resource/2670。
总结
本文主要介绍了小游戏的开发,画布功能的使用。