今天,我给大家带了一个新的项目《变色方块》,下面我介绍一下它的实现过程。
介绍
变色方块是一款小游戏,进入关卡后,有n*n个小方块组成的方块,点击某个小方块,会将这个小方块及其上下左右方向的方块变一种颜色,需将所有浅蓝色方块变成粉色后方可进入下一关
环境搭建
安装DevEco Studio,详情请参考下载和安装软件。
设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:• 如果可以直接访问Internet,只需进行下载HarmonyOS SDK操作。• 如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境。
开发者可以参考以下链接,完成设备调试的相关配置: 使用真机进行调试• 使用模拟器进行调试
项目结构
项目展示
小游戏第一关如下
点击方块,蓝色方块变为粉色,游戏进入下一关。点击重新开始按钮,提示玩家“会把你传送到第一关”。点击重玩本关按钮,提示玩家“会把你传送到刚进入本关的状态”,并将所有按钮恢复。点击游戏说明按钮,提示玩家游戏规则。如下图所示。
实现代码
主要页面index
翻转(turnover
):
根据盒子的位置(行和列索引),翻转当前盒子及其上下左右的盒子。
调用 isAllOver
方法检查是否所有盒子都已翻转。
点击盒子时,会触发 turnover
方法,改变盒子的状态并检查游戏是否结束。
判断(isAllOver
):
遍历所有盒子,检查是否所有盒子都已翻转。
如果所有盒子都已翻转,显示过关对话框,并增加 startLine
以进入下一关。
调用 boxes.reload
方法重新加载新关卡的盒子。
构建(build
):
使用 Column
和 Row
布局组件构建页面布局。
包含三个按钮:重新开始、重玩本关和游戏说明,每个按钮都有相应的点击事件处理逻辑。
使用 GridRow
和 GridCol
组件创建一个网格布局,用于显示和点击盒子。
ForEach
循环遍历 boxes.boxes
,为每个盒子创建一个 boxView
组件。
import { boxes } from "../viewmodel/boxes"
import boxList from "../viewmodel/boxes"
import { box } from "../viewmodel/box"
import { boxView } from '../view/boxview'
@Entry
@Component
struct Index {
@State boxes: boxes = boxList
@State startLine: number = 1
aboutToAppear() {
boxList.init(this.startLine)
}
//翻转
turnover(box: box) {
console.log(box.colIndex + " " + box.rowIndex + " " + box.index)
if (box.rowIndex < this.startLine) {
this.boxes.boxes[box.index+1].changeTurned()
console.log("右")
}
if (box.rowIndex > 1) {
this.boxes.boxes[box.index-1].changeTurned()
console.log("左")
}
if (box.colIndex > 1) {
this.boxes.boxes[box.index-this.startLine].changeTurned()
console.log("上")
}
if (box.colIndex < this.startLine) {
this.boxes.boxes[box.index+this.startLine].changeTurned()
console.log("下")
}
box.changeTurned()
this.isAllOver()
}
//判断
isAllOver() {
for (let i = 0; i < this.boxes.index; i++) {
console.log(this.boxes.index.toString())
console.log(this.boxes.boxes[i].turned ? "true" : "false")
if (!this.boxes.boxes[i].turned) {
return
}
}
//过关信息
AlertDialog.show({
title: "恭喜过关",
message: `恭喜你进入第${this.startLine + 1}关`,
confirm: {
value: "好",
action: () => {
}
}
})
this.startLine = this.startLine + 1
//再次进行加载
this.boxes.reload(this.startLine)
}
build() {
Column() {
Row() {
Text(`第${this.startLine}关`)
.fontSize(40)
.width("100%")
.fontWeight(FontWeight.Bold)
.textAlign(TextAlign.Center)
}.width("100%")
.height("15%")
Row() {
Button("重新开始").onClick(() => {
AlertDialog.show({
title: "重新开始?",
message: "会把你传送到第一关",
confirm: {
value: "好",
action: () => {
this.startLine = 1
this.boxes.reStart()
}
}
})
})
Button("重玩本关").onClick(() => {
AlertDialog.show({
title: "重玩本关?",
message: "会把你传送到刚进入本关的状态",
confirm: {
value: "好",
action: () => {
this.boxes.reLevel(this.startLine)
}
}
})
})
Button("游戏说明").onClick(() => {
AlertDialog.show({
title: "游戏说明",
message: "1.游戏玩法:点击色块,会改变其自身和上下左右相邻色块的颜色。\n" +
"2.游戏规则:当全部色块变为粉色,即为胜利。",
confirm: {
value: "我知道了",
action: () => {
}
}
})
})
}.width("100%")
.height("25%")
.justifyContent(FlexAlign.SpaceEvenly)
Column() {
GridRow(
{ columns: this.startLine }
) {
ForEach(this.boxes.boxes, (box: box) => {
GridCol() {
Row() {
boxView({ b: box })
}
.onClick(() => {
console.log(box.index.toString())
this.turnover(box)
})
}.width("70%")
.height(400/this.startLine)
})
}
}.height("600")
.width("100%")
}.width("100%").height("100%")
.backgroundColor("#F0FF00")
}
}
entryability
import UIAbility from '@ohos.app.ability.UIAbility';
import hilog from '@ohos.hilog';
import window from '@ohos.window';
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
}
onDestroy() {
(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage) {
// Main window is created, set main page for this ability
(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
windowStage.loadContent('pages/Index', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
});
}
onWindowStageDestroy() {
// Main window is destroyed, release UI related resources
(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
}
onForeground() {
// Ability has brought to foreground
(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
}
onBackground() {
// Ability has back to background
(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
}
}
box
这个类可以用于创建和管理游戏界面中的盒子元素,跟踪盒子翻转状态。
@Observed
export class box {
colIndex:number
rowIndex:number
turned:boolean
index:number
constructor(colIndex:number,rowIndex:number,turned:boolean,index:number) {
this.colIndex = colIndex
this.rowIndex = rowIndex
this.turned = turned
this.index = index
}
//改变是否翻转
changeTurned(){
this.turned = !this.turned
}
//设置Box 各项属性
setBox(colIndex:number,rowIndex:number,turned:boolean,index:number){
this.colIndex = colIndex
this.rowIndex = rowIndex
this.turned = turned
this.index = index
}
}
boxes
这个类提供了初始化、重新加载关卡、重玩本关和重新开始游戏的功能。它通过管理盒子数组来控制游戏的状态,包括盒子的数量和位置。
import {box} from "../viewmodel/box"
export class boxes {
boxes:Array<box> = []
index :number = 0
different :number = 0
constructor() {
}
//初始化
init (startLine:number){
for (let i = 1; i <= startLine; i++) {
for (let j = 1; j <= startLine; j++) {
this.boxes.push(new box(i, j, false, this.index))
this.index++
}
}
}
//重新加载
reload(startLine:number){
this.index = 0
//判断需要增加多少长度
this.different = startLine*startLine - (startLine-1)*(startLine-1)
for (let i = 0; i < this.different; i++) {
this.boxes.push(new box(0,0,false,0))
}
//将数组中的元素属性重新赋值
for (let i = 1; i <= startLine; i++) {
for (let j = 1; j <= startLine; j++) {
this.boxes[this.index].setBox(i,j,false,this.index)
this.index ++
}
}
}
//重玩本关
reLevel(startLine:number){
this.index = 0
for (let i = 1; i <= startLine; i++) {
for (let j = 1; j <= startLine; j++) {
this.boxes[this.index].setBox(i,j,false,this.index)
this.index ++
}
}
}
//重新开始
reStart (){
this.index = 0
this.boxes.splice(1,this.boxes.length)
this.boxes[0].setBox(1,1,false,0)
}
}
const boxList = new boxes()
export default boxList as boxes