学习日记 飞机大战游戏详解

本文分享了一个游戏开发项目的实现过程,包括整体思路、绘制背景图片、飞机及子弹的方法、碰撞检测和爆炸效果等关键技术细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.整体实现思路

在做这个游戏刚开始第一天时,不知如何着手,思路很乱,不能统观全局,抓不住其中要点,窥不透真义.几天下来,在江哥的引导下,基本完成了简单的功能,现在回顾一下过程中的心得以及遇到的问题:首先创建四个类,BOSS类和我方机子弹类,BOSS类,我方机类,类中定义各自的横竖x y坐标属性,值得注意的是,在写构造的时候,子弹的构造需要传入参数,因为子弹英雄机和敌机发出来的。再定义两种子弹移动方法。移动方法很好写,子弹垂直方向发,x——就行了。再在main中调用就行了。在这个过程中最重要的创建几个类来实现程序的运行。

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

首先,先创建一个背景类,然后定义图片的布局,创建一个图片类,并设置图片的大小和坐标,然后调用图片采用的布局方式,显示图片,创建数组然后添加图片,重要的是如何实现图片的滚动,使用while循环来写,然后实现图片的切换,设置一定的时间在几毫秒之间。最后实行while循环使一张图片来回播放,由于间隔时间较短所以肉眼很难分清是图片的滚动循环。

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
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.如何绘制飞机

首先绘制BOSS类飞机,首先定义飞机的坐标,定义飞机的宽度和高度,然后定义飞机的速度和计数器,然后 定义飞机时间的间隔最后定义飞机的血量,给飞机定义一个初始血量为Hp,然后用Canvas的方法调用到飞机的图片,最后再在主类中调用Myplane中的draw。 

我方飞机:

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.bitmap = bitmap;
        this.bitmapHp = bitmapHp;
        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_STATE = 2;
        }
        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);
        }
    }
    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;
                }
            }
        }
    }
    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){
                noCollision = true;
                if (hp>0){
                    hp--;
                }
                return true;
            }
        }
        return false;
    }
    public boolean isCollision(BossPlane bossPlane) {
        if (noCollision){
            return false;
        }else{
            if(bossPlane.getY()+bossPlane.getFrameH()>y&&bossPlane.getY()+bossPlane.getFrameH()<y+height){
                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;
    }

}

敌方飞机:

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.Log;
public class BossPlane {
    private Bitmap bitmap;
    private int x,y;
    private int frameW,frameH;
    private int speed=5;//boos飞机的速度
    private int crazySpeed=50;//疯狂速度
    private int count;//计数器
    private int time=500;//疯狂模式间隔
    private boolean isCrazy;
    private int bossHp = 10000;
    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.save();
        canvas.clipRect(x,y,x+frameW,y+frameH);
        canvas.drawBitmap(bitmap,x,y,paint);
        canvas.restore();
        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;
            }
        }
    }
        public boolean isCollision(Bullet bullet){
            if(bullet.getX()>x&&bullet.getX()+bullet.getBitmap().getWidth()<x+frameW&&bullet.getY()>y&&bullet.getY()<y+frameH){
                bossHp--;
                bullet.setDead(true);
                if (bossHp<0){
                    MySurfaceView.GAME_STATE = 1;
                }
                return true;
            }
            return false;
    }
    public int getX() {
        return x;
    }
    public int getY() {
        return y;
    }
    public int getFrameW() {
        return frameW;
    }
    public int getFrameH() {
        return frameH;
    }}

4.如何绘制子弹
子弹和飞机本质上几乎相同,所以考虑到把它们都继承自Entity类。不同的是子弹是跟飞机位置有联系的,它从飞机的头部发射出来,之后才能脱离飞机的控制自由运动。子弹不能像飞机一样随意出现在屏幕上,当标志说明子弹没有出现时,将其坐标设定为飞机头部所在坐标;当标志说明子弹已经出现时,则在子弹现有坐标的基础上Y轴增加,每次的增加量是子弹的速度。另外子弹和飞机都是受系统控制自己运动,所以都要放在update()函数中,并且由于update()函数刷新很快,需要设定一定的时延。
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
public class Bullet {
    private Bitmap bitmap;
    private int x, y;
    private int speed = 10;
    private boolean isDead;
    private int type;
    public Bullet(Bitmap bitmap, int x, int y,int type) {
        this.bitmap = bitmap;
        this.x = x;
        this.y = y;
        this.type = type;
    }
    public Bullet() {
    }
    public void draw(Canvas canvas, Paint paint) {
        canvas.drawBitmap(bitmap, x, y, paint);
        logic();
    }
    public void logic() {
        switch (type){
            //玩家子弹
            case 0:
                y -= speed+5;
                if (y < 0) {
                    isDead = true;
                }
                break;
            //Boss子弹
            case 1:
                y += speed+8;
                if (y < 0) {
                    isDead = true;
                }
                break;
                default:
                    break;
        } }  

5.如何判断碰撞(子弹与飞机碰撞,飞机与飞机碰撞)

当飞机的坐标和子弹的坐标重合一样的时候,就会实现玩家飞机血量的减少,来体现玩家飞机已经碰撞上了子弹,当子弹碰到飞机的整个坐标(包括宽度和高度)就会发生碰撞,当BOSS机的坐标与玩家飞机坐标相互重合或者相交就会使得飞机与飞机相撞,就会实现玩家的血量下降!

//我方飞机与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;
    }

6.如何绘制爆炸效果

首先,创建一个boom类,当子弹坐标与飞机坐标相互重合,就会产生碰撞,最终实现爆炸效果,爆炸效果由一组图片完成,他会参照背景图片一样的方式来实现,由第一张图片迅速闪过到最后一张图片,从而产生爆炸效果。

//我方飞机与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;
    }
7.如何添加音效
首先,创建一个gamesoundpool类,先让他实例化,然后赋予他音频文件,

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);
    }
}

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

继承和接口就MySurfaceView中实现,这个类要继承SurfaceView,还要实现SurfaceHolder.Callback,Runnable的接口。

在飞机和子弹,飞机与飞机的碰撞中定义了同一个类名,然而参数列表不一样,调用的时候,就按照里面的参数来进行传参。
分装在各个类中都有存在,police和private等,在各个类中都有实现。
9.我的收获与感悟
通过这一个月的实训学习,说实话真的学到了不少,虽然没有那种信手捏来的飞速敲代码,但是我从心底里感觉变化了许多,至少,在这之前,看代码好像是天书一样,但是现在至少可以看懂了许多,懂得了怎么样去学习,怎样去运用方法等,每次代码敲了很久之后的那种烦躁与头疼,在程序成功运行出来之后,完全被冲洗掉了,那是种成就的感觉,说实话,如果让我独立完成,没有参照江哥打的代码,不太可能会打出来。真的,只要在上课跟着江哥的思路走,仿佛一切困难都成了纸老虎,程序员这条道路上是长远的,而我们都只是刚刚迈出第一步,仿佛是一个孩子一样刚刚来到这个世界,对这个世界的好奇,就这样,好奇成了我们坚持敲代码的信念,我相信我们会在这条路走的更远,虽然中途可能会有人掉队,但是这段实训期间给我们的不仅仅是这些,还有我们对成功的执着与追求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值