美文网首页AndroidAndroid知识Android开发
Android Canvas打飞机之敌机出场秀

Android Canvas打飞机之敌机出场秀

作者: Galaxy北爱 | 来源:发表于2016-12-28 16:25 被阅读228次

今天通过关卡模拟学习绘制敌机以及敌机出场的动画,我随意写了一些简单的逻辑算法,差不多26种模式,其实也是主要使用<a href="http://www.jianshu.com/p/1114eca3393b">DrawEnemy</a>来绘制敌机出场逻辑。

device-2016-12-28-162117.png
1.创建一个管理关卡的抽象类
public abstract class BaseLevel {
    private Context context;

    public BaseLevel(Context context,Object... objects) {
        this.context = context;
        initialize(objects);
    }

    public abstract void initialize(Object... objects);
    public abstract Map<Integer,Integer> enemyLevelArray(int enemyArrayIndex);

    public Context getContext() {
        return context;
    }
}```

######2.建立游戏的第一关(整个游戏我也只写了一关),创建Level1类继承上面的抽象类,有两个方法解释一下。

<b>initialize()</b>关卡初始化,比如当前关卡需要用到的各种资源。
<b>enemyLevelArray(int enemyArrayIndex)</b>每次循环都会来调用此方法获取当前需要出场的敌机,不能一次性加入画布中,不然会很卡,甚至奔溃(oom内存溢出)。
初始化的方法没有什么特点需要介绍,主要说说获取敌机出场的思路。

/**
* 获取每一波分配好的敌机集合
* @param enemyArrayIndex
* @return
*/
@Override
public Map<Integer,Integer> enemyLevelArray(int enemyArrayIndex) {
Map<Integer,Integer> tempMap = new HashMap<>();
switch (enemyArrayIndex){
case 0:
tempMap.put(DrawEnemy.TYPE_E,3);
tempMap.put(DrawEnemy.TYPE_A,4);
break;
case 1:
tempMap.put(DrawEnemy.TYPE_E,3);
tempMap.put(DrawEnemy.TYPE_D,4);
break;
case 2:
tempMap.put(DrawEnemy.TYPE_E,3);
tempMap.put(DrawEnemy.TYPE_B,4);
break;
case 3:
tempMap.put(DrawEnemy.TYPE_E,3);
tempMap.put(DrawEnemy.TYPE_C,4);
break;
case 4:
tempMap.put(DrawEnemy.TYPE_E,3);
tempMap.put(DrawEnemy.TYPE_F,4);
break;
case 5:
tempMap.put(DrawEnemy.TYPE_E,4);
tempMap.put(DrawEnemy.TYPE_G,3);
break;
case 6:
tempMap.put(DrawEnemy.TYPE_E,4);
tempMap.put(DrawEnemy.TYPE_H,4);
break;
case 7:
tempMap.put(DrawEnemy.TYPE_E,4);
tempMap.put(DrawEnemy.TYPE_I,4);
break;
case 8:
tempMap.put(DrawEnemy.TYPE_E,4);
tempMap.put(DrawEnemy.TYPE_A,2);
tempMap.put(DrawEnemy.TYPE_J,4);
break;
case 9:
tempMap.put(DrawEnemy.TYPE_E,4);
tempMap.put(DrawEnemy.TYPE_D,2);
tempMap.put(DrawEnemy.TYPE_K,4);
break;
case 10:
tempMap.put(DrawEnemy.TYPE_L,4);
break;
case 11:
tempMap.put(DrawEnemy.TYPE_M,4);
break;
case 12:
tempMap.put(DrawEnemy.TYPE_G,4);
break;
case 13:
tempMap.put(DrawEnemy.TYPE_E,4);
break;
case 14:
tempMap.put(DrawEnemy.TYPE_E,4);
tempMap.put(DrawEnemy.TYPE_N,4);
break;
case 15:
tempMap.put(DrawEnemy.TYPE_E,4);
tempMap.put(DrawEnemy.TYPE_O,4);
break;
case 16:
tempMap.put(DrawEnemy.TYPE_E,4);
break;
case 17:
tempMap.put(DrawEnemy.TYPE_P,4);
break;
case 18:
tempMap.put(DrawEnemy.TYPE_Q,4);
break;
case 19:
tempMap.put(DrawEnemy.TYPE_E,4);
tempMap.put(DrawEnemy.TYPE_R,4);
break;
case 20:
tempMap.put(DrawEnemy.TYPE_E,4);
tempMap.put(DrawEnemy.TYPE_S,4);
break;
case 21:
tempMap.put(DrawEnemy.TYPE_T,1);
tempMap.put(DrawEnemy.TYPE_U,1);
break;
case 22:
tempMap.put(DrawEnemy.TYPE_A,4);
tempMap.put(DrawEnemy.TYPE_V,4);
break;
case 23:
tempMap.put(DrawEnemy.TYPE_D,4);
tempMap.put(DrawEnemy.TYPE_W,4);
break;
case 24:
tempMap.put(DrawEnemy.TYPE_X,4);
break;
case 25:
tempMap.put(DrawEnemy.TYPE_Y,1);
break;
case 26:
tempMap.put(DrawEnemy.TYPE_Z,1);
break;
case 27:
tempMap.put(DrawEnemy.TYPE_T,1);
tempMap.put(DrawEnemy.TYPE_U,1);
break;
case 28:
tempMap.put(DrawEnemy.TYPE_E,4);
tempMap.put(DrawEnemy.TYPE_Y,4);
break;
case 29:
tempMap.put(DrawEnemy.TYPE_H,4);
tempMap.put(DrawEnemy.TYPE_I,4);
break;
case 30:
tempMap.put(DrawEnemy.TYPE_J,4);
tempMap.put(DrawEnemy.TYPE_K,4);
break;
case 31:
tempMap.put(DrawEnemy.TYPE_L,4);
tempMap.put(DrawEnemy.TYPE_M,4);
break;
case 32:
tempMap.put(DrawEnemy.TYPE_B,4);
tempMap.put(DrawEnemy.TYPE_C,4);
break;
case 33:
tempMap.put(DrawEnemy.TYPE_L,4);
tempMap.put(DrawEnemy.TYPE_M,4);
break;
case 34:
tempMap.put(DrawEnemy.TYPE_P,5);
break;
case 35:
tempMap.put(DrawEnemy.TYPE_Q,5);
break;
case 36:
tempMap.put(DrawEnemy.TYPE_N,5);
break;
case 37:
tempMap.put(DrawEnemy.TYPE_O,5);
break;
case 38:
tempMap.put(DrawEnemy.TYPE_N,5);
tempMap.put(DrawEnemy.TYPE_O,5);
break;
case 39:
tempMap.put(DrawEnemy.TYPE_B,5);
tempMap.put(DrawEnemy.TYPE_C,5);
break;
case 40:
tempMap.put(DrawEnemy.TYPE_J,5);
tempMap.put(DrawEnemy.TYPE_K,5);
tempMap.put(DrawEnemy.TYPE_H,5);
tempMap.put(DrawEnemy.TYPE_I,5);
break;
}
return tempMap;
}```
上面的方法我一共模拟了41次的敌机出场,方法的里面的数字判断0到40就是从第一次到最后的按顺序出场的。每一个case下的内容可以把他们都看成一个组,每组敌机加入画布的时间间隔通过createEnemyTime来设置

/** * 控制敌机加入的时间间隔 */
private int mCountEnemy;
private int createEnemyTime=100;

每一个组是一个Map,Map的key放敌机的类型,value放这个敌机类型(key)需要出场的数量;每一组需要出场几种不同类型的敌机就通过put多种类型的敌机。

tempMap.put(DrawEnemy.TYPE_J,5);
tempMap.put(DrawEnemy.TYPE_K,5);
tempMap.put(DrawEnemy.TYPE_H,5);
tempMap.put(DrawEnemy.TYPE_I,5);
3.出场的敌机准备好以后,迭代Map把所有的敌机装入一个list集合。
Paste_Image.png

游戏总是需要结束的或者进行到最后,所以我们也需要设置一个该关卡敌机最多出现多少波,现在可能体现用处不大,但是后面涉及到大BOSS的时候会用到,所以先写出来备用。

/** * 当前关卡最多出现多少波敌机 */
private int maxEnemy=40;
4.回到GameView类中使用调用关卡类。
  • 定义关卡相关的变量
Paste_Image.png
  • 新增一个方法来处理敌机出场逻辑。
/**
     * 分配敌机资源
     */
    public void distribution(){
        if(mLevelArray!=null){
            mLevelArray.clear();
        }
        boolean senior = seniorEnemy();
        if(senior) return;
        //不是高级敌机出场就去获取普通敌机
        mLevelArray = mLevel.enemyLevelArray(mLevel.getEnemyArrayIndex());
    }```
这里有一个seniorEnemy的方法,也是新增一个方法,该方法主要是表示高级敌机出场的时候,其他普通敌机暂时不需要加入,也就是说这时候画布中只有主角和高级敌机在PK,其他敌机等待高级敌机被消亡在继续添加。

/**
* 高级敌机出场
*/
private boolean seniorEnemy(){
for (DrawEnemy en:mLevel.getEnemyList()) {
//当高级将领出现 其余战机 处于待命状态,并且降低背景循环运行的速度,一个视觉差的感觉
if(en.getEnemyType()==DrawEnemy.TYPE_T||en.getEnemyType()==DrawEnemy.TYPE_U){
mDrawBackground.setSpeedBY(4);
return true;
}else if(en.getEnemyType()==DrawEnemy.TYPE_Y){
mDrawBackground.setSpeedBY(4);
return true;
}
}
mDrawBackground.setSpeedBY(10);
return false;
}```
其中mDrawBackground.setSpeedBY(10)是设置当进入高级敌机Pk的时候变更背景的移动速度来增加游戏视觉效果和游戏气氛。

5.新增onDrawEnemy方法用于绘制敌机和处理敌机移动以及动画效果。
/**
     * 绘制敌机
     * 判断敌机是否失效
     */
    private void onDrawEnemy(){
        mLevel.addEnemy(mLevelArray);//添加敌机
        List<DrawEnemy> drawEnemies = mLevel.getEnemyList();
        for (int i=0;i<drawEnemies.size();i++) {
            DrawEnemy en = drawEnemies.get(i);
            if(en.isDead()){
                drawEnemies.remove(en);
            }else{
                en.updateGame();
                en.onDraw(mCanvas);
                if((en.getEnemyType()==DrawEnemy.TYPE_V ||en.getEnemyType()==DrawEnemy.TYPE_W)&&en.isEnemyStopTop() ||en.getEnemyType()==DrawEnemy.TYPE_J ||en.getEnemyType()==DrawEnemy.TYPE_K){//追踪主角的战机
                    en.getAngleRotate(mPlayer.getPlayerX(), mPlayer.getPlayerY(),true);
                }else if(en.getEnemyType()==DrawEnemy.TYPE_A||en.getEnemyType()==DrawEnemy.TYPE_D||en.getEnemyType()==DrawEnemy.TYPE_E||en.getEnemyType()==DrawEnemy.TYPE_P||en.getEnemyType()==DrawEnemy.TYPE_Q||en.getEnemyType()==DrawEnemy.TYPE_T||en.getEnemyType()==DrawEnemy.TYPE_U){
                    en.getAngleRotate(mPlayer.getPlayerX(), mPlayer.getPlayerY(),false);
                }
            }
        }
    }```
其中用到了DrawEnemy类中的getAngleRotate方法,该方法的用处<a href="http://www.jianshu.com/p/1114eca3393b">上一篇</a>已经说过,这里就不作解释了。
######6.在GameView中的onGameDraw方法调用onDrawEnemy方法

![Paste_Image.png](https://img.haomeiwen.com/i3982371/3f213a0ac148eb7c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

关卡类的东西较多,其实大部分都是针对敌机出场的逻辑判断,在出场顺序和算法的地方有点绕,最开始我用的二维数组实现的,写完后连我自己都有点晕,所以改成Map比较好理解一些,但是可能拓展性不够强,希望在后期能够找到更好的优化方式,我们还是主要学些canvas为主,算法不是我的强项。


![enemy.gif](https://img.haomeiwen.com/i3982371/3dc7e966f5f96f7c.gif?imageMogr2/auto-orient/strip)

<a href="https://github.com/tangyxgit/GameCanvas">源码</a>已经通过git更新,下一篇给敌机配备武器。

<a href="http://www.jianshu.com/p/1114eca3393b">上一篇</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.jianshu.com/p/b4c2d19a4f9f">下一篇</a>

相关文章

  • Android Canvas打飞机之敌机出场秀

    今天通过关卡模拟学习绘制敌机以及敌机出场的动画,我随意写了一些简单的逻辑算法,差不多26种模式,其实也是主要使用 ...

  • Android Canvas打飞机之被打中的敌机

    上一篇文章已经是去年的事情了,去年我们把主角和敌机都已经完美的绘制到了画布,并且做了对应的移动动画和手势操作效果,...

  • Android Canvas打飞机之主角秀

    上一篇讲过游戏背景图的加载以及场景运动效果,如果还需要了解的请 移驾这里 今天要研究的是游戏主角战机的运动以及逻辑...

  • Android Canvas打飞机之超级BOSS

    年底了,各种事情糅合在一起,不过还是磨磨叽叽的把Canvas学习的最后一部分写完了,这一篇文章应该是Canvas学...

  • Android Canvas打飞机之别人家的武器

    上一篇 敌机已经出场,并且也通过关卡模拟了出场逻辑。今天这里就是给敌机配置武器,敌机武器暂时实现了两种,自由攻击,...

  • 飞机大战

    # 敌机出场 ##目标 *使用**定时器**添加敌机 *设计`Enemy`类 ## 01. 使用定时器添加敌机 运...

  • 飞机大战-敌机出场

    目标 使用 定时器 添加敌机 设计 Enemy 类 01. 使用定时器添加敌机 游戏启动后,每隔 1 秒 会 出现...

  • Android Canvas打飞机之让子弹飞

    上一篇的主角已经登场,如果你还没见过,可以通过这里进行查看 主角秀 主角登场没有武器是不行的,所以这一篇的核心就是...

  • 053_wz_hm_项目实战——飞机大战之敌机

    敌机出场 使用定时器添加敌机 游戏启动后,每隔一秒出现一架敌机 每架敌机向屏幕下方飞行,飞行速度各不相同 每架敌机...

  • Android绘图之PathMeasure(16)

    Android 绘图学习 android绘图之Paint(1)android绘图之Canvas基础(2)Andro...

网友评论

    本文标题:Android Canvas打飞机之敌机出场秀

    本文链接:https://www.haomeiwen.com/subject/dfpyvttx.html