图片 4

[GitHub开源]Android自定义View实现微信打飞机游戏

七日游表达

  1. 飞机一贯发射子弹,用指尖滑动可以改换飞机的地点
  2. 差异的敌机抗击打才干不等,当敌机被击中一定子弹数量时会爆炸,爆炸有动漫效果
  3. 每间距一段时间都会有双发子弹或炸弹等器具嘉奖
  4. 获得双发子弹之后,子弹变为双发
  5. 收获炸弹道具之后,能够通过双击将显示屏内的保有敌机炸毁图片 1
    图片 2

3.1 绘制进度

三大进度:onMeasure衡量、onLayout构造、onDraw画

GitHub: 

实现

  • 大家定义了Sprite类,即Smart类,游戏中的飞机、子弹、表彰器械等都是三翻五次自该类,我们透过moveTo(卡塔尔(قطر‎、move(卡塔尔(قطر‎等情势调控Smart的职分,通过beforeDraw(卡塔尔(قطر‎、onDraw(卡塔尔国、afterDraw(卡塔尔国达成相应的绘图逻辑。精灵类及其子类世袭如下所示:

这里写图片描述

  • GameView是大家自定义的View类,首要重写了onDraw()onTouchEvent()主意。onDraw(卡塔尔(قطر‎源码如下所示:

    @Override
    protected void onDraw(Canvas canvas) {
        //我们在每一帧都检测是否满足延迟触发单击事件的条件
        if(isSingleClick()){
            onSingleClick(touchX, touchY);
        }
    
        super.onDraw(canvas);
    
        if(status == STATUS_GAME_STARTED){
            drawGameStarted(canvas);
        }else if(status == STATUS_GAME_PAUSED){
            drawGamePaused(canvas);
        }else if(status == STATUS_GAME_OVER){
            drawGameOver(canvas);
        }
    }
    

    在某一整天GameView有二种情景:游戏开首STATUS_GAME_STARTED、游戏暂停STATUS_GAME_PAUSED和玩耍结束STATUS_GAME_OVE帕杰罗。在分裂的动静下大家会调用分裂的绘图方法,那多少个措施中都会调用方法postInvalidate(),这样驱动着View不断重绘,进而不断调用onDraw()措施完毕游戏的动态效果。关于绘图工夫,能够远瞻另一篇博文《Android中Canvas绘图功底详明(附源码下载)》。

  • 大家也重写了GameView的onTouchEvent()办法。由于View只帮忙单击事件,而不协助双击事件,所以我们友好定义了多少个resolveTouchType()方法,通过这些措施可以合成大家同心合力想要的平地风波类型,譬如双击事件。我们记录MotionEvent.ACTION_DOWNMotionEvent.ACTION_UP的岁月,一次单击事件由ACTION_DOWN和ACTION_UP四个事件合成,假诺从ACTION_DOWN到ACTION_UP间隔小于200纳秒,大家就以为发生了三遍单击事件。一遍双击事件由八个点击事件合成,五个单击事件时期小于300纳秒,大家就感觉发生了一遍双击事件。在接触了双击事件的时候,我们就能够触发炸弹,将荧屏内的敌机都炸毁。当处于ACTION_MOVE状态时,大家就通过event.getX()event.getY()变越来越大战机的岗位。关于MotionEvent的详细消息能够参另一篇博文《Android中Touch伊夫nt触摸事件机制》。

  • 咱俩还为GameView提供了start(卡塔尔(قطر‎、pause(卡塔尔(قطر‎、resume(卡塔尔(قطر‎和destroy(卡塔尔(قطر‎等办法,使其颇有雷同于Activity的生命周期,方便在Activity中对GameView举行景况管理。

  • 小敌机类,体量小,抗打击工夫低;中敌机类,容积中等,抗打击技巧中等;大敌机类,体量大,抗打击本领强。当敌机销毁的时候,大家运用了爆炸效果,使用了之类的图纸:

这里写图片描述

那张图片演示了爆炸从初始到甘休14个阶段的效能图,大家用两帧绘制爆炸的二个品级,那样完整绘制贰个爆裂效果必要28帧,在绘制完尾数阶段之后,Explosion类会销毁本身。

全体源码已经开源到GitHub,即便以为不错,迎接大家Star和Fork!

GitHub:
https://github.com/iSpring/GamePlane/

1.3.1 velocityTracker速度追踪

//追踪当前速度
VelocityTracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);
//获取1000ms时间的速度
velocityTracker.computeCurrentVelocity(1000);
int xVelocity = (int) velocityTracker.getXVelocity();
int yVelocity = (int) velocityTracker.getYVelocity();
//回收
velocityTracker.clear();
velocityTracker.recycle();

实现

大家定义了Sprite类,即Smart类,游戏中的飞机、子弹、奖赏器械等都以三回九转自该类,大家透过moveTo(卡塔尔(قطر‎、move(卡塔尔(قطر‎等方法调节精灵的职分,通过beforeDraw(卡塔尔国、onDraw(卡塔尔国、afterDraw(卡塔尔国实现相应的绘图逻辑。Smart类及其子类继承如下所示:

图片 3

GameView是我们自定义的View类,主要重写了onDraw()onTouchEvent()方法。onDraw(卡塔尔源码如下所示:

@Override
protected void onDraw(Canvas canvas) {
    //我们在每一帧都检测是否满足延迟触发单击事件的条件
    if(isSingleClick()){
        onSingleClick(touchX, touchY);
    }

    super.onDraw(canvas);

    if(status == STATUS_GAME_STARTED){
        drawGameStarted(canvas);
    }else if(status == STATUS_GAME_PAUSED){
        drawGamePaused(canvas);
    }else if(status == STATUS_GAME_OVER){
        drawGameOver(canvas);
    }
}

在某一任何时候GameView有三种状态:游戏开始STATUS_GAME_STARTED、游戏暂停STATUS_GAME_PAUSED和娱乐甘休STATUS_GAME_OVE君越。在分化的情况下大家会调用区别的绘图方法,这多少个方式中都会调用方法postInvalidate(),那样驱动着View不断重绘,进而不断调用onDraw()主意完毕游戏的动态效果。关于绘图技术,能够参见另一篇博文《Android中Canvas绘图底工详细明白(附源码下载)》。

咱俩也重写了GameView的onTouchEvent()方法。由于View只协助单击事件,而不帮助双击事件,所以大家友好定义了二个resolveTouchType()方式,通过这一个主意可以合成大家温馨想要的风云类型,比方双击事件。大家记录MotionEvent.ACTION_DOWNMotionEvent.ACTION_UP的大运,三回单击事件由ACTION_DOWN和ACTION_UP多个事件合成,假诺从ACTION_DOWN到ACTION_UP间隔小于200纳秒,我们就认为产生了叁遍单击事件。二次双击事件由八个点击事件合成,五个单击事件之间小于300纳秒,我们就以为发生了一遍双击事件。在触发了双击事件的时候,我们就能够触发炸弹,将显示器内的敌机都炸毁。当远在ACTION_MOVE状态时,大家就由此event.getX()event.getY()改换大战机的岗位。关于MotionEvent的详细音讯能够参另一篇博文《Android中Touch伊芙nt触摸事件机制》。

小编们还为GameView提供了start(卡塔尔、pause(State of Qatar、resume(卡塔尔国和destroy(卡塔尔国等办法,使其独具相符于Activity的生命周期,方便在Activity中对GameView举行状态管理。

小敌机类,体量小,抗打击掌艺低;中敌机类,体量中等,抗打击本领中等;大敌机类,体量大,抗打击才能强。当敌机销毁的时候,大家运用了爆炸效果,使用了之类的图纸:

图片 4

那张图片演示了爆炸从伊始到停止拾七个阶段的效果图,大家用两帧绘制爆炸的一个品级,这样完整绘制一个爆裂效果需求28帧,在绘制完最终一个品级之后,Explosion类会销毁自个儿。

GitHub:
https://github.com/iSpring/GamePlane/

1.3.2 GestureDetector

检查实验单击、滑动、长按、双击等行为。

//创建对象,实现OnGestureListener或者OnDoubleTapListener接口。this代表实现的接口
GestureDetector mGestureDetector = new GestureDetector(this);
//解决长安无法拖动
mGestureDetector.setIsLongpressEnabled(false);
//在onTouchEvent中接管监听view
boolean onsume = mGestureDetector.onTouchEvent(event);
return onsume;
```javascript
然后在OnGestureListener和OnDoubleTapListener监听
OnGestureListener:

onDown:即ACTION_DOWN
onShowPress:手指按下,未放手未拖动
onSingleTapUp:单击行为的ACTION_UP
onScroll:按下并拖动
onLongPress:长按
onFling:按下,飞速滑动后卸下

onDoubleTapListener:
onSingleTapConfirmed:单击行为 (不会是双击中的一次)
onDoubleTap:双击
onDoubleTapEvent:双击行为中的ACTION_DOWN ACTION_MOVE
ACTION_UP都会触发

###1.3.3 滑动
scrollTo/scrollBy
只滑动内容,不改变view在布局中的位置
mScrollX、mScrollY,view内容位置和布局位置的距离
从左向右滑动100,mSrollX = -100; 其他类似

#二 view的事件分发
##2.1 事件传递规则
用一张图就可以掌握

![](http://upload-images.jianshu.io/upload_images/3633065-46e707cef0d7f2a0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

箭头代表代码会这样走,会如何去调用
onInterceptTouchEvent事件拦截,只有viewgroup才有
除了onInterceptTouchEvent其他的返回true都是消费。
理清这个图,在脑海里有个U型概念,记住onInterceptTouchEvent,其它规则都相似
##2.2 滑动冲突
理解了事件的分发,滑动冲突就很好解决了。方法通常有两种
外部拦截:父视图需要就拦截,不需要就分发下去。
内部拦截:父视图都不拦截,子视图需要就消费,不需要就传递给父视图消费。
这里推荐使用外部拦截:即onInterceptTouchEvent
```javascript
case MotionEvent.ACTION_DOWN:
    intercepted = false;
    break;
case MotionEvent.ACTION_MOVE:
    if (需要父视图消费){
        intercepted = true;
    } else {
        intercepted = false;
    }
    break;
case MotionEvent.ACTION_UP:
    intercepted = false;
    break;

本博文演示了哪些通过自定义View达成Wechat自慰游戏。

不论什么事源码已经开源到GitHub,假诺认为不错,迎接大家Star和Fork!

3.1.1

怎么样绘制出来:
DecorView:顶级view
Viewroot:即viewrootImpl,WindowManager创建ViewRoot来管理DecorView

DecorView经常为八个竖直方向的LinearLayout,LinearLayout分为上下几个部分(主要跟设置主旨有关)
上边是标题栏,上面是内容栏。例:activity中setContentView实际不是setView

总体源码已经开源到GitHub,借使认为不错,招待大家Star和Fork!

事情发生前写了无数自定义View理论方面包车型地铁篇章,具体能够仰慕《Android中自定义View、ViewGroup理论根基详细解释》
。 理论辅导施行,本博文演示了何等通过自定义View达成Wechat手淫游戏。

onDraw

(viewrootImpl)performTraversals -> (viewrootImpl)performDraw ->
(viewrootImpl)Draw -> (viewrootImpl)drawSoftware
看下drawSoftware有那样一句话

mView.draw(canvas);

以此draw方法正是view.java中的draw
在View中draw犹如下代码:

...
drawBackground(canvas);
...
onDraw(canvas);
...
dispatchDraw(canvas);
...

末段调用到ViewGroup的dispatchDraw,遍历子view

for (int i = disappearingCount; i >= 0; i--) {
   final View child = disappearingChildren.get(i);
   more |= drawChild(canvas, child, drawingTime);
}

看下drawChild

protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
        return child.draw(canvas, this, drawingTime);
    }

16日游表达

  1. 飞机平素发射子弹,用指头滑动能够转移飞机的岗位
  2. 不等的敌机抗击打本事不等,当敌机被打中一定子弹数量时会爆炸,爆炸有动漫效果
  3. 每间距一段时间都会有双发子弹或炸弹等道具嘉勉
  4. 获得双发子弹之后,子弹变为双发
  5. 获取炸弹装备之后,能够经过双击将荧屏内的富有敌机炸毁

这边写图片描述

此处写图片描述


1.2.2 TouchSlop:

被系统料定为滑行的小不点儿间距
赢得那些值:ViewConfiguration.get(Context卡塔尔国.getScaledTouchSlop(State of Qatar;
ViewConfiguration中还定义了众多任何值

1.2.1 MotionEvent:

事件:ACTION_DOWN、ACTION_UP、ACTION_MOVE、ACTION_CANCEL等
点击事件坐标:
getX/getY,当前view左上角坐标;
getRawX/getRawY,想对于手提式有线电话机显示屏左上角坐标;

1.2 MotionEvent && TouchSlop

一 view基础

地点参数、MotionEvent、TouchSlop、VelocityTracker、GestureDetector和滑动

Measure

(viewrootImpl)performTraversals -> (viewrootImpl)performMeasure ->
(DecorViwe)measure -> (DecorViwe)onMeasure
DecorViwe的onMeasure中调用super.onMeasure即 (FrameLayout)onMeasure
在(FrameLayout)onMeasure中:

int count = getChildCount();
...
for (int i = 0; i < count; i++) {
    final View child = getChildAt(i);
    ...
    measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
    ...

如此遍历全数view树,layout进程看似

1.3 VelocityTracker、GestureDetector、滑动

三 View的干活原理

3.1.2三大流程

viewrootImpl中performTraversals函数带头绘制DecorView
performTraversals中各种调用performMeasure、performLayout、performDraw

1.1 地方参数

相对于父容器
left:左上角横坐标 right:右下角横坐标 top:左上角纵坐标
bottom:右下角纵坐标
x:左上角横坐标 y:左上角纵坐标
translationX:左上角想对于父容器的横向偏移量
translationY:左上角想对于父容器的纵向偏移量 偏移量默以为0;
八个参数都有get/set方法:e.g:setLeft(卡塔尔; getLeft(卡塔尔(قطر‎;
width = right – left;
height = bottom – top;
view平移时:left、right、top、bottom原始音信,值不变,对应改动的是x、y、translationX、translationY;

发表评论

电子邮件地址不会被公开。 必填项已用*标注