Android Canvas打飞机之让子弹飞

上一篇的主角已经登场,如果你还没见过,可以通过这里进行查看<a href="http://www.jianshu.com/p/8b65e7e73f70">主角秀</a>
主角登场没有武器是不行的,所以这一篇的核心就是给主角进行武器装备。

device-2016-12-24-142259.png
1.创建一个子弹的类DrawPlayerBullet
package com.tangyx.game.holder;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;

import com.tangyx.game.util.ScreenUtils;

/**
 * Created by tangyx on 2016/12/24.
 *
 */

public class DrawPlayerBullet extends DrawGame {
    /**
     * 子弹样式
     */
    private Bitmap mBullet;
    private float mBulletX;
    private float mBulletY;
    /**
     * 子弹模式
     */
    public final static int PLAYER_BULLET_A=1;//垂直中间发出
    public final static int PLAYER_BULLET_B=2;//左边发出
    public final static int PLAYER_BULLET_C=3;//右边发出
    public final static int PLAYER_BULLET_D=4;//双重子弹
    private int mBulletType=0;
    /**
     * 子弹运行速度
     */
    private float mBulletSpeed=0;
    /**
     * 子弹是否有效,当子弹飞出屏幕不可见的时候,这时候子弹已经失效。
     */
    private boolean isDead;


    public DrawPlayerBullet(Context context, Object... objects) {
        super(context);
        initialize(objects);
    }

    @Override
    void initialize(Object... objects) {
        mBulletX = (float) objects[0];
        mBulletY = (float) objects[1];
        mBullet = (Bitmap) objects[2];
        mBulletType = (int) objects[3];
    }

    @Override
    void onDraw(Canvas canvas) {
        canvas.drawBitmap(mBullet,mBulletX,mBulletY,mPaint);
    }

    @Override
    void updateGame() {
        onSetSpeed();
        switch (mBulletType){
            case PLAYER_BULLET_D:
            case PLAYER_BULLET_A:
                mBulletY -=mBulletSpeed;
                break;
            case PLAYER_BULLET_B://左边倾斜飞行
                mBulletY -=mBulletSpeed;
                mBulletX -=mBulletSpeed/4;
                break;
            case PLAYER_BULLET_C://右边倾斜飞行
                mBulletY -=mBulletSpeed;
                mBulletX +=mBulletSpeed/4;
                break;
        }
        if(mBulletY<0){
            isDead = true;
        }
    }

    /**
     * 根据屏幕高度计算子弹飞行的速度
     */
    private void onSetSpeed(){
        float screenHeight = ScreenUtils.getScreenHeight(getContext());
        switch (mBulletType){
            case PLAYER_BULLET_B:
            case PLAYER_BULLET_C:
            case PLAYER_BULLET_D:
            case PLAYER_BULLET_A:
                mBulletSpeed = screenHeight / 48f;
                break;
        }
    }

    public boolean isDead() {
        return isDead;
    }

}
2.目前主要实现了三种武器模式,普通武器,双重武器以及散弹武器。

<b>普通武器:</b>子弹出发的位置位于战机当前位置的中心(黄色子弹)
<b>双重武器:</b>子弹出发的位置位于战机当前位置的两边,每次发出由两组子弹出现,一边一组子弹对称(红色子弹)
<b>散弹武器:</b>每次生成三组子弹,位于战机当前位置,一边一组和中心一组(月牙形子弹)
每一颗子弹我们也可以看做一个对象,这个对象就是DrawPlayerBullet。DrawPlayerBullet根据不同的子弹类型来实现不同的逻辑,其实每一颗子弹都是自己一个单独的运行逻辑,和其他子弹没有关系,只需要按照顺序绘制出来就能产生一体的感觉。
<b>子弹类的使用方式:</b>

3.回到GameView类,定义子弹相关的参数
Paste_Image.png
4.在GameView类中自定义一个添加主角子弹的方法并且实现逻辑
/**
     * 添加主角子弹
     */
    private void addPlayerBullet(){
        mCountPlayerBullet++;
        int mCreatePlayerBullet = 7;//间接性循环加入子弹
        if(mCountPlayerBullet % mCreatePlayerBullet ==0){
            int bullet = mPlayer.getBulletType();
            float playerX = mPlayer.getPlayerX();
            float playerY = mPlayer.getPlayerY();
            float bulletX;
            switch (bullet){
                case DrawPlayerBullet.PLAYER_BULLET_A:
                    bulletX = playerX+(mPlayer.getWidth()-mPlayerBulletA.getWidth())/2;
                    mPlayerBullets.add(new DrawPlayerBullet(getContext(),bulletX, playerY,mPlayerBulletA,bullet));
                    break;
                case DrawPlayerBullet.PLAYER_BULLET_B:
                case DrawPlayerBullet.PLAYER_BULLET_C:
                    //中间
                    bulletX = playerX+(mPlayer.getWidth()-mPlayerBulletC.getWidth())/2;
                    mPlayerBullets.add(new DrawPlayerBullet(getContext(),bulletX, playerY,mPlayerBulletC,DrawPlayerBullet.PLAYER_BULLET_A));
                    //左边
                    bulletX = playerX - mPlayerBulletC.getWidth();
                    mPlayerBullets.add(new DrawPlayerBullet(getContext(),bulletX, playerY,mPlayerBulletC,DrawPlayerBullet.PLAYER_BULLET_B));
                    //右边
                    bulletX = playerX + mPlayer.getWidth();
                    mPlayerBullets.add(new DrawPlayerBullet(getContext(),bulletX, playerY,mPlayerBulletC,DrawPlayerBullet.PLAYER_BULLET_C));
                    break;
                case DrawPlayerBullet.PLAYER_BULLET_D:
                    //左边
                    bulletX = playerX;
                    mPlayerBullets.add(new DrawPlayerBullet(getContext(),bulletX,playerY,mPlayerBulletB,bullet));
                    //右边
                    bulletX = playerX+mPlayer.getWidth()-mPlayerBulletB.getWidth();
                    mPlayerBullets.add(new DrawPlayerBullet(getContext(),bulletX, playerY,mPlayerBulletB,bullet));
                    break;
            }
        }
        for (int i=0;i<mPlayerBullets.size();i++) {
            DrawPlayerBullet bullet = mPlayerBullets.get(i);
            if(bullet.isDead()){//如果有子弹已经飞出屏幕直接移除。
                mPlayerBullets.remove(bullet);
            }else{
                bullet.updateGame();
                bullet.onDraw(mCanvas);
            }
        }
        //模拟子弹类型变化
        mTempBulletType++;
        if(mTempBulletType == 50){
            mPlayer.setBulletType(DrawPlayerBullet.PLAYER_BULLET_D);
        }else if(mTempBulletType == 100){
            mPlayer.setBulletType(DrawPlayerBullet.PLAYER_BULLET_C);
        }
    }```

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/3982371-3fe6f1397fe9c730.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
类型PLAYER_BULLET_B,PLAYER_BULLET_C是一起使用的,因为他就是双重子弹武器。
<b>实现思路:</b>
通过得到当前战机的位置X,Y。并且得到当前主角子弹的设置的类型。<b>DrawPlayer</b>中新增了一个参数

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/3982371-7884131682b0a628.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

根据子弹类型进入不同的分子设置子弹X的坐标。
Y为什么不需要设置?因为Y就是战机的位置,子弹肯定是从飞机的位置发射的。
除了普通武器,其他武器为了保证子弹的合理性所以需要设置好每一组子弹的x坐标位置,并且传入子弹的类型,然后去<b>DrawPlayerBullet</b>类中进行对应逻辑计算。

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/3982371-42f475b1d729936e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

######5.为了保证游戏的流畅性和性能,肯定不能一直都在加入子弹,每一个子弹都是一个新生成的对象,会占用内存,所以我们需要处理子弹是否失效,如果失效就需要移除对象。
子弹失效的判断通过子弹Y的坐标是否小于0,因为子弹是往上运动, 所以Y坐标在减小,小于0肯定就飞出顶部屏幕了,所以直接就在<b>DrawPlayerBullet</b>中判断失效后,移除集合。

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/3982371-77c0ba5a6846bb1d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


![Paste_Image.png](http://upload-images.jianshu.io/upload_images/3982371-3a991ba887ba4861.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


######6.在GameView的onGameDraw方法中调用子弹类,只有在游戏运行状态才执行子弹的逻辑处理。

/**
* 绘制内容以及更新内容
*/
private void onGameDraw(){
if(mCanvas==null)return;
mCanvas.drawColor(Color.WHITE);
//背景
mDrawBackground.onDraw(mCanvas);
mDrawBackground.updateGame();
//主角
mPlayer.onDraw(mCanvas);
mPlayer.updateGame();
//判断当前游戏状态
switch (GAME_STATE){
case ING:
addPlayerBullet();
break;
case READY:
mPlayer.onDrawCollect(mCanvas,getContext().getString(R.string.reading));
break;
case PAUSE:
mPlayer.onDrawCollect(mCanvas,getContext().getString(R.string.conution));
break;
}
}```


bullet.gif

其他更多的思路就需要自己通过源码去了解。
<b>实践才是唯一的真理。</b>
<a href="https://github.com/tangyxgit/GameCanvas">源码传送门</a>
<a href="http://www.jianshu.com/p/8b65e7e73f70">上一篇</a>     <a href="http://www.jianshu.com/p/1114eca3393b">下一篇</a>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容