小时候有个游戏叫俄罗斯方块,大人小孩都喜欢玩,我们就一起看看如何能用 OpenHarmony 学习做个 Tetris。
效果如下图:
开发
①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.randomType()
this.drawall()
})
}
.width('100%')
}
.height('100%')
.backgroundColor("#cccccc")
}
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.drawBox()
this.drawSideBlock()
this.drawBoxBlock()
this.drawScore()
}
因为都是画布画的,所以布局有点麻烦,需要画几个部分:
drawBox() {
this.context.lineWidth = 4
this.context.beginPath()
this.context.lineCap = 'butt'
this.context.moveTo(0, 100)
this.context.lineTo(270, 100)
this.context.moveTo(270, 100)
this.context.lineTo(270, 690)
this.context.moveTo(0, 690)
this.context.lineTo(270, 690)
}
绘制提示方块:
drawSideBlock() {
this.context.fillStyle = 'rgb(250,0,0)'
let bs = this.blockSize
let coords = this.blockShapBasic[this.blockType]
let x = this.sideStartX coords[0][0]*this.blockSize
let y = this.sideStartY coords[0][1]*this.blockSize
this.context.fillRect(x, y, bs, bs)
this.context.rect(x, y, bs, bs)
console.info("x,y" x.toString() ":" y.toString())
x = this.sideStartX coords[1][0]*this.blockSize
y = this.sideStartY coords[1][1]*this.blockSize
this.context.fillRect(x, y, bs, bs)
this.context.rect(x, y, bs, bs)
console.info("x,y" x.toString() ":" y.toString())
x = this.sideStartX coords[2][0]*this.blockSize
y = this.sideStartY coords[2][1]*this.blockSize
this.context.fillRect(x, y, bs, bs)
this.context.rect(x, y, bs, bs)
console.info("x,y" x.toString() ":" y.toString())
x = this.sideStartX coords[3][0]*this.blockSize
y = this.sideStartY coords[3][1]*this.blockSize
this.context.fillRect(x, y, bs, bs)
this.context.rect(x, y, bs, bs)
console.info("x,y" x.toString() ":" y.toString())
this.context.stroke()
}
绘制运动方块:
drawBoxBlock() {
this.setDirection()
this.context.fillStyle = 'rgb(250,0,0)'
let bs = this.blockSize
let coords = this.curBlockShap
let starty = this.slotStartY this.step * this.blockSize
let x = this.slotStartX coords[0][0]*this.blockSize
let y = starty coords[0][1]*this.blockSize
this.context.fillRect(x, y, bs, bs)
this.context.rect(x, y, bs, bs)
console.info("x,y" x.toString() ":" y.toString())
x = this.slotStartX coords[1][0]*this.blockSize
y = starty coords[1][1]*this.blockSize
this.context.fillRect(x, y, bs, bs)
this.context.rect(x, y, bs, bs)
console.info("x,y" x.toString() ":" y.toString())
x = this.slotStartX coords[2][0]*this.blockSize
y = starty coords[2][1]*this.blockSize
this.context.fillRect(x, y, bs, bs)
this.context.rect(x, y, bs, bs)
console.info("x,y" x.toString() ":" y.toString())
x = this.slotStartX coords[3][0]*this.blockSize
y = starty coords[3][1]*this.blockSize
this.context.fillRect(x, y, bs, bs)
this.context.rect(x, y, bs, bs)
console.info("x,y" x.toString() ":" y.toString())
this.context.stroke()
this.slotBottomY = y
}
绘制得分区域:
drawScore() {
this.context.fillStyle = 'rgb(0,0,0)'
this.context.font = '80px sans-serif'
this.context.fillText("Score:" this.score.toString(), 20, 740)
}
③游戏逻辑
简单的小游戏主体游戏逻辑为:等待开始,开始。
结束流程图如下:
graph LR
timer开始 --> 方块下落
timer开始 --> click[点击]
click[点击] --> 方块变形
方块下落 --> |落到底| 能消除 --> 计分 --> 堆积
方块下落 --> |落到底| 不能消除 --> 堆积
堆积 --> |堆积到顶| 满了 --> 游戏结束
堆积 --> |堆积到顶| 未满 --> 方块下落
doClick() {
this.direction = 1
}
完整逻辑:
@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 blockShapBasic = [
[[0,0],[0,1],[0,2],[0,3]],
[[0,0],[0,1],[0,2],[1,2]],
[[0,0],[0,1],[1,1],[0,2]],
[[0,0],[0,1],[1,1],[1,2]],
[[0,0],[0,1],[1,0],[1,1]],
]
private blockShap = [
[[0,0],[0,1],[0,2],[0,3]],
[[0,0],[0,1],[0,2],[1,2]],
[[0,0],[0,1],[1,1],[0,2]],
[[0,0],[0,1],[1,1],[1,2]],
[[0,0],[0,1],[1,0],[1,1]],
]
private curBlockShap = []
private sideStartX = 300;
private sideStartY = 150;
private slotStartX = 120;
private slotStartY = 150;
private slotBottomY = 150;;
private score = 0;
private step = 0;
private direction = 0;
aboutToDisappear() {
}
aboutToAppear() {
this.sleep(1000)
}
async sleep(ms: number) {
return new Promise((r) => {
setInterval(() => {
console.log(this.message)
this.drawStep()
}, ms)
})
}
doClick() {
this.direction = 1
}
drawBox() {
this.context.lineWidth = 4
this.context.beginPath()
this.context.lineCap = 'butt'
this.context.moveTo(0, 100)
this.context.lineTo(270, 100)
this.context.moveTo(270, 100)
this.context.lineTo(270, 690)
this.context.moveTo(0, 690)
this.context.lineTo(270, 690)
}
setDirection() {
this.curBlockShap = this.blockShap[this.blockType]
if (this.direction > 0) {
for (let i=0;i<4;i ) {
let x = this.curBlockShap[i][0]
this.curBlockShap[i][0] = this.curBlockShap[i][1]
this.curBlockShap[i][1] = x
}
this.direction = 0
}
}
drawSideBlock() {
this.context.fillStyle = 'rgb(250,0,0)'
let bs = this.blockSize
let coords = this.blockShapBasic[this.blockType]
let x = this.sideStartX coords[0][0]*this.blockSize
let y = this.sideStartY coords[0][1]*this.blockSize
this.context.fillRect(x, y, bs, bs)
this.context.rect(x, y, bs, bs)
console.info("x,y" x.toString() ":" y.toString())
x = this.sideStartX coords[1][0]*this.blockSize
y = this.sideStartY coords[1][1]*this.blockSize
this.context.fillRect(x, y, bs, bs)
this.context.rect(x, y, bs, bs)
console.info("x,y" x.toString() ":" y.toString())
x = this.sideStartX coords[2][0]*this.blockSize
y = this.sideStartY coords[2][1]*this.blockSize
this.context.fillRect(x, y, bs, bs)
this.context.rect(x, y, bs, bs)
console.info("x,y" x.toString() ":" y.toString())
x = this.sideStartX coords[3][0]*this.blockSize
y = this.sideStartY coords[3][1]*this.blockSize
this.context.fillRect(x, y, bs, bs)
this.context.rect(x, y, bs, bs)
console.info("x,y" x.toString() ":" y.toString())
this.context.stroke()
}
drawBoxBlock() {
this.setDirection()
this.context.fillStyle = 'rgb(250,0,0)'
let bs = this.blockSize
let coords = this.curBlockShap
let starty = this.slotStartY this.step * this.blockSize
let x = this.slotStartX coords[0][0]*this.blockSize
let y = starty coords[0][1]*this.blockSize
this.context.fillRect(x, y, bs, bs)
this.context.rect(x, y, bs, bs)
console.info("x,y" x.toString() ":" y.toString())
x = this.slotStartX coords[1][0]*this.blockSize
y = starty coords[1][1]*this.blockSize
this.context.fillRect(x, y, bs, bs)
this.context.rect(x, y, bs, bs)
console.info("x,y" x.toString() ":" y.toString())
x = this.slotStartX coords[2][0]*this.blockSize
y = starty coords[2][1]*this.blockSize
this.context.fillRect(x, y, bs, bs)
this.context.rect(x, y, bs, bs)
console.info("x,y" x.toString() ":" y.toString())
x = this.slotStartX coords[3][0]*this.blockSize
y = starty coords[3][1]*this.blockSize
this.context.fillRect(x, y, bs, bs)
this.context.rect(x, y, bs, bs)
console.info("x,y" x.toString() ":" y.toString())
this.context.stroke()
this.slotBottomY = y
}
drawScore() {
this.context.fillStyle = 'rgb(0,0,0)'
this.context.font = '80px sans-serif'
this.context.fillText("Score:" this.score.toString(), 20, 740)
}
randomType() {
this.blockType = Math.floor(Math.random()*5)
console.info("blocktype:" this.blockType.toString())
}
drawStep() {
this.context.clearRect(0,0,this.context.width,this.context.height)
this.step = 1
this.drawBox()
this.drawSideBlock()
this.drawBoxBlock()
this.drawScore()
if (this.slotBottomY >= 660) {
this.step = 0
this.randomType()
}
}
drawall() {
this.drawBox()
this.drawSideBlock()
this.drawBoxBlock()
this.drawScore()
}
build() {
Row() {
Column() {
Canvas(this.context)
.width('100%')
.height('100%')
.onClick((ev: ClickEvent) => {
console.info("click!!")
this.doClick()
})
.onReady(() =>{
this.context.imageSmoothingEnabled = false
this.randomType()
this.drawall()
})
}
.width('100%')
}
.height('100%')
.backgroundColor("#cccccc")
}
}
遗留问题:
下面我们将继续完善页面,增加了左右按键和之前方块显示,方块消除。
①按键增加之前我们布局一直是只有个 Canvas 控件,现在我们需要设置高度后增加一个 Row 的布局,并增加两个 Button 控件,以下就是基础的 Hap 的 page 文件:index.ets。
build() {
Column() {
Column() {
Canvas(this.context)
.width('100%')
.height('100%')
.onClick((ev: ClickEvent) => {
console.info("click!!")
this.doClick()
})
.onTouch((ev) => {
console.info("touch:" ev.type.toString())
console.info("touch x:" ev.touches[0].screenX.toString())
console.info("touch y:" ev.touches[0].screenY.toString())
})
.onReady(() =>{
this.context.imageSmoothingEnabled = false
this.randomType()
this.drawall()
})
}
.height('92%')
.width('100%')
Row() {
Button() { //按钮控件
Text('左')
.fontSize(20)
.fontWeight(FontWeight.Bold)
}.type(ButtonType.Capsule)
.width('20%')
.height('6%')
.backgroundColor('#0D9FFB')
.onClick(() => { //点击事件
if (this.left > 0) {
this.moveAction -= 1
}
})
Button() { //按钮控件
Text('右')
.fontSize(20)
.fontWeight(FontWeight.Bold)
}.type(ButtonType.Capsule)
.width('20%')
.height('6%')
.backgroundColor('#0D9FFB')
.onClick(() => { //点击事件
if (this.rightX < 240) {
this.moveAction = 1
}
})
}
}
.width('100%')
.height('100%')
.backgroundColor("#cccccc")
}
②游戏完善的说明
之前我们的游戏只有布局,方块显示和变形,在完善后我们增加了积累方块的显示,消除,计分,游戏结束判断等。
积累方块显示:drawBlockmap() {
let bs = this.blockSize
this.context.fillStyle = 'rgb(250,0,0)'
for (let i=0;i<23;i ) {
for (let j=0;j<9;j ) {
//是否有方块
if (this.blockmap[i][j] == 1) {
let y = i * this.blockSize
let x = j * this.blockSize
this.context.fillRect(x, y, bs, bs)
this.context.rect(x, y, bs, bs)
console.info("drawBlockmap:" x.toString() ":" y.toString())
}
}
this.context.stroke()
console.info("drawBlockmap:" this.storeBlock.length.toString())
}
}
因为都是画布画的,为了重绘已经存在的方块,我们应用二维数组 blockmap 表示,值为 1 则有方块,数组索引则表示绘制坐标位置。
判断是否到底还是到顶: checkBlockmap() {
if (this.storeBlock.length == 0) {
if (this.slotBottomY >= 660) {
return 1
}
} else {
let coords = this.curBlockShap
let startx = this.slotStartX this.moveAction * this.blockSize
let starty = this.slotStartY this.step * this.blockSize
for (let i=0;i<4;i ) {
let x = startx coords[i][0]*this.blockSize
let y = starty coords[i][1]*this.blockSize this.blockSize
for (let k=0;k<22;k ) {
for (let l=0;l<9;l ) {
if (this.blockmap[k][l] == 1) {
let blocky = k * this.blockSize
let blockx = l * this.blockSize
//判断是否到底
if ((x == blockx && y == blocky) || y > 660) {
//判断是否到顶
if (y == 210) {
this.context.drawImage( this.gameoverImg,this.startX,this.startY,300,90)
//到顶回2
return 2
}
//到底回1
return 1
}
}
}
}
}
}
return 0
}
先判断是否到底,到底的同时判断是否到顶,如果到顶了就是满了,如果只是到底则表明游戏可以继续。
到底积累方块:stackBlock() {
let block = []
let coords = this.curBlockShap
let startx = this.slotStartX this.moveAction * this.blockSize
let starty = this.slotStartY this.step * this.blockSize
for (let i=0;i<4;i ) {
let x = startx coords[i][0]*this.blockSize
let y = starty coords[i][1]*this.blockSize
console.info("stackBlock x:" x.toString() "y:" y.toString())
let indexX = x/this.blockSize
let indexY = y/this.blockSize
this.blockmap[indexY][indexX] = 1
console.info("stackBlock:" indexX ":" indexY)
block.push([x,y])
}
this.storeBlock.push(block)
console.info("stackBlock:" this.storeBlock.length.toString())
}
如果到底了,就用坐标计算出 索引,然后在 blockmap 里标识为 1,说明此处有方块,这样方便后面的绘制的显示。
清除方块:cleanBlockmap() {
//检查是否一行满了
let needMove = 0
for (let i=22;i>=0;i--) {
let linecnt = 0
for (let j = 8;j >= 0; j--) {
//是否有方块
if (this.blockmap[i][j] == 1) {
linecnt = 1
}
}
if (linecnt == 9) {
//此行都是方块,消除,计分
for (let j = 8;j >= 0; j--) {
this.blockmap[i][j] = 0
}
needMove = 1
this.score = 1
} else if (needMove > 0) {
for (let j = 8;j >= 0; j--) {
this.blockmap[i needMove][j] = this.blockmap[i][j]
this.blockmap[i][j] = 0
}
}
}
}
二维数组的好处就是方便每行计数清除,然后从底向上再逐层替换。
绘制每一步:drawStep() {
this.context.clearRect(0,0,this.context.width,this.context.height)
this.step = 1
this.drawBox()
this.drawBlockmap()
this.cleanBlockmap()
this.drawSideBlock()
this.drawBoxBlock()
this.drawScore()
let stepType = this.checkBlockmap()
if ( stepType == 1) {
this.stackBlock()
this.step = 0
this.randomType()
} else if (stepType == 2) {
this.state= 2
this.context.drawImage( this.gameoverImg,this.startX,this.startY,300,90)
}
}
绘制每一步其实就是重绘界面,包括如果游戏结束显示 game over。
③游戏逻辑简单的小游戏主体游戏逻辑为:等待开始,开始,结束流程图如下:
graph LR
timer开始 --> 方块下落
timer开始 --> click[点击]
click[点击] --> 方块变形
方块下落 --> |落到底| 能消除 --> 计分 --> 堆积
方块下落 --> |落到底| 不能消除 --> 堆积
堆积 --> |堆积到顶| 满了 --> 游戏结束
堆积 --> |堆积到顶| 未满 --> 方块下落
doClick() {
if (this.state == 0) {
this.direction = 1
} else if (this.state == 2) {
this.state = 0
this.score = 0
this.storeBlock = []
this.initMap()
}
}
游戏结束后需要重新初始化内部数据。
④完整逻辑@Entry
@Component
struct Index {
@State message: string = 'Hello World'
private settings: RenderingContextSettings = new RenderingContextSettings(true);
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
private gameoverImg:ImageBitmap = new ImageBitmap("common/images/gameover.png")
private blockType: number = 0
private blockSize: number = 30
private blockShapBasic = [
[[0,0],[0,1],[0,2],[0,3]],
[[0,0],[0,1],[0,2],[1,2]],
[[0,0],[0,1],[1,1],[0,2]],
[[0,0],[0,1],[1,1],[1,2]],
[[0,0],[0,1],[1,0],[1,1]],
]
private blockShap = [
[[0,0],[0,1],[0,2],[0,3]],
[[0,0],[0,1],[0,2],[1,2]],
[[0,0],[0,1],[1,1],[0,2]],
[[0,0],[0,1],[1,1],[1,2]],
[[0,0],[0,1],[1,0],[1,1]],
]
private blockmap = [];
private curBlockShap = []
private storeBlock = []
private sideStartX = 300;
private sideStartY = 150;
private startX = 20
private startY = 300
private slotStartX = 120;
private slotStartY = 150;
private slotBottomY = 150;
private xleft = 0;
private rightX = 0;
private score = 0;
private step = 0;
private direction = 0;
private moveAction = 0;
private state = 0;
aboutToDisappear() {
}
aboutToAppear() {
this.initMap()
this.sleep(1000)
}
initMap() {
for (let i=0;i<23;i ) {
let item = []
for (let j=0;j<9;j ) {
item.push(0)
}
this.blockmap.push(item)
}
}
async sleep(ms: number) {
return new Promise((r) => {
setInterval(() => {
// console.log(this.message)
if (this.state == 0) {
this.drawStep()
}
}, ms)
})
}
doClick() {
if (this.state == 0) {
this.direction = 1
} else if (this.state == 2) {
this.state = 0
this.score = 0
this.storeBlock = []
this.initMap()
}
}
drawBox() {
this.context.lineWidth = 4
this.context.beginPath()
this.context.lineCap = 'butt'
this.context.moveTo(0, 100)
this.context.lineTo(270, 100)
this.context.moveTo(270, 100)
this.context.lineTo(270, 690)
this.context.moveTo(0, 690)
this.context.lineTo(270, 690)
}
setDirection() {
this.curBlockShap = this.blockShap[this.blockType]
if (this.direction > 0) {
for (let i=0;i<4;i ) {
let x = this.curBlockShap[i][0]
this.curBlockShap[i][0] = this.curBlockShap[i][1]
this.curBlockShap[i][1] = x
}
this.direction = 0
}
}
drawSideBlock() {
this.context.fillStyle = 'rgb(250,0,0)'
let bs = this.blockSize
let coords = this.blockShapBasic[this.blockType]
for (let i=0;i<4;i ) {
let x = this.sideStartX coords[i][0]*this.blockSize
let y = this.sideStartY coords[i][1]*this.blockSize
this.context.fillRect(x, y, bs, bs)
this.context.rect(x, y, bs, bs)
// console.info("x,y" x.toString() ":" y.toString())
}
this.context.stroke()
}
drawBoxBlock() {
let min = 690
let max = 0
this.setDirection()
this.context.fillStyle = 'rgb(250,0,0)'
let bs = this.blockSize
let coords = this.curBlockShap
let startx = this.slotStartX this.moveAction * this.blockSize
let starty = this.slotStartY this.step * this.blockSize
for (let i=0;i<4;i ) {
let x = startx coords[i][0]*this.blockSize
let y = starty coords[i][1]*this.blockSize
min = min > x ? x:min
max = max < x ? x:max
this.context.fillRect(x, y, bs, bs)
this.context.rect(x, y, bs, bs)
// console.info("x,y" x.toString() ":" y.toString())
this.slotBottomY = y
this.xleft = min
this.rightX = max
}
this.context.stroke()
// console.info("min,max" min.toString() ":" max.toString())
}
stackBlock() {
let block = []
let coords = this.curBlockShap
let startx = this.slotStartX this.moveAction * this.blockSize
let starty = this.slotStartY this.step * this.blockSize
for (let i=0;i<4;i ) {
let x = startx coords[i][0]*this.blockSize
let y = starty coords[i][1]*this.blockSize
console.info("stackBlock x:" x.toString() "y:" y.toString())
let indexX = x/this.blockSize
let indexY = y/this.blockSize
this.blockmap[indexY][indexX] = 1
console.info("stackBlock:" indexX ":" indexY)
block.push([x,y])
}
this.storeBlock.push(block)
console.info("stackBlock:" this.storeBlock.length.toString())
}
checkBlockmap() {
if (this.storeBlock.length == 0) {
if (this.slotBottomY >= 660) {
return 1
}
} else {
let coords = this.curBlockShap
let startx = this.slotStartX this.moveAction * this.blockSize
let starty = this.slotStartY this.step * this.blockSize
for (let i=0;i<4;i ) {
let x = startx coords[i][0]*this.blockSize
let y = starty coords[i][1]*this.blockSize this.blockSize
for (let k=0;k<22;k ) {
for (let l=0;l<9;l ) {
if (this.blockmap[k][l] == 1) {
let blocky = k * this.blockSize
let blockx = l * this.blockSize
//判断是否到底
if ((x == blockx && y == blocky) || y > 660) {
//判断是否到顶
if (y == 210) {
this.context.drawImage( this.gameoverImg,this.startX,this.startY,300,90)
//到顶回2
return 2
}
//到底回1
return 1
}
}
}
}
}
}
return 0
}
cleanBlockmap() {
//检查是否一行满了
let needMove = 0
for (let i=22;i>=0;i--) {
let linecnt = 0
for (let j = 8;j >= 0; j--) {
//是否有方块
if (this.blockmap[i][j] == 1) {
linecnt = 1
}
}
if (linecnt == 9) {
//此行都是方块,消除,计分
for (let j = 8;j >= 0; j--) {
this.blockmap[i][j] = 0
}
needMove = 1
this.score = 1
} else if (needMove > 0) {
for (let j = 8;j >= 0; j--) {
this.blockmap[i needMove][j] = this.blockmap[i][j]
this.blockmap[i][j] = 0
}
}
}
}
drawBlockmap() {
let bs = this.blockSize
this.context.fillStyle = 'rgb(250,0,0)'
for (let i=0;i<23;i ) {
for (let j=0;j<9;j ) {
//是否有方块
if (this.blockmap[i][j] == 1) {
let y = i * this.blockSize
let x = j * this.blockSize
this.context.fillRect(x, y, bs, bs)
this.context.rect(x, y, bs, bs)
console.info("drawBlockmap:" x.toString() ":" y.toString())
}
}
this.context.stroke()
console.info("drawBlockmap:" this.storeBlock.length.toString())
}
}
drawScore() {
this.context.fillStyle = 'rgb(0,0,0)'
this.context.font = '80px sans-serif'
this.context.fillText("Score:" this.score.toString(), 20, 140)
}
randomType() {
this.blockType = Math.floor(Math.random()*5)
console.info("blocktype:" this.blockType.toString())
}
drawStep() {
this.context.clearRect(0,0,this.context.width,this.context.height)
this.step = 1
this.drawBox()
this.drawBlockmap()
this.cleanBlockmap()
this.drawSideBlock()
this.drawBoxBlock()
this.drawScore()
let stepType = this.checkBlockmap()
if ( stepType == 1) {
this.stackBlock()
this.step = 0
this.randomType()
} else if (stepType == 2) {
this.state= 2
this.context.drawImage( this.gameoverImg,this.startX,this.startY,300,90)
}
}
drawall() {
this.drawBox()
this.drawSideBlock()
this.drawBoxBlock()
this.drawScore()
}
build() {
Column() {
Column() {
Canvas(this.context)
.width('100%')
.height('100%')
.onClick((ev: ClickEvent) => {
console.info("click!!")
this.doClick()
})
.onTouch((ev) => {
console.info("touch:" ev.type.toString())
console.info("touch x:" ev.touches[0].screenX.toString())
console.info("touch y:" ev.touches[0].screenY.toString())
})
.onReady(() =>{
this.context.imageSmoothingEnabled = false
this.randomType()
this.drawall()
})
}
.height('92%')
.width('100%')
Row() {
Button() { //按钮控件
Text('左')
.fontSize(20)
.fontWeight(FontWeight.Bold)
}.type(ButtonType.Capsule)
.width('20%')
.height('6%')
.backgroundColor('#0D9FFB')
.onClick(() => { //点击事件
if (this.xleft > 0) {
this.moveAction -= 1
}
})
Button() { //按钮控件
Text('右')
.fontSize(20)
.fontWeight(FontWeight.Bold)
}.type(ButtonType.Capsule)
.width('20%')
.height('6%')
.backgroundColor('#0D9FFB')
.onClick(() => { //点击事件
if (this.rightX < 240) {
this.moveAction = 1
}
})
}
}
.width('100%')
.height('100%')
.backgroundColor("#cccccc")
}
}
遗留问题:
等游戏完整发布,会有两个版本,单机和联机版本。
总结
本文主要介绍了小游戏的开发,画布功能的使用,游戏逻辑,分布式。
作者:王石
Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved