c# winform 拼图游戏

发布于:2025-09-02 ⋅ 阅读:(19) ⋅ 点赞:(0)

1. 效果介绍

屏幕录制 2025-09-01 094804

2.实现

2.1 分割并打乱图片

创建 c# winform 项目 pintu_game

        private const int CellSize = 100;//每块拼图的大小
        private PictureBox[,] pictureBoxes = new PictureBox[3, 3];//创建3x3个picturebox
        private Dictionary<PictureBox, Point> originalPositions = new Dictionary<PictureBox, Point>();//初始位置
        private Dictionary<PictureBox, Point> currentPositions = new Dictionary<PictureBox, Point>();//当前位置

用picturebox存放拼图

用Dictionary<PictureBox, Point>存放数据

只要比较 originalPositions和currentPositions就能判断胜利

        private bool IsPuzzleSolved()
        {
            foreach (var entry in currentPositions)
            {
                PictureBox pb = entry.Key;
                Point currentPos = entry.Value;
                Point originalPos = originalPositions[pb];

                if (currentPos.X != originalPos.X || currentPos.Y != originalPos.Y)
                {
                    return false;
                }
            }
            return true;
        }

entry.Key 表示字典中的键(Key),对应拼图块的控件对象

entry.Value 表示字典中的值(Value),对应拼图块的坐标(Point 类型,包含 X 和 Y 属性)。

调整原图尺寸:

        private Image resize_img(Image originalImage)
        {
            //调整原图的尺寸为300x300
            Bitmap resizedImage = new Bitmap(300, 300);
            using (Graphics g = Graphics.FromImage(resizedImage))
            {
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                g.DrawImage(originalImage, 0, 0, 300, 300);
            }
            return resizedImage;
        }

  • 新建一个300x300像素的空白位图作为目标画布

  • 通过Graphics.FromImage获取目标位图的绘图对象

  • 指定使用双三次插值法(Bicubic Interpolation)

        分割图片
        private void CutImage()
        {
            for (int i = 0; i < GridSize; i++)
            {
                for (int j = 0; j < GridSize; j++)
                {
                    // 创建每个部分的位图
                    Bitmap part = new Bitmap(CellSize, CellSize);
                    using (Graphics g = Graphics.FromImage(part))
                    {
                        // 计算源图像中的矩形区域
                        Rectangle srcRect = new Rectangle(j * CellSize, i * CellSize, CellSize, CellSize);
                        // 计算目标图像中的矩形区域
                        Rectangle destRect = new Rectangle(0, 0, CellSize, CellSize);
                        // 绘制图像部分
                        g.DrawImage(originalImage, destRect, srcRect, GraphicsUnit.Pixel);
                    }
                    imageParts[i, j] = part;
                }
            }
        }

打乱顺序

            // 收集所有拼图块
            foreach (PictureBox pb in pictureBoxes)
            {
                boxes.Add(pb);
            }

            // 洗牌
            int n = boxes.Count;
            while (n > 1)
            {
                n--;
                int k = rand.Next(n + 1);
                PictureBox temp = boxes[k];
                boxes[k] = boxes[n];
                boxes[n] = temp;

此阶段代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace pintu_game
{
    public partial class Form1 : Form
    {
        private const int CellSize = 100;//每块拼图的大小
        static private int GridSize = 3;//拼图数
        private PictureBox[,] pictureBoxes = new PictureBox[GridSize, GridSize];//创建3x3个picturebox
        private Dictionary<PictureBox, Point> originalPositions = new Dictionary<PictureBox, Point>();//初始位置
        private Dictionary<PictureBox, Point> currentPositions = new Dictionary<PictureBox, Point>();//当前位置
        private Image originalImage = Image.FromFile("rabbit.png");//原图
        private Image[,] imageParts = new Image[GridSize, GridSize];//分割后的图片
        private const int Spacing = 5;//分割图片之间的留白大小

        public Form1()
        {
            InitializeComponent();
            InitializeGame();
        }

        private void InitializeGame()
        {

            //调整尺寸
            originalImage = resize_img(originalImage);


            // 切割图片
            CutImage();

            // 创建游戏面板
            CreateGameBoard();

            // 打乱拼图
            ShufflePuzzle();

        }


        //调整尺寸
        private Image resize_img(Image originalImage)
        {
            //调整原图的尺寸为300x300
            Bitmap resizedImage = new Bitmap(300, 300);
            using (Graphics g = Graphics.FromImage(resizedImage))
            {
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                g.DrawImage(originalImage, 0, 0, 300, 300);
            }
            return resizedImage;
        }


        //分割图片
        private void CutImage()
        {
            for (int i = 0; i < GridSize; i++)
            {
                for (int j = 0; j < GridSize; j++)
                {
                    // 创建每个部分的位图
                    Bitmap part = new Bitmap(CellSize, CellSize);
                    using (Graphics g = Graphics.FromImage(part))
                    {
                        // 计算源图像中的矩形区域
                        Rectangle srcRect = new Rectangle(j * CellSize, i * CellSize, CellSize, CellSize);
                        // 计算目标图像中的矩形区域
                        Rectangle destRect = new Rectangle(0, 0, CellSize, CellSize);
                        // 绘制图像部分
                        g.DrawImage(originalImage, destRect, srcRect, GraphicsUnit.Pixel);
                    }
                    imageParts[i, j] = part;
                }
            }
        }

        private void CreateGameBoard()
        {

            Controls.Clear();
            ClientSize = new Size(CellSize * GridSize + Spacing * (GridSize + 1),
                                 CellSize * GridSize + Spacing * (GridSize + 1) + 30);

            // 重新开始按钮
            Button restartButton = new Button
            {
                Text = "重新开始",
                Location = new Point(10, ClientSize.Height - 25),
                Size = new Size(100, 20)
            };
            restartButton.Click += (s, e) => ShufflePuzzle();
            Controls.Add(restartButton);

            // 检查按钮
            Button checkButton = new Button
            {
                Text = "检查",
                Location = new Point(150, ClientSize.Height - 25),
                Size = new Size(100, 20)
            };

            Controls.Add(checkButton);

            // 创建所有拼图块
            for (int i = 0; i < GridSize; i++)
            {
                for (int j = 0; j < GridSize; j++)
                {
                    PictureBox pb = new PictureBox
                    {
                        Size = new Size(CellSize, CellSize),
                        Location = new Point(Spacing + j * (CellSize + Spacing),
                                           Spacing + i * (CellSize + Spacing)),
                        Image = imageParts[i, j],
                        SizeMode = PictureBoxSizeMode.StretchImage,

                    };



                    Controls.Add(pb);
                    pictureBoxes[i, j] = pb;
                    originalPositions.Add(pb, new Point(i, j));
                    currentPositions.Add(pb, new Point(i, j));
                }
            }
        }

        private void ShufflePuzzle()
        {
            Random rand = new Random();
            List<PictureBox> boxes = new List<PictureBox>();

            // 收集所有拼图块
            foreach (PictureBox pb in pictureBoxes)
            {
                boxes.Add(pb);
            }

            // 洗牌
            int n = boxes.Count;
            while (n > 1)
            {
                n--;
                int k = rand.Next(n + 1);
                PictureBox temp = boxes[k];
                boxes[k] = boxes[n];
                boxes[n] = temp;
            }

            // 重新排列图片和位置
            for (int i = 0; i < GridSize; i++)
            {
                for (int j = 0; j < GridSize; j++)
                {
                    int index = i * GridSize + j;
                    PictureBox pb = boxes[index];

                    // 更新物理位置
                    pb.Location = new Point(Spacing + j * (CellSize + Spacing),
                                           Spacing + i * (CellSize + Spacing));

                    // 更新位置字典
                    currentPositions[pb] = new Point(i, j);
                    pictureBoxes[i, j] = pb;
                }
            }

        }









        private bool IsPuzzleSolved()
        {
            foreach (var entry in currentPositions)
            {
                PictureBox pb = entry.Key;
                Point currentPos = entry.Value;
                Point originalPos = originalPositions[pb];

                if (currentPos.X != originalPos.X || currentPos.Y != originalPos.Y)
                {
                    return false;
                }
            }
            return true;
        }

    }
}

运行后:

2.2 拖与放



        private void PictureBox_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                var pb = (PictureBox)sender;
                pb.DoDragDrop(pb, DragDropEffects.Move);
            }
        }

        private void PictureBox_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(PictureBox)))
            {
                e.Effect = DragDropEffects.Move;
            }
        }


        private void PictureBox_DragDrop(object sender, DragEventArgs e)
        {
            var targetPb = (PictureBox)sender;
            var sourcePb = (PictureBox)e.Data.GetData(typeof(PictureBox));

            // 交换物理位置
            Point tempLoc = targetPb.Location;
            targetPb.Location = sourcePb.Location;
            sourcePb.Location = tempLoc;

            // 交换currentPositions记录
            Point tempPos = currentPositions[targetPb];
            currentPositions[targetPb] = currentPositions[sourcePb];
            currentPositions[sourcePb] = tempPos;

            // 同步更新pictureBoxes数组
            for (int i = 0; i < GridSize; i++)
            {
                for (int j = 0; j < GridSize; j++)
                {
                    if (pictureBoxes[i, j] == targetPb)
                        pictureBoxes[i, j] = sourcePb;
                    else if (pictureBoxes[i, j] == sourcePb)
                        pictureBoxes[i, j] = targetPb;
                }
            }

            // 强制刷新界面
            targetPb.Refresh();
            sourcePb.Refresh();
        }

完整拖放流程

  1. 按下鼠标 → MouseDown 启动拖放。
  2. 拖入控件边界 → DragEnter 验证并显示反馈。
  3. 释放鼠标 → DragDrop 执行实际交换操作。

3.完整代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace pintu_game
{
    public partial class Form1 : Form
    {
        private const int CellSize = 100;//每块拼图的大小
        static private int GridSize = 3;//拼图数
        private PictureBox[,] pictureBoxes = new PictureBox[GridSize, GridSize];//创建3x3个picturebox
        private Dictionary<PictureBox, Point> originalPositions = new Dictionary<PictureBox, Point>();//初始位置
        private Dictionary<PictureBox, Point> currentPositions = new Dictionary<PictureBox, Point>();//当前位置
        private Image originalImage = Image.FromFile("rabbit.png");//原图
        private Image[,] imageParts = new Image[GridSize, GridSize];//分割后的图片
        private const int Spacing = 5;//分割图片之间的留白大小

        public Form1()
        {
            InitializeComponent();
            InitializeGame();
        }

        private void InitializeGame()
        {

            //调整尺寸
            originalImage = resize_img(originalImage);


            // 切割图片
            CutImage();

            // 创建游戏面板
            CreateGameBoard();

            // 打乱拼图
            ShufflePuzzle();

        }


        //调整尺寸
        private Image resize_img(Image originalImage)
        {
            //调整原图的尺寸为300x300
            Bitmap resizedImage = new Bitmap(300, 300);
            using (Graphics g = Graphics.FromImage(resizedImage))
            {
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                g.DrawImage(originalImage, 0, 0, 300, 300);
            }
            return resizedImage;
        }


        //分割图片
        private void CutImage()
        {
            for (int i = 0; i < GridSize; i++)
            {
                for (int j = 0; j < GridSize; j++)
                {
                    // 创建每个部分的位图
                    Bitmap part = new Bitmap(CellSize, CellSize);
                    using (Graphics g = Graphics.FromImage(part))
                    {
                        // 计算源图像中的矩形区域
                        Rectangle srcRect = new Rectangle(j * CellSize, i * CellSize, CellSize, CellSize);
                        // 计算目标图像中的矩形区域
                        Rectangle destRect = new Rectangle(0, 0, CellSize, CellSize);
                        // 绘制图像部分
                        g.DrawImage(originalImage, destRect, srcRect, GraphicsUnit.Pixel);
                    }
                    imageParts[i, j] = part;
                }
            }
        }

        private void CreateGameBoard()
        {

            Controls.Clear();
            ClientSize = new Size(CellSize * GridSize + Spacing * (GridSize + 1),
                                 CellSize * GridSize + Spacing * (GridSize + 1) + 30);

            // 重新开始按钮
            Button restartButton = new Button
            {
                Text = "重新开始",
                Location = new Point(10, ClientSize.Height - 25),
                Size = new Size(100, 20)
            };
            restartButton.Click += (s, e) => ShufflePuzzle();
            Controls.Add(restartButton);

            // 检查按钮
            Button checkButton = new Button
            {
                Text = "检查",
                Location = new Point(150, ClientSize.Height - 25),
                Size = new Size(100, 20)
            };
            checkButton.Click += (s, e) => checksuccess();
            Controls.Add(checkButton);

            // 创建所有拼图块
            for (int i = 0; i < GridSize; i++)
            {
                for (int j = 0; j < GridSize; j++)
                {
                    PictureBox pb = new PictureBox
                    {
                        Size = new Size(CellSize, CellSize),
                        Location = new Point(Spacing + j * (CellSize + Spacing),
                                           Spacing + i * (CellSize + Spacing)),
                        Image = imageParts[i, j],
                        SizeMode = PictureBoxSizeMode.StretchImage,

                    };

                    // 拖放事件
                    pb.MouseDown += PictureBox_MouseDown;
                    pb.DragEnter += PictureBox_DragEnter;
                    pb.DragDrop += PictureBox_DragDrop;
                    pb.AllowDrop = true;

                    Controls.Add(pb);
                    pictureBoxes[i, j] = pb;
                    originalPositions.Add(pb, new Point(i, j));
                    currentPositions.Add(pb, new Point(i, j));
                }
            }
        }



        private void ShufflePuzzle()
        {
            Random rand = new Random();
            List<PictureBox> boxes = new List<PictureBox>();

            // 收集所有拼图块
            foreach (PictureBox pb in pictureBoxes)
            {
                boxes.Add(pb);
            }

            // 洗牌
            int n = boxes.Count;
            while (n > 1)
            {
                n--;
                int k = rand.Next(n + 1);
                PictureBox temp = boxes[k];
                boxes[k] = boxes[n];
                boxes[n] = temp;
            }

            // 重新排列图片和位置
            for (int i = 0; i < GridSize; i++)
            {
                for (int j = 0; j < GridSize; j++)
                {
                    int index = i * GridSize + j;
                    PictureBox pb = boxes[index];

                    // 更新物理位置
                    pb.Location = new Point(Spacing + j * (CellSize + Spacing),
                                           Spacing + i * (CellSize + Spacing));

                    // 更新位置字典
                    currentPositions[pb] = new Point(i, j);
                    pictureBoxes[i, j] = pb;
                }
            }

        }



        private void PictureBox_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left) // 检查是否左键按下
            {
                var pb = (PictureBox)sender;
                pb.DoDragDrop(pb, DragDropEffects.Move);// 开始拖放操作
            }
        }

        private void PictureBox_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(PictureBox))) // 检查拖入的是否是PictureBox
            {
                e.Effect = DragDropEffects.Move;// 允许移动操作
            }
        }

        //当用户释放鼠标左键(完成拖放)时触发。
        private void PictureBox_DragDrop(object sender, DragEventArgs e)
        {
            var targetPb = (PictureBox)sender;
            var sourcePb = (PictureBox)e.Data.GetData(typeof(PictureBox));

            // 交换物理位置
            Point tempLoc = targetPb.Location;
            targetPb.Location = sourcePb.Location;
            sourcePb.Location = tempLoc;

            // 交换currentPositions记录
            Point tempPos = currentPositions[targetPb];
            currentPositions[targetPb] = currentPositions[sourcePb];
            currentPositions[sourcePb] = tempPos;

            // 同步更新pictureBoxes数组
            for (int i = 0; i < GridSize; i++)
            {
                for (int j = 0; j < GridSize; j++)
                {
                    if (pictureBoxes[i, j] == targetPb)
                        pictureBoxes[i, j] = sourcePb;
                    else if (pictureBoxes[i, j] == sourcePb)
                        pictureBoxes[i, j] = targetPb;
                }
            }

            // 强制刷新界面
            targetPb.Refresh();
            sourcePb.Refresh();
        }






        private bool IsPuzzleSolved()
        {
            foreach (var entry in currentPositions)
            {
                PictureBox pb = entry.Key;
                Point currentPos = entry.Value;
                Point originalPos = originalPositions[pb];

                if (currentPos.X != originalPos.X || currentPos.Y != originalPos.Y)
                {
                    return false;
                }
            }
            return true;
        }


        private void checksuccess()
        {
            if (IsPuzzleSolved())
            {
                MessageBox.Show("恭喜你完成了拼图!", "游戏胜利");
            }
            else
            {
                MessageBox.Show("未完成");
            }
        }


    }
}