Android安卓手机游戏开发

在android中,事件主要包括点击、长按、拖曳、滑动等操作,这些构成了Android的事件响应,总体来说,所有的事件都由如下三个部分作为基础构成:

按下(action_down),移动(action_move),抬起(action_up)。各种响应归根结底都是基于View以及ViewGroup的,这两者中响应的方法分别有:

View.java中:

publi boolean dispatchTouchEvent(MotionEvent event)

public boolean onTouchEvent(MotionEvent event)

ViewGroup.java中

public boolean dispatchTouchEvent(MotionEvent event)

public boolean onTouchEvent(MotionEvent event)

public boolean onInterceptTouchEvent(MotionEvent event)

在组件嵌套的情况下,对于事件的响应处理会从最顶层的组件不断向子组件传递,一直到最后的View组件。

可以看到ViewGroup中比View中多出了一个onInterceptTouchEvent方法,这是因为ViewGroup组件可以存在子组件,因此需要通过Intercept判断是否将该事件传递到子组件中。

函数的具体功能如下:

onTouchEvent是真正用来进行业务逻辑处理的地方,返回true表示已经将该事件消费,返回false表明事件继续传递。

onInterceptTouchEvent是用来进行判断是否需要对事件进行拦截从而阻止其继续往子组件传递的,返回false表示无需拦截,则递归的调用子组件的dispatchTouchEvent方法;返回true表示需要拦截,则直接调用本组件的onTouchEvent方法进行处理。

以上两个的功能相对好理解一些,最主要的是第三个,之前在网上看了很多,但是都没有讲的特别清楚的。大都说是用于事件分发的,返回true表示不继续分发,返回false表示继续分发。但是一直没讲明白这个跟采用onInterceptTouchEvent的区别在哪里。。

直接点说,Android对于touch事件的处理是通过递归来进行的,而这种递归就体现在dispatchTouchEvent上。以上所写的两个函数就是在dispatchTouchEvent中被调用并且执行从而实现其分发的业务逻辑的。

在dispatchTouchEvent中有可能会调用三个方法:

1、本组件的onInterceptTouchEvent

2、子组件的dispatchTouchEvent

3、本组件的onTouchEvent

ViewGroup中dispatchTouchEvent()具体的执行逻辑:

1、首先执行本组件的onInterceptTouchEvent。如果返回false,表明无需拦截,则调用第二个方法,即子组件的dispatchTouchEvent方法;如果返回true,无需向子组件传递,则直接调用本组件的onTouchEvent方法

2、第一步中如果需要向子组件传递事件。如果递归调用子组件的dispatchTouchEvent返回false,则调用本组件的onTouchEvent方法;如果返回true,则无需调用本组件的onTouchEvent方法

3、根据前两步的执行结果,将该dispatchTouchEvent的返回值返回给父组件的dispatchTouchEvent方法。

view中的dispatchTouchEvent会直接调用其自身的onTouchEvent。

一般没有必要重写dispatchTouchEvent方法,如果一定要重写,请注意调用super.dispatchTouchEvent()方法,否则递归调用到此处即停止。

在不考虑dispatchTouchEvent的情况下,简单的执行流程是这样的:

最顶层的组件首先响应事件,然后不断向子组件进行传递,调用子组件的onInterceptTouchEvent方法,一直到某个组件A的onInterceptTouchEvent方法返回true或者到达了view组件,然后调用该组件的onTouchEvent方法,之后不断向父组件进行返回,调用父组件的onTouchEvent直到某个父组件的onTouchEvent方法返回true。

其实就是个首先从父组件不断向下调用onInterceptTouchEvent,然后从子组件不断向上调用onTouchEvent的过程。

还需要注意的一点是,假如这个过程中某个组件截获并处理了ACTION_DOWN事件,则之后相应的ACTION_MOVE、ACTION_UP等其他事件将不再会被传递到他的子孙组件,而是传递到该组件后就执行返回的流程。

过程中看到有篇文章里对dispatchTouchEvent的代码进行了注释,可以更清楚的说明问题,具体如下,引用地址为:http://blog.csdn.net/hdxiaoyu2/article/details/25563453

 @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
        }

        // Check for interception.
        final boolean intercepted;//拦截的标记变量
        if (actionMasked == MotionEvent.ACTION_DOWN
                || mFirstTouchTarget != null) {
            final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
            if (!disallowIntercept) {

                //调用自身的 onInterceptTochEvent,判断是否需要拦截
                intercepted = onInterceptTochEvent(ev);
                ev.setAction(action); // restore action in case it was changed
            } else {
                intercepted = false;
            }
        } else {
            // There are no touch targets and this action is not an initial down
            // so this view group continues to intercept touches.
            intercepted = true;
        }

        //假如没拦截
        if (!canceled && !intercepted) {
            if (actionMasked == MotionEvent.ACTION_DOWN
                    || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
                    || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {

                if (newTouchTarget == null && childrenCount != 0) {
                    final float x = ev.getX(actionIndex);
                    final float y = ev.getY(actionIndex);
                    // Find a child that can receive the event.
                    // Scan children from front to back.
                    final View[] children = mChildren;

                    final boolean customOrder = isChildrenDrawingOrderEnabled();
                    //遍历所有的子View,并且调用他们的事件分发方法dispatchTouchEvent()

                    for (int i = childrenCount - 1; i >= 0; i--) {                      final int childIndex = customOrder ?
                                getChildDrawingOrder(childrenCount, i) : i;
                        final View child = children[childIndex];
                        if (!canViewReceivePointerEvents(child)
                                || !isTransformedTouchPointInView(x, y, child, null)) {
                            continue;
                        }

                        newTouchTarget = getTouchTarget(child);
                        //newTouchTarget表示事件传递的View目标,当不为空的时候,直接跳出循环
                        if (newTouchTarget != null) {

                            newTouchTarget.pointerIdBits |= idBitsToAssign;
                            break;
                        }

                        resetCancelNextUpFlag(child);
                        //递归调用子View分发事件方法,
                        if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) { 

                            mLastTouchDownTime = ev.getDownTime();
                            mLastTouchDownIndex = childIndex;
                            mLastTouchDownX = ev.getX();
                            mLastTouchDownY = ev.getY();
                            //设置分发目标newTouchTarget为当前View
                            newTouchTarget = addTouchTarget(child, idBitsToAssign);
                            //标记子View的分发结果,为True的话,下面的代码是不会调用当前View的onTouch方法的,也就是规则1生成的原因
                            alreadyDispatchedToNewTouchTarget = true;
                            break;
                        }
                    }
                }

            }
        }

        if (mFirstTouchTarget == null) {
            // No touch targets so treat this as an ordinary view.
            handled = dispatchTransformedTouchEvent(ev, canceled, null,
                    TouchTarget.ALL_POINTER_IDS);
        } else {
            // Dispatch to touch targets, excluding the new touch target if we already
            // dispatched to it.  Cancel touch targets if necessary.
            TouchTarget predecessor = null;
            TouchTarget target = mFirstTouchTarget;
            while (target != null) {
                final TouchTarget next = target.next;

                //如果刚才alreadyDispatchedToNewTouchTarget设为True的话,就不执行下面的dispatchTransformedTouchEvent
                //alreadyDispatchedToNewTouchTarget是由子View的onTouch返回值决定的,

                if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
                    handled = true;
                } else {
                    final boolean cancelChild = resetCancelNextUpFlag(target.child)
                            || intercepted;

                    //执行自身的Touch事件,
                    if (dispatchTransformedTouchEvent(ev, cancelChild,
                            target.child, target.pointerIdBits)) {
                        handled = true;
                    }
                    if (cancelChild) {
                        if (predecessor == null) {
                            mFirstTouchTarget = next;
                        } else {
                            predecessor.next = next;
                        }
                        target.recycle();
                        target = next;
                        continue;
                    }
                }
                predecessor = target;
                target = next;
            }
        }
    }

另外还看到两篇将的不错的,可以作为参考:

http://www.infoq.com/cn/articles/android-event-delivery-mechanism

http://blog.csdn.net/hdxiaoyu2/article/details/25563453

Android安卓手机游戏开发

时间: 2024-08-02 02:49:34

Android安卓手机游戏开发的相关文章

海量安卓andriod手机游戏开发手机app开发PDF电子书定制制作下载

本人背靠海量纸质图书,可以制作各种纸质书籍的电子化,有需要可以Q:1481449626 <Andriod移动开发技术与应用>作者:李学华主编 页数:228 出版社:北京市:北京邮电大学出版社 出版日期:2013.08 简介:本书以生动具体的案例介绍android移动开发技术,力求通过实际的应用案例使读者快速掌握android移动开发技术. <移动终端应用开发技术 Android实战>作者:林少丹著 页数:232 出版社:北京市:机械工业出版社 出版日期:2013.02 简介:本书共

Android研究之游戏开发摄像头更新

 游戏中摄像头的原理介绍        在游戏开发中更新摄像头的位置可以决定屏幕显示的内容,尤其是RPG类游戏摄像头有着非常重要的作用,我举一个例子 有时候我们在玩RPG游戏的时候进入一个新的场景 触发一段脚本后 发现镜头开始向上移动 根据镜头移动玩家可以大概浏览一下这个场景有什么东西 ,触发什么样的剧情.这个实现的方式就是游戏摄像头原理.上章学习了Android游戏开发地图编辑器有需要的可以看下. 如图所示:首先摄像头显示的区域也是手机屏幕显示的区域 如果需要更改摄像头的位置  其实是更改

Android研究之游戏开发碰撞检测

 游戏碰撞的大致可以分为这几种类 1.主角与边界的碰撞,限制主角不能走出手机屏幕外. 2.主角与物理层的碰撞,与地图中的房子 桌子 椅子等等. 3.主角与游戏人物之间的碰撞,这里指NPC等. 4.主角与脚本框发生的碰撞,例如走进房间出线一段剧情对话等等. 由此可见游戏中的碰撞主要是可以分为 1.点与矩形之间的碰撞 2.矩形与矩形之间的碰撞 3.圆形与圆形之间的碰撞 4.圆形与矩形之间的碰撞          今天我主要介绍一下以上中最特殊的一个碰撞方式 主角与物理层之间的碰撞. 如图所示:每

Android研究之游戏开发处理按键的响应

1.onKeyDown 方法 onKeyDown 方法是KeyEvent.Callback 接口中的一个抽象方法,重写onKeyDown 方法可以监听到按键被按下的事件,我们先看看onKeyDown方法的函数原型. 第一个参数为键值,手机中每一个按钮都拥有一个完全独立的键值 通过按键键值就可以确定当前按下的是那一个按键. 第二个参数为按键事件,  该对象中保存着当前按键的所有信息 比如 按键发生的时间 按键发生的次数  按键发生的类型等等. 通过以上两个参数就可以拿到当前按键事件的所附带的一切信

Cocos2d-x手机游戏开发视频教程 手游入门到精通视频教程

Cocos2d-x是一个开源的移动2D游戏框架,MIT许可证下发布的.Cocos2d-X发展的重点是围绕Cocos2d跨平台,Cocos2d-x提供的框架. 手机游戏,可以写在C++或者Lua中,使用API是Cocos2d-iPhone完全兼容.Cocos2d-x项目可以很容易地建立和运行在iOS,Android,黑莓Blackberry等操作系统中. Cocos2d-x还支持Windows.Mac和Linux等桌面操作系统,因此,开发者编写的源代码很容易在桌面操作系统中编辑和调试. 当前3G技

安卓手机应用开发培训讲义笔记和心得(Java和Mono两种模式)

培训内容    —————————————————————————————————————————————————————————————————— 昨天夏主要讲了两个方面的安卓手机开发 一:Java语言开发手机安卓 ① 准备发软件工具  环境   (可以直接本地搭建环境) 开发IDE:Eclipse(仅次于VS的强大IDE) 其它一大堆的东西:Android SDK  模拟器   SDK JDK DAT ②  window下搭建Eclipse+andro开发环境 安装步骤:一般首先安装ava运

Android研究之游戏开发帧动画实现

 1.帧动画的原理        帧动画帧动画顾名思义,一帧一帧播放的动画就是帧动画. 帧动画和我们小时候看的动画片的原理是一样的,在相同区域快速切换图片给人们呈现一种视觉的假象感觉像是在播放动画,其实不过是N张图片在一帧一帧的切换罢了.对摄像头不清楚的请看Android研究之游戏开发摄像头更新        如图所示:人物行走动画的实现方式, 4帧行走动画在播放区域 一帧一帧向左切换播放 给人们一种播放动画的假象 ,图片就动了起来, 很简单吧,其它三方向播放动画的方法类似我就不再一一举例.

手机游戏开发工程师培训教程

我分享一套系统性学习手游开发的课程,能让你完整的学习手游开发,并且配套有几个企业实战的项目咨询QQ:779591710 课程有以下六大特色:一.业内独家专业手游开发网络培训课程二.注重手机游戏开发基础,全程项目贯穿三.Android4.3游戏开发基础.Cocos2D-X,Unity2D,Unity3D一个都不能少四.课程首次涉及跨平台游戏引擎技术,国内独家(AndEngine引擎.libGDX引擎)五.跨平台技术(HTML5技术)六.经典游戏重现(捕鱼达人.斗地主.天天酷跑.围住神经猫) 专题一

Android研究之游戏开发主角与地图的滚动

 人物移动地图的平滑滚动处理         玩过rpg游戏的朋友应该都知道RPG的游戏地图一般都比较大 今天我和大家分享一下在RPG游戏中如何来处理超出手机屏幕大小的游戏地图. 如图所示为程序效果动画图 . 地图滚动的原理        在本人之前博客的文章中介绍过人物在屏幕中的移动方式,因为之前拼的游戏地图是完全填充整个手机屏幕的,所以无需处理地图的平滑滚动.这篇文章我着重的向大家介绍一下控制人物移动后地图滚动的处理方式.举个例子 如上图所示 比如人物向右移动,如果地图贴在屏幕左边边界