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实现立体旋转 添加粒子消散特效
相关推荐
开开心心就好3 小时前
发票合并打印工具,多页布局设置实时预览
linux·运维·服务器·windows·pdf·harmonyos·1024程序员节
獨枭3 小时前
PyCharm 跑通 SAM 全流程实战
windows
仙剑魔尊重楼3 小时前
音乐制作电子软件FL Studio2025.2.4.5242中文版新功能介绍
windows·音频·录屏·音乐·fl studio
PHP小志4 小时前
Windows 服务器怎么修改密码和用户名?账户被系统锁定如何解锁
windows
wxin_VXbishe5 小时前
C#(asp.net)学员竞赛信息管理系统-计算机毕业设计源码28790
java·vue.js·spring boot·spring·django·c#·php
专注VB编程开发20年5 小时前
vb.net datatable新增数据时改用数组缓存
java·linux·windows
仙剑魔尊重楼5 小时前
专业音乐制作软件fl Studio 2025.2.4.5242中文版新功能
windows·音乐·fl studio
rjc_lihui7 小时前
Windows 运程共享linux系统的方法
windows
失忆爆表症7 小时前
01_项目搭建指南:从零开始的 Windows 开发环境配置
windows·postgresql·fastapi·milvus
穿过锁扣的风7 小时前
一文搞懂 SQL 五大分类:DQL/DML/DDL/DCL/TCL
数据库·microsoft·oracle