????????在鴻蒙應用開發中,游戲類應用能很好地鍛煉 UI 布局、狀態管理與邏輯交互能力。本文將以一個隨機迷宮游戲為例,詳細拆解從首頁設計到迷宮生成、角色控制、通關判定的完整開發流程,帶你掌握 ArkUI 框架的核心應用技巧。
一、項目整體架構
本次開發的隨機迷宮游戲包含兩個核心頁面,頁面間通過router
路由實現跳轉,整體結構清晰,便于后續擴展維護:
頁面名稱 | 頁面功能 | 核心組件 / 邏輯 |
---|---|---|
UI_test1(首頁) | 游戲入口,展示標題與開始按鈕 | Column、Stack、Button、router.pushUrl |
migong(迷宮頁) | 隨機迷宮生成、角色控制、通關判定 | Grid、@State 狀態管理、BFS 路徑檢測、AlertDialog |
二、首頁開發:打造簡潔的游戲入口
首頁作為用戶的第一個交互界面,需兼顧視覺吸引力與操作便捷性。我們采用背景圖 + 居中布局的設計,突出 “迷宮游戲” 主題與 “開始游戲” 按鈕。
界面演示:
1. 核心代碼解析
typescript
import router from '@ohos.router'; // 導入路由模塊,實現頁面跳轉
@Entry
@Component
struct UI_test1{build() {// 外層Column確保頁面占滿屏幕Column(){// Stack實現背景圖與前景內容的層疊Stack(){// 背景圖:寬度100%、高度100%,鋪滿整個頁面Image($r("app.media.bg")).width('100%').height('100%')// 內層Column:居中展示標題與按鈕Column(){// 游戲標題:白色、斜體、加粗,調整margin優化位置Text('迷宮游戲 ').fontColor(Color.White).fontSize(58).width(250).height(100).fontStyle(FontStyle.Italic).fontWeight(FontWeight.Bold).margin({ left: '12.00vp' })// 開始游戲按鈕:淡藍色背景、白色文字,點擊跳轉迷宮頁Button('開始游戲').fontColor(Color.White).fontSize(30).width(200).height(50).backgroundColor('#9964f0fd').margin({ top: '400.00vp' }) // 向下偏移,與標題形成層次感.onClick(()=>{// 路由跳轉:跳轉到test_pages目錄下的migong頁面router.pushUrl({ url: "test_pages/migong" });});}.width('100%').height('100%').justifyContent(FlexAlign.Center) // 子組件垂直居中}}.width('100%').height('100%')}
}
2. 關鍵設計思路
- 層疊布局(Stack):通過 Stack 將背景圖與前景內容(標題、按鈕)疊加,避免背景圖被其他組件遮擋;
- 路由跳轉(router):使用
router.pushUrl
實現首頁到迷宮頁的跳轉,url
需與頁面實際路徑一致(此處為test_pages/migong
); - 視覺優化:標題采用 “斜體 + 加粗” 組合提升辨識度,按鈕使用半透明背景色(
#9964f0fd
,前兩位99
為透明度),避免與背景圖產生強烈沖突。
三、迷宮頁開發:核心邏輯與交互實現
迷宮頁是整個游戲的核心,需實現隨機迷宮生成、角色移動、路徑檢測、通關彈窗四大功能。下面分模塊拆解實現細節。
1. 隨機迷宮生成:確保有有效路徑
迷宮本質是一個 20x20 的網格(1 表示墻壁,0 表示可通行區域),為避免生成 “死胡同” 迷宮,我們通過固定邊界 + 隨機填充 + 路徑檢測的邏輯,確保從 “入口(1,1)” 到 “出口(18,18)” 有有效路徑。
界面演示:
(1)核心函數:generateRandomWall
typescript
// 生成隨機迷宮數組
generateRandomWall() {const originalWall = [/* 初始迷宮數組,略 */]; // 基礎迷宮模板const rows = 20; // 迷宮行數const cols = 20; // 迷宮列數let newWall: number[] = [];// 1. 固定邊界:第一列、最后一列、第一行、最后一行保持為墻壁(1)// 固定第一行for (let i = 0; i < cols; i++) {newWall.push(originalWall[i]);}// 固定中間行的第一列和最后一列for (let r = 1; r < rows - 1; r++) {newWall.push(originalWall[r * cols]); // 第一列(墻壁)// 中間列隨機填充:50%概率為可通行區域(0),50%為墻壁(1)for (let c = 1; c < cols - 1; c++) {let randomValue = Math.random() > 0.5 ? 1 : 0;// 固定入口(1,1)和出口(18,18)為可通行區域if (r === 1 && c === 1) randomValue = 0;if (r === rows - 2 && c === cols - 2) randomValue = 0;newWall.push(randomValue);}newWall.push(originalWall[r * cols + cols - 1]); // 最后一列(墻壁)}// 固定最后一行for (let i = cols * (rows - 1); i < cols * rows; i++) {newWall.push(originalWall[i]);}// 2. 路徑檢測:若當前迷宮無有效路徑,重新生成while (!this.checkPathExists(newWall)) {let tempWall = this.generateRandomWall();newWall = tempWall.slice(); // 深拷貝新迷宮數組}return newWall;
}
(2)路徑檢測:BFS 算法確保連通性
使用廣度優先搜索(BFS)?檢測從入口到出口是否存在可通行路徑,避免生成 “無法通關” 的迷宮:
界面演示:
typescript
// 檢查迷宮是否存在有效路徑(BFS算法)
checkPathExists(wall: number[]) {const rows = 20;const cols = 20;const startX = 1, startY = 1; // 入口坐標const endX = cols - 2, endY = rows - 2; // 出口坐標// visited數組:記錄已訪問的格子,避免重復檢測let visited: boolean[][] = [];for (let i = 0; i < rows; i++) {visited[i] = new Array(cols).fill(false);}// 隊列:存儲待訪問的格子坐標(BFS核心)let queue: [number, number][] = [];queue.push([startX, startY]);visited[startY][startX] = true;// 四個移動方向:上、下、左、右const directions = [[0, 1], [1, 0], [0, -1], [-1, 0]];while (queue.length > 0) {let item = queue.shift(); // 取出隊列頭部格子if (item) {const [x, y] = item;// 若到達出口,返回true(存在有效路徑)if (x === endX && y === endY) return true;// 遍歷四個方向,檢測相鄰格子是否可通行for (let direction of directions) {const newX = x + direction[0];const newY = y + direction[1];// 條件判斷:1. 格子在迷宮范圍內;2. 未被訪問;3. 可通行(值為0)if (newX >= 0 && newX < cols && newY >= 0 && newY < rows && !visited[newY][newX] && wall[newY * cols + newX] === 0) {queue.push([newX, newY]);visited[newY][newX] = true;}}}}// 遍歷完所有格子仍未到達出口,返回false(無有效路徑)return false;
}
2. 迷宮渲染:使用 Grid 組件構建網格
通過Grid
組件將wall
數組(20x20)渲染為可視化迷宮,其中:
- 值為 0 的格子:白色背景(可通行區域);
- 值為 1 的格子:灰色背景(墻壁)。
核心代碼:
typescript
// 迷宮網格渲染
Grid() {// ForEach:遍歷wall數組,生成每個格子ForEach(this.wall, (item: number) => {GridItem() {if (item === 0) { // 可通行區域Text('').fontSize(32).backgroundColor(Color.White).width(18).height(21).textAlign(TextAlign.Center)} else if (item === 1) { // 墻壁Text('').fontSize(32).backgroundColor('#8a5e929b').width(18).height(21).textAlign(TextAlign.Center)}}})
}
// 網格配置:20列、20行,列間距與行間距為1(避免格子粘連)
.columnsTemplate('1fr 1fr ... 1fr') // 重復20次1fr,省略部分代碼
.rowsTemplate('1fr 1fr ... 1fr') // 重復20次1fr,省略部分代碼
.columnsGap(1).rowsGap(1)
.width('90%').height(400) // 控制網格大小,適配屏幕
.backgroundColor(Color.White)
3. 角色控制:狀態管理實現移動邏輯
通過@State
裝飾器管理角色的坐標(peoplex
、peopley
)與當前格子索引(positionnumber
),點擊方向按鈕(←↑↓→)時更新角色位置,并判斷是否撞墻(撞墻則回退位置)。
(1)狀態定義
typescript
@State wall: number[] = this.generateRandomWall(); // 迷宮數組(初始生成)
@State peoplex: number = 34; // 角色初始X坐標
@State peopley: number = 100; // 角色初始Y坐標
@State positionnumber: number = 1; // 角色初始格子索引(對應入口)
@State over: boolean = false; // 通關狀態標記
(2)方向按鈕邏輯(以 “→” 和 “↓” 為例)
typescript
// 向右移動按鈕
Button('→').backgroundColor('#20101010').height(60).width(60).onClick(() => {this.positionnumber += 1; // 索引+1(向右移動一格)// 若目標格子可通行(值為0),更新X坐標;否則回退索引if (this.wall[this.positionnumber] === 0) {this.peoplex += 16.4; // 每次移動的像素值(根據格子寬度計算)} else {this.positionnumber -= 1; // 撞墻,回退到原位置}})// 向下移動按鈕(含通關判定)
Button('↓').backgroundColor('#20101010').height(60).width(60).onClick(() => {// 若當前位置是出口前一格,觸發通關彈窗if (this.positionnumber === this.wall.length - 2) {AlertDialog.show({title: '游戲成功',message: '恭喜通關',autoCancel: true,alignment: DialogAlignment.Bottom,primaryButton: {value: '確定',action: () => console.info('通關彈窗-確定按鈕點擊')},secondaryButton: {value: '最優路徑',action: () => router.pushUrl({ url: "test_pages/migong1" }) // 跳轉最優路徑頁},cancel: () => console.info('彈窗關閉')});} else {// 普通向下移動邏輯(與向右類似)this.positionnumber += 20; // 索引+20(向下移動一行,共20列)if (this.wall[this.positionnumber] === 0) {this.peopley += 20;} else {this.positionnumber -= 20;}}})
4. 角色渲染與額外功能
- 角色顯示:使用
Image
組件加載角色圖片,通過position
屬性綁定peoplex
和peopley
,實現角色隨坐標更新而移動; - 返回首頁:左上角添加 “返回” 圖標,點擊通過
router
跳轉回首頁; - 最優路徑:底部添加 “解鎖最優路徑” 按鈕,跳轉至
migong1
頁面(可擴展 Dijkstra 算法實現最優路徑繪制)。
四、開發總結與優化方向
1. 核心技術點回顧
- ArkUI 布局:靈活使用 Column、Stack、Grid 組件實現復雜 UI 結構;
- 狀態管理:
@State
裝飾器實現角色位置、迷宮數組的響應式更新; - 路由跳轉:
router
模塊實現頁面間的無縫切換; - 算法應用:BFS 算法確保迷宮連通性,為后續擴展最優路徑(如 Dijkstra、A*)奠定基礎。
2. 可優化方向
- 角色移動優化:當前通過固定像素值移動,可改為根據格子寬高動態計算,適配不同屏幕;
- 觸摸控制:新增滑動手勢控制角色移動(如左滑→向左移動),提升操作體驗;
- 難度分級:增加 “簡單(10x10)”“中等(20x20)”“困難(30x30)” 選項,動態調整迷宮大小;
- 路徑可視化:在
migong1
頁面中,通過改變格子背景色(如綠色)繪制最優路徑,幫助用戶理解迷宮邏輯。
????????通過本次隨機迷宮游戲開發,不僅能掌握 ArkUI 的核心語法與組件使用,還能將數據結構(如 BFS)與實際應用結合,為后續鴻蒙游戲或復雜應用開發積累經驗。如果你有更多優化想法,歡迎在評論區交流!