代码改变世界

hge引擎写的一个扫雷小游戏

2011-11-14 22:59  gavin's world  阅读(960)  评论(0编辑  收藏  举报
/*
*前些天,没事玩扫雷,发现无雷区域展开很像优先搜索,索性google了一下,果然不出所料,
*用到得算法就是BFS,正好这阵子看了一点hge游戏引擎设计,就写了一个hge下的扫雷小
*游戏*/
好了开始说思路了
1.首要写一个棋盘(20*20个正方形),由二维结构体数组便可实现
struct node1
{
int x,y;                       //x,y 是真实的物理坐标
int flag;                      //flag=1 有雷 =0 无雷
int around;                    //该点周围雷数
bool shownumber;               //是否显示周围雷数
};
node1 Node[N][N];                        //N=20
另外用 bool used[N][N]; 来标记是否被访问过
再定义一个辅助方向二维数组,用来遍历当前位置周围8个位置是否有雷及个数
int dir[8][2] = 
{
{-1, 0}, {1, 0}, {0, -1}, {0, 1}, 
{-1, -1}, {-1, 1}, {1, -1}, {1, 1}
};                                  
static int   leinumber;                 //总雷数     
static int  counter;                    //记录被用户标记的雷个数
float   x,y;                           //获得鼠标坐标
bool Flag[N][N];                        //记录用户标记的雷的位置
这样基本准备工作就做完了
2.雷盘得初始化
  可先将雷盘统一设置为无雷
   used[i][j]=0;
                              
   Node[i][j].around=0;                                  
   Node[i][j].x=j*20;                    //每个单元大小为20像素
   Node[i][j].y=i*20;                    //平铺雷盘
   Node[i][j].flag=0;
   Node[i][j].shownumber=false;
  由于雷毕竟少,可以在此时点对点布雷,可用随机数函数产生列号
   for(t=0;t<3;t++)
    {
int j=rand()%15+3;                //每行3个雷
Node[i][j].flag=1;
    }
   //统计总雷数
   for(i=2;i<N-2;i++)
     for(j=2;j<N-2;j++)
{
           if(Node[i][j].flag==1);
           leinumber++;                
}
3.核心程序
  其实扫雷最为主要得就是实现无雷区域的展开,何时继续何时停止最关键,要不然很容易死循环
  所以标记二维数组used[][]很重要!!!,
  下面模拟一下人机交互过程,简单的想象一下:
   0)初始化,雷藏与地面下,等待用户点选
   1)用户触发一块区域,有雷,无雷两种情况(左击)
       若有雷,终止游戏
       若无雷,搜索周围8个位置是否有雷,有雷则Node[x][y].around++,若点击位置周围没有雷 
       把当前位置进队列,然后把8个位置也进队列,在对这些位置进行同样的检索,直到其周围有雷
       或碰到边界为止。
   2)右键操作
     和平常一样,右击一次标红旗表示有雷,再次撤销
   3)判断过程
     当用户标记的红旗数和规定的相等时,进行Examine操作,如果标记位置,正确...错误....              
   下面看代码:
   //无雷区域展开算法
   //x,y经由鼠标坐标转化而来,映射到雷盘上的二维数组
   void BFS(int x,int y)
   {
if(Flag[x][y]==true) return;                           //点击位置 被访问过就不做反应了  
if(Node[x][y].flag==1)                                 //点到雷,就挂了
{
MessageBox(NULL, "Sorry,failed", "", MB_OK | MB_ICONERROR | MB_APPLMODAL);
return ;
}
queue<node1 > my_que;                                  //临时队列,存放扩展源中心
node1 cur,que;                                         //cur 当前位置  que  周围位置
cur.x = x;
cur.y = y;
cur.around=0;
used[cur.x][cur.y]=true;
my_que.push(cur);
while (!my_que.empty())
{
cur = my_que.front();
my_que.pop();
for (int i = 0; i < 8; ++i)
{
que.x = cur.x + dir[i][0];
que.y = cur.y + dir[i][1];
                        //边界判断
if ((que.x >= 2 && que.x < N-2) &&  (que.y >= 2 && que.y < N-2))
{
if (Node[que.x][que.y].flag == 1)
{
++(cur.around); 
Node[cur.x][cur.y].shownumber=true;
}
}
}
                //开始扩展
if (cur.around == 0)
{
used[cur.x][cur.y] = true; //!!! 很重要
for (int i = 0; i < 8; ++i)             //遍历周围8个位置
{
que.x = cur.x + dir[i][0];
que.y = cur.y + dir[i][1];
if (que.x >= 2 && que.x < N-2 && que.y >=2 && que.y < N-2)
{
if (used[que.x][que.y] == false)
{
que.around = 0; 
my_que.push(que);
used[que.x][que.y] = true;
}
}
}
}
                //如果当前位置周围有雷,就停止搜索,显示雷数
if (cur.around != 0)
{
Node[cur.x][cur.y].around=cur.around;
Node[cur.x][cur.y].shownumber=true;
used[cur.x][cur.y] = true;
if(Flag[cur.x][cur.y]==true)    
{
Flag[cur.x][cur.y]=false;
counter--;
}
   }
       }  
                      
   下面是关于游戏完成判断的(当leinumber==counter时调用)
   bool Examine()
   {
bool tag=false;
        //表里雷盘排查
for(int i=2;i<N-2;i++)
{
for(int j=2;j<N-2;j++)
{
                        //两种错误情况:实际有雷用户未标出 , 实际没雷用户错标
if( (Node[i][j].flag==1 && Flag[i][j]==false) || (Node[i][j].flag==0 && Flag[i][j]==true)) 
{
               MessageBox(NULL, "The found may has some error!Please check again!", "", MB_OK | MB_ICONERROR | MB_APPLMODAL);
  return false;
}
else if(Node[i][j].flag==1 && Flag[i][j]==true)
{
tag=true;
}
}
      
}
if(tag==true)
return true;
    }
   以下时是右键标雷操作,没什么好说得了,就是别忘了点击位置要先确定是否已经访问过
   void SetFlag(int x,int y)
   {
if(used[x][y]==false)
{
if(Flag[x][y]==false)
  {
 Flag[x][y]=true;
 counter++;
//  used[x][y]=true;
 }
else
{
Flag[x][y]=false;
counter--;
// used[x][y]=false;
   }
}
if(counter==leinumber)
{
  if(Examine()==true);
  {
   MessageBox(NULL, "Congrauations!!!", "", MB_OK | MB_ICONERROR | MB_APPLMODAL);
hge->System_Shutdown();
hge->Release();
  }
     
}
 
    }

  差点忘了,上张图吧:

   

  剩下的就是hge引擎的操作了,用到的都是些最基本的函数——加载,释放资源 和渲染,google一下就可以啦~~
  在此就不再多说了,想进一步了解hge的 ,可以和下面一起下载
  额...还有由于刚刚编译完成,界面还比较简陋,可能还有几个bug,见谅.

  下载链接:http://115.com/file/e6mtdath#saolei.zip