Flutter for OpenHarmony 实战:2048游戏完整开发指南

欢迎加入开源鸿蒙跨平台社区:开源鸿蒙跨平台开发者社区

Flutter for OpenHarmony 实战:2048游戏完整开发指南

文章目录

  • [Flutter for OpenHarmony 实战:2048游戏完整开发指南](#Flutter for OpenHarmony 实战:2048游戏完整开发指南)
    • 摘要
    • 一、项目背景与功能概述
      • [1.1 2048游戏介绍](#1.1 2048游戏介绍)
      • [1.2 应用功能规划](#1.2 应用功能规划)
      • [1.3 方块颜色设计](#1.3 方块颜色设计)
    • 二、数据模型设计
      • [2.1 游戏数据结构](#2.1 游戏数据结构)
      • [2.2 游戏初始化](#2.2 游戏初始化)
    • 三、随机方块生成
      • [3.1 添加随机方块](#3.1 添加随机方块)
    • 四、移动与合并算法
      • [4.1 向左移动](#4.1 向左移动)
      • [4.2 向右移动](#4.2 向右移动)
      • [4.3 向上移动](#4.3 向上移动)
      • [4.4 向下移动](#4.4 向下移动)
    • 五、游戏状态管理
      • [5.1 移动处理](#5.1 移动处理)
      • [5.2 检查游戏状态](#5.2 检查游戏状态)
      • [5.3 检查是否还能移动](#5.3 检查是否还能移动)
    • 六、UI界面实现
      • [6.1 网格构建](#6.1 网格构建)
      • [6.2 方块UI](#6.2 方块UI)
      • [6.3 颜色映射](#6.3 颜色映射)
      • [6.4 控制按钮](#6.4 控制按钮)
    • 七、总结

摘要

2048是由Gabriel Cirulla在2014年创造的经典益智游戏,通过滑动屏幕合并相同数字的方块,目标是合成2048这个数字。本文将详细介绍如何使用Flutter for OpenHarmony框架开发一款功能完整的2048游戏。文章涵盖了方块合并算法、随机生成策略、分数计算、游戏状态管理等核心技术点。通过本文学习,读者将掌握Flutter在滑动类游戏开发中的完整流程,了解数组操作和游戏逻辑的实现。


一、项目背景与功能概述

1.1 2048游戏介绍

2048是一款简单但极具挑战性的益智游戏:

  • 目标:合成数字为2048的方块
  • 规则
    1. 滑动时所有方块向该方向移动
    2. 相同数字的方块碰撞时合并
    3. 每次移动后在空位生成2或4
    4. 无法移动时游戏结束

1.2 应用功能规划

功能模块 具体功能
方向控制 上下左右四个方向移动
方块合并 相同数字合并为2倍值
随机生成 90%概率生成2,10%生成4
分数计算 每次合并累加分数
最高分记录 保存历史最高分
胜利判断 合成2048时获胜
失败判断 无法移动时游戏结束
颜色映射 不同数字不同颜色

1.3 方块颜色设计

数字 背景色 文字色
0 灰色300 -
2 灰色100 深灰
4 琥珀100 深灰
8 琥珀200 白色
16 橙色200 白色
32 橙色300 白色
64 橙色400 白色
128 深橙300 白色
256 深橙400 白色
512 红色300 白色
1024 红色400 白色
2048 红色500 白色

二、数据模型设计

2.1 游戏数据结构

dart 复制代码
class _GamePageState extends State<GamePage> {
  // 4×4游戏板
  late List<List<int>> _board;

  // 游戏状态
  int _score = 0;
  int _bestScore = 0;
  bool _gameOver = false;
  bool _gameWon = false;
  final Random _random = Random();
}

2.2 游戏初始化

dart 复制代码
void _initGame() {
  _board = List.generate(4, (_) => List.filled(4, 0));
  _score = 0;
  _gameOver = false;
  _gameWon = false;

  _addRandomTile();
  _addRandomTile();

  setState(() {});
}

三、随机方块生成

3.1 添加随机方块

dart 复制代码
void _addRandomTile() {
  final emptyCells = <Point>[];

  // 收集所有空位
  for (int r = 0; r < 4; r++) {
    for (int c = 0; c < 4; c++) {
      if (_board[r][c] == 0) {
        emptyCells.add(Point(r, c));
      }
    }
  }

  // 随机选择一个空位
  if (emptyCells.isNotEmpty) {
    final randomCell = emptyCells[_random.nextInt(emptyCells.length)];
    _board[randomCell.x.toInt()][randomCell.y.toInt()] =
      _random.nextDouble() < 0.9 ? 2 : 4;
  }
}

关键设计

  • 90%概率生成2,10%概率生成4
  • 只在空位生成
  • 每次移动后生成一个新方块

四、移动与合并算法

4.1 向左移动

dart 复制代码
bool _moveLeft() {
  bool moved = false;

  for (int r = 0; r < 4; r++) {
    // 1. 过滤掉0,收集非零元素
    final row = _board[r].where((n) => n != 0).toList();
    final newRow = <int>[];

    // 2. 合并相同数字
    for (int i = 0; i < row.length; i++) {
      if (i + 1 < row.length && row[i] == row[i + 1]) {
        final merged = row[i] * 2;
        newRow.add(merged);
        _score += merged;
        if (merged == 2048 && !_gameWon) {
          _gameWon = true;
        }
        i++; // 跳过下一个
      } else {
        newRow.add(row[i]);
      }
    }

    // 3. 补齐0
    while (newRow.length < 4) {
      newRow.add(0);
    }

    // 4. 更新棋盘并检测是否有移动
    for (int c = 0; c < 4; c++) {
      if (_board[r][c] != newRow[c]) {
        moved = true;
      }
      _board[r][c] = newRow[c];
    }
  }

  return moved;
}

算法步骤

  1. 过滤掉空白格(0)
  2. 合并相邻的相同数字
  3. 在末尾补齐0
  4. 检测是否有变化

4.2 向右移动

dart 复制代码
bool _moveRight() {
  bool moved = false;

  for (int r = 0; r < 4; r++) {
    final row = _board[r].where((n) => n != 0).toList();
    final newRow = <int>[];

    // 从右向左合并
    for (int i = row.length - 1; i >= 0; i--) {
      if (i - 1 >= 0 && row[i] == row[i - 1]) {
        final merged = row[i] * 2;
        newRow.insert(0, merged);
        _score += merged;
        if (merged == 2048 && !_gameWon) {
          _gameWon = true;
        }
        i--; // 跳过前一个
      } else {
        newRow.insert(0, row[i]);
      }
    }

    // 在前面补齐0
    while (newRow.length < 4) {
      newRow.insert(0, 0);
    }

    for (int c = 0; c < 4; c++) {
      if (_board[r][c] != newRow[c]) {
        moved = true;
      }
      _board[r][c] = newRow[c];
    }
  }

  return moved;
}

4.3 向上移动

dart 复制代码
bool _moveUp() {
  bool moved = false;

  for (int c = 0; c < 4; c++) {
    // 收集列的非零元素
    final col = <int>[];
    for (int r = 0; r < 4; r++) {
      if (_board[r][c] != 0) {
        col.add(_board[r][c]);
      }
    }

    final newCol = <int>[];

    // 从上向下合并
    for (int i = 0; i < col.length; i++) {
      if (i + 1 < col.length && col[i] == col[i + 1]) {
        final merged = col[i] * 2;
        newCol.add(merged);
        _score += merged;
        if (merged == 2048 && !_gameWon) {
          _gameWon = true;
        }
        i++; // 跳过下一个
      } else {
        newCol.add(col[i]);
      }
    }

    while (newCol.length < 4) {
      newCol.add(0);
    }

    for (int r = 0; r < 4; r++) {
      if (_board[r][c] != newCol[r]) {
        moved = true;
      }
      _board[r][c] = newCol[r];
    }
  }

  return moved;
}

4.4 向下移动

dart 复制代码
bool _moveDown() {
  bool moved = false;

  for (int c = 0; c < 4; c++) {
    final col = <int>[];
    for (int r = 0; r < 4; r++) {
      if (_board[r][c] != 0) {
        col.add(_board[r][c]);
      }
    }

    final newCol = <int>[];

    // 从下向上合并
    for (int i = col.length - 1; i >= 0; i--) {
      if (i - 1 >= 0 && col[i] == col[i - 1]) {
        final merged = col[i] * 2;
        newCol.insert(0, merged);
        _score += merged;
        if (merged == 2048 && !_gameWon) {
          _gameWon = true;
        }
        i--; // 跳过前一个
      } else {
        newCol.insert(0, col[i]);
      }
    }

    while (newCol.length < 4) {
      newCol.insert(0, 0);
    }

    for (int r = 0; r < 4; r++) {
      if (_board[r][c] != newCol[r]) {
        moved = true;
      }
      _board[r][c] = newCol[r];
    }
  }

  return moved;
}

五、游戏状态管理

5.1 移动处理

dart 复制代码
void _handleMove(String direction) {
  if (_gameOver) return;

  bool moved = false;

  switch (direction) {
    case 'left':
      moved = _moveLeft();
      break;
    case 'right':
      moved = _moveRight();
      break;
    case 'up':
      moved = _moveUp();
      break;
    case 'down':
      moved = _moveDown();
      break;
  }

  if (moved) {
    _addRandomTile();

    if (_score > _bestScore) {
      _bestScore = _score;
    }

    _checkGameState();

    setState(() {});
  }
}

5.2 检查游戏状态

dart 复制代码
void _checkGameState() {
  // 检查是否胜利
  if (_gameWon) {
    _showWinDialog();
    return;
  }

  // 检查是否游戏结束
  if (!_canMove()) {
    _gameOver = true;
    _showGameOverDialog();
  }
}

5.3 检查是否还能移动

dart 复制代码
bool _canMove() {
  // 检查是否有空格
  for (int r = 0; r < 4; r++) {
    for (int c = 0; c < 4; c++) {
      if (_board[r][c] == 0) return true;
    }
  }

  // 检查是否有相邻相同的数字
  for (int r = 0; r < 4; r++) {
    for (int c = 0; c < 4; c++) {
      final current = _board[r][c];
      if (c + 1 < 4 && _board[r][c + 1] == current) return true;
      if (r + 1 < 4 && _board[r + 1][c] == current) return true;
    }
  }

  return false;
}

检测条件

  1. 有空格:可以移动
  2. 有相邻相同的数字:可以合并
  3. 都不满足:游戏结束

六、UI界面实现

6.1 网格构建

dart 复制代码
Widget _buildBoard() {
  return Container(
    padding: const EdgeInsets.all(8),
    decoration: BoxDecoration(
      color: Colors.brown.shade300,
      borderRadius: BorderRadius.circular(8),
    ),
    child: GridView.builder(
      primary: true,
      padding: EdgeInsets.zero,
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 4,
        crossAxisSpacing: 8,
        mainAxisSpacing: 8,
        childAspectRatio: 1.0,
      ),
      itemCount: 16,
      itemBuilder: (context, index) {
        final row = index ~/ 4;
        final col = index % 4;
        return _buildTile(row, col);
      },
    ),
  );
}

6.2 方块UI

在这里插入图片描述

dart 复制代码
Widget _buildTile(int row, int col) {
  final value = _board[row][col];

  return Container(
    decoration: BoxDecoration(
      color: _getTileColor(value),
      borderRadius: BorderRadius.circular(8),
    ),
    child: Center(
      child: value == 0
        ? null
        : Text(
            '$value',
            style: TextStyle(
              fontSize: value >= 1000 ? 24 : 32,
              fontWeight: FontWeight.bold,
              color: _getTextColor(value),
            ),
          ),
    ),
  );
}

6.3 颜色映射

dart 复制代码
Color _getTileColor(int value) {
  switch (value) {
    case 0: return Colors.grey.shade300;
    case 2: return Colors.grey.shade100;
    case 4: return Colors.amber.shade100;
    case 8: return Colors.amber.shade200;
    case 16: return Colors.orange.shade200;
    case 32: return Colors.orange.shade300;
    case 64: return Colors.orange.shade400;
    case 128: return Colors.deepOrange.shade300;
    case 256: return Colors.deepOrange.shade400;
    case 512: return Colors.red.shade300;
    case 1024: return Colors.red.shade400;
    case 2048: return Colors.red.shade500;
    default: return Colors.purple;
  }
}

Color _getTextColor(int value) {
  if (value <= 4) return Colors.grey.shade800;
  return Colors.white;
}

6.4 控制按钮

dart 复制代码
Container(
  padding: const EdgeInsets.all(16),
  color: Colors.grey.shade200,
  child: Column(
    children: [
      Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          ElevatedButton(
            onPressed: () => _handleMove('left'),
            style: ElevatedButton.styleFrom(
              minimumSize: const Size(60, 60),
            ),
            child: const Icon(Icons.arrow_back, size: 30),
          ),
        ],
      ),
      Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          ElevatedButton(
            onPressed: () => _handleMove('up'),
            style: ElevatedButton.styleFrom(
              minimumSize: const Size(60, 60),
            ),
            child: const Icon(Icons.arrow_upward, size: 30),
          ),
          const SizedBox(width: 16),
          ElevatedButton(
            onPressed: () => _handleMove('down'),
            style: ElevatedButton.styleFrom(
              minimumSize: const Size(60, 60),
            ),
            child: const Icon(Icons.arrow_downward, size: 30),
          ),
        ],
      ),
      const SizedBox(height: 8),
      ElevatedButton.icon(
        onPressed: () => _initGame(),
        icon: const Icon(Icons.refresh),
        label: const Text('重新开始'),
        style: ElevatedButton.styleFrom(
          backgroundColor: Colors.blue,
          foregroundColor: Colors.white,
        ),
      ),
    ],
  ),
)

七、总结

本文详细介绍了使用Flutter for OpenHarmony开发2048游戏的完整过程,涵盖了以下核心技术点:

  1. 数据模型:4×4游戏板、分数、游戏状态
  2. 随机生成:空位收集、概率控制
  3. 移动算法:四方向移动、数字合并、零填充
  4. 状态检测:胜利判断、失败检测、可移动检测
  5. UI实现:网格构建、方块渲染、颜色映射
  6. 交互设计:方向按钮、重新开始

这个项目展示了Flutter在滑动类游戏开发中的完整流程,特别是数组操作和合并逻辑的实现。


欢迎加入开源鸿蒙跨平台社区 : 开源鸿蒙跨平台开发者社区

相关推荐
毕设源码-邱学长2 小时前
【开题答辩全过程】以 基于python的游戏管理平台的开发为例,包含答辩的问题和答案
游戏
大雷神3 小时前
HarmonyOS智慧农业管理应用开发教程--高高种地--第31篇:桌面小组件开发
华为·harmonyos
血色橄榄枝4 小时前
13-14 底部选项卡 flutter on openHarmony
flutter·开源·鸿蒙
一起养小猫4 小时前
Flutter for OpenHarmony 实战:排球计分系统完整开发指南
flutter·harmonyos
qwerasda1238526 小时前
游戏场景中的敌方目标检测与定位实战使用mask-rcnn_regnetx模型实现
人工智能·目标检测·游戏
一起养小猫7 小时前
Flutter for OpenHarmony 实战:推箱子游戏完整开发指南
flutter·游戏·harmonyos
子春一7 小时前
Flutter for OpenHarmony:构建一个 Flutter 数字华容道(15-Puzzle),深入解析可解性保障、滑动逻辑与状态同步
flutter·游戏
●VON7 小时前
React Native for OpenHarmony:贪吃蛇游戏的开发与跨平台适配实践
学习·react native·react.js·游戏·openharmony
软件资深者7 小时前
游戏组件DirectX修复工具(DirectX Repair)v4.4增强版
windows·游戏·电脑·系统修复