前言:扫雷游戏是Windows系统的一款经典游戏。搜索一下google,有94万条网页。包括本人也写过2个版本的扫雷游戏。其实我们注重的不是游戏本身,而是技术或者说是知识点。
先看看我要介绍的这款扫雷涉及哪些知识点。
1)自定义控件
2)GDI+
3)枚举
4)集合
5)属性
6)递归
大致看来涉及这些。我在介绍的过程中尽量结合C#的知识点运用。
需求说明:
1)有不同级别,不同级别有不同的砖块,地雷数也不同
2)点击砖块,如果没有地雷显示周围地雷数
3)右击砖块可以设置多种状态:标志、疑问、取消标志
4)如果砖块周围无雷,则打开周围的无雷区
5)鼠标移动到砖块上,砖块颜色变化
1.制作砖块
需求分析:
1)为了实现“鼠标移动到砖块上,砖块颜色变化”,决定采用自定义控件,这样将每个砖块都作为一个控件,可以定义MouseEnter和MouseLeave事件
(1)创建自定义控件Brick
public partial class Brick : UserControl{
……
}
(2)定义砖块状态的枚举
public partial class Brick : UserControl{
///<summary>
///砖块状态
///</summary>
public enum BrickState {
UnSwept = 0, //未扫
Mark = 1, //标记
Unknow = 2, //未知
Swept = 3 //已扫
}
}
(3)定义一些成员变量。如:状态、周围地雷数、位置以及是否有地雷
(4)根据不同的状态,显示不同的图片。这里我采用了属性设置。通过setter访问器实现状态与背景图片的关联。
[DefaultValue("UnSwept"), Description("砖块状态"), Category("Appearance")]
public BrickState State {
get { return state; }
set {
state = value;
if(state == BrickState.UnSwept) {
BackgroundImage = images[0];
} else if(state == BrickState.Mark) {
BackgroundImage = images[1];
} else if(state == BrickState.Unknow) {
BackgroundImage = images[2];
} else if(state == BrickState.Swept && !IsMine) {
BackgroundImage = images[3];
} else if(state == BrickState.Swept && IsMine) {
BackgroundImage = images[11];
}
}
}
注意到[DefaultValue("UnSwept"), Description("砖块状态"), Category("Appearance")],这是为了让VS2005能看属性窗口中看到自定义的属性。
DefaultValue是默认值,Description是说明
(5)鼠标事件:鼠标移动砖块上(MouseEnter)、鼠标移出砖块(MouseLeave)、鼠标点击(左击、右击、左右同击)
这里说明一下,鼠标左右同击比较难以判断。现采用这种方式:当左键点击后记录下来,右键点击后也记录下来,再判断两个记录值,如果都为true表示左右同击。当鼠标键抬起时也要将记录改过来。
private void Brick_MouseEnter(object sender, EventArgs e) {
if(state == BrickState.UnSwept) {
BackgroundImage = images[4];
}
}
private void Brick_MouseLeave(object sender, EventArgs e) {
if(state == BrickState.UnSwept) {
BackgroundImage = images[0];
}
}
bool leftButton = false, rightButton = false;
private void Brick_MouseDown(object sender, MouseEventArgs e) {
if(e.Button == MouseButtons.Left) {
leftButton = true;
} else if(e.Button == MouseButtons.Right) {
rightButton = true;
}
if(state == BrickState.Swept && leftButton && rightButton) {
//左右键同时双击数字
TogetherClick();
} else if(state != BrickState.Swept && leftButton) {
//左键未扫砖块
LeftClick();
} else if(state != BrickState.Swept && rightButton) {
//右键未扫砖块
RightClick();
}
}
private void Brick_MouseUp(object sender, MouseEventArgs e) {
if(e.Button == MouseButtons.Left) {
leftButton = false;
} else if(e.Button == MouseButtons.Right) {
rightButton = false;
}
}
(6)后面就是不同点击的逻辑问题
- usingSystem;
- usingSystem.Collections.Generic;
- usingSystem.ComponentModel;
- usingSystem.Drawing;
- usingSystem.Data;
- usingSystem.Text;
- usingSystem.Windows.Forms;
- namespaceMineSweeper{
- ///<summary>
- ///砖块
- ///</summary>
- publicpartialclassBrick:UserControl{
- ///<summary>
- ///砖块状态
- ///</summary>
- publicenumBrickState{
- UnSwept=0,
- Mark=1,
- Unknown=2,
- Swept=3
- }
- privateBrickStatestate;
- privateBitmap[]images=newBitmap[14];
- privateintarroundMines;
- privateintx;
- privateinty;
- privateboolisMine;
- [DefaultValue("UnSwept"),Description("砖块状态"),Category("Appearance")]
- publicBrickStateState{
- get{returnstate;}
- set{
- state=value;
- if(state==BrickState.UnSwept){
- BackgroundImage=images[0];
- }elseif(state==BrickState.Mark){
- BackgroundImage=images[1];
- }elseif(state==BrickState.Unknown){
- BackgroundImage=images[2];
- }elseif(state==BrickState.Swept&&!IsMine){
- if(ArroundMines==0){
- BackgroundImage=images[3];
- }else{
- BackgroundImage=images[ArroundMines+4];
- }
- }elseif(state==BrickState.Swept&&IsMine){
- BackgroundImage=images[13];
- }
- }
- }
- [DefaultValue("0"),Description("四周地雷数"),Category("Appearance")]
- publicintArroundMines{
- get{returnarroundMines;}
- set{arroundMines=value;}
- }
- [DefaultValue("0"),Description("距离左边的个数"),Category("Appearance")]
- publicintX{
- get{returnx;}
- set{x=value;}
- }
- [DefaultValue("0"),Description("距离上方的个数"),Category("Appearance")]
- publicintY{
- get{returny;}
- set{y=value;}
- }
- [DefaultValue("false"),Description("标记该砖块是否是地雷"),Category("Appearance")]
- publicboolIsMine{
- get{returnisMine;}
- set{isMine=value;}
- }
- publicBrick(){
- InitializeComponent();
- images[0]=global::MineSweeper.Properties.Resources.blank;
- images[1]=global::MineSweeper.Properties.Resources.Mark;
- images[2]=global::MineSweeper.Properties.Resources.Unknown;
- images[3]=global::MineSweeper.Properties.Resources.blankBack;
- images[4]=global::MineSweeper.Properties.Resources.move;
- images[5]=global::MineSweeper.Properties.Resources._1;
- images[6]=global::MineSweeper.Properties.Resources._2;
- images[7]=global::MineSweeper.Properties.Resources._3;
- images[8]=global::MineSweeper.Properties.Resources._4;
- images[9]=global::MineSweeper.Properties.Resources._5;
- images[10]=global::MineSweeper.Properties.Resources._6;
- images[11]=global::MineSweeper.Properties.Resources._7;
- images[12]=global::MineSweeper.Properties.Resources._8;
- images[13]=global::MineSweeper.Properties.Resources.mine;
- BackgroundImageLayout=ImageLayout.Stretch;
- BackgroundImage=images[0];
- }
- #region鼠标相关事件
- //鼠标Hover事件
- privatevoidBrick_MouseEnter(objectsender,EventArgse){
- if(state==BrickState.UnSwept){
- BackgroundImage=images[4];
- }
- }
- privatevoidBrick_MouseLeave(objectsender,EventArgse){
- if(state==BrickState.UnSwept){
- BackgroundImage=images[0];
- }
- }
- boolleftButton=false,rightButton=false;
- privatevoidBrick_MouseDown(objectsender,MouseEventArgse){
- if(e.Button==MouseButtons.Left){
- leftButton=true;
- }elseif(e.Button==MouseButtons.Right){
- rightButton=true;
- }
- if(state==BrickState.Swept&&leftButton&&rightButton){
- //左右键同时双击数字
- TogetherClick();
- }elseif(state!=BrickState.Swept&&leftButton){
- //左键未扫砖块
- LeftClick();
- }elseif(state!=BrickState.Swept&&rightButton){
- //右键未扫砖块
- RightClick();
- }
- }
- privatevoidBrick_MouseUp(objectsender,MouseEventArgse){
- if(e.Button==MouseButtons.Left){
- leftButton=false;
- }elseif(e.Button==MouseButtons.Right){
- rightButton=false;
- }
- }
- //左右键同时按键事件
- privatevoidTogetherClick(){
- }
- //左键事件
- privatevoidLeftClick(){
- SweepBricks(X,Y);
- }
- //
- privatevoidSweepBricks(intx,inty){
- introws=Game.Bricks.GetLength(0);
- intcols=Game.Bricks.GetLength(1);
- if(x<0||x>rows-1||y<0||y>cols-1)
- return;
- Brickbrick=Game.Bricks[x,y];
- if(brick.state==BrickState.UnSwept){
- brick.State=BrickState.Swept;
- Console.WriteLine("({0},{1})",x,y);
- if(brick.ArroundMines==0){
- SweepBricks(x-1,y);
- SweepBricks(x+1,y);
- SweepBricks(x,y-1);
- SweepBricks(x,y+1);
- }
- }
- }
- //右键标记
- privatevoidRightClick(){
- if(this.State!=BrickState.Swept){
- if(!this.isMine){
- State=(BrickState)((((int)state)+1)%3);
- }else{
- State=BrickState.Swept;
- }
- }
- }
- #endregion
- }
- }