软件工程 Android小游戏 猜拳大战

一、前言

最近学校举办的大学生程序设计竞赛,自己利用课余时间写了一个小游戏,最近一直在忙这个写这个小游戏,参加比赛,最终是老师说自己写的简单,可以做的更复杂的点的。加油

二、内容简介

    自己玩过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;
            }
        }
    };

五、设计重点和难点

1、在实现多线程的UI界面更新时,开始选用的是继承Thread类,同时覆写了本类中的run()方法,后来发现可以使用Handler类运行更流畅。

2、在实现画图时,使用的Android 图形2DCanvas类,在设置设置每个图形的显示区域时,以为跟使用JavaRectangle是一样的,后来发现跟MFC中的RECT结构一样。

APK的下载地址:http://pan.baidu.com/s/1hs4h544

提取码:yd4k

posted @ 2016-04-02 17:19  saucxs  阅读(3372)  评论(4编辑  收藏  举报