1. 前言
1024一起专注游戏是在屏幕上画上N x N个方格(如4x4共16个),格子内任意填写上从1开始顺序生成的数字(如1 ~ 16共16个数字)。游戏时,要求玩家用手指按从小到大(如1 ~ 16)的顺序依次指出其位置,按完所有数字后,显示所用的时间(秒)。所用时间越短,注意力水平越高。能够培养注意力集中、分配、控制能力;拓展视幅;加快视频;提高视觉的稳定性、辨别人、定向搜索能力。此游戏为最简单,最有效也是最科学的注意力训练方法。寻找目标数字时,注意力是需要极度集中的,把这短暂的高强度的集中精力过程反复练习,大脑的集中注意力功能就会不断的加固,提高。注意水平越来越高。
2. 项目结构图
![基于ArkUI框架的舒尔特方格游戏-开源基础软件社区](//file.elecfans.com/web2/M00/4F/63/pYYBAGLBwYmACZ6tAAGZBKPa9nY229.jpg)
![基于ArkUI框架的舒尔特方格游戏-开源基础软件社区](//file.elecfans.com/web2/M00/4E/C8/poYBAGLBwZuAMNz_AAFG-ERQXmQ868.jpg)
3. 项目开发介绍
舒尔特方格游戏有主界面和游戏界面两个页面组成,主界面拆开为title和body两个自定义组件组成,游戏界面拆开为title,body和footer三个自定义组件组成,utils为随机生成数字公共类。下面我们来一个一个界面和组件介绍:
3.1 主界面代码,只是一个程序入口,具体页面布局在自定义组件实现:
3.1.1 Index代码
import { Title } from '../common/home/title'
import { Body } from '../common/home/body'
@Entry
@Component
struct Index {
build() {
Column() {
Title();
Body();
}
.alignItems(HorizontalAlign.Center)
}
}
3.1.2 Title自定义组件代码:
@Component
export struct Title {
build() {
Column() {
Text("舒尔特方格")
.fontSize(34).margin({top: 30})
.fontWeight(FontWeight.Bold)
Text("SchulteGrid")
.fontSize(20).margin({top: 3, bottom: 60})
.fontWeight(FontWeight.Bold)
}
.width('100%')
}
}
3.1.3 Body自定义组件代码
import router from '@system.router'
@Component
export struct Body {
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Start }) {
// 3x3, 4x4, 5x5 按钮布局
Row() {
Button("3X3", { type: ButtonType.Circle, stateEffect: true })
.width(70).height(70).backgroundColor(0x317aff).fontSize(20)
.onClick(() => { this.startGame(3) })
Button("4X4", { type: ButtonType.Circle, stateEffect: true })
.width(70).height(70).backgroundColor(0x317aff).fontSize(20)
.margin({left: 30, right: 30})
.onClick(() => { this.startGame(4) })
Button("5X5", { type: ButtonType.Circle, stateEffect: true })
.width(70).height(70).backgroundColor(0x317aff).fontSize(20)
.onClick(() => { this.startGame(5) })
}.alignItems(VerticalAlign.Center).margin({bottom: 30})
// 6x6, 7x7 按钮布局
Row() {
Button("6X6", { type: ButtonType.Circle, stateEffect: true })
.width(70).height(70).backgroundColor(0x317aff).fontSize(20)
.onClick(() => { this.startGame(6) })
Button("7X7", { type: ButtonType.Circle, stateEffect: true })
.width(70).height(70).backgroundColor(0x317aff).fontSize(20)
.margin({left: 30}).onClick(() => { this.startGame(7) })
}.alignItems(VerticalAlign.Center).margin({bottom: 30})
// 8x8, 9x9 按钮布局
Row() {
Button("8X8", { type: ButtonType.Circle, stateEffect: true })
.width(70).height(70).backgroundColor(0x317aff).fontSize(20)
.onClick(() => { this.startGame(8) })
Button("9X9", { type: ButtonType.Circle, stateEffect: true })
.width(70).height(70).backgroundColor(0x317aff).fontSize(20)
.margin({left: 30})
.onClick(() => { this.startGame(9) })
}.alignItems(VerticalAlign.Center)
}
.width('100%')
.height('100%')
}
// 开始游戏
startGame(idx:number) {
router.push({
uri: 'pages/game',
params: {index: idx}
})
}
}
3.2. 游戏界面代码,具体页面布局在自定义组件实现:
3.2.1 Game代码:
import router from '@system.router'
import { Title } from '../common/game/title'
import { Body } from '../common/game/body'
import { Footer } from '../common/game/footer'
import { getRandomData } from '../utils/utils'
@Entry
@Component
struct Game {
private idx: number = router.getParams().index
@State index: number = this.idx
@State numArray: String[] = getRandomData(this.idx)
@State time: number = 0
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceBetween }) {
Title()
Body({idx: $index, numArray: $numArray, time: $time})
Footer({idx: $index, time: $time})
}
.width('100%')
.height('100%')
}
}
3.3.2 游戏Title自定义组件代码:
import router from '@system.router'
@Component
export struct Title {
build() {
Row() {
Image($r("app.media.back"))
.objectFit(ImageFit.Contain)
.width(50)
.height(50)
.margin({ right: 10 })
.onClick(()=>{ this.onBack() })
Text("游戏开始")
.fontSize(24)
.fontColor(Color.White)
.fontWeight(FontWeight.Bold)
}
.width('100%')
.padding({ top: 10, bottom: 10})
.backgroundColor(0x317aff)
}
onBack() {
router.back();
}
}
3.2.3 游戏Body自定义组件代码:
@Component
export struct Body {
@Link idx: number;
@Link numArray: String[];
@Link time: number;
private btnSize: number[] = [32, 18, 12, 8, 6, 4, 4]
private btnFont: number[] = [32, 24, 22, 12, 7, 8, 6]
private gridHeight: number[] = [48, 48, 48, 44, 46, 50, 66]
private template: string[] = ['1fr 1fr 1fr', '1fr 1fr 1fr 1fr', '1fr 1fr 1fr 1fr 1fr', '1fr 1fr 1fr 1fr 1fr 1fr', '1fr 1fr 1fr 1fr 1fr 1fr 1fr', '1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr', '1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr']
private flagNum: number = 1
private startTime: number = new Date().getTime()
build() {
Grid() {
ForEach(this.numArray, (day: string) => {
GridItem() {
Button(day, { type: ButtonType.Circle, stateEffect: true })
.width(this.btnSize[this.idx-3] * this.idx)
.height(this.btnSize[this.idx-3] * this.idx)
.backgroundColor(0x317aff).fontSize(this.btnFont[this.idx-3])
.onClick(() => { this.startGame(Number(day)) })
}
}, day => day)
}
.columnsTemplate(this.template[this.idx-3])
.rowsTemplate(this.template[this.idx-3])
.columnsGap(10)
.rowsGap(10)
.width(96+'%')
.height(this.gridHeight[this.idx-3]+'%')
}
startGame(num:number) {
if (num == this.numArray.length && this.flagNum == this.numArray.length ) {
AlertDialog.show({ message: '恭喜您挑战成功'})
this.time = (new Date().getTime() - this.startTime) * 1.0 / 1000
}
if (num > this.flagNum) {
AlertDialog.show({ message: '请点击小于此数字'})
} else if (num < this.flagNum) {
AlertDialog.show({ message: '当前点击的数字,已点击过'})
} else {
this.flagNum++
}
}
}
3.2.4 游戏Footer自定义组件代码:
@Component
export struct Footer {
@Link idx: number;
@Link time: number;
build() {
Stack({ alignContent: Alignment.Bottom }) {
Row() {
// 耗时
Button({ type: ButtonType.Capsule, stateEffect: false }) {
Row() {
Image($r('app.media.trophy')).width(20).height(20).margin({ left: 12 })
Text(this.time + '"').fontSize(16).fontColor(0xffffff).margin({ left: 5, right: 12 })
}.alignItems(VerticalAlign.Center).width(100)
}.backgroundColor(0x317aff).opacity(0.7).width(100)
Button({ type: ButtonType.Capsule, stateEffect: false }) {
Row() {
Image($r('app.media.time')).width(20).height(20).margin({ left: 12 })
Text('计时中').fontSize(16).fontColor(0xffffff).margin({ left: 5, right: 12 })
}.alignItems(VerticalAlign.Center).width(100)
}.backgroundColor(0x317aff).opacity(0.7).width(100)
.margin({left: 20, right: 20})
Button({ type: ButtonType.Capsule, stateEffect: true }) {
Row() {
Image($r('app.media.help')).width(20).height(20).margin({ left: 12 })
Text('帮助').fontSize(16).fontColor(0xffffff).margin({ left: 5, right: 12 })
}.alignItems(VerticalAlign.Center).width(100)
}.backgroundColor(0x317aff).width(100)
.onClick(() => { this.showHelp() })
}
}.width('100%').height(100).margin({ top: 5, bottom: 10 })
}
showHelp() {
AlertDialog.show({ message: '以最快速度从 1 选到 ' + (this.idx*this.idx) })
}
}
3.3. Utils公共函数实现:
export function getRandomData(idx:number): Array<String> {
let count:number = idx * idx;
let result:Array<String> = [];
do {
let num = Math.floor(Math.random() * count + 1);
if (-1 == result.indexOf(num+'')) {
result.push(num+'');
}
if (count == result.length) {
break;
}
}while(true)
return result;
};
**总结:**看到主界面和游戏界面代码,是不是很简洁,声明式开发范式之美,那你还等什么?跟上步伐开始声明式开发吧!!!