飞机大战详解

整体实现思路

主要分为以下步骤
1.实现循环背景滚动
2.添加玩家飞机
3.玩家飞机发射子弹
4.添加Boss飞机
5.Boss飞机发射子弹
6.飞机被击中血量减少及无敌状态
7.玩家飞机和子弹碰撞,Boss和玩家飞机碰撞
8.子弹击中飞机爆炸效果
9.添加音效
10.添加游戏开始和结束界面

如何绘制循环滚动的背景图片

先是定义一个X和Y坐标,然后把图片在画布上画出来,获取背景。
然后做一个判断语句,当背景图片长度小于屏幕长度时 重置图片。
代码如下:
/**
* 背景
*/

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;

public class BackGroud {
private int y1;
private int y2;
private Bitmap bitmap;

public BackGroud(Bitmap bitmap){
    this.bitmap = bitmap;
    y1 = 0;
    y2 = y1-bitmap.getHeight();


}


public void draw(Canvas canvas){
    logic();
    Paint paint = new Paint();
    canvas.drawBitmap(bitmap,0, y1,paint);
    canvas.drawBitmap(bitmap,0, y2,paint);


}
public void logic(){ //逻辑方法
    y1+=10;
    y2+=10;
    if(y1>=bitmap.getHeight()){
        y1 = y2-bitmap.getHeight(); //移动在第二张    上面

    }
    if(y2>=bitmap.getHeight()){
        y2=y1-bitmap.getHeight();

    }
}

}

如何绘制飞机

创建一个飞机类,玩家飞机比较简单直接绘制出来,然后添加到画布上,但和背景图片的顺序不能颠倒
Boos飞机要用到裁剪,canvas.clip() 这个方法裁剪出一个Boss飞机的大小,然后再添加到画布上。
代码如下:
`/**
*玩家飞机
*/
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.MotionEvent;

public class Myplane {
private Bitmap bitmap;
private Bitmap bitmapHp;
private int x, y;
private int width, height;
private boolean noCollision;
private int noCollisionCount;
private int Hp = 3;

public Myplane(Bitmap bitmap, Bitmap bitmapHp) {
    this.bitmapHp = bitmapHp;
    this.bitmap = bitmap;
    x = MySurfaceView.width / 2 - bitmap.getWidth() / 2;//中间
    y = MySurfaceView.height - bitmap.getHeight();
    width = bitmap.getWidth();
    height = bitmap.getHeight();
}


public void draw(Canvas canvas, Paint paint) {
    if(Hp<=0){
        MySurfaceView.Game_start = 3;
    }
    if (noCollision) {
        noCollisionCount++;
        if (noCollisionCount % 10 == 0) {
            canvas.drawBitmap(bitmap, x, y, paint);//闪烁:无敌状态
        }
        if (noCollisionCount > 100) { //无敌时间
            noCollision = false;
            noCollisionCount = 0;
        }
    } else {
        canvas.drawBitmap(bitmap, x, y, paint);//非无敌状态
    }
    for (int i = 0; i < Hp; i++) {
        canvas.drawBitmap(bitmapHp, i * bitmapHp.getWidth(), MySurfaceView.height - bitmapHp.getHeight(), paint);//HP位置
    }


}

public void touchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_MOVE) {
        float ex = event.getX();
        float ey = event.getY();
        if (ex > x && ex < x + width && ey > y && ey < y + height) {
            x = (int) (ex - width / 2);
            y = (int) (ey - height / 2);
            if (y < 0) {
                y = 0;
            }
            if (y + height > MySurfaceView.height) {
                y = MySurfaceView.height - height;
            }
        }
    }
}
//我方飞机与boss子弹
public boolean isCollision(Bullet bullet) {
    if (noCollision) {
        return false;
    }
    if (bullet.getX() > x && bullet.getX() < x + width && bullet.getY() > y && bullet.getY() < y + height) {
        noCollision = true;
        if (Hp > 0) {
            Hp--;
        }
        return true;
    }
    return false;

}
//我方飞机与boss
public boolean Attack(Bossplane bossplane) {
    if (noCollision) {
        return false;

    }
    if(y<bossplane.getY()+bossplane.getFrameH()&&y+height>bossplane.getY() ){

        if (x < bossplane.getX() && x+width > bossplane.getX()) {//我方战机左边碰撞
            noCollision = true;
            if (Hp > 0) {
                Hp--;
            }
            return true;
        }

        if (x > bossplane.getX() && x+width < bossplane.getX() + bossplane.getFrameW()) {//我方飞机中间碰撞
            noCollision = true;
            if (Hp > 0) {
                Hp--;
            }
            return true;
        }

        if (x < bossplane.getX() && x+width > bossplane.getX()+bossplane.getFrameW()) {//我方飞机右边碰撞
            noCollision = true;
            if (Hp > 0) {
                Hp--;
            }
            return true;
        }
    }

    return false;
}



public int getX() { return x; }

public int getY() { return y; }

public int getWidth() {
    return width;
}

public int getHeight() {
    return height;
}

}
`

如何绘制子弹

创建一个子弹类,同样的也需要把子弹绘制到画布上,子弹需要跟随玩家或者boss移动,所以要获取玩家飞机的位置或者Boss飞机的位置,子弹的速度不能比背景滚动的速度慢,否则当Boss向冲刺的时候就会出现子弹静止不动的情况。
子弹类需要用到数组把要发射的子弹数组放到里面,但是发射的子弹如果不删除就会一直占着内存,导致内存占用一直增大,所以在每一组子弹消失在屏幕的顶端时,就要从数组中删除这组子弹的数据。
代码如下:
public class Bullet {
private int speed=10;
private int x;
private int y;
private Bitmap bitmap;
private int type;
private boolean isDead;
public Bullet(Bitmap bitmap, int x, int y, int type){
this.bitmap = bitmap;
this.x = x;
this.y = y;
this.type = type;

}
public void draw(Canvas canvas, Paint paint){
    canvas.drawBitmap(bitmap,x,y,paint);
    logic();
}

public void setDead(boolean dead) {
    isDead = dead;
}

public Bitmap getBitmap() {
    return bitmap;
}

public int getX() {
    return x;
}

public int getY() {
    return y;
}

public void logic() {
    switch (type){
        //玩家子弹
        case 0:
            y -= speed;
            if (y < 0) {
                isDead = true;

            }
            break;
        //boos子弹
        case 1:
            y += speed;
            if (y < 0) {
                isDead = true;

            }
            break;
    }



}

public boolean isDead() {
    return isDead;
}

}

如何判断碰撞

当飞机的坐标和子弹的坐标重合时即判定为碰撞,同理玩家飞机和Boss飞机的坐标重合也判定为碰撞

        if (noCollision) {
            return false;
        }
        if (bullet.getX() > x && bullet.getX() < x + width && bullet.getY() > y && bullet.getY() < y + height) {
            noCollision = true;
            if (Hp > 0) {
                Hp--;
            }
            return true;
        }
        return false;

    }
                   }

玩家飞机与Boss子弹碰撞

        if (noCollision) {
            return false;

        }
        if(y<bossplane.getY()+bossplane.getFrameH()&&y+height>bossplane.getY() ){

            if (x < bossplane.getX() && x+width > bossplane.getX()) {//我方战机左边碰撞
                noCollision = true;
                if (Hp > 0) {
                    Hp--;
                }
                return true;
            }

            if (x > bossplane.getX() && x+width < bossplane.getX() + bossplane.getFrameW()) {//我方飞机中间碰撞
                noCollision = true;
                if (Hp > 0) {
                    Hp--;
                }
                return true;
            }

            if (x < bossplane.getX() && x+width > bossplane.getX()+bossplane.getFrameW()) {//我方飞机右边碰撞
                noCollision = true;
                if (Hp > 0) {
                    Hp--;
                }
                return true;
            }
        }

        return false;
    }


如何绘制爆炸效果

首先创建一个Boom类,需要爆炸效果资源图,获取爆炸效果的位置坐标
爆炸效果的构造函数,爆炸效果绘制,爆炸效果的逻辑

代码如下:

mport android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.Log;

public class Boom {
    private Bitmap bitmap;
    private int x,y;
    private int totalFrame;
    private int currentFrame;
    private int frameW,frameH;
    private  boolean isEnd;

//爆炸效果的构造函数
    public Boom(Bitmap bitmap, int x, int y, int totalFrame) {
        this.bitmap = bitmap;
        this.x = x;
        this.y = y;
        this.totalFrame = totalFrame;
        frameW = bitmap.getWidth()/totalFrame;
        frameH = bitmap.getHeight();
    }
    //爆炸效果绘制
    public void draw(Canvas canvas, Paint paint){

        canvas.save();

        canvas.clipRect(x,y,x+frameW,y+frameH);
        canvas.drawBitmap(bitmap,x-currentFrame*frameW,y,paint);
        canvas.restore();
        logic();
    }
    //爆炸效果的逻辑
    public void  logic(){
        if(currentFrame<totalFrame){
            currentFrame++;
        }else{
            isEnd = true;
        }
    }

    public boolean isEnd() {
        return isEnd;
    }
}

如何添加音效

首先在res文件夹下创建raw文件夹用来存放音频文件,然后要用到SoundPoll,
SoundPool提供了一个构造器,该构造器可以指定它总共支持多少个声音。
SoundPool提供的播放指定声音的方法:
int play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate):该方法的第一个参数指定播放哪个声音;leftVolume、rightVolume指定左、右的音量:priority指定播放声音的优先级,数值越大,优先级越高;loop指定是否循环,0为不循环,-1为循环;rate指定播放的比率,数值可从0.5到2, 1为正常比率。
代码如下:



import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;

public class GameSoundPool {
    private SoundPool soundPool;
    private int s1;
    private int s2;
    public GameSoundPool(Context context){
        this.soundPool = new SoundPool(2,AudioManager.STREAM_MUSIC,0);
        this.soundPool = new SoundPool(1,AudioManager.STREAM_MUSIC,0);
        s1 = soundPool.load(context,R.raw.shoot,1);
        s2 = soundPool.load(context,R.raw.button,1);
    }
    public void playSound(){
        soundPool.play(s1,1,1,1,1,1.0f);
        soundPool.play(s2,1,1,1,1,1.0f);
    }
}

哪些地方用到封装,继承,多态,接口,方法重载

在项目中的每个类都用到了封装,

public class MySurfaceView extends SurfaceView  implements SurfaceHolder.Callback,Runnable{//继承和实现接口

方法的重载
画布裁剪的时候用到了方法的重载

多态
在玩家飞机和子弹碰撞时,玩家飞机和Boss碰撞时,做出不同的反应

我的收获与感悟

四个星期的实训不知不觉中已经到了尾声,前两个星期基本上都时教的java基础,由于学校老师教的课听的不是很懂,所以听的很认真,没天虽然有些疲惫但每天的都有收获,说实话在实训课之前,在学校JAVA基本上等于没学,但经过前两个星期的课程对JAVA的基本知识和结构不敢说都会但也能看懂代码了,但由于基础不是很好,所以有些知识掌握的还不是很全面,后两个星期就时主要在Andrio Studio中做飞机大战这个项目,刚开始的时候老师演示项目成品的时候,心想这是我们能做出来的吗?,经过两个星期课程里面大部分都是和JAVA相关的知识,项目刚刚开始的时候勉强能够跟上,由于对一些代码不熟悉,和代码的行数越来越多,越往后感觉越吃力。总之在这四个星期中收获很多,不仅仅是在知识上,学习的方法和一些以后会遇到的事都有了一些了解,虽然努力和收获不一定成正比,但努力一定会有收获。

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值