当前位置: 首页 > news >正文

c# winform 拼图游戏

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个pictureboxprivate 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){//调整原图的尺寸为300x300Bitmap 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个pictureboxprivate 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){//调整原图的尺寸为300x300Bitmap 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("未完成");}}}
}

http://www.xdnf.cn/news/1417033.html

相关文章:

  • 预处理——嵌入式学习笔记
  • leetcode 1576 替换所有的问号
  • Linux 定时任务 crontab 完全指南 —— 让服务器自动干活,解放双手
  • Kubernetes集群升级与etcd备份恢复指南
  • 《IC验证必看|随机稳定性 / 再现性》
  • 今日分享:C++ -- vector
  • Python备份实战专栏第4/6篇:Vue.js + Flask 打造企业级备份监控面板
  • line-height属性详解
  • Kafka消息中间件安装配置
  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段(23):文法+单词第7回5+考え方3
  • 【DeepSeek】蓝耘元生代 | 蓝耘MaaS平台与DeepSeek-V3.1重构智能应用开发
  • 【数据库】Sql Server数据库中isnull、iif、case when三种方式的使用和空值判断
  • 【重学MySQL】九十七、MySQL目录结构与文件系统解析
  • 2025年06月 Scratch 图形化(四级)真题解析#中国电子学会#全国青少年软件编程等级考试
  • Dify之插件开发之Crawl4ai 爬虫(简单逻辑实现)
  • 【XR技术概念科普】VST(视频透视)vs OST(光学透视):解码MR头显的两种核心技术路径
  • 高并发场景下的热点数据处理:从预热到多级缓存的性能优化实践
  • Java 双链表
  • 云市场周报 (2025.09.01):解读腾讯云向量数据库、阿里云西安节点与平台工程
  • 【Pycharm】Pychram软件工具栏Git和VCS切换
  • 【数据可视化-105】Pyecharts主题组件:让你的图表瞬间高大上
  • 飞牛nas修改crontab计划默认编辑器
  • leetcode-hot-100 (贪心算法)
  • 构建共享新生态的智慧物流开源了
  • TensorFlow 2.10 是最后一个支持在原生Windows上使用GPU的TensorFlow版本
  • TensorFlow深度学习实战(36)——自动机器学习(AutoML)
  • Golang之GoWorld深度解析:基于Go语言的分布式游戏服务器框架
  • 【最新版】Win11 24H2 正式版2025年8月版 Windows11的24H2全系列下载 官方原版光盘系统ISO文件下载
  • .net 微服务jeager链路跟踪
  • Java全栈开发工程师面试实战:从基础到微服务的完整技术演进