宇宙飞机大战

MyFighter Myfig;
ArrayList<FlyObject> enemyFighters = new ArrayList<>();
ArrayList<FlyObject> enemyBullets = new ArrayList<>();
ArrayList<FlyObject> MyBullets = new ArrayList<>();
boolean gift = true;
BufferedImage img = new BufferedImage (800, 600, BufferedImage.TYPE_INT_ARGB);

首先声明Myfig对象,表示我的飞机。接着利用基于数组上的链表ArrayList,泛型数据类型为FlyObject,分别声明了敌机,敌方子弹和我的子弹。接着声明了布尔类型变量gift为true,接着调用类BufferedImage,其生成的图片在内存中有一个图片缓冲区,声明对象img的宽高800,600,ARGB表示带透明色的对象。

{
        Myfig = new MyFighter();
        BattleThread battleThread = new BattleThread(this);
        new Thread(battleThread).start();
        AutoThread autoThread = new AutoThread(this);
        new Thread(autoThread).start();
        EnemyBulletThread enemyBulletThread = new EnemyBulletThread(this);
        new Thread(enemyBulletThread).start();
        MybulletThread mybulletThread = new MybulletThread(this);
        new Thread(mybulletThread).start();
        CollisionThread collisionThread = new CollisionThread(this);//这一段代码段什么结构。this充当什么成分?
        new Thread(collisionThread).start();
    }

再次声明Myfig对象,我的飞机。然后先后声明并调用了几个线程,分别是battleThread,autoThread,enemyBulletThread,mybulletThread,collisionThread,以便后续运行。

public void init(){
        setTitle ("飞机大战");
        setSize (800, 600);
        setDefaultCloseOperation (EXIT_ON_CLOSE);

        setVisible (true);

        Graphics g = this.getGraphics ();

        addMouseMotionListener(new MouseAdapter() {
            @Override
            public void mouseMoved(MouseEvent e) {
                Myfig.setX(e.getX());
                Myfig.setY(e.getY());
            }
        });


    }

接着是init方法。设定标题“飞机大战”,设定大小宽高。设置默认的关闭操作,参数“在关闭动作时退出”。设置窗体可见,增加鼠标监听器,写图片类对象g,增加鼠标动作监听器,重写鼠标动作类,Myfig.setX(e.getX())实现我的飞机随着鼠标移动的坐标移动而移动。

public static void main(String[] args){ //java虚拟机首先运行的就是main函数
        GameUI g = new GameUI();
        g.init();
        AudioPlay1.play();
    }

main方法,游戏界面对象g来启动界面,同时调用AudioPlay1来播放。

class AudioPlay1{
    static File file = new File ("resource/background.wav");

    public static void play(){
        URI uri = file.toURI ();
        System.out.println (uri);
        // AudioClip 只能播放 wav 格式的music
        AudioClip audioClip = null;
        try {
            audioClip = Applet.newAudioClip (uri.toURL ());
        } catch (MalformedURLException e) {
            throw new RuntimeException (e);
        }
        audioClip.play ();// 独立线程播放
        //循环播放
        audioClip.loop ();
    }

}

类AudioPlay1,声明静态类文件resource,静态方法play,获取图片文件的URI地址,Applet实现独立线程播放和循环播放。

public class FlyObject {
    private int x;
    private int y;
    private int speedx;
    private int speedy;
    private int height;
    private int width;
    private Image img;
    private int state = 1;
    private int ph;

    String path;  // ?

    public int getPh() {  //  ?
        return ph;//血量
    }
    public void setPh(int ph){
        this.ph = ph;
    }
    // state = 1 存活
    // state = 2 碰撞
    // state = 3 死亡

    public int getState() {
        return state;
    }
    public void setState(int state) {
        this.state = state;
    }
    public int getHeight() {
        return height;
    }
    public void setHeight(int height) {
        this.height = height;
    }
    public int getWidth() {
        return width;
    }
    public void setWidth(int width) {
        this.width = width;
    }
    public int getSpeedx() {
        return speedx;
    }
    public void setSpeedx(int speedx) {
        this.speedx = speedx;
    }
    public int getY() {
        return y;
    }
    public void setY(int y) {
        this.y = y;
    }
    public int getSpeedy() {
        return speedy;
    }
    public void setSpeedy(int speedy) {
        this.speedy = speedy;
    }
    public int getX() {
        return x;
    }
    public void setX(int x) {
        this.x = x;
    }

    public void setImg(String path){
        this.path = path;
        this.img = new ImageIcon(path).getImage();
    }
    public String getImg(){
        return path;
    }

    public void show(Graphics g){

        g.drawImage (img, x-width/2, y-height/2, width, height, null);
    }
    public void move(){
        x -= speedx;
        y += speedy;
    }
}

声明飞行物类,定义私有属性横坐标纵坐标高宽,图片,飞行状态,飞行器的血量,并声明一些方法来获取并设置血量状态宽度高度飞行速度,和坐标,并获得图片的信息,声明展示和移动方法。

class MyFighter extends FlyObject{
    // 初始化飞机的信息
    MyFighter(){
        int x = 350;
        int y = 350;
        int width=65;
        int height=85;
        int speedx=2;
        int speedy=2;
        setX (x);
        setY (y);
        setWidth (width);
        setHeight (height);
        setSpeedx (speedx);
        setSpeedy(speedy);
        setImg("resource/myfighter.png");
        setPh(500);
    }
}

声明类MyFighter继承FlyObject对象,用构造函数初始化飞机的信息。

class EnemyFighter extends FlyObject{
    public boolean getGift() {
        return gift;
    }

    public void setGift(boolean gift) {
        this.gift = gift;
    }

    boolean gift;

    EnemyFighter(int x,int y,int speedy){
        int width=50;
        int height=60;
        int speedx=20;  // 设置敌机横向飞行速度
        setX (x);
        setY (y);
        setWidth (width);
        setHeight (height);
        setSpeedx (speedx);
        setSpeedy(speedy);
        setImg ("resource/Elmfighter.png");
        setPh(5);
        setGift(false);
    }
}

声明类EnemyFighter继承飞行物类,并声明布尔类型方法,获取并设置布尔值gift。接着用构造方法来设置了敌机的相关属性,包括血量为5等。

class Enemybullet extends FlyObject{
    Enemybullet(int x, int y,int speedy){
        int width=13;
        int height=11;
        int speedx=60;   // 设置子弹横向飞行速度
        setX (x);
        setY (y);
        setWidth (width);
        setHeight (height);
        setSpeedx (speedx);
        setSpeedy(speedy);
        setImg ("resource/bullet.png");
    }
}

class Mybullet extends FlyObject{
//    private int x;
//    private int y;
//    private int speedx;
//    private int speedy;
//    private int height;
//    private int width;
//    private Image img = null;

    Mybullet(int x, int y){
        int width=13;
        int height=11;
        int speedx=-60;   // 设置子弹横向飞行速度
        int speedy = 0;
        setX (x);
        setY (y);
        setWidth (width);
        setHeight (height);
        setSpeedx (speedx);
        setSpeedy(speedy);
        setImg ("resource/Mybullet.png");
    }

//    @Override
//    public void move(){
//        x += speedx;
//        y += speedy;
//    }
}

敌方子弹,我的子弹的类的声明,同样是继承了飞行物的类,并利用构造函数设定了相关属性参数。

public class CollisionThread implements Runnable{
    MyFighter Myfighter;
    ArrayList<FlyObject> enemyFighters;
    ArrayList<FlyObject> enemyBullets;
    ArrayList<FlyObject> MyBullets;
    GameUI gui;
    BufferedImage img;

    CollisionThread(GameUI gui){
        this.gui = gui;
        this.Myfighter = gui.Myfig;
        this.enemyBullets = gui.enemyBullets;
        this.enemyFighters = gui.enemyFighters;
        this.MyBullets = gui.MyBullets;
        this.img = gui.img;
    }

冲撞线程继承Runnable接口,初始化对象:几个飞行物。接着仍然是用构造函数this给属性赋值。

if(MyBullets != null & enemyBullets != null){
                // 判断子弹之间有没有碰撞
                for (int i=0;i<MyBullets.size();i++){
                    for(int j=0;j<enemyBullets.size();j++){
                        Mybullet mybullet = (Mybullet) MyBullets.get(i);
                        Enemybullet enemybullet = (Enemybullet) enemyBullets.get(j);
                        if(is_collision(mybullet.getX(),mybullet.getY(),enemybullet.getX(),enemybullet.getY(),
                                mybullet.getHeight(),mybullet.getWidth(),enemybullet.getHeight(),enemybullet.getWidth())){
                            mybullet.setState(3);
                            enemybullet.setState(3);
                        }
                        if(is_Out(mybullet.getX(),mybullet.getY())){
                            mybullet.setState(3);
                        }
                        if(is_Out(enemybullet.getX(),enemybullet.getY())){
                            enemybullet.setState(3);
                        }
                    }
                }
            }

判断我方飞机的子弹和敌方飞机的子弹有没有碰撞,如果碰撞了,则二者都执行设置为第三种状态,即setState(3)。

if(enemyBullets != null & Myfighter != null){
                // 判断敌机的子弹和飞机有没有碰撞
                for(int j=0;j<enemyBullets.size();j++){
                    Enemybullet enemybullet = (Enemybullet) enemyBullets.get(j);
                    if(is_collision(Myfighter.getX(),Myfighter.getY(),enemybullet.getX(),enemybullet.getY(),
                            Myfighter.getHeight(),Myfighter.getWidth(),enemybullet.getHeight(),enemybullet.getWidth())){
                        Myfighter.setPh(Myfighter.getPh()-3);  // 飞机减少的ph值
                        enemybullet.setState(3);
                    }
                    if(is_Out(enemybullet.getX(),enemybullet.getY())){
                        enemybullet.setState(3);
                    }
                }
            }

判断敌机的子弹和我方的飞机有没有碰撞,同时调用is_collision方法,如果碰撞了,则二者都执行设置为第三种状态,即setState(3)。

if(MyBullets != null & enemyFighters != null){
                // 判断敌机和我们飞机的子弹有没有碰撞
                for (int i=0;i<MyBullets.size();i++){
                    for(int j=0;j<enemyFighters.size();j++){
                        Mybullet mybullet = (Mybullet) MyBullets.get(i);
                        EnemyFighter enemyFighter = (EnemyFighter) enemyFighters.get(j);
                        if(is_collision(mybullet.getX(),mybullet.getY(),enemyFighter.getX(),enemyFighter.getY(),
                                mybullet.getHeight(),mybullet.getWidth(),enemyFighter.getHeight(),enemyFighter.getWidth())){
                            mybullet.setState(3);
                            enemyFighter.setPh(enemyFighter.getPh()-3);
                            if(enemyFighter.getPh()<0){
                                enemyFighter.setImg("resource/bomb.png");
                                enemyFighter.show(img.getGraphics());

                                enemyFighter.setState(3);
                            }
                        }
                        if(is_Out(enemyFighter.getX(),enemyFighter.getY())){
                            enemyFighter.setState(3);
                        }
                    }
                }
            }

判断我方子弹和敌方飞机有没有发生碰撞,同时调用is_collision方法,如果碰撞了,则二者都执行设置为第三种状态,即setState(3)。若果发生了collision,则敌方飞机就设置血量为原有血量-3,如果敌方飞机的血量<0,此时敌方飞机setimag为bomb.png即设置爆炸图片。如果敌方飞机的横纵坐标离开了界面,那么等同于消失,同时设置状态3。

if(enemyFighters != null & Myfighter != null){
                // 判断敌机和我们的飞机有没有碰撞
                for(int j=0;j<enemyFighters.size();j++){
                    EnemyFighter enemyFighter = (EnemyFighter) enemyFighters.get(j);
                    if(is_collision(Myfighter.getX(),Myfighter.getY(),enemyFighter.getX(),enemyFighter.getY(),
                            Myfighter.getHeight(),Myfighter.getWidth(),enemyFighter.getHeight(),enemyFighter.getWidth())){
                        Myfighter.setPh(Myfighter.getPh()-3);
                        enemyFighter.setState(2);
                        enemyFighter.setImg("resource/boom.png");
                        System.out.println("Myfighter剩余的血量是:"+Myfighter.getPh());
                        AudioPlay.play();
                        //enemyFighter.setState(3);
                    }
                    if(is_Out(enemyFighter.getX(),enemyFighter.getY())){
                        enemyFighter.setState(3);
                    }
                }
            }

判断敌方飞机和我放飞机有没有发生碰撞,如果发生了碰撞,则播放音乐。同时输出我方飞机的剩余血量。

long end =  System.currentTimeMillis();;
            if( end - start > 6000){  // 1分钟进行一次删除
                delet();
                start = end;
                System.out.println("!!!!!!!!!!!!!!!!!!delete_not_useful_ones!!!!!!!!!!!!!!!!!!");
            }

一分钟进行一次删除操作。

public boolean is_collision(int X1, int Y1, int X2, int Y2, int height1, int width1, int height2, int width2){
        if(Math.abs(X1-X2)<= (width1/2 + width2/2) & Math.abs(Y1-Y2)<= (height1/2 + height2/2)){
            return true;
        }
        return false;
    }

这时定义布尔型方法碰撞操作。如果两个飞行物横坐标差的绝对值小于两者各自宽度二分之一的和,或者纵坐标的差的绝对值小于两者各自高度的二分之一的和,则返回true表示已碰撞,如果不满足条件则返回值false。

public boolean is_Out(int x, int y){
        if(x < 0 || x > 800 || y < 0 || y > 600){
            return true;
        }
        return false;
    }

接着定义布尔型方法出局操作。如果飞行物的横坐标小于0或者大于800,或者纵坐标小于0或者大于600的话,则该布尔型方法返回值true表示已经出局,如果没有,则返回值false。

class AudioPlay{
    static File file = new File ("resource/bomb.wav");

    public static void play(){
        URI uri = file.toURI ();
        System.out.println (uri);
        // AudioClip 只能播放 wav 格式的music
        AudioClip audioClip = null;
        try {
            audioClip = Applet.newAudioClip (uri.toURL ());
        } catch (MalformedURLException e) {
            throw new RuntimeException (e);
        }
        audioClip.play ();// 独立线程播放
        //循环播放
        //audioClip.loop ();
    }

}

静态方法play,统一资源标志符声明,用类Applet来创建播放音乐的对象audioClip,并且实现独立播放和循环播放。

public class BattleThread implements Runnable{
    MyFighter Myfighter;
    private GameUI gui;
    Graphics g;
    private Random random = new Random();
    ArrayList<FlyObject> MyBullets;
    ArrayList<FlyObject> enemyFighters;
    ArrayList<FlyObject> enemyBullets;
    BufferedImage img;

    public BattleThread(GameUI gui){
        this.gui = gui;
        this.Myfighter = gui.Myfig;
        this.g = gui.getGraphics();
        this.MyBullets  = gui.MyBullets;
        this.enemyFighters = gui.enemyFighters;
        this.enemyBullets = gui.enemyBullets;
        this.img = gui.img;
    }

战斗线程继承Runnable接口,然后构造方法BattleThread来为对象的属性赋值。

 @Override
    public void run(){
        while(true){
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if(g == null){
                g = gui.getGraphics();
            }
            else{
                Graphics2D g2d = (Graphics2D) img.getGraphics ();
                // 设置背景图片
                Image background = new ImageIcon("resource/planet.jpg").getImage();

                g2d.drawImage(background,-150,-200,950,800,null);
                //g2d.setColor (new Color (238, 238, 238));
                //g2d.fillRect (0, 0, 800, 600);

                Myfighter.show(g2d);
                g2d.drawString(""+(Myfighter.getPh()),0,500);

                for(int i = 0;i<MyBullets.size();i++){

                    if(MyBullets.get(i).getState()==1){
                        MyBullets.get(i).move();
                        MyBullets.get(i).show(g2d);
                    }
                }

                // let the enenmyfighters move
                for(int i = 0;i<enemyFighters.size();i++){
                    if(enemyFighters.get(i).getState() != 3) {
                        enemyFighters.get(i).move();//链式表达式


//                        EnemyFighter fighter =  enemyFighters.get(i);
//                        fighter.move();


                        enemyFighters.get(i).show(g2d);
                        if(enemyFighters.get(i).getState() == 2){
                            enemyFighters.get(i).setState(3);
                        }
                    }
                }

                // let the enenmyfighters move
                for(int i = 0;i<enemyBullets.size();i++){
                    if(enemyBullets.get(i).getState() != 3){
                        enemyBullets.get(i).move();
                        enemyBullets.get(i).show(g2d);
                    }
                }
                g.drawImage (img, 0, 0, null);
            }
        }
    }
}

线程休眠0.5秒,调用抽象图2D类,设置背景图片background,同时让我方飞机出现在背景中,输出字符串“我方飞机的血量”。接下来遍历全体子弹,并设置子弹的状态为1,并让他们得到并移动。接着遍历敌机的数量,如果状态为2,则设置敌机的状态为3,如果子弹的状态不为3,则表明子弹存活,此时展示g2d的图像。

class AutoThread implements Runnable{
    private Random random = new Random();
    boolean flag;
    GameUI gui;
    ArrayList<FlyObject> enemyFighters;

    AutoThread(GameUI gui){
        this.flag = true;
        this.gui = gui;
        this.enemyFighters = gui.enemyFighters;
    }

    @Override
    public void run() {
        while(true){
            try {
                Thread.sleep(200);   // 生成飞机的速度
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 随机生成敌机
            int x = random.nextInt(10)+800;
            int y = random.nextInt(600);
            int speedy;
            if(flag){
                speedy = random.nextInt(10);
                flag = false;
            }
            else{
                speedy = -1*random.nextInt(10);
                flag = true;
            }
            synchronized (gui){
                EnemyFighter enemyFighter = new EnemyFighter(x,y,speedy);
                enemyFighters.add(enemyFighter);
            }
            System.out.println("number of enemyFighters:"+enemyFighters.size());
        }
    }
}

接着是自动攻击线程继承了Runnable接口,私有变量随机数Random,敌机存储在一个可以动态修改的数组ArrayList里面,接着随机生成敌机,

int x = random.nextInt(10)+800;
int y = random.nextInt(600); 

即横纵坐标都是random的随机数,如果标识符flag为true,纵速度就为10附近的一个随机整数,并设置flag为false。否则flag为false的话,则设置纵速度为-1*random.nextInt(10),synchronizd关键字声明的方法同一时间只能被一个线程访问,线程执行同步代码块是分顺序的,保证了有序性。

class EnemyBulletThread implements Runnable{
    ArrayList<FlyObject> enemyBullets;
    ArrayList<FlyObject> enemyFighters;
    GameUI gui;

    EnemyBulletThread(GameUI gui){
        this.gui = gui;
        this.enemyFighters = gui.enemyFighters;
        this.enemyBullets = gui.enemyBullets;
    }

    @Override
    public void run() {
        while(true){
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            for(int i=0;i<enemyFighters.size();i++){
                EnemyFighter enemyFighter = (EnemyFighter) enemyFighters.get(i);
                synchronized (gui){//只能一个线程使用,参数可以是对象或者是基本数据类型
                    if(enemyFighter.getState() != 3){
                        enemyBullets.add(new Enemybullet(enemyFighter.getX(),enemyFighter.getY(),enemyFighter.getSpeedy()));
                    }
                }
            }
        }
    }
}

 敌方子弹线程,依然是一个synchronized加锁,表明这一方法同时只能被一个线程访问,如果敌机的状态不为3,敌方子弹增加到新的子弹里面,敌机的x值y值。

class MybulletThread implements Runnable{
    ArrayList<FlyObject> MyBullets;
    MyFighter myFighter;
    GameUI gui;
    boolean gift;

    MybulletThread(GameUI gui){
        this.gui = gui;
        this.MyBullets = gui.MyBullets;
        this.myFighter = gui.Myfig;
        this.gift = gui.gift;
    }

    @Override
    public void run() {
        while(true){
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (gui){
                if(gift){
                    Mybullet mybullet=new Mybullet(myFighter.getX(),myFighter.getY());
                    MyBullets.add(mybullet);//
                    MyBullets.add(new Mybullet(myFighter.getX(),myFighter.getY()-30));
                    MyBullets.add(new Mybullet(myFighter.getX(),myFighter.getY()+30));
                }
                else{
                    MyBullets.add(new Mybullet(myFighter.getX(),myFighter.getY()));
                }
            }

        }
    }
}

接下来是我的子弹线程,依然是用构造函数this来给对象的属性赋值。启动run方法循环执行,创建我的子弹对象,并把它添加到子弹类中,我的子弹类增加新的子弹,子弹的坐标就是我的飞机的横坐标,纵坐标为我的飞机的纵坐标-30,和+30。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值