C#扫雷游戏-1(砖块部分)

本文介绍使用C#自定义控件实现扫雷游戏的过程,重点讲解如何通过自定义控件实现砖块的不同状态及鼠标交互效果,并展示了递归算法在游戏中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:扫雷游戏是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)后面就是不同点击的逻辑问题

Code:
  1. usingSystem;
  2. usingSystem.Collections.Generic;
  3. usingSystem.ComponentModel;
  4. usingSystem.Drawing;
  5. usingSystem.Data;
  6. usingSystem.Text;
  7. usingSystem.Windows.Forms;
  8. namespaceMineSweeper{
  9. ///<summary>
  10. ///砖块
  11. ///</summary>
  12. publicpartialclassBrick:UserControl{
  13. ///<summary>
  14. ///砖块状态
  15. ///</summary>
  16. publicenumBrickState{
  17. UnSwept=0,
  18. Mark=1,
  19. Unknown=2,
  20. Swept=3
  21. }
  22. privateBrickStatestate;
  23. privateBitmap[]images=newBitmap[14];
  24. privateintarroundMines;
  25. privateintx;
  26. privateinty;
  27. privateboolisMine;
  28. [DefaultValue("UnSwept"),Description("砖块状态"),Category("Appearance")]
  29. publicBrickStateState{
  30. get{returnstate;}
  31. set{
  32. state=value;
  33. if(state==BrickState.UnSwept){
  34. BackgroundImage=images[0];
  35. }elseif(state==BrickState.Mark){
  36. BackgroundImage=images[1];
  37. }elseif(state==BrickState.Unknown){
  38. BackgroundImage=images[2];
  39. }elseif(state==BrickState.Swept&&!IsMine){
  40. if(ArroundMines==0){
  41. BackgroundImage=images[3];
  42. }else{
  43. BackgroundImage=images[ArroundMines+4];
  44. }
  45. }elseif(state==BrickState.Swept&&IsMine){
  46. BackgroundImage=images[13];
  47. }
  48. }
  49. }
  50. [DefaultValue("0"),Description("四周地雷数"),Category("Appearance")]
  51. publicintArroundMines{
  52. get{returnarroundMines;}
  53. set{arroundMines=value;}
  54. }
  55. [DefaultValue("0"),Description("距离左边的个数"),Category("Appearance")]
  56. publicintX{
  57. get{returnx;}
  58. set{x=value;}
  59. }
  60. [DefaultValue("0"),Description("距离上方的个数"),Category("Appearance")]
  61. publicintY{
  62. get{returny;}
  63. set{y=value;}
  64. }
  65. [DefaultValue("false"),Description("标记该砖块是否是地雷"),Category("Appearance")]
  66. publicboolIsMine{
  67. get{returnisMine;}
  68. set{isMine=value;}
  69. }
  70. publicBrick(){
  71. InitializeComponent();
  72. images[0]=global::MineSweeper.Properties.Resources.blank;
  73. images[1]=global::MineSweeper.Properties.Resources.Mark;
  74. images[2]=global::MineSweeper.Properties.Resources.Unknown;
  75. images[3]=global::MineSweeper.Properties.Resources.blankBack;
  76. images[4]=global::MineSweeper.Properties.Resources.move;
  77. images[5]=global::MineSweeper.Properties.Resources._1;
  78. images[6]=global::MineSweeper.Properties.Resources._2;
  79. images[7]=global::MineSweeper.Properties.Resources._3;
  80. images[8]=global::MineSweeper.Properties.Resources._4;
  81. images[9]=global::MineSweeper.Properties.Resources._5;
  82. images[10]=global::MineSweeper.Properties.Resources._6;
  83. images[11]=global::MineSweeper.Properties.Resources._7;
  84. images[12]=global::MineSweeper.Properties.Resources._8;
  85. images[13]=global::MineSweeper.Properties.Resources.mine;
  86. BackgroundImageLayout=ImageLayout.Stretch;
  87. BackgroundImage=images[0];
  88. }
  89. #region鼠标相关事件
  90. //鼠标Hover事件
  91. privatevoidBrick_MouseEnter(objectsender,EventArgse){
  92. if(state==BrickState.UnSwept){
  93. BackgroundImage=images[4];
  94. }
  95. }
  96. privatevoidBrick_MouseLeave(objectsender,EventArgse){
  97. if(state==BrickState.UnSwept){
  98. BackgroundImage=images[0];
  99. }
  100. }
  101. boolleftButton=false,rightButton=false;
  102. privatevoidBrick_MouseDown(objectsender,MouseEventArgse){
  103. if(e.Button==MouseButtons.Left){
  104. leftButton=true;
  105. }elseif(e.Button==MouseButtons.Right){
  106. rightButton=true;
  107. }
  108. if(state==BrickState.Swept&&leftButton&&rightButton){
  109. //左右键同时双击数字
  110. TogetherClick();
  111. }elseif(state!=BrickState.Swept&&leftButton){
  112. //左键未扫砖块
  113. LeftClick();
  114. }elseif(state!=BrickState.Swept&&rightButton){
  115. //右键未扫砖块
  116. RightClick();
  117. }
  118. }
  119. privatevoidBrick_MouseUp(objectsender,MouseEventArgse){
  120. if(e.Button==MouseButtons.Left){
  121. leftButton=false;
  122. }elseif(e.Button==MouseButtons.Right){
  123. rightButton=false;
  124. }
  125. }
  126. //左右键同时按键事件
  127. privatevoidTogetherClick(){
  128. }
  129. //左键事件
  130. privatevoidLeftClick(){
  131. SweepBricks(X,Y);
  132. }
  133. //
  134. privatevoidSweepBricks(intx,inty){
  135. introws=Game.Bricks.GetLength(0);
  136. intcols=Game.Bricks.GetLength(1);
  137. if(x<0||x>rows-1||y<0||y>cols-1)
  138. return;
  139. Brickbrick=Game.Bricks[x,y];
  140. if(brick.state==BrickState.UnSwept){
  141. brick.State=BrickState.Swept;
  142. Console.WriteLine("({0},{1})",x,y);
  143. if(brick.ArroundMines==0){
  144. SweepBricks(x-1,y);
  145. SweepBricks(x+1,y);
  146. SweepBricks(x,y-1);
  147. SweepBricks(x,y+1);
  148. }
  149. }
  150. }
  151. //右键标记
  152. privatevoidRightClick(){
  153. if(this.State!=BrickState.Swept){
  154. if(!this.isMine){
  155. State=(BrickState)((((int)state)+1)%3);
  156. }else{
  157. State=BrickState.Swept;
  158. }
  159. }
  160. }
  161. #endregion
  162. }
  163. }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值