C# Winform实现拼图游戏

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

六、扩展建议

  1. AI对战模式 实现基于A*算法的自动求解 添加难度分级系统
  2. 网络对战功能 使用Socket实现联机对战 开发匹配系统和排行榜
  3. 成就系统 记录最快通关时间 解锁特殊拼图模板
  4. 3D效果增强 使用OpenGL实现立体旋转 添加粒子消散特效
相关推荐
小涛不学习1 小时前
手写线程池(从0实现 ThreadPoolExecutor 核心思想)
windows
twc8292 小时前
大模型生成 QA Pairs 提升 RAG 应用测试效率的实践
服务器·数据库·人工智能·windows·rag·大模型测试
wenlonglanying3 小时前
Windows安装Rust环境(详细教程)
开发语言·windows·rust
沪漂阿龙4 小时前
Python 面向对象编程完全指南:从新手到高手的进阶之路
开发语言·python·microsoft
polaris06304 小时前
Windows操作系统部署Tomcat详细讲解
java·windows·tomcat
mldlds4 小时前
windows手动配置IP地址与DNS服务器以及netsh端口转发
服务器·windows·tcp/ip
取个名字太难了a5 小时前
DebugActiveProcess 调试流程分析(一)
windows
Java.熵减码农5 小时前
火绒安全软件误杀explorer.exe导致黑屏解决方法
windows
love530love5 小时前
不用聊天软件 OpenClaw 手机浏览器远程访问控制:Tailscale 配置、设备配对与常见问题全解
人工智能·windows·python·智能手机·tailscale·openclaw·远程访问控制
夏末蝉未鸣015 小时前
Windows环境下载并安装milvus
windows·milvus