精华内容
下载资源
问答
  • 简单的窗体小游戏,通俗易懂
  • 使用面向对象的思想(继承和派生),并借助窗体重载OnPaint方法实现飞机、子弹、爆炸的绘制效果。代码中使用大量注释,以帮助读者更好的理解代码 打开游戏后,回车即可开始游戏,上下左右键 用于 控制战机方向
  • C#窗体连连看小游戏(超详细)

    千次阅读 多人点赞 2020-12-17 17:52:31
    文章目录成品链接项目展示全部代码窗体控件命名连连看功能类窗体功能实现各部分功能解释一、项目分析二、项目设计 成品链接 项目展示 全部代码 窗体控件命名 namespace Linkup { partial class MainWindow { //...

    成品链接

    https://download.csdn.net/download/weixin_45525272/13713452

    项目展示

    在这里插入图片描述
    在这里插入图片描述

    各部分功能解释

    一、项目分析

    系统设计思路

    (1)设计连连看功能类:LinkClass,Line
    (2)设计两个事件:成功事件和失败事件
    (3)成功事件:1.垂直事件2.水平事件3.一个拐点事件4.两个拐点事件
    (4)失败事件:

    1. 一个按钮点击两次
    2. 点击的两个按钮所带图片不一样
    3. 点击两个具有相同图案的按钮但没有通路

    (5)可以选择三种行和列:88,1010,12*12
    (6)可以选择两种模式:数字,图片
    (7)设计随机数并且随机数要配对
    (8)赋予按钮应有的相关属性
    (9)计时器设计,暂停按钮时计时器停止计时,开始按钮显示继续游戏
    (10)每消除一对图片,计分加100
    (11)重新排列功能,每重新排列一次总得分减400

    二、项目设计

    一、难度和模式
    用两个comboBox分别设计行和列,图片或者数字模式

    
    if (comboBox1.Text == ""|| comboBox2.Text=="")
    {
       MessageBox.Show("请选择难度或者模式", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    else
    {
       // 选择的关卡难度文本
       string Diffcult = comboBox1.Text;
       //根据对应难度初始化数组并给n赋值
       switch (Diffcult)
       {
           case "8*8":
               hang = 8;
               break;
           case "10*10":
               hang = 10;
               break;
           case "12*12":
               hang = 12;
               break; 
       }
    //判断用户选的是图片还是数字
             string mul = comboBox2.Text;
             if (mul == "数字")
             {
                 Button btnLinker = new Button() // 设置每个小按钮的相关属性
                 {
                     Text = rnd.ToString(),//按钮上显示的是随机数
                     Tag = img,//标签
                     Name = string.Format("{0},{1}", row, col),//每个按钮命名
                     Dock = DockStyle.Fill,//调整控件层次,填充
                     Margin = new Padding(1),//调整外边距
                 };
                 btnLinker.Click += BtnLinker_Click; // 让每个按钮都拥有点击事件
                 this.TableLp.Controls.Add(btnLinker, col, row);//将按钮加进去并赋给位置
             }
             else//即用户选择了图片
             {
                 Button btnLinker = new Button() // 设置每个小按钮的相关属性
                 {
                     BackgroundImage = GetImageByName(img),//给按钮填充背景图片
                     BackgroundImageLayout = ImageLayout.Stretch,//背景图片拉申
                     Tag = img,
                     Name = string.Format("{0},{1}", row, col),
                     Dock = DockStyle.Fill,
                     Margin = new Padding(1),
                 };
                 btnLinker.Click += BtnLinker_Click; // 让每个按钮都拥有点击事件
                 this.TableLp.Controls.Add(btnLinker, col, row);
             }
         }
       }
       this.LinkObj.LinkBoard = linkBoard;//初始化棋盘
       this.TableLp.Enabled = false;
    
    

    2、进度条分数模块
    用计时器线程来计时,进行进度条与时间标签的实时更新

    
            // 计时器线程
            Thread timeDelay;       // 线程变量
            int timetemp = 0;       // 计时器中间变量
     // 定时器事件:时间剩余
            void timeDelay_Tick()
            {
                //ma.WaitOne(); // 根据是否收到信号判断是否阻塞当前线程
                while (this.curDelay > 0 )   // 当前时间大于零
                {
                    if (!isClosing)
                    {
                        this.curDelay--;
                        this.pbTimeDelay.Value = this.curDelay;
                        this.lblTimeDelay.Text = this.curDelay.ToString();
                        
                    }
                    Thread.Sleep(1000);
                }
                if (!isClosing)
                {
                  
                    this.btnStart.Enabled = true;
                    this.TableLp.Enabled = false;
                  
                }
            }
    

    3、开始游戏(游戏初始化)
    清除残余,并且设置新的表格

    this.TableLp.ColumnStyles.Clear();
                    this.TableLp.RowStyles.Clear();
                    this.TableLp.Controls.Clear();
    this.TableLp.ColumnCount = hang + 2;
                    this.TableLp.RowCount = hang + 2;
    
    设置按钮及边框所占的比列
    for (int i = 0; i < hang + 2; i++)
                    {
                        //设置等宽等高  边缘2,里面内容10
                        if (i == 0 || i == hang + 1)
                        {
                            this.TableLp.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 2));//占总画面的2%
                            this.TableLp.RowStyles.Add(new RowStyle(SizeType.Percent, 2));
                        }
                        else
                        {
                            this.TableLp.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 10));//占总画面的10%
                            this.TableLp.RowStyles.Add(new RowStyle(SizeType.Percent, 10));
                        }
                    }
    
    为每个按钮赋给图片或者相应的数字
     string img = string.Format("_1_{0}", rnd.ToString("00"));//给图片命名
                            linkBoard[row, col] = rnd;//赋给每个位置随机数字
                            //判断用户选的是图片还是数字
                            string mul = comboBox2.Text;
                            if (mul == "数字")
                            {
                                Button btnLinker = new Button() // 设置每个小按钮的相关属性
                                {
                                    Text = rnd.ToString(),//按钮上显示的是随机数
                                    Tag = img,//标签
                                    Name = string.Format("{0},{1}", row, col),//每个按钮命名
                                    Dock = DockStyle.Fill,//调整控件层次,填充
                                    Margin = new Padding(1),//调整外边距
                                };
                                btnLinker.Click += BtnLinker_Click; // 让每个按钮都拥有点击事件
                                this.TableLp.Controls.Add(btnLinker, col, row);//将按钮加进去并赋给位置
                            }
                            else//即用户选择了图片
                            {
                                Button btnLinker = new Button() // 设置每个小按钮的相关属性
                                {
                                    BackgroundImage = GetImageByName(img),//给按钮填充背景图片
                                    BackgroundImageLayout = ImageLayout.Stretch,//背景图片拉申
                                    Tag = img,
                                    Name = string.Format("{0},{1}", row, col),
                                    Dock = DockStyle.Fill,
                                    Margin = new Padding(1),
                                };
                                btnLinker.Click += BtnLinker_Click; // 让每个按钮都拥有点击事件
                                this.TableLp.Controls.Add(btnLinker, col, row);
                            }
                        }
      }
    

    4、暂停游戏
    通过将当前时间的变量赋值为0来结束当前计时器线程,并且当点击继续游戏的时候,通过开启新线程来重新运行计数功能

    暂停

            private void btnPause_Click(object sender, EventArgs e)
            {
                this.TableLp.Enabled = false;
      
                btnStart.Enabled = true;
                btnStart.Text = "继续游戏";
                //ma.Reset();//信号关闭阻塞当前线程
    
                timetemp = this.curDelay;
                this.curDelay = 0;
                lblTimeDelay.Text = timetemp.ToString();
           }
    

    继续

     else if (btnStart.Text == "继续游戏")
                {
                    //ma.Set();//信号打开,不阻塞当前线程
                    btnStart.Text = "开始游戏";
                    btnStart.Enabled = false;
                    this.TableLp.Enabled = true;
                    this.curDelay= timetemp;// 将中间变量赋值给新的当前时间
                    lblTimeDelay.Text = this.curDelay.ToString();
                    timeDelay = new Thread(new ThreadStart(this.timeDelay_Tick));//新的计时器
                    timeDelay.Start();
                }
    

    5、重新排列
    设置随机二维数组,将原来的数字所在的行和列用随机的二维数组替代

    int rnd, rnd2;
                    // 打乱二维数组顺序
                    for (int row = 1; row < hang + 1; row++)
                    {
                        for (int col = 1; col < hang + 1; col++)
                        {
                            // 产生随机数
                            rnd = r.Next(1, 1000) % hang + 1;
                            rnd2 = r.Next(1, 1000) % hang + 1;
    
                            int temp = linkBoard[rnd, rnd2];
                            linkBoard[rnd, rnd2] = linkBoard[row, col];
                            linkBoard[row, col] = temp;
    
                        }
                    }
    

    6、判断连接的核心算法
    (1)垂直事件
    获取按钮1和按钮2的y值,并利用循环来判断按钮1和按钮2之间是否为通路

     private bool vertical(Point a, Point b)
            {
                int col_start = a.Y < b.Y ? a.Y : b.Y;    //获取a,b中较小的y值
                int col_end = a.Y < b.Y ? b.Y : a.Y;      //获取a,b中较大的y值
    
                //遍历a,b之间是否通路,如果一个不是就返回false;
                for (int i = col_start + 1; i < col_end; i++)
                {
                    if (this.LinkBoard[a.X, i] != 0)//0是空的状态(即没有按钮)
                    {
                        return false;
                    }
                }
                return true;
            }
    

    (2)水平事件
    获取按钮1和按钮2的x值,并利用循环来判断按钮1和按钮2之间是否为通路

    private bool horizon(Point a, Point b)
            {
                int row_start = a.X < b.X ? a.X : b.X;//获取a,b中较小的x值
                int row_end = a.X < b.X ? b.X : a.X;//获取a,b中较大的x值
                for (int i = row_start + 1; i < row_end; i++)
                {
                    if (this.LinkBoard[i, a.Y] != 0)//0是空的状态(即没有按钮)
                    {
                        return false;//return是函数结束
                    }
                }
                return true;
            }
    

    (3)一个拐点事件
    首先判断拐点位置是否有按钮,若没有,将剩下部分看做由一个垂直事件和一个水平事件组成

    private bool oneCorner(Point a, Point b)
            {
                // 拐角点的x,y分别等于两点各个x,y
                Point c = new Point(b.X, a.Y);
                Point d = new Point(a.X, b.Y);
                // 判断C点是否有元素,有就继续执行下面判断条件,没有就看a与c,b与c之间是否能水平或者垂直连线                
                if (this.LinkBoard[c.X, c.Y] == 0)
                {
                    bool path1 = vertical(b, c) && horizon(a, c);
                    return path1;   //path1本身就是bool值
                }
    
                //判断D点是否有元素
                if (this.LinkBoard[d.X, d.Y] == 0)
                {
                    bool path2 = vertical(a, d) && horizon(b, d);
                    return path2;//path2本身就是bool值
                }
                
                // 能执行到这就说明前面判断不成功,不存在一个拐点的情况
                return false;
               
            }
    

    (4)两个拐点事件
    首先判断两个拐点是都有按钮,并且判断两个拐点间是否为通路,此过程用到新建的scan函数,剩下即有两个水平事件或者两个垂直事件构成

    private List<Line> scan(Point a, Point b)
            {
                List<Line> linkList = new List<Line>();// 新建一个直线对象List容器,用来存成立的拐点之间的直线
    
                //检测a点上方是否能够水平直连
                for (int i = a.Y; i >= 0; i--)
                {
                    if (this.LinkBoard[a.X, i] == 0 && this.LinkBoard[b.X, i] == 0 && horizon(new Point(a.X, i), new Point(b.X, i)))
                    {
                        linkList.Add(new Line(new Point(a.X, i), new Point(b.X, i), 0));
                    }
                }
    
                //检测a点下方是否能够水平直连
                for (int i = a.Y; i < Col; i++)
                {
                    if (this.LinkBoard[a.X, i] == 0 && this.LinkBoard[b.X, i] == 0 && horizon(new Point(a.X, i), new Point(b.X, i)))
                    {
                        linkList.Add(new Line(new Point(a.X, i), new Point(b.X, i), 0));
                    }
                }
    
                //检测a点左侧是否能够垂直直连
                for (int j = a.X; j >= 0; j--)
                {
                    if (this.LinkBoard[j, a.Y] == 0 && this.LinkBoard[j, b.Y] == 0 && vertical(new Point(j, a.Y), new Point(j, b.Y)))
                    {
                        linkList.Add(new Line(new Point(j, a.Y), new Point(j, b.Y), 1));
                    }
                }
    
                //检测a点右侧是否能够垂直直连
                for (int j = a.X; j < Row; j++)
                {
                    if (this.LinkBoard[j, a.Y] == 0 && this.LinkBoard[j, b.Y] == 0 && vertical(new Point(j, a.Y), new Point(j, b.Y)))
                    {
                        linkList.Add(new Line(new Point(j, a.Y), new Point(j, b.Y), 1));
    
                    }
                }
    
                return linkList;
            }
    }
     private bool twoCorner(Point a, Point b)
            {
                // list容器:相当于一个Line类型的数组,存扫到的连通路径
                List<Line> ll = scan(a, b);//此时的直线已经判断成功并且拐点位置没有数字
                if (ll.Count == 0)  // 没扫到返回false,List容器里面的计数方法
                {
                    return false;
                }
    
                for (int i = 0; i < ll.Count; i++)
                {
                    Line tempLine = ll[i];  // 临时连线变量用于判断拐点与a,b的通路是否成立
                    if (tempLine.direct == 1)   // 两个拐点之间是水平直连
                    {// 判断分别两个拐点与a,b能否相连
                        if (horizon(a, tempLine.a) && horizon(b, tempLine.b))//判断a与a"之间是否有通路;判断b与b"之间是否有通路
                        {
                            return true;
                        }
                    }
                    else if (tempLine.direct == 0)  // 两个拐点之间是垂直直连
                    {// 判断分别两个拐点与a,b能否相连
                        if (vertical(a, tempLine.a) && vertical(b, tempLine.b))//判断a与a"之间是否有通路;判断b与b"之间是否有通路
                        {
                            return true;
                        }
                    }
                }
                return false;
            }
    
    

    7.重新排列
    将原本储存的二维数组重新打乱顺序,在按照打乱后的数组动态生成按钮

      // 打乱二维数组顺序
          for (int row = 1; row < hang + 1; row++)
          {
              for (int col = 1; col < hang + 1; col++)
              {
                  // 产生随机数
                  rnd = r.Next(1, 1000) % hang + 1;
                  rnd2 = r.Next(1, 1000) % hang + 1;
    
                  int temp = linkBoard[rnd, rnd2];
                  linkBoard[rnd, rnd2] = linkBoard[row, col];
                  linkBoard[row, col] = temp;
    
              }
          }
    
    

    8.连接成功判断
    用两个循环挨个遍历数组元素并计数,最后判断计数是否够元素的个数

            // 判断成功
            private void Judge()
            {
                int count=0;
                // 将内置元素进行随机数分配等操作
                for (int row = 1; row < hang + 1; row++)
                {
                    for (int col = 1; col < hang + 1; col++)
                    {
                        if (this.LinkObj.LinkBoard[row,col]==0)
                        {
                            count++;
                        }
                    }
                }
                if (count==hang*hang)
                {
                    MessageBox.Show("拼完了,你可真厉害!","提示",MessageBoxButtons.OK,MessageBoxIcon.Asterisk);
                    this.TableLp.Enabled = false;
                    btnStart.Enabled = true;
    
                    timetemp = this.curDelay;
                    this.curDelay = 0;
                    lblTimeDelay.Text = timetemp.ToString();
                }
            }
    
    

    全部代码

    窗体控件命名

    namespace Linkup
    {
        partial class MainWindow
        {
            /// <summary>
            /// 必需的设计器变量。
            /// </summary>
            private System.ComponentModel.IContainer components = null;
    
            /// <summary>
            /// 清理所有正在使用的资源。
            /// </summary>
            /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
            protected override void Dispose(bool disposing)
            {
                if (disposing && (components != null))
                {
                    components.Dispose();
                }
                base.Dispose(disposing);
            }
    
            #region Windows 窗体设计器生成的代码
    
            /// <summary>
            /// 设计器支持所需的方法 - 不要修改
            /// 使用代码编辑器修改此方法的内容。
            /// </summary>
            private void InitializeComponent()
            {
                System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainWindow));
                this.TableLp = new System.Windows.Forms.TableLayoutPanel();
                this.btnStart = new System.Windows.Forms.Button();
                this.pbTimeDelay = new System.Windows.Forms.ProgressBar();
                this.lblTimeDelay = new System.Windows.Forms.Label();
                this.lableScore = new System.Windows.Forms.Label();
                this.btnStop = new System.Windows.Forms.Button();
                this.comboBox1 = new System.Windows.Forms.ComboBox();
                this.btnPause = new System.Windows.Forms.Button();
                this.btnReset = new System.Windows.Forms.Button();
                this.comboBox2 = new System.Windows.Forms.ComboBox();
                this.label1 = new System.Windows.Forms.Label();
                this.label2 = new System.Windows.Forms.Label();
                this.SuspendLayout();
                // 
                // TableLp
                // 
                this.TableLp.ColumnCount = 1;
                this.TableLp.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
                this.TableLp.Location = new System.Drawing.Point(61, 12);
                this.TableLp.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
                this.TableLp.Name = "TableLp";
                this.TableLp.RowCount = 1;
                this.TableLp.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
                this.TableLp.Size = new System.Drawing.Size(534, 534);
                this.TableLp.TabIndex = 0;
                // 
                // btnStart
                // 
                this.btnStart.Location = new System.Drawing.Point(697, 44);
                this.btnStart.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
                this.btnStart.Name = "btnStart";
                this.btnStart.Size = new System.Drawing.Size(243, 36);
                this.btnStart.TabIndex = 1;
                this.btnStart.Text = "开始游戏";
                this.btnStart.UseVisualStyleBackColor = true;
                this.btnStart.Click += new System.EventHandler(this.btnStart_Click);
                // 
                // pbTimeDelay
                // 
                this.pbTimeDelay.Location = new System.Drawing.Point(61, 573);
                this.pbTimeDelay.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
                this.pbTimeDelay.Name = "pbTimeDelay";
                this.pbTimeDelay.Size = new System.Drawing.Size(451, 19);
                this.pbTimeDelay.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
                this.pbTimeDelay.TabIndex = 2;
                // 
                // lblTimeDelay
                // 
                this.lblTimeDelay.AutoSize = true;
                this.lblTimeDelay.Location = new System.Drawing.Point(542, 573);
                this.lblTimeDelay.Name = "lblTimeDelay";
                this.lblTimeDelay.Size = new System.Drawing.Size(15, 15);
                this.lblTimeDelay.TabIndex = 3;
                this.lblTimeDelay.Text = "0";
                // 
                // lableScore
                // 
                this.lableScore.AutoSize = true;
                this.lableScore.Location = new System.Drawing.Point(724, 573);
                this.lableScore.Name = "lableScore";
                this.lableScore.Size = new System.Drawing.Size(60, 15);
                this.lableScore.TabIndex = 4;
                this.lableScore.Text = "分数:0";
                // 
                // btnStop
                // 
                this.btnStop.Location = new System.Drawing.Point(697, 160);
                this.btnStop.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
                this.btnStop.Name = "btnStop";
                this.btnStop.Size = new System.Drawing.Size(243, 36);
                this.btnStop.TabIndex = 1;
                this.btnStop.Text = "结束游戏";
                this.btnStop.UseVisualStyleBackColor = true;
                this.btnStop.Click += new System.EventHandler(this.btnStop_Click);
                // 
                // comboBox1
                // 
                this.comboBox1.FormattingEnabled = true;
                this.comboBox1.Location = new System.Drawing.Point(780, 318);
                this.comboBox1.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
                this.comboBox1.Name = "comboBox1";
                this.comboBox1.Size = new System.Drawing.Size(160, 23);
                this.comboBox1.TabIndex = 5;
                // 
                // btnPause
                // 
                this.btnPause.Location = new System.Drawing.Point(697, 102);
                this.btnPause.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
                this.btnPause.Name = "btnPause";
                this.btnPause.Size = new System.Drawing.Size(243, 36);
                this.btnPause.TabIndex = 1;
                this.btnPause.Text = "暂停游戏";
                this.btnPause.UseVisualStyleBackColor = true;
                this.btnPause.Click += new System.EventHandler(this.btnPause_Click);
                // 
                // btnReset
                // 
                this.btnReset.Location = new System.Drawing.Point(697, 218);
                this.btnReset.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
                this.btnReset.Name = "btnReset";
                this.btnReset.Size = new System.Drawing.Size(243, 36);
                this.btnReset.TabIndex = 1;
                this.btnReset.Text = "重新排列";
                this.btnReset.UseVisualStyleBackColor = true;
                this.btnReset.Click += new System.EventHandler(this.btnReset_Click);
                // 
                // comboBox2
                // 
                this.comboBox2.FormattingEnabled = true;
                this.comboBox2.Location = new System.Drawing.Point(780, 367);
                this.comboBox2.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
                this.comboBox2.Name = "comboBox2";
                this.comboBox2.Size = new System.Drawing.Size(160, 23);
                this.comboBox2.TabIndex = 5;
                // 
                // label1
                // 
                this.label1.AutoSize = true;
                this.label1.Location = new System.Drawing.Point(694, 321);
                this.label1.Name = "label1";
                this.label1.Size = new System.Drawing.Size(52, 15);
                this.label1.TabIndex = 6;
                this.label1.Text = "难度:";
                // 
                // label2
                // 
                this.label2.AutoSize = true;
                this.label2.Location = new System.Drawing.Point(694, 372);
                this.label2.Name = "label2";
                this.label2.Size = new System.Drawing.Size(52, 15);
                this.label2.TabIndex = 6;
                this.label2.Text = "模式:";
                // 
                // MainWindow
                // 
                this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F);
                this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
                this.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("$this.BackgroundImage")));
                this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
                this.ClientSize = new System.Drawing.Size(1008, 652);
                this.Controls.Add(this.label2);
                this.Controls.Add(this.label1);
                this.Controls.Add(this.comboBox2);
                this.Controls.Add(this.comboBox1);
                this.Controls.Add(this.lableScore);
                this.Controls.Add(this.lblTimeDelay);
                this.Controls.Add(this.pbTimeDelay);
                this.Controls.Add(this.btnReset);
                this.Controls.Add(this.btnPause);
                this.Controls.Add(this.btnStop);
                this.Controls.Add(this.btnStart);
                this.Controls.Add(this.TableLp);
                this.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
                this.Name = "MainWindow";
                this.Text = "Form1";
                this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing);
                this.Load += new System.EventHandler(this.Form1_Load);
                this.ResumeLayout(false);
                this.PerformLayout();
    
            }
    
            #endregion
    
            private System.Windows.Forms.TableLayoutPanel TableLp;
            private System.Windows.Forms.Button btnStart;
            private System.Windows.Forms.ProgressBar pbTimeDelay;
            private System.Windows.Forms.Label lblTimeDelay;
            private System.Windows.Forms.Label lableScore;
            private System.Windows.Forms.Button btnStop;
            private System.Windows.Forms.ComboBox comboBox1;
            private System.Windows.Forms.Button btnPause;
            private System.Windows.Forms.Button btnReset;
            private System.Windows.Forms.ComboBox comboBox2;
            private System.Windows.Forms.Label label1;
            private System.Windows.Forms.Label label2;
        }
    }
    
    
    

    连连看功能类

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Drawing;
    
    namespace Linkup
    {
        // 连连看功能类
        public class LinkClass
        {
            // 连连看 看板
            public int[,] LinkBoard { get; set; }//命名为LinkBoard的连连看看板
    
            // 连线成功事件
            public event EventHandler SucClick;
            // 连接失败事件
            public event EventHandler FailClick;
    
            //Col是行
            private int col = 10;
            public int Col 
            {
                get
                {
                    return col;
                }
                set
                {
                    col = value;
                }
            }
    
            // Row是列
            private int row = 10;
            public int Row
            {
                get
                {
                    return row;
                }
                set
                {
                    row = value;
                }
            }
    
            // 连接测试函数
            public void LinkLine(Point first,Point second)//点击的第一个点为first;点击的第二个点为second
            {
                // EventArgs:事件参数
                EventArgs e = new EventArgs();
                if (checkLink(first, second))   // 判断是否连接成功
                {
                    // 连线成功
                    this.LinkBoard[first.X, first.Y] = 0;//清除记忆中的first,以便下一次消除
                    this.LinkBoard[second.X, second.Y] = 0;//清除记忆中的second,以便下一次消除
                    if (this.SucClick != null)  // 给事件添加事件参数
                    {
                        SucClick(this, e); 
                    }
                }
                else
                {
                    // 连线失败
                    if (this.FailClick != null)//给事件添加事件参数
                    {
                        FailClick(this, e);
                    }
                }
    
    
            }
    
            // 是否赋
            public bool IsChecked(Point p)
            {
                bool flag = false;
                if (p.X != -1 && p.Y != -1)
                {
                    flag = true;
                }
                return flag;
            }
    
    
            // 判断是否连接成功——核心算法
            /*
                a,第一个点   b,第二个点
             */
            private bool checkLink(Point a,Point b)
            {
                if (!Point.Equals(a,b)) // 如果点击的不是同一位置
                {
                    // 如果点击的不是同一位置
                    if (this.LinkBoard[a.X, a.Y] == this.LinkBoard[b.X, b.Y])//如果两者为同一图案
                    {
                        // 判断连线能否成功
                        if (a.X == b.X && vertical(a, b))//垂直
                        {
                            return true;
                        }
                        if (a.Y == b.Y && horizon(a, b))//水平
                        {
                            return true;
                        }
                        if (oneCorner(a, b))//一个拐点
                        {
                            return true;
                        }
                        else//两个拐点
                        {
                            return twoCorner(a, b);
                        }
                    }
                    else
                    {
                        // 如果点击的不是同一个图案,直接返回false
                        return false;
                    }
                }
                else
                {
                    // 如果点击的是同一个位置的图案,直接返回false;
                    return false;
                }
    
            }
    
    
            // 垂直的连线情况
            private bool vertical(Point a, Point b)
            {
                int col_start = a.Y < b.Y ? a.Y : b.Y;    //获取a,b中较小的y值
                int col_end = a.Y < b.Y ? b.Y : a.Y;      //获取a,b中较大的y值
    
                //遍历a,b之间是否通路,如果一个不是就返回false;
                for (int i = col_start + 1; i < col_end; i++)
                {
                    if (this.LinkBoard[a.X, i] != 0)//0是空的状态(即没有按钮)
                    {
                        return false;
                    }
                }
                return true;
            }
    
            // 水平的连线情况
            private bool horizon(Point a, Point b)
            {
                int row_start = a.X < b.X ? a.X : b.X;//获取a,b中较小的x值
                int row_end = a.X < b.X ? b.X : a.X;//获取a,b中较大的x值
                for (int i = row_start + 1; i < row_end; i++)
                {
                    if (this.LinkBoard[i, a.Y] != 0)//0是空的状态(即没有按钮)
                    {
                        return false;//return是函数结束
                    }
                }
                return true;
            }
    
            // 一个拐角连线情况
            private bool oneCorner(Point a, Point b)
            {
                // 拐角点的x,y分别等于两点各个x,y
                Point c = new Point(b.X, a.Y);
                Point d = new Point(a.X, b.Y);
                // 判断C点是否有元素,有就继续执行下面判断条件,没有就看a与c,b与c之间是否能水平或者垂直连线                
                if (this.LinkBoard[c.X, c.Y] == 0)
                {
                    bool path1 = vertical(b, c) && horizon(a, c);
                    return path1;   //path1本身就是bool值
                }
    
                //判断D点是否有元素
                if (this.LinkBoard[d.X, d.Y] == 0)
                {
                    bool path2 = vertical(a, d) && horizon(b, d);
                    return path2;//path2本身就是bool值
                }
                
                // 能执行到这就说明前面判断不成功,不存在一个拐点的情况
                return false;
               
            }
    
            // 两个拐点
            private bool twoCorner(Point a, Point b)
            {
                // list容器:相当于一个Line类型的数组,存扫到的连通路径
                List<Line> ll = scan(a, b);//此时的直线已经判断成功并且拐点位置没有数字
                if (ll.Count == 0)  // 没扫到返回false,List容器里面的计数方法
                {
                    return false;
                }
    
                for (int i = 0; i < ll.Count; i++)
                {
                    Line tempLine = ll[i];  // 临时连线变量用于判断拐点与a,b的通路是否成立
                    if (tempLine.direct == 1)   // 两个拐点之间是水平直连
                    {// 判断分别两个拐点与a,b能否相连
                        if (horizon(a, tempLine.a) && horizon(b, tempLine.b))//判断a与a"之间是否有通路;判断b与b"之间是否有通路
                        {
                            return true;
                        }
                    }
                    else if (tempLine.direct == 0)  // 两个拐点之间是垂直直连
                    {// 判断分别两个拐点与a,b能否相连
                        if (vertical(a, tempLine.a) && vertical(b, tempLine.b))//判断a与a"之间是否有通路;判断b与b"之间是否有通路
                        {
                            return true;
                        }
                    }
                }
                return false;
            }
    
            // 扫描A与B之间的连接点组成的线(scan)
            //List为容器
            private List<Line> scan(Point a, Point b)
            {
                List<Line> linkList = new List<Line>();// 新建一个直线对象List容器,用来存成立的拐点之间的直线
    
                //检测a点上方是否能够水平直连
                for (int i = a.Y; i >= 0; i--)
                {
                    if (this.LinkBoard[a.X, i] == 0 && this.LinkBoard[b.X, i] == 0 && horizon(new Point(a.X, i), new Point(b.X, i)))
                    {
                        linkList.Add(new Line(new Point(a.X, i), new Point(b.X, i), 0));
                    }
                }
    
                //检测a点下方是否能够水平直连
                for (int i = a.Y; i < Col; i++)
                {
                    if (this.LinkBoard[a.X, i] == 0 && this.LinkBoard[b.X, i] == 0 && horizon(new Point(a.X, i), new Point(b.X, i)))
                    {
                        linkList.Add(new Line(new Point(a.X, i), new Point(b.X, i), 0));
                    }
                }
    
                //检测a点左侧是否能够垂直直连
                for (int j = a.X; j >= 0; j--)
                {
                    if (this.LinkBoard[j, a.Y] == 0 && this.LinkBoard[j, b.Y] == 0 && vertical(new Point(j, a.Y), new Point(j, b.Y)))
                    {
                        linkList.Add(new Line(new Point(j, a.Y), new Point(j, b.Y), 1));
                    }
                }
    
                //检测a点右侧是否能够垂直直连
                for (int j = a.X; j < Row; j++)
                {
                    if (this.LinkBoard[j, a.Y] == 0 && this.LinkBoard[j, b.Y] == 0 && vertical(new Point(j, a.Y), new Point(j, b.Y)))
                    {
                        linkList.Add(new Line(new Point(j, a.Y), new Point(j, b.Y), 1));
    
                    }
                }
    
                return linkList;
            }
        }
    
        // 两个拐点之间构成连线类
        public class Line
        {
            public Point a;
            public Point b;
            public int direct; //连线方向———  1:水平直连   0:垂直直连
            public Line(Point a, Point b, int direct)//Line是个构造函数
            {
                this.a = a;
                this.b = b;
                this.direct = direct;
            }
    
        }
    }
    
    
    

    窗体功能实现

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace Linkup
    {
        public partial class MainWindow : Form
        {
            private int curDelay = 0;                           // 当前剩余时间
            private LinkClass LinkObj = new LinkClass();        // 连连看功能类对象(变量),以后在这对象层面上操作
            private Point first = new Point(-1, -1);            // 第一次点击的位置
            private Point second = new Point(-1, -1);           // 第二次点击的位置
            private int score = 0;                              // 分数
            private bool isClosing = false;                     // 界面是否关闭
    
            public MainWindow()
            {
                InitializeComponent();
    
                //以下采用双缓冲方式,减少闪烁
                this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
                this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
                this.SetStyle(ControlStyles.UserPaint, true);
    
                // 给该对象添加点击事件
                this.LinkObj.SucClick += Link_SucClick;
                this.LinkObj.FailClick += Link_FailClick;
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                //在combox加载三种关卡
                comboBox1.Items.Add("8*8");
                comboBox1.Items.Add("10*10");
                comboBox1.Items.Add("12*12");
    
                comboBox2.Items.Add("图片");
                comboBox2.Items.Add("数字");
            }
    
            // 初始化连连看数组
            int hang = 0;   // 行列数
            private void InitLinkGameOne()
            {
                // 难度设置
                if (comboBox1.Text == ""|| comboBox2.Text=="")
                {
                    MessageBox.Show("请选择难度或者模式", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else
                {
                    // 选择的关卡难度文本
                    string Diffcult = comboBox1.Text;
                    //根据对应难度初始化数组并给n赋值
                    switch (Diffcult)
                    {
                        case "8*8":
                            hang = 8;
                            break;
                        case "10*10":
                            hang = 10;
                            break;
                        case "12*12":
                            hang = 12;
                            break; 
                    }
    
                    // 用于产生不重复随机数
                    long tick = DateTime.Now.Ticks;
                    Random r = new Random((int)(tick & 0xffffffffL) | (int)(tick >> 32));
                    // 棋盘周围空出一圈0
                    int[,] linkBoard = new int[hang + 2, hang + 2];
                    this.LinkObj.Row = hang + 2;
                    this.LinkObj.Col = hang + 2;
    
                    // 将内置元素进行随机数分配等操作
                    for (int row = 1; row < hang + 1; row++)
                    {
                        for (int col = 1; col < (hang + 1)/2+1; col++)
                        {
                            int rnd;
                            switch (hang)
                            {
                                case 8:
                                    rnd = r.Next(1, 1000) % 13 + 1;//13种图
                                    break;
                                case 10:
                                    rnd = r.Next(1, 1000) % 15 + 1;//15种图
                                    break;
                                case 12:
                                    rnd = r.Next(1, 1000) % 17 + 1;//17种图
                                    break;
                                default:
                                    rnd = 0;
                                    break;
                            }
                            // n种图
    
                            string img = string.Format("_1_{0}", rnd.ToString("00"));//给图片命名
    
                            linkBoard[row, col] = rnd;                      // 赋给每个位置随机数字
                            linkBoard[row, (hang + 1) / 2 + col] = rnd;     // 赋给相对位置随机数字
                        }
                    }
                    this.LinkObj.LinkBoard = linkBoard;//初始化棋盘
                    this.TableLp.Enabled = false;
    
                    // 控件变量等初始化
                    this.btnStart.Enabled = false;
                    //设置时间以及按钮
                    this.curDelay = pbTimeDelay.Maximum;//让剩余时间为计时条的最大值
                    this.pbTimeDelay.Value = this.curDelay;//给进度条赋值
                    this.lblTimeDelay.Text = this.curDelay.ToString();//显示剩余时间
                    this.TableLp.Enabled = true;
                    score = 400;//计分
    
                    // 启动用多线程计时器函数
                    timeDelay = new Thread(timeDelay_Tick);
                    //ma.Set();
                    timeDelay.Start();  //启动定时器线程
                }
    
            }
    
            // 获取图片名
            internal static Bitmap GetImageByName(string name)
            {
                // 全局资源搜索
                object obj = global::Linkup.Properties.Resources.ResourceManager.GetObject(name, global::Linkup.Properties.Resources.Culture);
                return ((Bitmap)(obj));
            }
    
            // 打乱顺序函数
            private void Reset()
            {
                //设置tableLayoutPanel的列数和行数
                this.TableLp.ColumnCount = hang + 2;
                this.TableLp.RowCount = hang + 2;
                // 清除残余属性
                this.TableLp.ColumnStyles.Clear();
                this.TableLp.RowStyles.Clear();
                this.TableLp.Controls.Clear();
    
                for (int i = 0; i < hang + 2; i++)
                {
                    //设置等宽等高  边缘2,里面内容10
                    if (i == 0 || i == hang + 1)
                    {
                        this.TableLp.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 2));
                        this.TableLp.RowStyles.Add(new RowStyle(SizeType.Percent, 2));
                    }
                    else
                    {
                        this.TableLp.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 10));
                        this.TableLp.RowStyles.Add(new RowStyle(SizeType.Percent, 10));
                    }
                }
                this.TableLp.Padding = new Padding(1);//约束控件内边距
                this.TableLp.CellBorderStyle = TableLayoutPanelCellBorderStyle.None;    // 不显示边框线
                long tick = DateTime.Now.Ticks;
                // 用于产生不重复随机数
                Random r = new Random((int)(tick & 0xffffffffL) | (int)(tick >> 32));
    
                int[,] linkBoard = new int[hang + 2, hang + 2];
    
                linkBoard = this.LinkObj.LinkBoard;//将这个对象的数组值赋给这个变量,便于操作
                                                   // 将内置元素进行随机贴图等操作
                int rnd, rnd2;
                // 打乱二维数组顺序
                for (int row = 1; row < hang + 1; row++)
                {
                    for (int col = 1; col < hang + 1; col++)
                    {
                        // 产生随机数
                        rnd = r.Next(1, 1000) % hang + 1;
                        rnd2 = r.Next(1, 1000) % hang + 1;
    
                        int temp = linkBoard[rnd, rnd2];
                        linkBoard[rnd, rnd2] = linkBoard[row, col];
                        linkBoard[row, col] = temp;
    
                    }
                }
                this.LinkObj.LinkBoard = linkBoard;//初始化棋盘
    
                for (int row = 1; row < hang + 1; row++)
                {
                    for (int col = 1; col < hang + 1; col++)
                    {
                        if (linkBoard[row, col] != 0)
                        {
                            if (comboBox2.Text=="图片")
                            {
                                string img = string.Format("_1_{0}", linkBoard[row, col].ToString("00"));//给图片命名
                                Button btnLinker = new Button() // 设置每个小按钮的相关属性
                                {
                                    BackgroundImage = GetImageByName(img),//给按钮填充背景图片
                                                                          //Text = rnd.ToString(),
                                    BackgroundImageLayout = ImageLayout.Stretch,//背景图片拉伸
                                    Tag = img,//标签
                                    Name = string.Format("{0},{1}", row, col),//将按钮的名字分成为x,y
                                    Dock = DockStyle.Fill,//调整控件的层次,填充
                                    Margin = new Padding(1),//调整外边距
                                };
                                btnLinker.Click += BtnLinker_Click; // 让每个按钮都拥有点击事件
                                this.TableLp.Controls.Add(btnLinker, col, row);
                            }
                            else
                            {
                                string img = string.Format("_1_{0}", linkBoard[row, col].ToString("00"));//给图片命名
                                Button btnLinker = new Button() // 设置每个小按钮的相关属性
                                {
                                    Text = linkBoard[row, col].ToString(),
                                    Tag = img,//标签
                                    Name = string.Format("{0},{1}", row, col),//将按钮的名字分成为x,y
                                    Dock = DockStyle.Fill,//调整控件的层次,填充
                                    Margin = new Padding(1),//调整外边距
                                };
                                btnLinker.Click += BtnLinker_Click; // 让每个按钮都拥有点击事件
                                this.TableLp.Controls.Add(btnLinker, col, row);
                            }
                            
                        }
                    }
                }
    
                score -= 400;
                lableScore.Text = "分数:" + score.ToString();
            }
    
            // 判断成功
            private void Judge()
            {
                int count=0;
                // 将内置元素进行随机数分配等操作
                for (int row = 1; row < hang + 1; row++)
                {
                    for (int col = 1; col < hang + 1; col++)
                    {
                        if (this.LinkObj.LinkBoard[row,col]==0)
                        {
                            count++;
                        }
                    }
                }
                if (count==hang*hang)
                {
                    MessageBox.Show("拼完了,你可真厉害!","提示",MessageBoxButtons.OK,MessageBoxIcon.Asterisk);
                    this.TableLp.Enabled = false;
                    btnStart.Enabled = true;
    
                    timetemp = this.curDelay;
                    this.curDelay = 0;
                    lblTimeDelay.Text = timetemp.ToString();
                }
            }
    
            // 事件
            // 每个小图片按钮单击事件
            private void BtnLinker_Click(object sender, EventArgs e)
            {
                Button btnLinker = (Button)sender;                  // 事件参数
                btnLinker.FlatStyle = FlatStyle.Flat;               // 决定按钮的外观
                btnLinker.FlatAppearance.BorderColor = Color.Red;   // 按钮外边框颜色
                btnLinker.FlatAppearance.BorderSize = 2;            // 按钮外边框的大小
                string[] loc = btnLinker.Name.Split(',');           // 将按钮的名字分成x,y
                if (!LinkObj.IsChecked(first))                      // 第一次点给第一个点赋值
                {
                    first = new Point(int.Parse(loc[0]), int.Parse(loc[1]));
                }
                else// 第二次点给第二个参数赋值
                {
                    second = new Point(int.Parse(loc[0]), int.Parse(loc[1]));
                    // 如果就第二次点击,则进行判断
                    LinkObj.LinkLine(first, second);
                }
            }
    
            // 计时器线程
            Thread timeDelay;       // 线程变量
            int timetemp = 0;       // 计时器中间变量
    
            // 开始按钮事件
            private void btnStart_Click(object sender, EventArgs e)
            {
                if (btnStart.Text=="开始游戏")
                {
                    // 先初始化连连看板
                    InitLinkGameOne();
                    // 打乱顺序
                    Reset();
                }
                else if (btnStart.Text == "继续游戏")
                {
                    //ma.Set();//信号打开,不阻塞当前线程
                    btnStart.Text = "开始游戏";
                    btnStart.Enabled = false;
                    this.TableLp.Enabled = true;
                    this.curDelay= timetemp;// 将中间变量赋值给新的当前时间
                    lblTimeDelay.Text = this.curDelay.ToString();
                    timeDelay = new Thread(new ThreadStart(this.timeDelay_Tick));//新的计时器
                    timeDelay.Start();
                }
                
            }
    
            // 结束按钮
            private void btnStop_Click(object sender, EventArgs e)
            {
                this.curDelay = 0;
                Thread.Sleep(100);
                btnStart.Text = "开始游戏";
            }
    
            // 重新排列
            private void btnReset_Click(object sender, EventArgs e)
            {
                // 扣分
                if (score<= -400)
                {
                    MessageBox.Show("你已经负债累累,不能再扣分了!","提示",MessageBoxButtons.OK,MessageBoxIcon.Stop);
                }
                else
                {
                    Reset();
                }
            }
    
            // 暂停按钮
            private void btnPause_Click(object sender, EventArgs e)
            {
                this.TableLp.Enabled = false;
      
                btnStart.Enabled = true;
                btnStart.Text = "继续游戏";
    
                timetemp = this.curDelay;
                this.curDelay = 0;
                lblTimeDelay.Text = timetemp.ToString();
            }
    
            // 定时器事件:时间剩余
            void timeDelay_Tick()
            {
                //ma.WaitOne(); // 根据是否收到信号判断是否阻塞当前线程
                while (this.curDelay > 0 )   // 当前时间大于零
                {
                    if (!isClosing)
                    {
                        this.curDelay--;
                        this.pbTimeDelay.Value = this.curDelay;
                        this.lblTimeDelay.Text = this.curDelay.ToString();
                        
                    }
                    Thread.Sleep(1000);
                }
                if (!isClosing)
                {
                  
                    this.btnStart.Enabled = true;
                    this.TableLp.Enabled = false;
                  
                }
            }
    
            // 连接成功事件
            private void Link_SucClick(object sender, EventArgs e)
            {
                //连接成功,则删除,重新初始化
                this.TableLp.GetControlFromPosition(this.first.Y, this.first.X).Visible = false;//第一块消失
                this.TableLp.GetControlFromPosition(this.second.Y, this.second.X).Visible = false;//第二块消失
                this.first = new Point(-1, -1);//初始化第一块的位置
                this.second = new Point(-1, -1);//初始化第一块的位置
                this.score += 100;  
                this.lableScore.Text = string.Format("分数:{0}", score);
    
                // 消除成功加时,保证进度条不会消失
                if (curDelay <= 98)
                {
                    curDelay += 2;
                }
                else if (curDelay == 99)
                {
                    curDelay += 1;
                }
                // 判断是否连完
                Judge();
            }
    
            // 连接失败事件
            private void Link_FailClick(object sender, EventArgs e)
            {
                //连接失败,则第一个按钮取消选择
                Control c1 = this.TableLp.GetControlFromPosition(this.first.Y, this.first.X);
                ((Button)c1).FlatAppearance.BorderSize = 0;//第一块的外边框消失
                this.first = new Point(this.second.X, this.second.Y);
                this.second = new Point(-1, -1);
            }
    
            // 界面关闭事件
            private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
            {
                this.isClosing = true;
                this.btnStop_Click(null, null);
                // 界面关闭,终止线程
                if (this.timeDelay != null && this.timeDelay.ThreadState == ThreadState.Running)
                {
                    this.timeDelay.Abort();
                }
            }
        }
    }
    
    
    展开全文
  • C# WINFORM小游戏

    2013-06-07 14:58:59
    本程序是C# WINFORM做的小游戏 此游戏为棋类,是我小时候在地上画着玩的游戏。 主要通过(Graphics)来实现棋子的移动,用位数组保存棋子的位置。 游戏有双人对战和人机对战模式,人机对战模式有点意思。
  • 提供了益智类游戏、控制类游戏、棋牌类游戏以及其它类游戏C#的开发源代码,是C#初学者甚至更高级专业人员的练手必备之作。
  • C#窗体加法程序

    2018-06-15 14:37:03
    是一个C#窗体加法程序。原代码都有,本身就是初学者,和大家共同努力。
  • 小游戏 C# 多窗口

    2013-11-09 14:29:11
    看看 对初学者有帮助 简单的使用的C#窗体的使用
  • C#开发的2048小游戏

    2015-11-27 18:46:31
    C#开发的2048小游戏,新手很有练手的帮助。
  • c#窗体猜数字小游戏(初级版)

    万次阅读 多人点赞 2018-06-10 16:29:48
    小游戏的简单实现,这种小游戏非常适合初学者,能够提升对编程的兴趣。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System....

    小游戏的简单实现,这种小游戏非常适合初学者,能够提升对编程的兴趣。

    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 WindowsFormsApp1
    {
        public partial class Form1 : Form
        {
            int n;//全局变量
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                Random a = new Random();                //用随机数赋值
                n = a.Next(1, 101);                     //答案的值
                int x = 10;
                int y = 60;
                for(int i=0;i<100;i++)                  //创建100个按钮
                {
                    label1.Visible = false;
                    Button bt = new Button();
                    bt.BackColor = System.Drawing.Color.Blue;//改变按钮的背景色
                    bt.Text = (i + 1).ToString();           //给按钮的text属性赋值
                    bt.Name = (i + 1).ToString();           //给按钮的名字赋值
                    bt.Width = 40;                          //设置按钮的宽和高
                    bt.Height = 40;
                    bt.Location = new Point(x, y);          //设置按钮的位置
                    bt.Click += new EventHandler(bt_Click); //给按钮点击添加事件
                    x += 36;
                    if((i+1)%10==0)                         //每十个换一行
                    {
                        x = 10;
                        y += 36;
                    }
                    Controls.Add(bt);                   //将按钮放入窗体控件集合中
                } 
            }
             private void bt_Click(object sender,EventArgs e)
            {
                Button but = (Button)sender;
                int t = int.Parse(but.Text);            //把按钮的Text的值转换为整型
                    if(t==n)
                    {
                    label1.Text = "恭喜你答对了!";
                    label1.Visible = true;
                    but.BackColor = System.Drawing.Color.Red;
                    }
                    else if (t<n)
                        but.Text = "小";
                    else
                        but.Text = "大";
            }
            private void button2_Click(object sender, EventArgs e)
            {
                Application.Exit();
            }
        }
    }
    
    

    还有很多功能没有实现,希望大家多提意见!

    界面设计(比较丑...):

    展开全文
  • C# =2048=小游戏实现

    2014-10-28 19:42:21
    2048是比较流行的一款数字游戏 2048首先在github上发布,原作者是Gabriele Cirulli。它是基于《1024》和《小3传奇》的玩法开发而成的新型数字游戏。 随后2048便出现各种版本,走各大平台。...2048小游戏实现 原创@Sky
  • c# Windows窗体应用程序设计综合实例(一)匹配游戏设计 ...今天来分享一个综合实例,设计一个匹配小游戏。 本次实例步骤较多,切勿搞混。 步骤一 新建项目 1.目的:创建项目并设计布局表。该表有助于将图标...

    c# Windows窗体应用程序设计综合实例(一)匹配游戏设计

    上次的计时器运行效果图如下:
    效果图
    = ------------------------------------------------------------------------------

    今天来分享一个综合实例,设计一个匹配小游戏。
    本次实例步骤较多,切勿搞混。

    步骤一 新建项目

    1.目的:创建项目并设计布局表。该表有助于将图标对齐到有序的 4x4 网格。需设置若干属性,以改善游戏板的外观。
    2.项目名称窗体text属性改为“匹配游戏”(其他名字也行),在size属性中将窗体大小设置为550*550。
    3. 添加一个TableLayoutPanel 控件,将BackColor属性设置为CornflowerBlue。(其他颜色也行,有些属性的更改可以直接粘贴文本进去设置。);将Dock属性设置为Fill(即覆盖整个窗体),将CellBorderStyle属性设置为Inset。
    4. 选择 TableLayoutPanel 右上角的三角形按钮,以显示任务菜单。
    在任务菜单上,选择“添加行”两次以再添加两行,然后选择“添加列”两次以再添加两列 。
    三角形按钮
    图一 三角形按钮
    菜单
    图二 菜单栏

    打开菜单,选择“编辑行和列”,打开“列和行样式”窗口 。将列和行的值都设置为25%(注意设置时,都要保证右侧的设置内容为百分比,现实前面的下拉框可以切换行和列。)
    属性
    图三 属性设置

    设置好了以后,点击确定,效果应该为是一个 4x4 网格,包含十六个大小相等的方块单元格。

    5.再向左上角单元格添加一个Label 控件,将BackColor属性设置为CornflowerBlue ,将AutoSize属性设置为False。,将Dock属性设置为Fill ;TextAlign属性设置为MiddleCenter” 。图标显示在单元格中间;选中Font属性, 此时应显示一个省略号 (… ) 按钮。选择省略号按钮,并将“Font”值设置为“Webdings”,将“Font Style”设置为“Bold”,并将“Size”设置为“48” ;text属性设置为“c”

    6.选择 Label 控件并将其复制到 TableLayoutPanel 中的下一单元格,保证每个单元格都被复制粘贴完成。注意每个单元格要先选中再粘贴(用快捷键ctrl+c、ctrl+v即可)

    效果图:
    设置效果

    步骤二 添加代码

    1.添加图标列表

    在本步骤中,要为游戏创建一组匹配的符号。 每个符号将添加到窗体上 TableLayoutPanel 中的两个随机单元格。
    查看代码的方法:在“解决方案资源管理器” 中,选择“Form1.cs” ,然后在菜单栏上选择“查看” ,选择 “代码” 。
    本次需要添加的代码如下(给Form窗口添加代码):

    public partial class Form1 : Form
    {
           Random random = new Random();
        List<string> icons = new List<string>() 
        { 
            "!", "!", "N", "N", ",", ",", "k", "k",
            "b", "b", "v", "v", "w", "w", "z", "z"
    };
    }
    
    

    2.分配随机图标

    以下代码添加给label控件:

    private void AssignIconsToSquares()
    {   
        foreach (Control control in tableLayoutPanel1.Controls)
        {
            Label iconLabel = control as Label;
            if (iconLabel != null)
            {
                int randomNumber = random.Next(icons.Count);
                iconLabel.Text = icons[randomNumber];
                iconLabel.ForeColor = iconLabel.BackColor;
                icons.RemoveAt(randomNumber);
            }
        }
    } 
    
    
    

    若要用图标填充游戏板,你需要在程序启动时调用 AssignIconsToSquares() 方法。在 Form1 构造函数中 直接添加一条语句。

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

    效果:保存并运行程序。它应该显示一个窗体,其中每个标签都分配了随机图标。

    3.添加事件处理程序

    匹配游戏的运行原理:当玩家选择一个带有隐藏图标的方块时,程序会通过将图标颜色更改为黑色来向玩家显示该图标。然后玩家选择另一个隐藏的图标。如果图标互相匹配,则它们保持可见。如果不匹配,则两个图标都会再次隐藏。

    1.在Windows 窗体设计器”中打开窗体。在“解决方案资源管理器” 中,选择“Form1.cs” 在菜单栏上,依次选择“视图” > “设计器” 。选择第一个标签控件以选中它。然后,按住 Ctrl 键选择其他每个标签,将它们选中。确保选中每个标签。

    2.选择“属性” 窗口工具栏上的“事件” 按钮,在“属性” 窗口中查看“事件” 页面。向下滚动到“Click” 事件,在框中输入“label_Click” ,最后回车一下。
    添加的代码如下:

    private void label_Click(object sender, EventArgs e)
    {
        Label clickedLabel = sender as Label;
    
        if (clickedLabel != null)
        {
            
            if (clickedLabel.ForeColor == Color.Black)
                return;
    
            clickedLabel.ForeColor = Color.Black;
        }
     }
    
    

    效果:最后运行程序看到一个背景为蓝色的空窗体。在窗体中选择任意单元格,其中一个图标应变为可见。继续在窗体中选择不同位置。当选择图标时,可以显示。

    4.添加标签引用

    使用下面的代码向窗体(Form1)中添加标签引用:

    private void label_Click(object sender, EventArgs e)
    {
        Label clickedLabel = sender as Label;
    
        if (clickedLabel != null)
        {
            // If the clicked label is black, the player clicked
            // an icon that's already been revealed --
            // ignore the click
            if (clickedLabel.ForeColor == Color.Black)
                return;
    
            // If firstClicked is null, this is the first icon 
            // in the pair that the player clicked,
            // so set firstClicked to the label that the player 
            // clicked, change its color to black, and return
            if (firstClicked == null)
            {
                firstClicked = clickedLabel;
                firstClicked.ForeColor = Color.Black;
    
                return;
            }
        }
    }
    
    

    效果 :保存并运行程序,选择其中一个标签控件,它的图标将显示。
    效果图

    5.添加计时器

    关于计时器,在上次写的《c# Windows窗体应用程序(四)》有一个关于Timer控件的用法。

    在插入Timer控件以后,将计时器的Interval 属性设置为 750。双击该计时器添加如下代码:

    private void timer1_Tick(object sender, EventArgs e)
    {
        timer1.Stop();
    
          firstClicked.ForeColor = firstClicked.BackColor;
        secondClicked.ForeColor = secondClicked.BackColor;
        firstClicked = null;
        secondClicked = null;
    }
    

    若要查看正在使用的新计时器,请转至代码编辑器,将以下代码添加到 label_Click() 事件处理程序方法的顶部和底部。(将两个 if 语句添加到顶部,将三个语句添加到底部;该方法的其余部分保持相同。)

    private void label_Click(object sender, EventArgs e)
    {
        if (timer1.Enabled == true)
            return;
    
        Label clickedLabel = sender as Label;
        if  (secondClicked !=  null)
            return;
    
        if (clickedLabel != null)
        {
            if (clickedLabel.ForeColor == Color.Black)
                return;
            if (firstClicked == null)
            {
                firstClicked = clickedLabel;
                firstClicked.ForeColor = Color.Black;
                return;
            }
    
      
            secondClicked = clickedLabel;
            secondClicked.ForeColor = Color.Black;
    
           
            timer1.Start();
        }
    }
    
    
    

    效果:保存并运行程序。选择一个图标,它将显示出来。选择另一个图标。 它会短暂显示,然后两个图标都消失。

    6.保持对可见

    将下面的 if 语句添加到 label_Click() 事件处理程序方法中,紧靠启动计时器的语句上方代码的结尾处。

    if (firstClicked.Text == secondClicked.Text)
            {
                firstClicked = null;
                secondClicked = null;
                return;
            }
            
            timer1.Start();   
    
    

    效果:保存并运行程序,然后开始选择窗体上的图标。如果选择的是不匹配的对,则将触发计时器的事件,两个图标都会消失。

    7.添加验证玩家是否获胜的方法

    1.在代码底部,CheckForWinner() 事件处理程序下方添加一个 timer1_Tick() 方法,如以下代码所示。

    private void CheckForWinner()
    {
           foreach (Control control in tableLayoutPanel1.Controls)
        {
            Label iconLabel = control as Label;
    
            if (iconLabel != null) 
            {
                if (iconLabel.ForeColor == iconLabel.BackColor)
                    return;
            }
        }    
           MessageBox.Show("You matched all the icons!", "Congratulations");
        Close();
    }
    
    

    2.让标签的 Click 事件处理程序调用新的 CheckForWinner() 方法。 请确保程序在显示玩家选择的第二个图标后立即检查是否有赢家。 查找设置第二个选中图标颜色的行,将以下代码复制到CheckForWinner() 方法中。

    secondClicked = clickedLabel;
    secondClicked.ForeColor = Color.Black;
    CheckForWinner();
    if (firstClicked.Text == secondClicked.Text)
    {
        firstClicked = null;
        secondClicked = null;
        return;
    }
    
    

    效果:保存并运行程序。 玩游戏并匹配所有图标。

    3.运行结果

    效果图如下:
    结果
    有什么好的建议或者问题可以在下方留言。

    展开全文
  • c#高级编程,使用其窗体实现的一款小游戏,可做课程设计、学习参考。代码结构清晰,易于学习。如果需要可以下载
  • 值得一看的小游戏,比较有意思的C#小程序,源码通俗易懂,适合初学者小白,是个压缩包,适合展示给授课老师看。
  • 写了一个基于C#窗体应用的抽奖程序,里面设置了一个号码必然中二等奖,一个号码必然中三等奖,三个号码必然不中一等奖,代码中都有注释,可修改
  • c#语言做的简单的扫雷小游戏,内容简单,代码简易,逻辑清晰,可供c#初学者制作参考,相信对初学者有所帮助。
  • =============== 简单的C#小游戏 ,适合初学者参考 喜欢的下载吧!
  • C#windows窗体猜数字小游戏

    热门讨论 2011-07-05 11:52:29
    windows窗体开发的猜数字小游戏,休闲,益智。
  • 一个简单的五子棋游戏,具有判定输赢、悔棋、重新开始等功能。简单的demo,可以自己完善,欢迎提BUG! (¦3[▓▓]
  • 主要为大家详细介绍了C#实现简单打字小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • C#winform 小游戏笔记

    千次阅读 2018-05-04 16:17:15
    我做了一个C#的winform程序的小游戏,游戏是这样的:界面上有若干小点和一个小人,所有小点每三秒钟随机变化一次位置,如果小点碰到小人就算游戏结束了,在这三秒钟内你也可以用鼠标拖动小人来选择一个你觉得可能...

    我做了一个C#的winform程序的小游戏,游戏是这样的:界面上有若干小点和一个小人,所有小点每三秒钟随机变化一次位置,如果小点碰到小人就算游戏结束了,在这三秒钟内你也可以用鼠标拖动小人来选择一个你觉得可能不会被碰撞的位置。其实这个游戏坚持的时间长短完全是靠运气,毕竟小点位置是随机的,并不是有规律可言的。下面记录我在做这个小游戏过程遇到的问题和解决的方式,如果有对这个游戏感兴趣的朋友私我要代码,其实很简单,会了下面我说的这几点知识你一定也可以做出来。

    1、线程间操作无效: 从不是创建控件“xxx”的线程访问它。

    先来看一段程序:

    public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            public void Setlocation(PictureBox p)
            {
                p.Left = 200;
                p.Top = 200;
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                PictureBox p = new PictureBox();
                p.Image = Image.FromFile("bullet_blue.png");
                p.Left = 50;
                p.Top = 50;
                this.Controls.Add(p);
                Thread t1=new Thread(()=>Setlocation(p));
                t1.Start();
            }
        }
    
    通过一个按钮来添加一个picturebox控件,然后通过一个新的线程来修改该控件的位置,运行程序就会提示“线程间操作无效: 从不是创建控件“xxx”的线程访问它”。因为你通过一个不是创建该控件的线程来修改此控件的状态了,这是在.net2之后不允许的。因为多线程同时操作某一控件的状态可能导致该控件处于不一致的状态。

    解决办法有两个:

     在窗体的构造函数中添加:Control.CheckForIllegalCrossThreadCalls = false ;
    public Form1()
            {
                InitializeComponent();
                Control.CheckForIllegalCrossThreadCalls = false;
            }

    这样可以使系统不去检查你是否跨线程访问控件了,但是这并不是标准的解决方法,因为系统之所以会去检查是因为怕你在后面的程序中出错,比如你两个线程同时修改同一个控件的状态;而你不让系统去检查,那么当你后续程序运行真的有多线程同时操作某一控件的状态的情况时,会出现更大的错误。

    通过委托来实现:

    public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
                Control.CheckForIllegalCrossThreadCalls = false;
            }
    
            public delegate void SetDelegate(PictureBox p);
            public void Setlocation(PictureBox p)
            {
                
                if(p.InvokeRequired)
                {
                    SetDelegate s = new SetDelegate(Setlocation);
                    this.BeginInvoke(s, new object[] { p });
                }
                else
                {
                    p.Left = 200;
                    p.Top = 200;
                }
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                PictureBox p = new PictureBox();
                p.Image = Image.FromFile("bullet_blue.png");
                p.Left = 50;
                p.Top = 50;
                this.Controls.Add(p);
                Thread t1=new Thread(()=>Setlocation(p));
                t1.Start();
            }
        }

    给修改控件的函数setlocation写一个委托,通过判断InvokeRequired可以知道是否需要用委托来调用当前控件的一些方法,如果需要那么把这个方法和参数封装之后传送给控件所在线程去执行。

    2、定时器Timer类:

    网上使用方式很多,我这里主要介绍一种定时器绑定的事件带有参数的(非系统参数):

    public partial class initialize : Form
    {
        System.Timers.Timer aTimer = new System.Timers.Timer();//定时器对象
        public void settimer(PictureBox[] arr)
            {
                //aTimer.Elapsed += new ElapsedEventHandler(Movement);
                aTimer.Elapsed += new ElapsedEventHandler((s,e)=>Movement(s,e,arr));//传递参数arr
                aTimer.Interval = 2000;//执行事件的间隔,单位毫秒
                aTimer.AutoReset = true;//执行一次变false,一直执行true
                //是否执行System.Timers.Timer.Elapsed事件 
                aTimer.Enabled = true;
            }
        public void Movement(object source, System.Timers.ElapsedEventArgs e,PictureBox[] arr)//Movement函数参数列表
    }

    想关闭定时器的方法为:aTimer.Stop();

    系统自定义的ElapsedEventHandler为:

    public delegate void ElapsedEventHandler(
                object sender,
                ElapsedEventArgs e
            )

    可以参考这篇文章 C#.NET 定时器类及使用方法写得非常好,C#程序中三种定时器类的介绍都有,还有具体用法。

    3、用鼠标拖动控件:

    以拖动button为例,当鼠标按下button时记录鼠标与button的实际坐标,并用一个bool变量记录当前鼠标状态为mousedown;
    然后在鼠标移动事件中拿当前鼠标实际坐标,与mouseDown时记录的坐标的偏差来加上button原坐标,便是现在的坐标;在鼠标抬起时,清除状态。

            //是否在拖拽
            bool isDrag = false;
            //鼠标相对于button控件左上角的坐标
            Point contextbtnPoint = Point.Empty;
            //将被拖动的控件 
            private Control control;
            private void button1_MouseDown(object sender, MouseEventArgs e)
            {
                isDrag = true;
                control = button1;
                if (e.Button == MouseButtons.Left)
                {
                    contextbtnPoint = button1.PointToClient(Control.MousePosition);  //鼠标相对于button左上角的坐标
                }
            }
    
    
            private void button1_MouseMove(object sender, MouseEventArgs e)
            {
                if (isDrag)
                {
                    Point formPoint = this.PointToClient(Control.MousePosition);//鼠标相对于窗体左上角的坐标
                    int x = formPoint.X - contextbtnPoint.X;
                    int y = formPoint.Y - contextbtnPoint.Y;
                    control.Location = new Point(x, y);
                }
            }
    
            private void button1_MouseUp(object sender, MouseEventArgs e)
            {
                if (isDrag)
                {
                    isDrag = false;
                }
            }
    关于获取鼠标坐标的方法有下面三种:
    Point screenPoint = Control.MousePosition;//鼠标相对于屏幕左上角的坐标
    Point formPoint = this.PointToClient(Control.MousePosition);//鼠标相对于窗体左上角的坐标
    Point contextMenuPoint = contextMenuStrip1.PointToClient(Control.MousePosition); //鼠标相对于contextMenuStrip1左上角的坐标

    4、长方形是否相交问题:

    
    
     Rectangle rectangle1 = new Rectangle(50, 50, 200, 100);//参数分别为长方形的横坐标,纵坐标,宽度,高度
     Rectangle rectangle2 = new Rectangle(70, 20, 100, 200);
    
    
    if (rectangle1.IntersectsWith(rectangle2))
       //相交
    else
       //不相交
    


    展开全文
  • ☆ 资料介绍:☆ 游戏名称:经典小游戏 - 连连看; 开发环境:Visual Studio 2010 SP1;
  • C# 窗体扫雷程序

    2018-02-28 10:58:09
    winform 扫雷游戏,想要学习绘图或做小游戏的朋友可以下载来参考看看,有代码注释,如有疑问,欢迎询问
  • 使用winform制作的猜数字小游戏窗体,调试阶段,底部会显示正确答案,主要练习了随机数的使用
  • c#2048小游戏

    2018-10-31 12:35:23
    c#工程文件压缩包,源码、可运行程序都有,个人原创,游戏设置和游戏作弊功能没有写,有需要的可删除或自行编写,难度不大。按上下左右键操作。欢迎一起交流讨论
  • C#基于窗体实现的贪吃蛇(原创简单版,适合新手学习)
  • 基于C#实现的RPG角色扮演类小游戏
  • 刚接触C#没多久,尝试着写了一个抽奖的程序(+—+)。 *功能简介:*它可以在规定时间内随机选取要抽取对象中的一个,可以连续抽取(重复也行,不重复也可以)。这个看自己要哪种效果啦。对了这个程序写得不是很...
  • 在Micsoft visual studio2010环境下,用GDI+图像编程实现了简单的贪吃蛇功能,可以计算得分,随着游戏的进行,蛇的速度回越来越快,适合初学者参考使用
  • 零基础学C#编程—C#从小白到大咖

    万人学习 2019-06-04 13:18:37
    本课程从初学者角度出发,提供了C#从入门到成为程序开发高手所需要掌握的各方面知识和技术。 【课程特点】 1 由浅入深,编排合理; 2 视频讲解,精彩详尽; 3 丰富实例,轻松易学; 4 每章总结配有难点解析文档。 15...
  • C#写的一个小游戏

    2018-09-11 21:17:54
    一个用C#写的简易游戏,挂机各种功能一个用C#写的简易游戏,挂机各种功能

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,032
精华内容 1,612
关键字:

c#窗体小游戏

c# 订阅