C# Winform实现拼图游戏,包含图片切割、拖拽交互、胜利判断等核心功能
一、项目架构设计
MainForm
GamePanel
ControlPanel
GameLogic
GraphicsRenderer
PieceManager
MapManager
PieceRenderer
InputHandler
二、核心代码实现
1. 主窗体设计 (MainForm.cs)
csharp
public partial class MainForm : Form
{
private PuzzleGame game;
private Image originalImage;
public MainForm()
{
InitializeComponent();
InitializeComponents();
LoadDefaultImage();
}
private void InitializeComponents()
{
// 初始化控件
this.Size = new Size(800, 600);
this.Text = "C# 拼图游戏 v1.0";
// 创建游戏面板
game = new PuzzleGame(this);
game.Dock = DockStyle.Fill;
this.Controls.Add(game);
// 创建控制面板
var controlPanel = new FlowLayoutPanel();
controlPanel.Dock = DockStyle.Bottom;
// 添加功能按钮
var loadButton = new Button { Text = "加载图片", Size = new Size(100, 30) };
loadButton.Click += (s, e) => LoadImage();
controlPanel.Controls.Add(loadButton);
var resetButton = new Button { Text = "重新开始", Size = new Size(100, 30) };
resetButton.Click += (s, e) => game.Reset();
controlPanel.Controls.Add(resetButton);
this.Controls.Add(controlPanel);
}
private void LoadImage()
{
using (var ofd = new OpenFileDialog())
{
ofd.Filter = "图片文件|*.jpg;*.png";
if (ofd.ShowDialog() == DialogResult.OK)
{
originalImage = Image.FromFile(ofd.FileName);
game.LoadImage(originalImage, 3); // 3x3拼图
}
}
}
}
2. 游戏逻辑核心 (PuzzleGame.cs)
csharp
public class PuzzleGame : Panel
{
private const int CellSize = 150; // 每个拼图块大小
private Image[,] puzzlePieces;
private Point[,] originalPositions;
private Point[,] currentPositions;
private int gridSize = 3;
private int moveCount = 0;
public event EventHandler<GameOverEventArgs> GameOver;
public PuzzleGame(Control parent) : base()
{
this.DoubleBuffered = true;
InitializeGame();
}
public void LoadImage(Image img, int gridSize)
{
this.gridSize = gridSize;
this.Size = new Size(CellSize * gridSize + 20, CellSize * gridSize + 20);
originalPositions = new Point[gridSize, gridSize];
currentPositions = new Point[gridSize, gridSize];
// 创建拼图块矩阵
puzzlePieces = new Image[gridSize, gridSize];
for (int i = 0; i < gridSize; i++)
{
for (int j = 0; j < gridSize; j++)
{
originalPositions[i, j] = new Point(j * CellSize, i * CellSize);
currentPositions[i, j] = new Point(j * CellSize, i * CellSize);
}
}
// 切割图片
CutImage(img);
RefreshPieces();
}
private void CutImage(Image img)
{
using (var bmp = new Bitmap(img, CellSize * gridSize, CellSize * gridSize))
{
for (int i = 0; i < gridSize; i++)
{
for (int j = 0; j < gridSize; j++)
{
var rect = new Rectangle(j * CellSize, i * CellSize, CellSize, CellSize);
puzzlePieces[i, j] = new Bitmap(rect.Width, rect.Height);
using (var g = Graphics.FromImage(puzzlePieces[i, j]))
{
g.DrawImage(bmp, rect, rect, GraphicsUnit.Pixel);
}
}
}
}
}
public void Reset()
{
moveCount = 0;
ShufflePieces();
RefreshPieces();
}
private void ShufflePieces()
{
var random = new Random();
for (int i = 0; i < gridSize * gridSize; i++)
{
int x = random.Next(gridSize);
int y = random.Next(gridSize);
SwapPieces(new Point(x, y), new Point(0, 0));
}
}
public void RefreshPieces()
{
this.Controls.Clear();
for (int i = 0; i < gridSize; i++)
{
for (int j = 0; j < gridSize; j++)
{
var pb = new PictureBox
{
Size = new Size(CellSize, CellSize),
Location = originalPositions[i, j],
Image = puzzlePieces[i, j],
SizeMode = PictureBoxSizeMode.StretchImage,
BorderStyle = BorderStyle.FixedSingle,
Tag = new Point(i, j)
};
pb.MouseDown += Pb_MouseDown;
pb.MouseMove += Pb_MouseMove;
pb.MouseUp += Pb_MouseUp;
this.Controls.Add(pb);
}
}
}
private void Pb_MouseDown(object sender, MouseEventArgs e)
{
var pb = sender as PictureBox;
if (pb == null) return;
var tag = pb.Tag as Point;
currentPositions[tag.X, tag.Y] = new Point(tag.X, tag.Y);
// 开始拖拽
var dragImage = new Bitmap(pb.Width, pb.Height);
using (var g = Graphics.FromImage(dragImage))
{
g.DrawImage(pb.Image, 0, 0);
}
pb.DoDragDrop(dragImage, DragDropEffects.Move);
}
private void Pb_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left) return;
var pb = sender as PictureBox;
if (pb == null) return;
var dragImage = new Bitmap(pb.Width, pb.Height);
using (var g = Graphics.FromImage(dragImage))
{
g.DrawImage(pb.Image, 0, 0);
}
Cursor.Clip = new Rectangle(this.PointToScreen(pb.Location), pb.Size);
}
private void Pb_MouseUp(object sender, MouseEventArgs e)
{
Cursor.Clip = null;
var pb = sender as PictureBox;
if (pb == null) return;
var targetPoint = this.PointToClient(Cursor.Position);
var targetCell = new Point(
(targetPoint.X - CellSize / 2) / CellSize,
(targetPoint.Y - CellSize / 2) / CellSize
);
if (IsValidMove(targetCell))
{
SwapPieces(targetCell, (Point)pb.Tag);
moveCount++;
CheckWinCondition();
}
}
private bool IsValidMove(Point target)
{
var (x, y) = (Point)pb.Tag;
return (Math.Abs(x - target.X) + Math.Abs(y - target.Y)) == 1;
}
private void SwapPieces(Point a, Point b)
{
var tempImg = puzzlePieces[a.X, a.Y];
puzzlePieces[a.X, a.Y] = puzzlePieces[b.X, b.Y];
puzzlePieces[b.X, b.Y] = tempImg;
RefreshPieces();
}
private void CheckWinCondition()
{
for (int i = 0; i < gridSize; i++)
{
for (int j = 0; j < gridSize; j++)
{
if (currentPositions[i, j] != originalPositions[i, j])
return;
}
}
GameOver?.Invoke(this, new GameOverEventArgs(moveCount));
}
}
public class GameOverEventArgs : EventArgs
{
public int MoveCount { get; }
public GameOverEventArgs(int moves)
{
MoveCount = moves;
}
}
三、关键功能扩展
1. 计时器功能
csharp
public class GameTimer
{
private System.Timers.Timer timer;
private int elapsedTime = 0;
public event EventHandler<TimeEventArgs> TimeUpdated;
public GameTimer()
{
timer = new System.Timers.Timer(1000);
timer.Elapsed += (s, e) =>
{
elapsedTime++;
TimeUpdated?.Invoke(this, new TimeEventArgs(elapsedTime));
};
}
public void Start() => timer.Start();
public void Stop() => timer.Stop();
}
public class TimeEventArgs : EventArgs
{
public int Seconds { get; }
public TimeEventArgs(int seconds)
{
Seconds = seconds;
}
}
2. 音效系统
csharp
public class SoundManager
{
private SoundPlayer clickSound;
private SoundPlayer successSound;
public SoundManager()
{
clickSound = new SoundPlayer("click.wav");
successSound = new SoundPlayer("success.wav");
}
public void PlayClick() => clickSound.Play();
public void PlaySuccess() => successSound.Play();
}
四、界面优化技巧
抗锯齿处理
csharp
this.SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.DoubleBuffer, true);
拖拽特效
csharp
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (dragging)
{
using (var g = this.CreateGraphics())
{
g.DrawRectangle(Pens.LightGray, dragRect);
}
}
}
动态难度选择
csharp
private void UpdateDifficulty(int level)
{
gridSize = level + 2; // 简单=3x3, 普通=4x4, 困难=5x5
Reset();
}
参考代码 C# 拼图游戏 源码 www.youwenfan.com/contentcsp/93149.html
五、完整项目结构
csharp
PuzzleGame/
├── MainForm.cs
├── PuzzleGame.cs
├── PuzzlePiece.cs
├── Resources/
│ ├── default.jpg
│ └── sounds/
├── Controls/
│ ├── GameTimer.cs
│ └── SoundManager.cs
└── Properties/
└── Settings.settings
六、扩展建议
- AI对战模式 实现基于A*算法的自动求解 添加难度分级系统
- 网络对战功能 使用Socket实现联机对战 开发匹配系统和排行榜
- 成就系统 记录最快通关时间 解锁特殊拼图模板
- 3D效果增强 使用OpenGL实现立体旋转 添加粒子消散特效