飞机大战游戏详解

时间:2022-01-24 14:51:56

1.整体思路

概述:这次的飞机大战游戏主要运用到Java中所学到的知识

基本功能:(1)设置一个战机具有一定的速度,通过鼠标可以控制战机的位置

                 (2)添加爆炸效果包括,战机子弹打中敌机爆炸,敌机子弹打中战机子弹爆炸,敌机与战机相撞所产生的                        效果

                 (3)为游戏界面添加了背景图片,并在敌机和战机发射子弹是添加了背景音效,在爆炸发生后子弹消失,                       战机的生命值减一

                  (4)最后游戏结束时公布结果,由图片显示你是获胜还是失败

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

在进行游戏时,首先要有游戏背景,将背景进行封装让飞机正常移动就用背景的移动来实现,还要有”画板”,"画笔",然后锁定画布,也不要忘记解锁画布,当第一张图片循环时,把第二张图片放在第一张图片后面接着循环,就会营造一种图片一直在循环的感觉,具体代码如下:

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

punlic class BackGround {
    private  int y1;
    private  int y2;
    private Bitmap bitmap;

    public BackGround(Bitmap bitmap){
        this.bitmap = bitmap;
        y1=0;
        y2=y1-bitmap.getHeight();
    }
    public void draw(Canvas canvas,Paint paint){
        logic();
        canvas.drawBitmap(bitmap,0,y1,paint);
        canvas.drawBitmap(bitmap,0,y2,paint);
    }

    public void logic() {
        y1+=10;
        y2+=10;
        if (y1>=MySurfaceView.height){
            y1=y2-bitmap.getHeight();//移动到第二张图片的顶部
        }
        if (y2>=MySurfaceView.height){
            y2=y1-bitmap.getHeight();
        }
    }
}

3.如何绘制飞机(主要分为战机和敌机两种)

要绘制飞机首先我们要在屏幕上找到屏幕的原点,然后规定飞机的高度和宽度,也就是确定飞机的x,y ,但是显示的飞机并不在屏幕正中间,这时候你会发现飞机位于屏幕中间偏右的位置,所以我们要减去半个飞机的宽度(飞机的宽度不是X),具体代码如下:

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.MotionEvent;
public class Myplane {
    private Bitmap bitmap;
    private int x,y;
    private int width,height;

    public Myplane(Bitmap bitmap){
        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){
        canvas.drawBitmap(bitmap,x,y,paint);
    }
    public void touchEvent(MotionEvent event){
        if (event.getAction()==MotionEvent.ACTION_MOVE){
            float ex = (int) event.getX();
            float ey = (int) 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;
                }
            }
        }
    }
}


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

public class BossPlane {
    private Bitmap bitmap;
    private int x,y;
    private int frameW,frameH;
    private int speed=5;
    private int crazySpeed=50;
    private int count;
    private int time=300;
    private boolean isCrazy;

    public BossPlane(Bitmap bitmap) {
        this.bitmap = bitmap;
        this.frameW = bitmap.getWidth()/10;
        this.frameH = bitmap.getHeight();
        x=MySurfaceView.width/2-frameH/2;
    }
    public void draw(Canvas canvas, Paint paint){
        canvas.clipRect(x,y,x+frameW,y+frameH);
        canvas.drawBitmap(bitmap,x,y,paint);
        logic();
    }
    public void logic(){
        count++;
        if (isCrazy){
            y = y+crazySpeed;
            crazySpeed--;
            if (y==0){
                isCrazy = false;
                crazySpeed = 50;
            }
        }else {
            if (count%time==0){
                isCrazy=true;
            }
            x = x+speed;
            if (x>MySurfaceView.width-frameH){
                speed = -speed;
            }
            if (x<0){
                speed = -speed;
            }
        }
    }
}

4.如何绘制子弹

这里跟上面的差不多,主要是多了一个speed,是为了给子弹赋速度,

 //绘制飞机子弹
                for (int i1 = 0; i1 < bossbulletVector.size(); i1++) {
                    bossbulletVector.elementAt(i1).draw(canvas, paint);
                    if (boosPlane.isCollision(bossbulletVector.elementAt(i1))) {
                        Boom boom = new Boom(BitmapFactory.decodeResource(getResources(),R.mipmap.boom),boosPlane.getX()+boosPlane.getX()/2,boosPlane.getY(),7);
                        boomVector.add(boom);
                    }
                }
 //绘制boss子弹
                for (int i = 0; i < bossbulletVector.size(); i++) {
                   bossbulletVector.elementAt(i).draw(canvas,paint);
                   myPlane.isCollision(bossbulletVector.elementAt(i));
                }

5.如何判断碰撞

(1)子弹与飞机的碰撞

这里主要说的是主类MysurfaceView,这个类主要是实现接口和继承,而碰撞则是判断当战机与敌机的子弹碰撞时战机会出现闪烁,战机的血量就会减少,当子弹的右边碰上战机的左边并子弹的左边小于战机的左边,子弹的右边小于战机的右边,当子弹的右边大于战机的左边并子弹的左边小于战机的右边这个时候就是战机与子弹的碰撞,代码如下: 

 public boolean isCollision(Bullet bullet) {
        if (noCollision) {
            return false;

        } else {
            if (bullet.getX() > x && bullet.getX() < x + width && bullet.getY() > y && bullet.getY() < y + height) {
                Log.e("AAA", "isCollision:..............");
                noCollision = true;
                if (hp > 0) {
                    hp--;
                }
                return true;
            }
        }
        return false;
    }

(2)飞机与飞机的碰撞

这里则是战机与敌机的碰撞运用了方法的重写,判断的条件与子弹和飞机的碰撞条件一样,代码如下:

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

6.如何绘制爆炸效果

爆炸效果是运用了画布的裁剪,用到了Canvas裁剪,在使用之前要先写上save和restore方法,之后还要在定义一个高度H和宽度W,裁剪主要是裁剪W,高度H是可以不用裁剪的,最后用W除以一个总个数,代码如下:

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

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*frameH,y,paint);
        canvas.restore();
       logic();
    }
    public void logic(){
        if (currentFrame<totalFrame) {
            currentFrame++;
        }else{
            isEnd = true;
        }
    }
    public boolean isEnd(){
        return isEnd();
    }
}

7.如何添加音效

在Android  studio里建立一个叫raw的包文件夹,然后将自己下载的音乐复制进去,第一个是上面的s,第二个和第三个是左右声道,第四个是优先级别,第六个是速率,你播放的音乐的速率,具体代码如下所示:

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);
        s1 = soundPool.load(context, R.raw.shoot,1);
        s2 = soundPool.load(context, R.raw.explosion2,1);
    }
    public void playSound(int s){
        switch (s){
            case 1:
                soundPool.play(s1,1,1,0,1,1.0f);
                break;
            case 2:
                soundPool.play(s2,1,1,0,1,1.0f);
                break;
        }


    }
}

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

(1)继承和接口主要是在mysurfaceview中体现,mysurfaceview继承了surfaceview中的属性和方法,还要实现SurfaceHolder.Callback,Runnable的接口。

(2)用的最多的就是封装每个类定义的变量有public型的还有private型的,讲到这个就不得不说四种范围访问修饰符:当前类访问权限:private,包访问权限:default,子类访问权限:protected,公共类访问权限:public。其中private型的只能通过set和get方法来调用。

(3)方法的重载主要体现在飞机类和子弹类中,在飞机和子弹类中,飞机与飞机的碰撞中定义了同一个类名,然而参数列表不一样,调用的时候,就按照里面的参数来进行传参。

9.收获与感悟

   主要学习了有关Java的知识。比如:Java的三大特性:继承,封装,多态;Java的基本数据类型,逻辑运算符,基本循环语句,分支语句,各类快捷键,IO流等等。由于之前开的Java课程都没怎么学导致学的很困难,但学习了之后还是有所收获。

    Eclipse主要是对Java的直接运用,Android  studio则是让我对Java有了更深的理解,先是做了图书管理系统,接着是飞机大战这个游戏它里面每一步,每一个代码都有着Java的知识,即使学着难了,但是我自己学会了认真分析,而不是一味看着代码一个一个的敲上去,错了我会试着去修改。以前觉着学计算机或是学软件就是玩玩电脑没什么大不了的,经过这次的实训,我明白了软件并不是那么简单但也不是那么无趣的。人生还是有很多需要学习的,即使它很难但是我还是会坚持去学习,毕竟能多学习一点也是不错,现在学习的会对以后产生很大帮助。

     虽然一个月的实训每天都是敲代码,敲代码,但是每天都能学到很多的知识,我也从刚开始的什么都不懂慢慢的学习到了很多,实训真的给我了我很大的帮助,说实话,一个月真的有点累,但是,能学到东西还是值得的。不论我实训学到了什么,我的心境还是得到了很大的提高,俗话说:不成功,便成仁;大概就是这个道理。