二十一点游戏 (Blackjack Game)
项目概述
本项目是一个基于Electron框架开发的二十一点游戏应用,专为鸿蒙PC平台设计。二十一点是世界上最流行的扑克牌游戏之一,玩家的目标是让手中的牌点数尽可能接近但不超过21点,同时击败庄家。

技术要点
1. Electron多进程架构
- 主进程设计:使用Electron的主进程管理应用生命周期、窗口创建和系统资源访问
- 渲染进程:负责游戏界面渲染和用户交互处理
- 进程间通信:通过preload脚本实现主进程和渲染进程之间的安全通信
2. 游戏核心算法
- 牌组管理:实现了多副牌(6副)的创建、洗牌和发牌逻辑,使用Fisher-Yates洗牌算法确保随机性
- 点数计算:智能处理A牌的1点/11点转换机制,确保得分计算准确
- 游戏规则实现:完整实现了黑杰克、爆牌、庄家行动(17点规则)等核心规则
- 下注系统:实现了灵活的下注机制,支持不同面额的筹码和赔率计算
3. UI/UX设计
- 响应式布局:游戏界面适配不同屏幕尺寸,提供良好的桌面体验
- 动画效果:添加了卡牌发放、胜利庆祝等平滑动画,提升游戏体验
- 视觉反馈:通过颜色变化和消息提示,为用户操作提供即时反馈
4. 交互设计
- 多模式控制:支持鼠标点击和键盘快捷键操作(S-开始、H-要牌、T-停牌、D-加倍、P-分牌)
- 状态管理:动态控制按钮可用性,防止无效操作
- 错误处理:对用户输入进行验证,如余额不足时显示警告信息
主要功能
-
完整的二十一点游戏流程
- 多副牌洗牌和发牌
- 黑杰克检测
- 玩家行动选项(要牌、停牌、加倍、分牌)
- 庄家自动行动逻辑
- 游戏结果判定和赔付
-
下注系统
- 多种下注面额选择
- 余额管理
- 下注清空功能
-
游戏界面
- 美观的扑克牌展示
- 牌面朝向控制(庄家暗牌)
- 实时分数显示
- 游戏状态消息提示
-
辅助功能
- 游戏规则说明
- 键盘快捷键支持
- 胜利动画效果
项目结构
27-blackjack/
├── main.js # Electron主进程文件
├── preload.js # 预加载脚本,用于进程间通信
├── index.html # 游戏主界面
├── style.css # 游戏样式文件
├── renderer.js # 游戏核心逻辑
├── package.json # 项目配置和依赖
└── README.md # 项目文档(当前文件)
实现细节
1. 主进程实现 (main.js)
主进程负责应用的生命周期管理和窗口创建:
javascript
const { app, BrowserWindow } = require('electron');
const path = require('path');
// 确保只有一个应用实例运行
const gotTheLock = app.requestSingleInstanceLock();
// 创建主窗口函数
function createWindow() {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
title: '二十一点游戏 - Electron for 鸿蒙PC项目实战案例',
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true,
contextIsolation: false,
}
});
// 加载主界面
mainWindow.loadFile('index.html');
}
// 应用生命周期事件处理
app.whenReady().then(() => {
createWindow();
// 在macOS上,点击dock图标重新创建窗口
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
// 窗口关闭事件处理
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit();
});
2. 游戏核心逻辑 (renderer.js)
游戏逻辑实现了完整的二十一点规则和用户交互:
javascript
// 游戏状态管理
let gameState = {
deck: [], // 牌组
playerHand: [], // 玩家手牌
dealerHand: [], // 庄家手牌
playerScore: 0, // 玩家分数
dealerScore: 0, // 庄家分数
balance: 1000, // 玩家余额
currentBet: 0, // 当前下注
gameStarted: false, // 游戏是否开始
gameOver: false, // 游戏是否结束
playerBlackjack: false, // 玩家是否黑杰克
dealerBlackjack: false, // 庄家是否黑杰克
canSplit: false, // 是否可以分牌
splitHands: [], // 分牌后的手牌
currentHandIndex: 0 // 当前处理的手牌索引
};
// 计算手牌点数(智能处理A牌)
function calculateScore(hand) {
let score = 0;
let aceCount = 0;
// 先计算所有非A的牌
for (let card of hand) {
if (!card.isFaceUp) continue;
if (card.value === 'A') {
aceCount++;
score += 11; // 暂时将A计为11点
} else if (['J', 'Q', 'K'].includes(card.value)) {
score += 10;
} else {
score += parseInt(card.value);
}
}
// 处理A的点数调整(如果总和超过21,将A从11点改为1点)
while (score > 21 && aceCount > 0) {
score -= 10;
aceCount--;
}
return score;
}
// 其他核心方法:洗牌、发牌、游戏流程控制等
3. UI渲染与交互 (index.html & style.css)
游戏界面设计注重用户体验,提供直观的操作和清晰的视觉反馈:
- 分区设计:信息区、游戏桌、控制面板
- 动画效果:卡牌发放动画、胜利庆祝动画
- 响应式设计:适配不同屏幕尺寸
- 视觉设计:使用温暖的配色方案,模拟真实赌场氛围
启动与运行
- 安装依赖
bash
npm install
- 启动应用
bash
npm start
游戏规则简介
-
基本目标:让手中的牌点数尽可能接近但不超过21点,同时击败庄家
-
牌面点数:
- 2-10:牌面值
- J、Q、K:10点
- A:1点或11点(根据当前手牌决定)
-
游戏流程:
- 下注:玩家选择下注金额
- 发牌:玩家和庄家各获得两张牌,庄家一张面朝下
- 玩家行动:可以选择要牌、停牌、加倍或分牌
- 庄家行动:点数小于17必须继续要牌
- 结算:比较点数,决定胜负
-
特殊规则:
- 黑杰克:首两张牌为A+10点牌,赔率1.5:1
- 爆牌:点数超过21点,直接输掉
- 分牌:两张相同点数的牌可以分牌(需要额外下注)
技术亮点
-
高效的状态管理:使用单一状态对象管理游戏的所有状态,简化状态同步和UI更新
-
智能的点数计算:通过优化的算法自动处理A牌的点数转换,确保计算准确高效
-
流畅的动画体验:使用CSS动画和JavaScript定时器实现平滑的游戏动画效果
-
友好的用户界面:清晰的视觉层次和交互设计,为用户提供直观的游戏体验
优化方向
-
性能优化:
- 优化牌组管理,减少内存占用
- 优化动画性能,提升游戏流畅度
-
功能扩展:
- 完善分牌功能的完整实现
- 添加更多游戏设置选项(如音量控制)
- 增加多语言支持
-
用户体验改进:
- 添加游戏教程和提示系统
- 实现游戏进度保存和加载
- 添加成就系统和排行榜
注意事项
- 本游戏仅供学习和娱乐目的,不涉及真实金钱交易
- 请遵守当地法律法规,合理安排游戏时间
- 如有任何问题或建议,请提交Issue或Pull Request