一、前言
最近学校举办的大学生程序设计竞赛,自己利用课余时间写了一个小游戏,最近一直在忙这个写这个小游戏,参加比赛,最终是老师说自己写的简单,可以做的更复杂的点的。加油
二、内容简介
自己玩过Android系统下的节奏大师,自己也就考虑做一个类似的,然后自己写技术水平有限,还是在学习Android阶段,自己就想到可以写一个猜拳的比较小游戏。
这是一款基于Android平台小游戏—猜拳大战,简单,易操作,趣味强,训练反应速度,内存小,没有广告,安全。
最大的特点:训练人的反应速度。
游戏规则:在30秒内,通过随机屏幕左右两边随机出现的石头剪刀布,判断哪一边获胜或平局。根据随机出现后迅速点击你判断的结果,然后继续判断下一题。点击判断结果速度越快每一题得到的分数也会越高。最终根据你的分数多少判断最后的等级(A,B,C,D,E,F)。
设计游戏里的逻辑规则:在0.6秒之内点击,加3分,在0.6-1秒之间点击,加2分,在1秒之后点击的,加1分。机器每一次自动产生石头剪刀布时间是1秒,人的反应时间是1秒,所以最多我们需要判断15次,最高分是45分。
结果分析:当自己的分数达到35分以上,得到是A,分数在30-35分,得到是B,分数在20-30分,得到是C,分数在15-20分,得到是D,分数在10-15分,得到是E,分数小于10分,得到是F。
三、效果图
四、设计分析
人在紧张和神经衰弱状态对外界对外界变化有时做出错误的判断,所以考虑开发一款训练人的快速反应的APP,积眼,手,脑同时对外界变化做出正确判断。
整个游戏由布局部分和实现部分组成。(一)布局Layout部分由主要有三部分组成,一个是进入界面,一个是游戏界面,一个是关于界面。(二)实现部分主要由View工具类和Activity两部分组成。
布局部分采用的是先设计自己的logo和游戏背景图,给人一种清新的感觉,一个start的界面,进入App的第一个界面,采用的是线性布局,工整漂亮。一个游戏的界面,进入后游戏界面,在倒计时3,2,1之后就开始了游戏,采用的嵌套线性布局和相对布局,在布局文件中定义ImageButton组件。一个about的关于的界面,介绍自己的版本以及其他信息介绍。
实现部分的(1)View部分,是采用的是使用Android 图形2D的Canvas类;通过setImageDrawable方法来设置按钮要显示的图标,同时对按钮设置事件监听 setOnClickListener,以此来捕捉事件并处理;在数字集合中使用随机函数,每一个数字对应的是个picture,所以就可以随机产生石头剪刀布。(2) Activity部分有三个界面触发,Appstart采用的是Handler类来实现线程UI界面更新,使用自己写的类Handle_Delay来控制更新时间,设定多长时间换下一张picture,同时使用的是一种是实现Runnable接口实现多线程操作。
代码部分:
(1)Appstart部分:实现动态实现的时候使用的是Handle_Delay类。
package com.jk.diy; import com.jk.fingerGame.R; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.widget.ImageView; public class Appstart extends Activity { private ImageView caiquan; public void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.appstart); caiquan = (ImageView) findViewById(R.id.caiquan); caiquan.setBackgroundResource(R.drawable.cq_back_1); /*延迟器,当apk启动后, 1、首先加载的是cq_back_1 2、在延迟一秒后市出现下一张照片,在android机上的时间1000=现实中的1秒 3、Handle_Delay这个类是自己定义的*/ Handle_Delay(0, 1000); Handle_Delay(1, 1300); Handle_Delay(2, 1600); Handle_Delay(3, 2000); Handle_Delay(4, 2400); Handle_Delay(5, 2700); Handle_Delay(6, 3000); Handle_Delay(7, 3100); Handle_Delay(8, 3200); Handle_Delay(9, 2300); Handle_Delay(10, 3400); Handle_Delay(11, 3500); } private void Handle_Delay(int chage, int time) { final int _Chage = chage; Handler _Animal_Handler = new Handler(); _Animal_Handler.postDelayed(new Runnable() { @Override public void run() { // TODO Auto-generated method stub if (_Chage == 0) { caiquan.setBackgroundResource(R.drawable.cq_back_2); } else if (_Chage == 1) { caiquan.setBackgroundResource(R.drawable.cq_back_3); } else if (_Chage == 2) { caiquan.setBackgroundResource(R.drawable.cq_back_4); }else if (_Chage == 3) { caiquan.setBackgroundResource(R.drawable.cq_back_5); } else if (_Chage == 4) { caiquan.setBackgroundResource(R.drawable.cq_back_6); } else if (_Chage == 5) { caiquan.setBackgroundResource(R.drawable.cq_back_1); } else if (_Chage == 6) { caiquan.setBackgroundResource(R.drawable.cq_back_2); } else if (_Chage == 7) { caiquan.setBackgroundResource(R.drawable.cq_back_3); } else if (_Chage == 8) { caiquan.setBackgroundResource(R.drawable.cq_back_4); } else if (_Chage == 9) { caiquan.setBackgroundResource(R.drawable.cq_back_5); } else if (_Chage == 10) { caiquan.setBackgroundResource(R.drawable.cq_back_6); } else { Intent intent = new Intent(Appstart.this, ButtonLongActivity.class); startActivity(intent); finish(); } } }, time);//这个时间是在appstart启动后在这个界面停留的时间。 } }
(2)获取分数部分
public void getMark() { if (endTime - beginTime <= 600) { mark = mark + 3; markImg.setVisibility(View.VISIBLE); markImg.setBackgroundResource(R.drawable.j3); markImg.startAnimation(myAnimation_Alpha); new Thread(r).start(); } else if (endTime - beginTime > 600 && endTime - beginTime <= 1000) { mark = mark + 2; markImg.setVisibility(View.VISIBLE); markImg.setBackgroundResource(R.drawable.j2); markImg.startAnimation(myAnimation_Alpha); new Thread(r).start(); } else if (endTime - beginTime >= 1000) { mark = mark + 1; markImg.setVisibility(View.VISIBLE); markImg.setBackgroundResource(R.drawable.j1); markImg.startAnimation(myAnimation_Alpha); new Thread(r).start(); } fs.setText("分数:" + mark); }
(3)随机猜拳实现(特点:两个石头剪刀布不是同时实现,一个先后)
/* 1、获得两个随机数 * 2、在得到两个随机数的时候是一个先得到,一个后得到*/ public void changeImg() { getRandomNumber(); if (number1 == 1) { p1.setBackgroundResource(R.drawable.jd); } else if (number1 == 2) { p1.setBackgroundResource(R.drawable.st); } else if (number1 == 3) { p1.setBackgroundResource(R.drawable.bu); } if (number2 == 1) { p2.setBackgroundResource(R.drawable.zjd); } else if (number2 == 2) { p2.setBackgroundResource(R.drawable.zst); } else if (number2 == 3) { p2.setBackgroundResource(R.drawable.zbu); } }
(4)计数部分
protected void onDraw(Canvas canvas) { super.onDraw(canvas); //给画笔设置 mPaint.setColor(Color.BLUE); canvas.drawRect(0,1 , getWidth(),getHeight() , mPaint); mPaint.setColor(Color.YELLOW); mPaint.setTextSize(30); String text = String.valueOf(mCount); mPaint.getTextBounds(text, 0, text.length(), mBounds); float textwidth=mBounds.width(); float texthight=mBounds.height(); canvas.drawText(text, getWidth() / 2 - textwidth / 2, getHeight() / 2 + texthight / 2, mPaint); } public void onClick(View arg0) { mCount++; invalidate(); }
(5)重复点击ImageButton实现
package com.jk.view; import android.content.Context; import android.os.SystemClock; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.widget.ImageButton; public class RepeatingImageButton extends ImageButton { private long mStartTime; // 记录长按开始 private int mRepeatCount; // 重复次数计数 private RepeatListener mListener; private long mInterval = 500; // Timer触发间隔,即每0.5秒算一次按下 public RepeatingImageButton(Context context) { this(context, null); } public RepeatingImageButton(Context context, AttributeSet attrs) { this(context, attrs, android.R.attr.imageButtonStyle); } public RepeatingImageButton(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); setFocusable(true); // 允许获得焦点 setLongClickable(true); // 启用长按事件 } public void setRepeatListener(RepeatListener l, long interval) { // 实现重复按下事件listener mListener = l; mInterval = interval; } @Override public boolean performLongClick() { mStartTime = SystemClock.elapsedRealtime(); mRepeatCount = 0; post(mRepeater); return true; } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { // 本方法原理同onKeyUp的一样,这里处理屏幕事件,下面的onKeyUp处理Android手机上的物理按键事件 removeCallbacks(mRepeater); if (mStartTime != 0) { doRepeat(true); mStartTime = 0; } } return super.onTouchEvent(event); } // 处理导航键事件的中键或轨迹球按下事件 @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_DPAD_CENTER: case KeyEvent.KEYCODE_ENTER: super.onKeyDown(keyCode, event); return true; } return super.onKeyDown(keyCode, event); } // 当按键弹起通知长按结束 @Override public boolean onKeyUp(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_DPAD_CENTER: case KeyEvent.KEYCODE_ENTER: removeCallbacks(mRepeater); // 取消重复listener捕获 if (mStartTime != 0) { doRepeat(true); // 如果长按事件累计时间不为0则说明长按了 mStartTime = 0; // 重置长按计时器 } } return super.onKeyUp(keyCode, event); } private Runnable mRepeater = new Runnable() { // 在线程中判断重复 public void run() { doRepeat(false); if (isPressed()) { postDelayed(this, mInterval); // 计算长按后延迟下一次累加 } } }; private void doRepeat(boolean last) { long now = SystemClock.elapsedRealtime(); if (mListener != null) { mListener.onRepeat(this, now - mStartTime, last ? -1 : mRepeatCount++); } } // 下面是重复Button // Listener接口的定义,调用时在Button中先使用setRepeatListener()方法实现RepeatListener接口 public interface RepeatListener { void onRepeat(View v, long duration, int repeatcount); // 参数一为用户传入的Button对象,参数二为延迟的毫秒数,第三位重复次数回调。 } }
(6)用Handler类来实现“跨越线程(Activity)更新UI。
Handler handle = new Handler() { @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); switch (msg.what) { case 4: img.setBackgroundResource(R.drawable.s3); break; case 3: img.setBackgroundResource(R.drawable.s2); break; case 2: img.setBackgroundResource(R.drawable.s1); break; case 1: img.setBackgroundResource(R.drawable.play); break; case 0: kaishi(); break; case 11: if (sumTime != 0) { sj.setText(((sumTime) / 1000 + "." + (sumTime) % 1000 / 10) + "秒"); } else { sj.setText("时间到"); l1.setVisibility(View.GONE); l2.setVisibility(View.VISIBLE); if (35 <= mark) { img.setBackgroundResource(R.drawable.a); } else if (30 <= mark && mark < 35) { img.setBackgroundResource(R.drawable.b); } else if (20 <= mark && mark < 30) { img.setBackgroundResource(R.drawable.c); } else if (15 <= mark && mark < 20) { img.setBackgroundResource(R.drawable.d); } else if (10 <= mark && mark < 15) { img.setBackgroundResource(R.drawable.e); } else if (mark < 10) { img.setBackgroundResource(R.drawable.f); } dj2.setVisibility(View.VISIBLE); dj1.setVisibility(View.GONE); } break; case 12: changeImg(); break; case 13: markImg.setVisibility(View.GONE); break; default: break; } } };
Normal
0
7.8 磅
0
2
false
false
false
EN-US
ZH-CN
X-NONE
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:普通表格;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-qformat:yes;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.5pt;
mso-bidi-font-size:11.0pt;
font-family:"Calibri","sans-serif";
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-font-kerning:1.0pt;}
五、设计重点和难点
1、在实现多线程的UI界面更新时,开始选用的是继承Thread类,同时覆写了本类中的run()方法,后来发现可以使用Handler类运行更流畅。
2、在实现画图时,使用的Android 图形2D的Canvas类,在设置设置每个图形的显示区域时,以为跟使用Java的Rectangle是一样的,后来发现跟MFC中的RECT结构一样。
APK的下载地址:http://pan.baidu.com/s/1hs4h544
提取码:yd4k
Normal
0
7.8 磅
0
2
false
false
false
EN-US
ZH-CN
X-NONE
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:普通表格;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-qformat:yes;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.5pt;
mso-bidi-font-size:11.0pt;
font-family:"Calibri","sans-serif";
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-font-kerning:1.0pt;}