思路:
1、点击开始按钮生成雷区。(使用按钮控件就足够了,还可以方便的监听点击事件)
2、点击雷区的按钮开始判断是否有雷,点中地雷游戏结束,点中空地则检查四周的雷的数量并显示出来。
3、空地全部点开以后游戏胜利。
首先要确定雷区的大小,因为手机屏幕较小,所以选择8*8的小雷区。
<wbr><wbr><wbr> intMAX_ROW=8;//8</wbr></wbr></wbr>行
<wbr><wbr><wbr> intMAX_C=8;//8</wbr></wbr></wbr>列
然后设置雷的数量。
<wbr><wbr><wbr> intMAX_BOOM=16;//</wbr></wbr></wbr>雷的数量
然后计算出需要点开多少空地。
<wbr><wbr><wbr> intSHOULD_FIND=MAX_ROW*MAX_C-MAX_BOOM;//</wbr></wbr></wbr>应该点开的按钮数量
<wbr><wbr><wbr> int find =0;//</wbr></wbr></wbr>已经找到的不是雷的数量
声明各种数组。l是布局里面的一行,b是雷区的按钮,date保存雷的位置。
<wbr><wbr><wbr> LinearLayoutl[]=new LinearLayout[MAX_ROW];<br><wbr><wbr><wbr> Buttonb[][]=new Button[MAX_ROW][MAX_C];<br><wbr><wbr><wbr> intdate[][]= newint[MAX_ROW][MAX_C];<br></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>加入开始退出的按钮。
<wbr><wbr><wbr> ButtonstartButton;<br><wbr><wbr><wbr> ButtonexitButton;<br></wbr></wbr></wbr></wbr></wbr></wbr>因为android的界面跟逻辑是分离的,所以需要把逻辑里的对象跟界面的对象联系起来
for(int i=0; i<MAX_ROW; i++){
<wbr><wbr><wbr><wbr><wbr><wbr>l[i]=(LinearLayout)findViewById(R.id.linearLayout1+i);<br> }<br></wbr></wbr></wbr></wbr></wbr></wbr>同过id来找寻到对象,对象的id是一个整数,同类型的id是连续的,所以我们可以用每次加1来循环,这样的话以后需要更改雷区大小,只用改变MAX_ROW,MAX_C的值,不用动别的代码。
exitButton=(Button)findViewById(R.id.button2);
startButton=(Button)findViewById(R.id.button1);
同理,把两个按钮的也找到。
这样,基本的准备工作就做完了。
接着我们为关闭按钮添加功能。设置一个点击事件的监听器,这个按钮被点击后会调用onClick里的东西。onClick里我们彻底的关闭了本程序的进程。
exitButton.setOnClickListener(new OnClickListener(){
@Override
publicvoid onClick(View v) {
<wbr><wbr><wbr> finish();</wbr></wbr></wbr>
<wbr><wbr>android.os.Process.killProcess(android.os.Process.myPid());</wbr></wbr>
<wbr><wbr><wbr>System.exit(0);</wbr></wbr></wbr>
}
});
然后是开始按钮。点击以后判断状态,如果开始按钮上的字是重新开始,那么证明游戏已经开始了,雷区有按钮,所以我们先调用rmButton来清除雷区的按钮,再开始新的游戏,如果开始按钮上的字是别的,那就直接开始游戏。
startButton.setOnClickListener(new OnClickListener(){
@Override
publicvoid onClick(View v) {
<wbr><wbr><wbr></wbr></wbr></wbr> if(startButton.getText()=="重新开始"){
<wbr><wbr><wbr></wbr></wbr></wbr> <wbr><wbr><wbr></wbr></wbr></wbr> rmButton();
<wbr><wbr><wbr></wbr></wbr></wbr> <wbr><wbr><wbr></wbr></wbr></wbr> startgame();
<wbr><wbr><wbr></wbr></wbr></wbr> }else{
<wbr><wbr><wbr></wbr></wbr></wbr> <wbr><wbr><wbr></wbr></wbr></wbr><wbr><wbr><wbr></wbr></wbr></wbr> startButton.setText("重新开始");
<wbr><wbr><wbr></wbr></wbr></wbr> <wbr><wbr><wbr></wbr></wbr></wbr><wbr><wbr><wbr></wbr></wbr></wbr> startgame();
<wbr><wbr><wbr></wbr></wbr></wbr> <wbr><wbr><wbr></wbr></wbr></wbr> }
<wbr><wbr><wbr></wbr></wbr></wbr> }
});
我们先来看看rmButton这个简单的函数。在这个函数里,遍历行跟列,把按钮数组设置为null(意思是什么也没有)。然后用removeAllViews把每一行的东西都给移除。
publicvoid rmButton(){
<wbr><wbr><wbr></wbr></wbr></wbr> for(int i=0;i<MAX_ROW;i++){
<wbr><wbr><wbr></wbr></wbr></wbr> <wbr><wbr><wbr></wbr></wbr></wbr> for(int j=0;j<MAX_C;j++){
<wbr><wbr><wbr></wbr></wbr></wbr><wbr><wbr><wbr></wbr></wbr></wbr> b[i][j]=null;
<wbr><wbr><wbr></wbr></wbr></wbr> }
<wbr><wbr><wbr></wbr></wbr></wbr> l[i].removeAllViews();
<wbr><wbr><wbr></wbr></wbr></wbr> }
}
接着就是开始游戏的函数了。首先初始化找到的地雷数量,一会会用这个值来判断游戏是否获胜。接着调用loadBoom随机生成雷的数组。注释掉的logBoom是调试时用来在LOG中显示雷的数组的值的函数,没问题了就不需要了。最后调用addButton来在布局里添加雷区的按钮。
public void startgame(){
find = 0;//初始化找到的为0
loadBoom();
//logBoom();
addButton();
}
最开始设计时我是先用固定的雷区数组,主要把精力放在了点击后的逻辑上,随机生成地雷是后面加入的功能。做游戏要分清主次,首先把最难得部分做完,剩下的就好办了。先用系统当前的时间做种子,来生成随机数。随机数就跟树一样,从一个种子发芽成长,要是种子一样,那么长出来的东西一样,因为随机数其实也是一个固定的算法。比如第一次生成1(种子生成),7,5,3,以后还是会生成一样的1,7,5,3。所以我们要给他一个不一样的种子,而系统时间正好是时刻变化的。
接着调用了clearDate,这个函数把date中的数据全部变成0。
最后得到2个0到7的随机数,如果这2个随机数指的位置没有雷的话,那么放上一个雷,如果已经有雷了,那就把i减1,表示失败,重新再来。
public void loadBoom(){
Random r=newRandom(System.currentTimeMillis());
clearDate();
for(int i = 0; i < MAX_BOOM;i++){
<wbr><wbr><wbr></wbr></wbr></wbr> int x = abs(r.nextInt()%8);
<wbr><wbr><wbr></wbr></wbr></wbr> int y = abs(r.nextInt()%8);
<wbr><wbr><wbr></wbr></wbr></wbr> if(date[x][y]!=1){
<wbr><wbr><wbr></wbr></wbr></wbr> date[x][y]=1;
}
else{
<wbr><wbr><wbr></wbr></wbr></wbr> i--;
}
}
}
以下就是clearDate。
public void clearDate(){
for(int i=0;i<MAX_ROW;i++){
<wbr><wbr><wbr></wbr></wbr></wbr> for(int j=0;j<MAX_C;j++){
<wbr><wbr><wbr></wbr></wbr></wbr> <wbr><wbr><wbr></wbr></wbr></wbr> date[i][j] = 0;
<wbr><wbr><wbr></wbr></wbr></wbr> }
}
}
最后是最重要的addButton函数,这个函数不光添加了按钮,还给每个按钮添加了不同的监听事件。(从windows弄到ubuntu来贴出来格式不对)下面就是addButton。
通过MAX_ROW,MAX_C来生成按钮的二维数组,前面一个数字是行号,后面一个是在这一行中的第几个。然后设置按钮的长,宽,按钮上的文字。下面添加点击事件监听时需要使用到当前的行列值,但是i,j是局部变量,不能引用,于是我们声明2个final型的临时变量来存放i,j的值。然后添加监听,监听时判断当前位置的date数组(雷的位置的数组)的值,如果是0,那就代表点击中了没有雷的按钮,那么找到的不是雷的计数器加一,加一后如果已经找出了所有的雷,那么执行游戏胜利的win。如果没有找出全部的雷,那么把按钮设置为不可用,并调用check把周围的雷的数量找出来显示在按钮上。如果,点击的位置相对的date里为1,那么代表踩到了地雷,则把踩中地雷的图像显示在按钮上,并运行gameover。
接下来添加长时间按住按钮的监听。如果长时间按住按钮,那么把按钮的文字设置为B代表标记地雷,并且禁止按钮的使用。
最后把按钮加到相应的行里面。
public void addButton(){
for(int i=0;i<MAX_ROW;i++){
for(int j=0;j<MAX_C;j++){
b[i][j]=new Button(this);
b[i][j].setHeight(60);
b[i][j].setWidth(60);
b[i][j].setText("");
final int ti=i;
final int tj=j;
//点击按钮
b[i][j].setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(date[ti][tj]==0){//没有地雷
find += 1;
if(find==SHOULD_FIND){win();}
else{
b[ti][tj].setEnabled(false);
b[ti][tj].setText(check(ti,tj));//把周围的雷数量显示在按钮上
}
}
else{
b[ti][tj].setBackgroundDrawable(getResources().getDrawable(R.drawable.wrong));
gameover();
}
}
});
//长按按钮
b[i][j].setOnCreateContextMenuLi<wbr>stener(newOnCreateContextMenuListe<wbr>ner() {</wbr></wbr>
@Override
public void onCreateContextMenu(ContextMenu menu, Viewv,
ContextMenuInfo menuInfo) {
// TODO Auto-generated method stub
menu.setHeaderTitle("地雷标记");
if(b[ti][tj].isEnabled()){
b[ti][tj].setText("B");
b[ti][tj].setEnabled(false);
}
}
});
l[i].addView(b[i][j]);//把按钮加入布局
}
}
}
这是最后一部分了。
下面就是四周雷的算法,需要注意按钮在边上,角上的边界问题,否则容易出现运行时数组访问越界问题。
//判断四周有没有雷
public String check(int i, int j){
int sum = 0;
<wbr></wbr>
if(i>0){
if(j<MAX_C-1){
if(date[i-1][j+1]!=0){sum++;}
}
if(date[i-1][j]!=0){sum++;}
}
if(j>0){
if(date[i][j-1]!=0){sum++;}
if(i<MAX_ROW-1){
if(date[i+1][j-1]!=0){sum++;}
}
}
if(i>0&&j>0){
if(date[i-1][j-1]!=0){sum++;}
}
if(i<MAX_ROW-1){
if(date[i+1][j]!=0){sum++;}
}
if(j<MAX_C-1){
if(date[i][j+1]!=0){sum++;}
}
if(i<(MAX_ROW-1)&&j<(MAX_C-1)){
if(date[i+1][j+1]!=0){sum++;}
}
return ""+sum;
}
<wbr></wbr>
//把所有的雷显示出来
public void showAllBoom(){
for(int i=0;i<MAX_ROW;i++){
for(int j=0;j<MAX_C;j++){
b[i][j].setEnabled(false);
if(date[i][j]!=0){
b[i][j].setBackgroundDrawable(getResources().getDrawable(R.drawable.wrong));//素材自己画了放到drawable里。
}
}
}
}
public void gameover(){
mvibrator.vibrate(pattern_Over, -1);
Toast.makeText(this, "gameover!!!!!!!!!",Toast.LENGTH_LONG).show();
showAllBoom();//把所有的雷显示出来
<wbr></wbr>
}
<wbr></wbr>
public void win(){
mvibrator.vibrate(pattern_Win, -1);
Toast.makeText(this, "you win!!!!!!!!!",Toast.LENGTH_LONG).show();
showAllBoom();//把所有的雷显示出来
}
还有第一下点击必不为雷,雷区大小,雷的数量等调整难度的就不做了,无非也就改改参数。下一个是俄罗斯方块。已经完成了,分批发上来。正在制作rpg中。