前言
繪制雷區
這一節我們主要涉及界面中雷區的繪制。繪制雷區需要三個變量來保存雷區行數、列數、以及地雷的數量。而且我們希望能夠自動獲取上次游戲的設置(初級,中級,高級,雷區的三個變量值不同)。因此這三個變量的值需要保存下來。我們在這里采用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編譯運行,得到最終結果: