项目概述
这是一个基于 Electron 开发的麻将游戏应用,实现了四人麻将的核心玩法和规则。本项目展示了如何在 Electron 环境中构建复杂的桌面游戏应用,包含游戏状态管理、AI 决策系统、用户交互处理和响应式界面设计。游戏支持 1 名人类玩家与 3 名 AI 对手进行对战,实现了完整的麻将游戏流程(洗牌、发牌、打牌、吃、碰、杠、胡)。同时新增鸿蒙 PC 平台适配方案,优化了 AI 决策效率、动画渲染流畅度和系统兼容性,核心玩法在鸿蒙端完全兼容,可作为复杂 Electron 游戏迁移鸿蒙 PC 的实践案例。

技术架构
项目采用 Electron 主进程 - 渲染进程架构,新增鸿蒙适配层,核心模块包括:
- 主进程模块:负责窗口管理、应用生命周期和鸿蒙环境适配
- 渲染进程模块:包含游戏核心逻辑、UI 渲染和用户交互(鸿蒙端优化)
- IPC 通信层:实现主进程和渲染进程之间的安全通信(鸿蒙端兼容)
- 游戏逻辑引擎:处理麻将规则、游戏流程和状态管理
- AI 决策系统:优化鸿蒙端决策效率,减少资源占用
- UI 渲染系统:适配鸿蒙 PC 窗口特性,简化动画提升流畅度
- 鸿蒙适配层:处理系统能力配置、库依赖管理和硬件兼容
核心算法实现(鸿蒙适配优化)
1. 游戏状态管理 - 鸿蒙兼容扩展
javascript
运行
// 游戏状态(鸿蒙兼容优化)
const gameState = {
status: 'ready', // ready, playing, paused, ended
currentPlayer: 0,
players: [
{ name: '玩家1', tiles: [], score: 0, isComputer: false },
{ name: '电脑1', tiles: [], score: 0, isComputer: true },
{ name: '电脑2', tiles: [], score: 0, isComputer: true },
{ name: '电脑3', tiles: [], score: 0, isComputer: true }
],
discardedTiles: [],
remainingTiles: [],
round: 1,
dealer: 0,
selectedTile: null,
// 新增:鸿蒙环境标记与性能配置
isHarmonyOS: process.env.OHOS_ENV ? true : false,
aiThinkDelay: process.env.OHOS_ENV ? 800 : 1000, // 鸿蒙端缩短AI思考延迟
animationSpeed: process.env.OHOS_ENV ? 0.7 : 1.0 // 鸿蒙端加快动画速度提升流畅度
};
2. 主进程代码(main.js)- 鸿蒙核心适配
javascript
运行
// Electron主进程代码(鸿蒙适配版)
const { app, BrowserWindow } = require('electron');
const path = require('path');
let mainWindow;
function createWindow() {
// 鸿蒙PC必须禁用硬件加速(解决窗口渲染异常、动画卡顿问题)
app.disableHardwareAcceleration();
mainWindow = new BrowserWindow({
width: 900,
height: 700,
title: '麻将游戏',
resizable: true,
webPreferences: {
preload: path.join(__dirname, 'src', 'preload.js'),
nodeIntegration: false, // 鸿蒙端强制关闭,提升安全性
contextIsolation: true, // 保持上下文隔离,兼容鸿蒙web引擎
enableRemoteModule: false
},
// 鸿蒙PC窗口适配优化
fullscreenable: false, // 禁用全屏,避免系统兼容性冲突
titleBarStyle: 'default', // 适配鸿蒙原生标题栏样式
backgroundColor: '#f5f5f5' // 优化鸿蒙端初始渲染背景
});
// 加载应用的index.html
mainWindow.loadFile(path.join(__dirname, 'src', 'index.html'));
// 鸿蒙环境检测与额外配置
if (process.env.OHOS_ENV) {
console.log('Running on HarmonyOS PC, applying compatibility patches');
// 鸿蒙端禁用窗口缩放动画,减少性能消耗
mainWindow.setHasShadow(false);
}
// 窗口关闭时触发
mainWindow.on('closed', () => {
mainWindow = null;
});
}
// 应用事件处理(保持原有逻辑,新增鸿蒙兼容)
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
3. AI 决策系统 - 鸿蒙性能优化
针对鸿蒙端资源限制,优化 AI 决策逻辑,减少计算耗时:
javascript
运行
// 电脑玩家动作(鸿蒙性能优化版)
function computerAction() {
if (gameState.status !== 'playing') return;
const player = gameState.players[gameState.currentPlayer];
// 鸿蒙端优化:简化AI决策算法,减少递归和循环次数
const tileToDiscard = gameState.isHarmonyOS
? selectTileToDiscardHarmony(player.tiles)
: selectTileToDiscard(player.tiles);
const tileIndex = player.tiles.findIndex(tile =>
tile.type === tileToDiscard.type && tile.value === tileToDiscard.value
);
// 鸿蒙端缩短思考延迟,提升游戏流畅度
setTimeout(() => {
discardTile(gameState.currentPlayer, tileIndex);
}, gameState.aiThinkDelay + (gameState.isHarmonyOS ? 0 : Math.random() * 1500));
}
// 鸿蒙端专用:简化的牌型分析与弃牌选择
function selectTileToDiscardHarmony(tiles) {
// 核心策略:优先弃置风牌、箭牌等难以组成顺子/刻子的牌
const sortedTiles = [...tiles].sort(sortTiles);
// 分离序数牌(万、条、饼)和字牌(风、龙)
const honorTiles = sortedTiles.filter(tile =>
tile.type === 'wind' || tile.type === 'dragon'
);
// 优先弃置字牌
if (honorTiles.length > 0) {
// 进一步筛选:弃置单张字牌,保留成对字牌
const honorCounts = {};
honorTiles.forEach(tile => {
const key = `${tile.type}-${tile.value}`;
honorCounts[key] = (honorCounts[key] || 0) + 1;
});
const singleHonors = honorTiles.filter(tile => {
const key = `${tile.type}-${tile.value}`;
return honorCounts[key] === 1;
});
return singleHonors.length > 0 ? singleHonors[0] : honorTiles[0];
}
// 无一字牌时,弃置最孤立的序数牌(简化版分析)
return sortedTiles[0];
}
4. 牌型识别与胡牌判定 - 鸿蒙算法优化
优化递归深度,避免鸿蒙端栈溢出,提升判定效率:
javascript
运行
// 判断是否可以胡牌(鸿蒙优化版)
function canWin(tiles) {
if (tiles.length !== 14) return false;
const sortedTiles = [...tiles].sort(sortTiles);
// 鸿蒙端优化:限制递归深度,使用迭代辅助判定
for (let i = 0; i < sortedTiles.length; i++) {
if (i < sortedTiles.length - 1 &&
sortedTiles[i].type === sortedTiles[i + 1].type &&
sortedTiles[i].value === sortedTiles[i + 1].value) {
const remainingTiles = [...sortedTiles];
remainingTiles.splice(i, 2);
// 鸿蒙端使用优化后的判定函数
if (gameState.isHarmonyOS) {
if (checkWinningPatternHarmony(remainingTiles)) return true;
} else {
if (checkWinningPattern(remainingTiles)) return true;
}
}
}
return false;
}
// 鸿蒙端专用:迭代式牌型判定(替代递归,减少栈消耗)
function checkWinningPatternHarmony(tiles) {
const stack = [tiles];
while (stack.length > 0) {
const currentTiles = stack.pop();
if (currentTiles.length === 0) return true;
// 尝试组成刻子
if (currentTiles.length >= 3 &&
currentTiles[0].type === currentTiles[1].type &&
currentTiles[0].value === currentTiles[1].value &&
currentTiles[0].type === currentTiles[2].type &&
currentTiles[0].value === currentTiles[2].value) {
const remaining = [...currentTiles];
remaining.splice(0, 3);
stack.push(remaining);
continue;
}
// 尝试组成顺子
if (currentTiles.length >= 3 &&
currentTiles[0].type === currentTiles[1].type &&
currentTiles[0].type === currentTiles[2].type &&
canFormSequence(currentTiles[0], currentTiles[1], currentTiles[2])) {
const remaining = [...currentTiles];
remaining.splice(0, 3);
stack.push(remaining);
continue;
}
}
return false;
}
5. UI 渲染系统 - 鸿蒙适配优化
简化动画效果,批量处理 DOM 操作,提升鸿蒙端渲染性能:
javascript
运行
// 更新玩家手牌显示(鸿蒙适配版)
function updatePlayerTiles() {
const currentPlayer = gameState.players[gameState.currentPlayer];
const playerTilesContainer = elements.playerTiles.south;
playerTilesContainer.innerHTML = '';
const sortedTiles = [...currentPlayer.tiles].sort(sortTiles);
// 鸿蒙端优化:使用DocumentFragment批量添加DOM,减少重绘
const fragment = document.createDocumentFragment();
sortedTiles.forEach((tile, index) => {
const tileElement = document.createElement('div');
tileElement.className = 'tile';
tileElement.dataset.index = index;
if (gameState.selectedTile === index) {
tileElement.classList.add('selected');
}
// 仅对当前人类玩家添加点击事件
if (!currentPlayer.isComputer) {
tileElement.addEventListener('click', () => selectTile(index));
}
// 鸿蒙端简化牌面样式,减少CSS渲染压力
if (gameState.isHarmonyOS) {
tileElement.style.transition = 'transform 0.2s ease, box-shadow 0.2s ease';
tileElement.innerHTML = `<span class="tile-icon simple">${getTileSimpleDisplayName(tile)}</span>`;
} else {
tileElement.textContent = getTileDisplayName(tile);
}
tileElement.dataset.type = tile.type;
tileElement.dataset.value = tile.value;
fragment.appendChild(tileElement);
});
playerTilesContainer.appendChild(fragment);
// 鸿蒙端优化:其他玩家手牌使用简化渲染(减少DOM节点)
updateOtherPlayersTilesHarmony();
}
// 鸿蒙端专用:简化其他玩家手牌渲染
function updateOtherPlayersTilesHarmony() {
const otherPlayers = ['north', 'east', 'west'];
otherPlayers.forEach(direction => {
const container = elements.playerTiles[direction];
container.innerHTML = '';
const player = gameState.players[getPlayerIndexByDirection(direction)];
const tileCount = player.tiles.length;
// 不渲染具体牌面,仅显示牌背数量(减少DOM压力)
for (let i = 0; i < tileCount; i++) {
const tileElement = document.createElement('div');
tileElement.className = 'tile tile-back simple';
container.appendChild(tileElement);
}
});
}
6. IPC 通信机制 - 鸿蒙兼容调整
保持通信逻辑不变,优化鸿蒙端消息传递效率:
javascript
运行
// 渲染进程preload.js(鸿蒙兼容版)
const { contextBridge, ipcRenderer } = require('electron');
const MAHJONG_CONSTANTS = require('./constants');
// 安全地暴露API给渲染进程
contextBridge.exposeInMainWorld('mahjongGame', {
// 游戏控制API(鸿蒙端保持兼容)
game: {
start: () => ipcRenderer.send('game:start'),
pause: () => ipcRenderer.send('game:pause'),
resume: () => ipcRenderer.send('game:resume'),
reset: () => ipcRenderer.send('game:reset')
},
// 窗口控制(适配鸿蒙窗口行为)
window: {
minimize: () => ipcRenderer.send('window:minimize'),
maximize: () => {
// 鸿蒙端禁用最大化,避免布局错乱
if (!process.env.OHOS_ENV) {
ipcRenderer.send('window:maximize');
}
},
close: () => ipcRenderer.send('window:close')
},
// 对话框(鸿蒙端优化:使用系统原生对话框)
dialog: {
showMessageBox: (options) => ipcRenderer.invoke('dialog:showMessageBox', {
...options,
// 鸿蒙端简化对话框样式,提升响应速度
type: gameState.isHarmonyOS ? 'none' : options.type
})
},
// 获取常量(新增鸿蒙环境标记)
constants: {
...MAHJONG_CONSTANTS,
IS_HARMONY_OS: process.env.OHOS_ENV ? true : false
}
});
项目结构
1. 原始 Electron 项目结构(保持不变)
plaintext
60-mahjong/
├── README.md # 项目说明文档
├── main.js # Electron主进程代码
├── package.json # 项目配置和依赖
└── src/ # 渲染进程代码
├── index.html # 应用主页面
├── preload.js # 预加载脚本
├── renderer.js # 游戏核心逻辑
├── constants.js # 游戏常量
└── style.css # 样式表
2. 鸿蒙 PC 适配后项目结构(新增 / 调整)
plaintext
ohos_hap/ # 鸿蒙应用根目录(整合Electron项目)
├── electron/ # Electron鸿蒙核心依赖
│ └── libs/
│ └── arm64-v8a/ # 鸿蒙核心库文件(必须完整)
│ ├── libelectron.so
│ ├── libadapter.so
│ ├── libffmpeg.so
│ └── libc++_shared.so
├── web_engine/
│ └── src/
│ └── main/
│ └── resources/
│ └── resfile/
│ └── resources/
│ └── app/ # 原有60-mahjong项目代码迁移至此
│ ├── main.js # 已适配鸿蒙的主进程代码
│ ├── package.json # 适配后的依赖配置
│ └── src/ # 原有src目录完整迁移
│ ├── index.html
│ ├── preload.js
│ ├── renderer.js
│ ├── constants.js
│ └── style.css
└── module.json5 # 鸿蒙应用配置文件(新增)
鸿蒙适配核心配置文件
1. package.json(适配调整)
json
{
"name": "mahjong-harmonyos",
"version": "1.0.0",
"main": "main.js",
"scripts": {
"start": "electron .", // 原有Electron运行脚本
"dev": "electron . --dev", // 原有开发模式脚本
"harmony:build": "ohos build --mode debug", // 新增鸿蒙编译脚本
"harmony:run": "ohos run" // 新增鸿蒙运行脚本
},
"dependencies": {
"electron": "^34.0.0" // 升级Electron至34+(鸿蒙适配最低要求)
},
// 新增鸿蒙适配配置
"harmonyos": {
"apiVersion": 20,
"sysCapabilities": ["windowManager", "storage", "graphics", "multimedia.audio"]
}
}
2. module.json5(鸿蒙新增配置文件)
json5
{
"app": {
"bundleName": "com.example.mahjong",
"bundleVersion": "1.0.0",
"minAPIVersion": 20
},
"module": {
"name": "mahjong_module",
"type": "application",
"srcPath": "./",
"deviceTypes": ["pc"], // 指定为鸿蒙PC设备
"reqSysCapabilities": [ // 仅保留必要系统能力
"windowManager", // 窗口管理能力
"storage", // 本地存储(游戏存档/分数记录)
"graphics", // 图形渲染(手牌/动画)
"multimedia.audio", // 音效播放
"permission:ohos.permission.READ_USER_STORAGE",
"permission:ohos.permission.WRITE_USER_STORAGE"
],
"abilities": [
{
"name": "MainAbility",
"srcPath": "./web_engine",
"description": "麻将游戏主入口",
"icon": "$media:icon",
"label": "Mahjong Game",
"visible": true,
"launchType": "standard"
}
]
}
}
鸿蒙 PC 适配改造核心步骤
1. 环境准备
- 系统要求:Windows 10/11、8GB RAM 以上、20GB 可用空间
- 工具安装 :
- DevEco Studio 5.0+(安装鸿蒙 SDK API 20+)
- Node.js 18.x+
- Electron 34+(鸿蒙适配最低版本)
2. 项目迁移与依赖配置
- 登录Electron 鸿蒙官方仓库
- 下载 Electron 34 + 版本的 Release 包(.zip 格式)
- 解压后将
electron/libs/arm64-v8a/目录复制到ohos_hap/electron/libs/下(确保 4 个核心.so 库完整) - 将原有 60-mahjong 项目的所有文件复制到
ohos_hap/web_engine/src/main/resources/resfile/resources/app/目录下
3. 代码改造
- 修改 main.js:添加硬件加速禁用代码,优化窗口配置
- 调整 package.json:升级 Electron 版本,新增鸿蒙编译 / 运行脚本
- 创建 module.json5:配置应用信息、系统能力和设备类型
- 优化 renderer.js:
- 新增鸿蒙环境判断逻辑
- 简化 AI 决策算法和 UI 渲染效果
- 用迭代替代部分递归,避免栈溢出
- 批量处理 DOM 操作,减少重绘
4. 编译与运行
- 在 DevEco Studio 中打开 ohos_hap 目录
- 配置签名:进入 File → Project Structure → Signing Configs,自动生成调试签名
- 连接鸿蒙 PC 设备:启用开发者模式和 USB 调试,通过 USB Type-C 连接电脑
- 编译运行:点击 Run 按钮或执行
npm run harmony:run
5. 验证检查项
- ✅ 应用窗口正常显示,无黑屏 / 闪退
- ✅ 洗牌、发牌流程正常,牌面无错位
- ✅ AI 玩家自动出牌,无卡顿
- ✅ 吃、碰、杠、胡等操作逻辑正常
- ✅ 分数计算准确,游戏状态同步更新
- ✅ 控制台无 "SysCap 不匹配" 或 "找不到.so 文件" 错误
- ✅ 响应式布局生效,窗口大小可调整
- ✅ 音效正常播放(若启用)
跨平台兼容性
| 平台 | 适配策略 | 特殊处理 |
|---|---|---|
| Windows | 标准 Electron 运行 | 无特殊配置 |
| macOS | 标准 Electron 运行 | 保留 dock 图标激活逻辑 |
| Linux | 标准 Electron 运行 | 确保系统依赖库完整 |
| 鸿蒙 PC | 通过 Electron 鸿蒙适配层运行 | 1. 禁用硬件加速2. 使用特定目录结构3. 简化 AI 决策和 UI 渲染4. 用迭代替代部分递归算法5. 批量处理 DOM 操作6. 配置必要系统能力(windowManager、storage、graphics) |
鸿蒙端调试技巧与常见问题解决
1. 调试技巧
- 日志查看:在 DevEco Studio 的 Log 面板中过滤 "Electron" 或 "Mahjong" 关键词,定位错误
- 性能分析:使用 DevEco Studio 的 Performance 工具,重点监控 AI 决策和 DOM 渲染耗时
- 断点调试:在鸿蒙适配相关代码(如 AI 优化函数、渲染函数)中打断点,逐步调试
2. 常见问题解决
| 问题现象 | 解决方案 |
|---|---|
| "SysCap 不匹配" 错误 | 检查 module.json5 中的 reqSysCapabilities,仅保留必要系统能力 |
| "找不到.so 文件" 错误 | 确认 arm64-v8a 目录下 4 个核心库文件完整 |
| 窗口不显示 / 黑屏 | 在 main.js 中添加 app.disableHardwareAcceleration (),检查窗口尺寸配置 |
| AI 决策卡顿 | 启用鸿蒙端专用 AI 函数 selectTileToDiscardHarmony,缩短思考延迟 |
| 胡牌判定错误 | 检查 checkWinningPatternHarmony 迭代逻辑,确保牌型分解正确 |
| 手牌渲染错位 | 简化鸿蒙端牌面样式,使用 DocumentFragment 批量添加 DOM |
| 存储失败 | 确认 module.json5 中已申请存储权限,使用 try-catch 包裹 localStorage 操作 |
性能优化建议(鸿蒙端专属)
-
算法优化:
- 用迭代替代递归(如胡牌判定),避免栈溢出和性能消耗
- 简化 AI 决策逻辑,优先基于规则筛选,减少复杂计算
- 缓存牌型分析结果,避免重复计算
-
渲染优化:
- 简化 UI 样式,减少 CSS 动画和复杂选择器
- 批量处理 DOM 操作,使用 DocumentFragment 减少重绘
- 其他玩家手牌使用简化渲染(仅显示牌背数量)
-
资源优化:
- 压缩音效和图片资源,减少加载时间
- 延迟加载非核心资源(如规则说明)
- 及时清理事件监听,避免内存泄漏
-
交互优化:
- 缩短 AI 思考延迟和动画时长
- 优化触摸板点击响应,提升操作精度
- 窗口失去焦点时自动暂停游戏,减少资源占用
如何运行
1. 原有 Electron 环境(Windows/macOS/Linux)
bash
运行
# 安装依赖
npm install
# 启动应用
npm start
# 开发模式
npm run dev
2. 鸿蒙 PC 环境
bash
运行
# 进入鸿蒙应用根目录
cd ohos_hap
# 安装依赖
npm install
# 编译项目
npm run harmony:build
# 连接设备后运行
npm run harmony:run
总结
本项目提供了完整的三消游戏实现和 Electron 迁移鸿蒙 PC 的详细方案,重点优化了动画性能、算法效率和系统兼容性。通过学习本项目,您可以掌握 Electron 桌面应用开发、三消游戏核心算法(匹配检测、特殊方块逻辑)以及鸿蒙 PC 平台适配的关键技术,适合 Electron 开发者和鸿蒙生态开发者参考实践。