Android简易打地鼠

先看看基本的效果(背景图片及老鼠图片来源于网络)

未开始时


开始后
停止播放背景音乐
时间到时

上面贴出的这几张就是该APP的游戏界面,下面谈谈一开始设计的基本思路

在布局方面,整体是一个线性布局,最下方是由两个按钮和一个文本组成

关于上方的游戏画面,有两种设计思想

1.最外层采用帧布局,设置背景为有9个空洞的那张图片,在帧布局中使用相对布局放置9个ImageView,分别放置在洞的位置。在画面左上角,设置一个CheckBox用于开关背景音乐

2.最外层采用帧布局,设置背景为有9个空洞的那张图片,在帧布局中使用相对布局放置9个按钮,分别放置在洞的位置。在画面左上角,设置一个CheckBox用于开关背景音乐

关于代码,主要的实现在于背景音乐的控制、老鼠的弹出、下方游戏时间的控制

背景音乐控制:采用了Service的基本用法,根据用户在游戏界面CheckBox的选中与否,分别开启和关闭服务,在服务中使用MediaPlayer播放背景音乐

老鼠的弹出:这个与游戏画面的不同设计有关。  对于第1种,是采用一个数组存放9个ImageView的对象,同时在线程中每隔1s生成一次随机数(0~8),刚好与ImageView的对象在数组中的序号对应,然后将对应的ImageView背景设置为那张老鼠。   对于第2种,是制作9张老鼠与背景的合成图分别作为背景,即每个洞分别与老鼠进行合成,然后将这9张图用一个数组存放起来,同时在线程中每隔1s生成一次随机数(0~8),刚好与9张合成图在数组中的序号对应,然后将包裹9个按钮的相对布局的背景设置为这张图片,由于图片的覆盖,所以看上去老鼠像是弹出的

下方游戏时间控制:当用户点击开始后,开启线程控制总时间的线程、弹出老鼠的线程和计时线程,总时间设定为60s,控制总时间的线程即sleep共60s,时间到后关闭点弹老鼠的线程和计时线程,在其sleep期间,计时线程每隔1s改变一次文本显示的内容(从60到0)


相比上次的Android简易老虎机  ,这次也是使用线程的相关知识,不同的就是添加了服务用于后台控制音乐的播放,使用了帧布局,而且解决了上次的一个小bug,就是在点击开始游戏后(开启各种线程),再次重复点击开始会造成线程重复启动,使老虎机中的转动絮乱,解决方法是使用一个标识flag,初始化为true,而且只有在flag为true时点击按钮才有效果,所以当点击开始后,会设置flag为false,同时启动一个线程,让该线程sleep一定时间,在sleep结束后设置flag为true,所以在该线程sleep期间,flag一直为flase,那么点击开始按钮是无效的

更为详细的解释都放在代码的注释中,这里贴出实现该游戏的主要代码,完整代码已上传到GitHub 

public class GameActivity extends Activity{

private Button playGame,overGame;

private TextView times;

private Button btn1,btn2,btn3,btn4,btn5,btn6,btn7,btn8,btn9;

private LinearLayout ll_bg_show;

private CheckBox cb_sound;

private intbgAtrr[] =new int[9];//保存九张带有老鼠的背景图

private intbtnAtrr[] =new int[9];//保存九个洞对应的按钮

private MyHandler myHandler=newMyHandler();

private SumTime sumTime;

private GameTime gameTime;

private GoTime goTime;

private ClickTime clickTime;

private intt=59;

private intsumMouse=0;//弹出老鼠总个数

private intclickMouse=0;//用户点中的老鼠个数

private intmouseCheckedId=0;//当前弹出图片在数组中的序号

private booleanflag=true;//用于限制开始按钮的有效点击次数

@Override

protected void onCreate(BundlesavedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.game_layout);

initView();//初始化控件

initAtrr();//添加图片id到数组bgAtrr中

initListener();//初始化监听器,将监听器与开始和结束按钮进行绑定

judgeMusic();//播放背景音乐

}

private void judgeMusic() {

Intent intent Service=newIntent(GameActivity.this,MyMusicService.class);

if(cb_sound.isChecked()) {

stopService(intentService);

}else{

startService(intentService);

}

}

/**

* 计时器,游戏开始,该线程sleep一分钟,时间到后,终止弹老鼠进程和计时进程并弹出提示框,传入MyHander的参数为0

*/

class SumTime extendsThread{

@Override

public voidrun() {

super.run();

try{

sleep(60000);

}catch(InterruptedExceptione) {

e.printStackTrace();

}

gameTime.isStop();//调用gameTime的isStop方法,使其停止弹出老鼠

goTime.isStop();//调用goTime的isStop方法,结束该线程

Message message=Message.obtain();

message.what=0;

myHandler.sendMessage(message);

}

}

/**

* 随机弹出老鼠图片,传入到MyHander的参数为1

*/

class GameTime extends Thread{

private boolean isStoped=false;

private void isStop() {

isStoped=true;

gameTime.interrupt();

}

@Override

public voidrun() {

super.run();

while(!isStoped) {

try{

sleep(1000);

}catch(InterruptedExceptione) {

e.printStackTrace();

}

Message message=Message.obtain();//获取Message对象

message.what=1;

myHandler.sendMessage(message);

}

}

}

/**

* 时间计数,传入到MyHander的参数为2

*/

class GoTime extends Thread{

private boolean isStoped=false;

private void isStop() {

isStoped=true;

goTime.interrupt();

}

@Override

public void run() {

super.run();

while(!isStoped) {

try{

sleep(1000);

}catch(InterruptedExceptione) {

e.printStackTrace();

}

Message message=Message.obtain();

message.what=2;

myHandler.sendMessage(message);

}

}

}

class ClickTime implements Runnable{

@Override

public voidrun() {

try{

Thread.sleep(60000);

}catch(InterruptedExceptione) {

e.printStackTrace();

}

flag=true;

}

}

/**

* 根据传入的参数进行处理,传入为0则表示游戏结束,传入为1表示开始游戏,传入2是倒时器开始

*/

class MyHandler extends Handler{

@Override

public void handleMessage(Messagemsg) {

super.handleMessage(msg);

switch(msg.what) {

case0:

sumTime.interrupt();

AlertDialog.Builderdialog=newAlertDialog.Builder(GameActivity.this);

dialog.setTitle("游戏结束");

dialog.setMessage("本轮地鼠总数为: "+sumMouse+" 只\n"+

"您逮住的地鼠共:"+clickMouse+" 只\n"+

"捕获率:"+clickMouse*100/sumMouse+"%"

);

dialog.setCancelable(false);

dialog.setPositiveButton("再试一次",newDialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterfacedialog,intwhich) {

times.setText(60+"");

t=60;

sumMouse=0;

clickMouse=0;

onRestart();

}

});

dialog.show();

break;

case1:

Random random=newRandom();

int index=random.nextInt(9);

ll_bg_show.setBackgroundResource(bgAtrr[index]);

sumMouse++;

if(btnAtrr[index] ==mouseCheckedId) {

clickMouse++;//判断当前老鼠所在的RadioButton的id与用户点击的是否一致,若一致则为打中地鼠

}

break;

case2:

times.setText(t+"");

t--;

break;

}

}

}

class ButtonListener implementsView.OnClickListener{

@Override

public voidonClick(Viewv) {

mouseCheckedId=v.getId();

switch(v.getId()) {

caseR.id.bt_play:

if(flag) {

sumTime=newSumTime();

sumTime.start();

gameTime=newGameTime();

gameTime.start();

goTime=newGoTime();

goTime.start();

}

flag=false;

clickTime=newClickTime();

newThread(clickTime).start();

break;

caseR.id.bt_over:

finish();

Intent intent=newIntent(GameActivity.this,MyMusicService.class);

stopService(intent);

break;

caseR.id.cb_sound:

judgeMusic();

break;

}

}

}


下面列出这次开发中的一些小知识点:

设置手机强制横屏

在配置文件中

在LInearLayout中设置 orientation属性为vertical时,layout_gravity只能够使用横向的如:left, right, center_horizontal   设置 orientation属性为horizontal时,layout_gravity只能够使用纵向的,如:top, bottom, center_vertical

在src中放置的是原图,是不会被拉伸的,如果在水平或者垂直方向需要拉伸,分别使用scaleX和scaleY,参数为缩放比例

在Activity中调用onRestart方法可以使当前Activity回到原始状态

使用Service,需要写一个类继承自Service,在需要使用服务的Activity中使用 Intent intent = new Intent(this, 定义的类.class); 使用startService(intent)开启服务  ,记得使用stopService来关闭服务,整体操作类似Activity的跳转

音频文件放在raw文件夹中(可能需要自己创建),然后使用 MediaPlayer mediaPlayer = MediaPlayer.create(this, R.raw.music) 创建播放器对象并指定音频位置,然后使用mediaPlayer.setLooping(true)设置循环播放,最后使用mediaPlayer.start()开始播放,在退出时使用mediaPlayer.release()释放资源




最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,743评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,296评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,285评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,485评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,581评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,821评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,960评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,719评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,186评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,516评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,650评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,936评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,757评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,991评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,370评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,527评论 2 349

推荐阅读更多精彩内容