掃雷游戲制作過程(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編譯運行,得到最終結果:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM