1. 五子棋游戏开发基础准备
用C#开发五子棋游戏是个特别适合初学者的项目,既能学习窗体程序开发,又能理解游戏逻辑的实现。我刚开始学C#时就做过这个项目,当时踩了不少坑,现在把经验都整理出来分享给大家。
首先需要准备Visual Studio开发环境,社区版就完全够用。新建一个Windows窗体应用项目,我习惯用.NET Framework 4.7.2版本,兼容性比较好。项目创建好后,你会看到一个默认的Form1窗体,这就是我们的主战场。
游戏开发离不开几个核心组件:
- 棋盘绘制:用Graphics绘图技术
- 棋子落子:处理鼠标点击事件
- 胜负判断:二维数组存储棋盘状态
- 界面交互:按钮控制游戏流程
建议先把窗体大小设为710×640像素,这个尺寸放15×15的棋盘正合适。我在MainSize类里定义了这些常量,后面修改起来特别方便:
csharp复制class MainSize {
public static int FormWidth => 710;
public static int FormHeight => 640;
public static int CBoardWidth => 600;
// 其他尺寸定义...
}
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 棋盘界面设计与绘制技巧
棋盘是五子棋的脸面,画得好游戏体验直接提升一个档次。我试过两种绘制方式:纯代码绘制和使用棋盘图片。新手建议先用代码绘制,理解原理后再换图片。
用Graphics画棋盘时,关键是要计算好每个格子的间距。我设置每个格子宽40像素,这样15×15的棋盘总共需要600×600像素的空间。画线时要注意:
csharp复制Pen pen = new Pen(Color.FromArgb(192, 166, 107)); // 木质颜色
for(int i=0; i<15; i++){
// 画横线
g.DrawLine(pen, 20, i*40+20, 580, i*40+20);
// 画竖线
g.DrawLine(pen, i*40+20, 20, i*40+20, 580);
}
后来我改用棋盘图片后发现视觉效果更好,特别是加了木质纹理后。这里有个小技巧:使用DrawImage方法时,要处理好图片的拉伸问题。我通过设置三个定位点来保持图片比例:
csharp复制Bitmap boardImg = new Bitmap("board.png");
g.DrawImage(boardImg,
new Point[] {
new Point(0,0),
new Point(600,0),
new Point(0,600)
});
3. 棋子落子与图形优化实战
棋子是游戏的核心交互元素,我花了最多时间优化这部分。最开始画的棋子就是个纯色圆,看起来特别假。后来加了渐变效果和抗锯齿处理,质感立马就上来了。
每个棋子的直径设为37像素,比格子间距小3像素,这样看起来比较舒服。黑子用深灰到黑色的线性渐变,白子用白到浅灰的渐变:
csharp复制// 黑子渐变
var blackBrush = new LinearGradientBrush(
new Point(20,0), new Point(20,40),
Color.FromArgb(122,122,122), Color.Black);
// 白子渐变
var whiteBrush = new LinearGradientBrush(
new Point(20,0), new Point(20,40),
Color.White, Color.FromArgb(204,204,204));
抗锯齿处理是关键,不加的话棋子边缘会有明显锯齿。设置这两个属性就能解决:
csharp复制g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
鼠标点击处理要注意坐标转换。点击位置需要转换为棋盘坐标:
csharp复制int x = e.X / 40; // 40是格子宽度
int y = e.Y / 40;
if(CheckBoard[x,y] == 0){ // 该位置无棋子
// 落子逻辑...
}
4. 游戏逻辑与胜负判定算法
游戏状态管理我用了个二维数组CheckBoard[15,15],0表示空位,1黑子,2白子。每次落子后都要更新这个数组,并检查是否获胜。
胜负判断是最烧脑的部分。需要检查四个方向:水平、垂直、左上到右下、右上到左下。我的实现方式是遍历棋盘,对每个棋子检查四个方向是否有五连珠:
csharp复制bool CheckWin(int[,] board, int player){
for(int i=0; i<15; i++){
for(int j=0; j<15; j++){
if(board[j,i] == player){
// 检查右侧
if(j<11 && board[j+1,i]==player && ...)
return true;
// 检查下方
if(i<11 && board[j,i+1]==player && ...)
return true;
// 检查右下
if(j<11 && i<11 && board[j+1,i+1]==player && ...)
return true;
// 检查左下
if(j>3 && i<11 && board[j-1,i+1]==player && ...)
return true;
}
}
}
return false;
}
游戏流程控制我用了几个状态变量:
- bool start:游戏是否开始
- bool ChessCheck:当前是黑子还是白子回合
- 按钮控制:开始游戏、重新开始、退出
5. 界面优化与用户体验提升
基本的游戏功能实现后,我开始琢磨怎么让界面更友好。首先是加了游戏状态提示,用Label显示当前回合:
csharp复制label1.Text = ChessCheck ? "黑子回合" : "白子回合";
然后是重新开始确认对话框,避免误操作:
csharp复制if(MessageBox.Show("确认重新开始?","提示",MessageBoxButtons.OKCancel)
== DialogResult.OK)
{
InitializeGame();
}
我还在Paint事件中加了棋子重绘逻辑,这样窗口最小化再恢复时,棋子不会消失:
csharp复制private void panel1_Paint(object sender, PaintEventArgs e){
ChessBoard.DrawCB(e.Graphics);
Chess.ReDrawC(panel1, CheckBoard);
}
最后给棋子落子加了音效,使用System.Media命名空间:
csharp复制SoundPlayer player = new SoundPlayer("drop.wav");
player.Play();
6. 常见问题排查与性能优化
开发过程中我遇到几个典型问题,这里分享下解决方案:
-
棋子显示不全:因为计算棋子中心坐标时少减了半径值。正确的计算方式应该是:
csharp复制int centerX = x * 40 + 20 - 18; // 20是偏移,18是半径 -
数组越界异常:鼠标点击棋盘边缘时会发生。解决方法是在MouseDown事件中加try-catch块。
-
画面闪烁问题:在窗体构造函数中设置这两个属性:
csharp复制this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); -
内存泄漏:记得释放Graphics对象和Brush资源:
csharp复制using(var g = panel1.CreateGraphics()){ // 绘图操作... }
性能优化方面,我有几个心得:
- 不要每次Paint都重新创建Graphics对象
- 使用using语句管理资源
- 棋盘背景图片只加载一次,缓存起来
- 避免在Paint事件中进行复杂计算
7. 扩展功能与进阶改进
基础版本完成后,可以尝试这些扩展功能:
-
悔棋功能:用Stack保存每一步的棋盘状态:
csharp复制Stack<int[,]> history = new Stack<int[,]>(); // 落子前保存状态 history.Push((int[,])CheckBoard.Clone()); -
游戏回放:记录每一步的坐标和玩家,用Timer控制回放速度。
-
AI对战:实现简单的评分算法,电脑会根据当前局面选择最优落子点。
-
网络对战:用Socket实现双人对战,需要设计简单的通信协议。
-
皮肤系统:允许玩家自定义棋盘和棋子样式,通过配置文件加载资源。
我后来给棋子加了阴影效果,使用PathGradientBrush:
csharp复制var path = new GraphicsPath();
path.AddEllipse(rect);
var pgb = new PathGradientBrush(path);
pgb.CenterColor = Color.FromArgb(100,0,0,0);
pgb.SurroundColors = new Color[]{Color.Transparent};
g.FillEllipse(pgb, rect);
8. 项目打包与发布指南
开发完成后,可以通过ClickOnce发布应用程序。在项目属性→发布中设置:
- 发布位置选本地文件夹
- 安装模式选"仅在线"
- 设置版本号自动递增
- 添加必要的依赖项
也可以生成安装包:
- 新建安装项目
- 添加主输出
- 创建桌面快捷方式
- 添加程序图标
记得测试不同分辨率下的显示效果,我在MainSize类里定义的尺寸在不同DPI下可能需要调整:
csharp复制// 根据DPI缩放
float scale = panel1.CreateGraphics().DpiX / 96f;
int actualSize = (int)(CBoardGap * scale);
开发过程中我积累了一些实用技巧:
- 使用#region组织代码块
- 为重要方法添加XML注释
- 用Debug.WriteLine输出调试信息
- 定期提交代码到版本控制系统
