博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
人机交互实验:Android开发之人物移动、地图滑动、传感器、触屏的应用
阅读量:4156 次
发布时间:2019-05-25

本文共 8478 字,大约阅读时间需要 28 分钟。

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

1.程序介绍

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

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

2.人物移动和地图滑动

参考该博客

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

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的类,都可以覆盖该方法。
关于该方法,可以见
怎么控制人物移动呢,我是通过获取手指的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)方法来实现地图缩放的,详情的话就参加我的代码,本文最后会给出下载链接。 这里遇到一个问题,那就是当地图不断缩小时,屏幕上剩余部分会残留之前刷新的图片,所以每次缩小之前,得先清屏一下。

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.通过摇一摇换人物主角(牧场物语矿石镇的伙伴男女主人公)

参考下面两个文章:

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 
= 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. 源代码下载

你可能感兴趣的文章
Multiple Object Tracking with High Performance Detection and Appearance Feature
查看>>
深度学习入门(上)-第一章 必备基础知识点
查看>>
Python中使用中文
查看>>
Python绘图详解
查看>>
Python 各种IDE比较
查看>>
ImportError: No module named cv2 解决方法
查看>>
python中if __name__ == '__main__': 的解析
查看>>
ubuntu unzip解压时提示错误 解决方法
查看>>
sprintf函数的说明
查看>>
BOOST_TYPEOF和BOOST_AUTO 作用
查看>>
白化原理及Matlab实现
查看>>
随机森林概述
查看>>
applet部署,无需修改客户端设置。
查看>>
查看数据库sql执行效率
查看>>
JAVA学习积累
查看>>
JVM原理
查看>>
ClassLoader简介
查看>>
jquery UI 写的拖拽功能
查看>>
Spring容器-Bean的生命周期
查看>>
oracle学习积累
查看>>