人机交互实验:Android开发之人物移动、地图滑动、传感器、触屏的应用

来源:互联网 发布:淘宝网怎么增加流量 编辑:程序博客网 时间:2024/06/05 14:24

Android开发,人物移动与地图滑动,传感器、触屏的应用

1.程序介绍

这是我们人机交互课的实验,老师对我们的要求如下:

  • 1.能绘制出二维卷轴地图,及人物可在地图上各方向移动
  • 2.在第1次的基础上加入交互,用手指控制人物的移动和地图的缩放等,实现一指交互、二指交互。
  • 3.在之前的基础上,实现使用手机上2种感应器在程序中的作用,例如重力感应器、GPS、加速度感应器等
    先给个程序的截图吧~

2.人物移动和地图滑动

参考该博客Android游戏开发之主角的移动和地图的平滑滚动
我程序的框架是参考该博客中的程序,它已经实现了地图的绘制、用键盘控制人物的移动,所以其它的功能我是在该程序的基础上实现的。
其余的不说了,先说说原来程序的不足之处

2.1 源程序引用数值较多

这是我很不喜欢源程序的地方,因为很多地方用的直接是数值,一方面很难让人知道该数值的含义,另一方面也使得若换不同的地图、不同屏幕像素的手机等,得重新改动,比如UpdateHero方法中,如何判断接下来是人物移动还是地图滑动,在if中用了很多数值,一开始看的话,你根本不知道这些数值代表什么!
在我的程序中,我多定义了些变量,由变量算出这些数值,这样换地图的话只要更改地图的宽高,换手机的话就什么都不用改。给出前后代码的对比。

//原来的人物往下移动的处理if (mHeroScreenY >= 320) {    if (mHeroIndexY >= 10 && mHeroIndexY <= 20) {        mMapPosY -= HERO_STEP;    } else {        mHeroScreenY += HERO_STEP;    }} else {    mHeroScreenY += HERO_STEP;}/* * 我对人物往下移动的处理 * 先对代码做一些解释,当然,数值是来源于原来代码中的。 * 地图上下移动有个范围,地图上界即屏幕上界~地图下界即屏幕下界  * 地图最上端为屏幕最上端时,320/32=10 * 地图最下端为屏幕最下端时,(800-160)/32=20 * 但若<=20,则地图最下面会有一小部分重复往上动,走到那里会出现多个人 改成17后,就没事了。 * 这是因为有的手机像素高度比较大(大于800),所以会出现最下面地图重复移动的情况 */if (mHeroScreenY >= h * 2) {    if (mHeroIndexY >= h * 2 / 32        && mHeroIndexY <= (SCENCE_HEIGHT - h) / 32) {    //mMapPosY:地图的坐标,即人物不动,地图往上移动,也就是地图的Y坐标减小        mMapPosY -= HERO_STEP;    } else {        mHeroScreenY += HERO_STEP;    }} else {    // 人就在屏幕上往下移动    mHeroScreenY += HERO_STEP;}

2.2 源程序对碰撞处理不是很好

我参考的源程序对碰撞进行了处理,但是处理考虑不全面!在控制人物移动过程中,刚开始,嗯,不错,碰撞处理挺好的。可是当你人物继续移动,直到人物在屏幕上位置不变,而地图开始移动的时候,这是若碰到物体,你会发现竟然穿过去了!!!我通过用Log.v()方法输出想要的内容,调试了好久,终于被我发现了错误。

先看看对碰撞的处理:

if (mCollision[mHeroIndexY][mHeroIndexX] == -1) {    mHeroPosX = mBackHeroPosX;    mHeroPosY = mBackHeroPosY;    mHeroScreenY = mBackHeroScreenY;    mHeroScreenX = mBackHeroScreenX;    //下面是我增加的    mMapPosX = mBackmMapPosX;    mMapPosY = mBackmMapPosY;    isAcotrCollision = true;} else {    mBackHeroPosX = mHeroPosX;    mBackHeroPosY = mHeroPosY;    mBackHeroScreenX = mHeroScreenX;    mBackHeroScreenY = mHeroScreenY;    //下面是我增加的    mBackmMapPosX = mMapPosX;    mBackmMapPosY = mMapPosY;    isAcotrCollision = false;}

若发生碰撞,人物在屏幕、地图中的x、y坐标进行回退,即回退到前一次的。细心的童鞋可以发现,它还缺少了一种可能。那就是当人物过了屏幕宽或高的三分之二,实际上是地图在滑动了。针对该种情形下发生碰撞,源代码中并没对地图的x,y坐标进行回退!所以导致地图在滑动的时候,即使发生碰撞,地图还在滑动,这就导致人物穿墙的问题!

3.触屏控制

3.1 一指触屏控制人物移动

原先是通过键盘控制的,若要增加触屏控制人物移动,其实很好办,因为原先的代码都已经把框架给写好了,原文中通过下面四个变量,来判断人物是往哪里移动。

    /** 按键下 **/    private boolean mIskeyDown = false;    /** 按键左 **/    private boolean mIskeyLeft = false;    /** 按键右 **/    private boolean mIskeyRight = false;    /** 按键上 **/    private boolean mIskeyUp = false;  

所以在触屏的代码中,我们只要根据手指不同的位置,通过原来代码中的下面方法:

public void setKeyState(int keyCode, boolean state) {        switch (keyCode) {        case KeyEvent.KEYCODE_DPAD_DOWN:            mIskeyDown = state;            break;        case KeyEvent.KEYCODE_DPAD_UP:            mIskeyUp = state;            break;        case KeyEvent.KEYCODE_DPAD_LEFT:            mIskeyLeft = state;            break;        case KeyEvent.KEYCODE_DPAD_RIGHT:            mIskeyRight = state;            break;        }        mAllkeyDown = state;}

用setKeyState()将对应方向的布尔变量设置为true,人自然而然就会往对应方向移动了。
一指触控的代码是实现了onTouchEvent()方法,该方法属于Activity,所以凡是继承了Activity的类,都可以覆盖该方法。
关于该方法,可以见Android开发教程: 触摸屏模拟实现方向键
怎么控制人物移动呢,我是通过获取手指的x,y坐标与人物在屏幕中的x,y坐标的差的绝对值,哪个大就在哪个方向上移动。具体见代码:

public boolean onTouchEvent(MotionEvent event) {    //这是两指触控实现缩放的,在这里先注释掉    //if (event.getPointerCount() == 2) {    //  setMultiTouch(event);    //}    float x = event.getX();    float y = event.getY();    float dx, dy;    float mX = mAnimView.mHeroScreenX, mY = mAnimView.mHeroScreenY;    switch (event.getAction()) {    // 触摸结束    case MotionEvent.ACTION_UP:        isFirst = true;        oldRate = rate;    // 手指离开屏幕,则人物不动,下面是我增加的方法,使所有方向都为false        mAnimView.setKeyStateFalse();          return false;    case MotionEvent.ACTION_DOWN:        // mAnimView.setKeyStateFalse();        dx = x - mX;        dy = y - mY;        int i,j;        float adx=Math.abs(dx);        float ady=Math.abs(dy);        if (adx >= ady) { // move from left -> right            //这里为什么>35,是因为我还要用<35的那些范围用于其它的功能实现。            //后面的48,也是同样道理。            if (dx > 35.0f) {                mAnimView.setKeyState(KeyEvent.KEYCODE_DPAD_RIGHT, true);            } else if (dx<-35.0f){                mAnimView.setKeyState(KeyEvent.KEYCODE_DPAD_LEFT, true);            }        } else { // move from top -> bottom or bottom -> top            if (dy > 48.0f) {                mAnimView.setKeyState(KeyEvent.KEYCODE_DPAD_DOWN, true);            } else if(dy<-48.0f){                mAnimView.setKeyState(KeyEvent.KEYCODE_DPAD_UP, true);            }        }        return true;        /**         * MOVE是介于MotionEvent.ACTION_DOWN和MotionEvent.ACTION_UP之间的,         * 所以通过MOVE来控制人物移动 如果用MotionEvent.ACTION_DOWN的话,         * 则至少在我的手机上,只能每次按一下走一步,太不方便了         */    case MotionEvent.ACTION_MOVE:        dx = x - mX;        dy = y - mY;        if (Math.abs(dx) >= Math.abs(dy)) { // move from left -> right            // or right -> left            if (dx > 0.0f) {                mAnimView.setKeyState(KeyEvent.KEYCODE_DPAD_RIGHT, true);            } else {                mAnimView.setKeyState(KeyEvent.KEYCODE_DPAD_LEFT, true);            }        } else { // move from top -> bottom or bottom -> top            if (dy > 0.0f) {                mAnimView.setKeyState(KeyEvent.KEYCODE_DPAD_DOWN, true);            } else {                mAnimView.setKeyState(KeyEvent.KEYCODE_DPAD_UP, true);            }        }        return true;    }    return super.onTouchEvent(event);}

3.2 二指实现地图缩放

《Android游戏编程之从零开始》里面有讲到,参考这个链接吧多触点实现图片缩放。我是通过上面中注释掉的setMultiTouch(event)方法来实现地图缩放的,详情的话就参加我的代码,本文最后会给出下载链接。 这里遇到一个问题,那就是当地图不断缩小时,屏幕上剩余部分会残留之前刷新的图片,所以每次缩小之前,得先清屏一下。android开发--Canvas清屏只需三句话

if (isShrink) {    Paint p = new Paint();    p.setXfermode(new PorterDuffXfermode(Mode.CLEAR));    mCanvas.drawPaint(p);    p.setXfermode(new PorterDuffXfermode(Mode.SRC));}//接下来可以通过mCanvas.drawColor(Color.WHITE)来改变背景颜色

4. 传感器的应用

4.1 加速度感应器的应用

我通过加速度感应器,实现了两个功能:1.控制人物移动,2.通过摇一摇换人物主角(牧场物语矿石镇的伙伴男女主人公)
参考下面两个文章:
Android游戏开发之小球重力感应实现
Android之摇一摇功能

4.2 光线传感器的使用

没办法, 老师要求要用两个传感器,可是发现可以用的传感器除了加速度感应,其它的实在没什么。。。所以勉强用了个光线传感器,若光线暗的话,就把背景从白色亮的变为灰色(保护眼睛)。。。真的是为了用而用。。。

两个传感器实现代码如下:

/*传感器相关变量 *private SensorManager mSensorMgr = null; *Sensor mSensor = null; *Sensor mSensor2 = null; *mSensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE); *mSensor = mSensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); *mSensor2 = mSensorMgr.getDefaultSensor(Sensor.TYPE_LIGHT); *mSensorMgr.registerListener(this, mSensor,SensorManager.SENSOR_DELAY_GAME); *mSensorMgr.registerListener(this, mSensor2,SensorManager。SENSOR_DELAY_GAME); */public void onSensorChanged(SensorEvent event) {    // 加速度传感器    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {          mGX = event.values[0];        mGY = event.values[1];        mGZ = event.values[2];        setKeyStateFalse();        if (Math.abs(mGX) >= Math.abs(mGY) && Math.abs(mGX) >= 1.0) {            if (mGX >= 0) {                 // 向左走                setKeyState(KeyEvent.KEYCODE_DPAD_LEFT, true);            } else {                // 向右走                setKeyState(KeyEvent.KEYCODE_DPAD_RIGHT, true);            }        } else if (Math.abs(mGX) < Math.abs(mGY) && Math.abs(mGY) >= 1.0) {            // 这里之所以设置成一个大于6.0,一个小于3.0,是因为人拿手机的时候,手机基本上就是倾斜的,mGY肯定大于0.            if (1.0 <mGY && mGY< 4.0) // 向上走                setKeyState(KeyEvent.KEYCODE_DPAD_UP, true);            else if (mGY >= 7.0) { // 向下走                setKeyState(KeyEvent.KEYCODE_DPAD_DOWN, true);            }        }        //摇一摇换主角            int minValue=19;        if (Math.abs(mGX) > minValue || Math.abs(mGY) > minValue || Math.abs(mGZ) > minValue) {            roleId=(roleId+1)%2;        }       }    //光线传感器    else if(event.sensor.getType() == Sensor.TYPE_LIGHT){        float lv=event.values[0];        if(lv>10.0f){            isNight=false;        }        else{            isNight=true;        }    }}

5.增加种植、收割功能

之前在3.1触屏控制人物移动的代码中提到,选取abs|dx|>35或者abs|dy|>48,才允许人物朝相应的方向移动。之所以留出人物周围一部分的范围,是用于种植一些农产品。就是当人物在农田中时,手指触摸人物一小部分范围内,可以种上东西。对种上东西的地方再触摸一次,就收割农产品。(说简单点,其实就是画上一个图片、消除一个图片。。。)
给个图:

这里用到了mMapAcotor数组,若值为-1,表示没有什么。若为0~5,对应6种不同的农产品。根据不同的索引值,在地图位置画上对应农产品的位图。在OnTouchEvent方法中增加的部分代码:

if(adx<=32.0f){    //先算出手指触摸的地方在地图中对应的数组索引    i=(-mAnimView.mMapPosX+(int)x)/mAnimView.TILE_WIDTH;    j=(-mAnimView.mMapPosY+(int)y)/mAnimView.TILE_HEIGHT;    if(mAnimView.mMapAcotor[j][i]==-1){        //随机一个农产品        int tmp=rand.nextInt(mAnimView.totOfProds);        mAnimView.mMapAcotor[j][i]=tmp;        //mAnimView.numOfProds[tmp]++;    }    else{        mAnimView.isHarvest=true; //起不了作用,屏幕没有显示收割。。。        //mAnimView.numOfProds[mAnimView.mMapAcotor[j][i]]--;        mAnimView.mMapAcotor[j][i]=-1;    }}

6. 增加背景音乐设置

详细就见代码,不说了,给个截图吧

        


7. 源代码下载

代码下载链接
0 0
原创粉丝点击