zoukankan      html  css  js  c++  java
  • 扫雷游戏制作过程(C#描述):第三节、雷区绘制

    前言

    这里给出教程原文地址
    该项目已经放在github上托管。

    绘制雷区

    这一节我们主要涉及界面中雷区的绘制。绘制雷区需要三个变量来保存雷区行数、列数、以及地雷的数量。而且我们希望能够自动获取上次游戏的设置(初级,中级,高级,雷区的三个变量值不同)。因此这三个变量的值需要保存下来。我们在这里采用Setting文件来保存这些数据。工程创建的时候,系统会自动生成一个Setting文件。因此我们不需要自己创建,只需要使用原有的Setting文件即可。在右方解决方案资源管理器面板中展开Properties,右击Settings.settings,选择打开即可。

    按照下图对它进行设置,设置完成后按Ctrl + S进行保存。

    我们需要一个paint事件来进行绘制雷区,选中主窗口,在左边的属性面板中,单击事件按钮,并找到Paint事件,双击该条目,系统会自动创建一个事件,我们将在这里绘制雷区。如下图所示:

    绘制雷区时我们需要考虑以下几点:

    • 我们需要定义三个基本变量行数、列数、地雷的数量,并初始化。
    • 我们需要一个二重的循环来绘制雷区,我们假定雷区为32×32的小方块,并且四周有一圈宽度为1的留白,用于与其它雷区区别,这样,每个雷区的实际大小为34×34。
    • 整个雷区距离上下左右边缘都应该有个间距,所以需要一个偏移量。
    • 我们需要Form窗口自动调整大小,来适应这个雷区的绘制。
    private int Sweep_width;      //雷区中的列数
    private int Sweep_high;       //雷区中的行数
    private int Sweep_num;        //雷区中的地雷数量
    private int nOffsetX;         //雷区绘制时的偏移量,距离窗口左边缘的距离
    private int nOffsetY;         //雷区绘制时的偏移量,距离窗口上边缘的距离
    
    public Form_Main()
    {
          //初始化操作
          InitializeComponent();
          nOffsetX = 6;                                   //初始化偏移量
          nOffsetY = 6 + UpMenu.Height;                   //初始化偏移量,UpMenu是菜单栏控件
          Sweep_num = Properties.Settings.Default.Sweep_num;      //初始化,从Settings读取地雷数量
          Sweep_high = Properties.Settings.Default.Sweep_high;    //初始化,从Settings读取行数
          Sweep_width = Properties.Settings.Default.Sweep_width;  //初始化,从Settings读取列数
          UpdateSize(Sweep_width,Sweep_high);                     //自适应窗口大小
    }
    private void Form_Main_Paint(object sender, PaintEventArgs e)
    {
          Graphics g = e.Graphics;                                //绘制句柄
          for (int i = 0; i < Sweep_width; i++)
          {
               for (int j = 0; j < Sweep_high; j++)
               {
                    g.FillRectangle(Brushes.Violet, new Rectangle(nOffsetX + 34 * i, nOffsetY + 34 * j + 1, 32, 32)); //绘制每一个小方块
               }
          }
    }
    private void UpdateSize(int width_temp, int high_temp)
    {
          //根据雷区行数,列数,来设置整个Form窗口的大小
          int width_update = width_temp * 34 + 12;     
          int high_update = high_temp * 34 + 12;
          Width = width_update + (this.Size.Width - this.ClientSize.Width);
          Height = high_update + UpMenu.Height + TableLayoutPanel_Main.Height + (this.Size.Height - this.ClientSize.Height);
    }                
    

    最后按Ctrl + F5编译运行,得到最终结果:

    下面我们为了使鼠标移动到雷区上时,能有高亮的效果做一些修改。首先我们需要能找到鼠标当前所在的位置,因此我们需要MouseMove事件,找到MouseMove事件,双击该条目:

    我们需要定义新的变量Point来方便我们标记鼠标的位置,鼠标的每次移动并不是都要重新刷新界面,当鼠标从某个32x32的小雷区移动到另一个32x32的小雷区时,我们就需要更改高亮的位置。我们需要采集的是当前鼠标处于哪一个32x32的小雷区,代码如下:
    应增加变量:

     private Point mousefocus_new; //鼠标新位置
     private Point mousefocus_old; //鼠标旧位置
    

    应对这两个变量初始化,在public Form_Sweeper(){ }中增加如下代码:

    mousefocus_new.X = mousefocus_old.X = 0;            //初始化鼠标位置
    mousefocus_new.Y = mousefocus_old.Y = 0;
    

    记录鼠标位置,其中变量mousefocus_new是此刻位置、moursefocus_old是上一时刻位置,两者进行对比,来判断当前鼠标处于的32x32的小雷区是否发生改变。代码如下:

    private void Form_Main_MouseMove(object sender, MouseEventArgs e)
    {
    	//x,y相当于雷区二维数组中的第几行,第几列。
    	int x = (e.X - nOffsetX) / 34 + 1;
    	int y = (e.Y - nOffsetY) / 34 + 1;
    	mousefocus_new.X = x;
    	mousefocus_new.Y = y;
    	if (e.X < nOffsetX || e.Y < nOffsetY)
    	{
    		//鼠标位置不在雷区时
    		mousefocus_new.X = mousefocus_new.Y = -1;
    		Refresh();
    	}
    	else if (mousefocus_new != mousefocus_old)
    	{
    		mousefocus_old = mousefocus_new;
    		Refresh();
    	}
    }
    

    Paint事件应做修改,代码如下:

    for (int i = 0; i < Sweep_width; i++)
    {
    	for (int j = 0; j < Sweep_high; j++)
    	{
    		if (i + 1 == mousefocus_new.X && j + 1 == mousefocus_new.Y)
    		{
    			g.FillRectangle(new SolidBrush(Color.FromArgb(100, Color.Violet)), new Rectangle(nOffsetX + 34 * i, nOffsetY + 34 * j + 1, 32, 32));  //产生高亮
    		}
    		else
    		{
    			g.FillRectangle(Brushes.Violet, new Rectangle(nOffsetX + 34 * i, nOffsetY + 34 * j + 1, 32, 32));
    		}
    	}
    }
    

    此时,按Ctrl + F5编译运行,发现屏幕会闪屏,在初始化模块增加如下代码:

    this.DoubleBuffered = true;                         //双缓冲技术,减少屏幕闪屏
    
    

    最后按Ctrl + F5编译运行,得到最终结果:

  • 相关阅读:
    python 网络爬虫框架scrapy使用说明
    计算机数据表示
    NoSQL 数据库应用
    什么是java序列化?什么情况下需要序列化?
    怎么实现动态代理?
    动态代理是什么?应用场景?
    什么是反射?有什么作用?
    nio中的Files类常用方法有哪些?
    什么是JAVA内部类?
    常见的异常类有哪些?
  • 原文地址:https://www.cnblogs.com/pengpeng123/p/7443270.html
Copyright © 2011-2022 走看看