飞机游戏(基于java实现)

Plane-War

github链接

在这里插入图片描述

游戏说明:

玩家的飞机最初出现在底部中央,通过方向键控制飞机移动,通过空格键发射子弹。当玩家的飞机被击中时,飞机将重新回到底部中央,同时更换为可以发射两发子弹的飞机,当玩家被击中三次时,游戏结束。同时,飞机共有两组,若期间玩家的飞机都未被击中,则玩家获得胜利。

实现效果:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

GamePlay类:

控制游戏的循环和面板的刷新,当在checkEvent中达到一定条件时更改stop_flag标志,结束游戏的循环

import javax.swing.*;
import java.awt.*;

import static java.lang.Thread.sleep;

public class GamePlay {
    public static boolean stop_flag = false;//为true时游戏结束
    public static boolean pause_flag = false;//为true时游戏暂停
    private static int choose;
    public static void main(String[] args) {
        JFrame frame = new gameFrame();
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //控制游戏重新开始的循环
        do {
            //控制游戏结束的循环
            while (!stop_flag) {
                try {
                    sleep(5);//让线程暂停一短时间,以免游戏元素的位置刷新过快
                } catch (InterruptedException e) {
                }
                if (!pause_flag) {
                    frame.getContentPane().repaint();
                }

            }
            if(Plane.life_num==0)
            choose=JOptionPane.showConfirmDialog(null,"是否重新开始:",
                    "你的生命数已经用尽",JOptionPane.YES_NO_OPTION);
            else
                choose=JOptionPane.showConfirmDialog(null,"是否重新开始:",
                        "恭喜你!通关了!",JOptionPane.YES_NO_OPTION);
            if(choose==JOptionPane.YES_OPTION) {
                stop_flag = false;
                frame.dispose();
                //重新游戏时初始化其中有意义的静态常量
                Plane.count=1;
                Enemy.enemy_group=1;
                Plane.life_num=3;
                enhanceElement.elementCatch=0;
                frame=new gameFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            }
        }while(choose==JOptionPane.YES_OPTION);
    }
}

gameFrame类:

作为一个游戏框架容器,用来添加菜单栏,相应的菜单和菜单项和游戏面板类。其中,菜单栏提供一些游戏属性的设置,游戏的说明等内容

import sun.audio.AudioData;
import sun.audio.AudioPlayer;
import sun.audio.AudioStream;
import sun.audio.ContinuousAudioDataStream;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileInputStream;
import java.io.InputStream;

class gameFrame extends JFrame {
    public final static  int WIDTH = 1200;
    public final static  int HEIGHT = 1000;
    public static gamePanel panel;
    JMenuBar menuBar;//声明一个菜单栏对象
    JMenu menu, help, music,plane_choose;//声明菜单对象
    JMenuItem plane_speed, enemy_speed,bullet_speed, exit, help1, about;//声明菜单项对象
    JMenuItem plane1,plane2,plane3,plane4;
    JRadioButtonMenuItem on, off;//复选框,将其加入JCheckBoxGroup()以实现单选
    boolean music_flag = true;//控制音乐开关标记
    InputStream in;//音频文件输入流
    AudioStream audioStream;
    Toolkit toolkit=Toolkit.getDefaultToolkit();
    public gameFrame() {
        //设置frame的大小,图标,标题
        super("Plane::War");
        //Dimension screenSize=toolkit.getScreenSize();
        setSize(WIDTH, HEIGHT);
        Image plane = new ImageIcon("image/plane3.png").getImage();
        setIconImage(plane);

        menuBar = new JMenuBar();
        setJMenuBar(menuBar);

        menu = new JMenu("菜单");
        help = new JMenu("帮助");
        music = new JMenu("音乐");
        plane_choose=new JMenu("选择飞机");

        plane_speed = new JMenuItem("飞机速度");
        enemy_speed = new JMenuItem("敌机速度");
        bullet_speed=new JMenuItem("子弹速度");
        exit = new JMenuItem("退出");
        help1 = new JMenuItem("帮助");
        about = new JMenuItem("关于");
        //存储飞机图像的菜单项
        plane1=new JMenuItem(new ImageIcon("image/plane1.png"));
        plane2=new JMenuItem(new ImageIcon("image/plane2.png"));
        plane3=new JMenuItem(new ImageIcon("image/plane3.png"));
        plane4=new JMenuItem(new ImageIcon("image/plane4.png"));

        on = new JRadioButtonMenuItem("开", true);
        off = new JRadioButtonMenuItem("关", false);
        ButtonGroup group = new ButtonGroup();
        group.add(on);
        group.add(off);
        music.add(on);
        music.add(off);

        menuBar.add(menu);
        menuBar.add(help);
        menuBar.add(plane_choose);

        menu.add(plane_speed);
        menu.add(enemy_speed);
        menu.add(bullet_speed);
        menu.add(music);
        menu.add(exit);
        help.add(help1);
        help.add(about);
        plane_choose.add(plane1);
        plane_choose.add(plane2);
        plane_choose.add(plane3);
        plane_choose.add(plane4);

        MenuItemListener listener = new MenuItemListener();//菜单项监听器
        //为每个菜单项添加监听器
        plane_speed.addActionListener(listener);
        enemy_speed.addActionListener(listener);
        bullet_speed.addActionListener(listener);
        exit.addActionListener(listener);
        help1.addActionListener(listener);
        about.addActionListener(listener);
        plane1.addActionListener(listener);
        plane2.addActionListener(listener);
        plane3.addActionListener(listener);
        plane4.addActionListener(listener);
        RadioButtonListener btnlistener = new RadioButtonListener();
        on.addActionListener(btnlistener);
        off.addActionListener(btnlistener);

        try {
            in = new FileInputStream("music/dragon rider.wav");
            audioStream = new AudioStream(in);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (music_flag) {
            AudioPlayer.player.start(audioStream);
        }
        panel = new gamePanel();
        panel.setFocusable(true);//设置panel获得焦点事件
        getContentPane().add(panel);
        setVisible(true);
    }

    /*
    内部动作监听类
    实现对菜单项动作的监听
    可以实现选择飞机,更改飞机速度,敌机速度,玩家子弹速度,还包括游戏说明
     */
    private class MenuItemListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
         //游戏暂停标志
            GamePlay.pause_flag=true;
            JMenuItem source = (JMenuItem) e.getSource();
            if (source == plane_speed) {
                String msg = JOptionPane.showInputDialog(null,
                        "请输入飞机速度:(整数,初始速度为4)", null);
                Plane.speed = Integer.parseInt(msg);
            } else if (source == enemy_speed) {
                String msg = JOptionPane.showInputDialog(null,
                        "请输入敌机速度:(整数,初始速度为1)", null);
                Enemy.speed = Integer.parseInt(msg);
            }else if(source==bullet_speed){
                String msg = JOptionPane.showInputDialog(null,
                        "请输入玩家子弹速度:(整数,初始速度为5)", null);
                Bullets.speed = Integer.parseInt(msg);
            }else if(source==help1){
                JOptionPane.showMessageDialog(null,
                        "本游戏中玩家通过方向键控制飞机上下左右移动,通过空格键发射子弹。"+
                        "\n玩家的飞机共有三次生命,期间可以通过吃到增强道具来强化能力。"+
                        "\n增强道具有两种,分别为发射两发子弹,子弹大小加倍。");
            }else if(source==about){
                JOptionPane.showMessageDialog(null,
                        "Plane::War" + "\n" + "2018级***");
            }else if(source==exit){
                System.exit(0);
            }else if(source==plane1){
                Plane.count=1;
                panel.plane=new Plane();
            }else if(source==plane2){
                Plane.count=2;
                panel.plane=new Plane();
            }else if(source==plane3){
                Plane.count=3;
                panel.plane=new Plane();
            }else if(source==plane4){
                Plane.count=4;
                panel.plane=new Plane();
            }
            GamePlay.pause_flag=false;
            //gameFrame.this.notifyAll();
        }
    }

    //对单选按钮的监听
    private class RadioButtonListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            JRadioButtonMenuItem source = (JRadioButtonMenuItem) e.getSource();
            if (source == on) {
                music_flag = true;
                AudioPlayer.player.start(audioStream);
            } else {
                music_flag = false;
                AudioPlayer.player.stop(audioStream);
            }
        }
    }
}

gamePanel类:

作为游戏的主面板,用于添加飞机,敌机,飞机子弹,敌机子弹等游戏元素,同时完成对这些元素在指定位置的绘制,这个类同时创建好两个标签game_stop和game_win,并在其中添加图片。当玩家被击中三次时,将game_stop标签加入面板,当玩家获胜时将game_win标签加入面板。同时包含一个处理键盘事件的内部类,用于控制玩家飞机的移动。

import sun.audio.AudioPlayer;
import sun.audio.AudioStream;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Random;

class gamePanel extends JPanel {
    public Plane plane;
    public ArrayList bulletlist;
    public ArrayList enemylist;
    public ArrayList enemybulletlist;
    public ArrayList elementlist=new ArrayList();
    private checkEvent checkevent;
    public static JLabel game_stop=new JLabel(new ImageIcon("image/over.png"));
    public static JLabel game_win=new JLabel(new ImageIcon("image/game_win.png"));
    public boolean shot_flag=false;
    public gamePanel() {
        //在创建游戏面板时创建飞机对象,敌机对象,子弹对象
        plane = new Plane();
        enemylist = new ArrayList();
        bulletlist = new ArrayList();
        enemybulletlist=Enemy.enemybulletlist;
        //在创建面板对象时,同时创建敌机对象,
        for (int i = 0; i < 20; i++)
            enemylist.add(new Enemy(i));
        checkevent = new checkEvent(plane, enemylist, bulletlist,enemybulletlist,elementlist,this);
        //添加键盘事件接口
        myKeyAdapter keyadapter = new myKeyAdapter();
        addKeyListener(keyadapter);
        setVisible(true);
    }
    //绘制panel背景
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        ImageIcon image=new ImageIcon("image/background"+Enemy.enemy_group+".jpg");
        g.drawImage(image.getImage(),0,0,this.getWidth(),this.getHeight(),null);
    }

    public void paint(Graphics g) {
        super.paint(g);
        checkevent.check();
        //绘制飞机对象
        Plane.updatePosition();
        g.drawImage(plane.getPlane(), plane.getX(), plane.getY(), this);
        enhanceElement.updatePosition(elementlist);
        for(int i=0;i<elementlist.size();i++){
            enhanceElement temp=(enhanceElement) elementlist.get(i);
            g.drawImage(temp.element,temp.x,temp.y,temp.element_width,temp.element_height,this);
        }
        /*
        先绘制玩家子弹对象,通过玩家子弹的color属性设置画笔设置画笔颜色,
        以实现对敌机子弹对象的更改,实现彩色子弹
         */
        //绘制子弹对象
        Bullets.updatePosition(bulletlist);
        for (int i = 0; i < bulletlist.size(); i++) {
            Bullets bullet = (Bullets) bulletlist.get(i);
            g.setColor(bullet.color);
            g.fillOval(bullet.getX(), bullet.getY(), bullet.width, bullet.height);
            //System.out.println(bulletlist.size());
        }
        //绘制敌机子弹对象
        EnemyBullet.updatePosition(enemybulletlist);
        for(int i=0;i<enemybulletlist.size();i++){
            EnemyBullet enemyBullet=(EnemyBullet) enemybulletlist.get(i);
            g.fillOval(enemyBullet.getX(),enemyBullet.getY(),enemyBullet.width,enemyBullet.height);
        }
        Enemy.updatePostion(enemylist);
        for (int i = 0; i < enemylist.size(); i++) {
            Enemy enemy = (Enemy) enemylist.get(i);
            g.drawImage(enemy.getImage(), enemy.getX(), enemy.getY(), Enemy.enemy_width, Enemy.enemy_height, this);
        }
    }

    //内部类,实现对键盘事件的响应,控制飞机的移动及子弹的添加
    private class myKeyAdapter extends KeyAdapter {
        public void keyPressed(KeyEvent e) {
            if (e.getKeyCode() == KeyEvent.VK_UP) {
                //plane.moveup();
                Plane.up_flag=true;
            }        //按压上键
            if (e.getKeyCode() == KeyEvent.VK_DOWN) {
                //plane.movedown();
                Plane.down_flag=true;
            }    //按压下键
            if (e.getKeyCode() == KeyEvent.VK_LEFT) {
                //plane.moveleft();
                Plane.left_flag=true;
            }    //按压左键
            if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
                //plane.moveright();
                Plane.right_flag=true;
            }    //按压右键
            if (e.getKeyCode() == KeyEvent.VK_SPACE) {
                //创建子弹时,将其初始位置设置为飞船上面中间的坐标
                try {
                    AudioPlayer.player.start(new AudioStream(new FileInputStream("music/shot.wav")));
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
                if(enhanceElement.elementCatch==2){
                    bulletlist.add(new Bullets(plane.getX() + plane.plane_width / 2 - Bullets.width / 2, plane.getY()));
                }
                if(enhanceElement.elementCatch==1){
                    //Bullets.width=30;
                    //Bullets.height=30;
                    bulletlist.add(new Bullets(plane.getX() + plane.plane_width / 2 - Bullets.width / 2-30, plane.getY()));
                    bulletlist.add(new Bullets(plane.getX() + plane.plane_width / 2 - Bullets.width / 2+30, plane.getY()));
                }
                else
                    bulletlist.add(new Bullets(plane.getX() + plane.plane_width / 2 - Bullets.width / 2, plane.getY()));
            }
            repaint();
        }
        public void keyReleased(KeyEvent e){
            if (e.getKeyCode() == KeyEvent.VK_UP) {
                //plane.moveup();
                Plane.up_flag=false;
            }        //按压上键
            if (e.getKeyCode() == KeyEvent.VK_DOWN) {
                //plane.movedown();
                Plane.down_flag=false;
            }    //按压下键
            if (e.getKeyCode() == KeyEvent.VK_LEFT) {
                //plane.moveleft();
                Plane.left_flag=false;
            }    //按压左键
            if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
                //plane.moveright();
                Plane.right_flag=false;
            }//按压右键
            repaint();
        }
    }
}

Plane类:

用于创建玩家飞机的类,主要包含坐标,飞机图像,飞机速度,图像的宽度和高度等属性。根据面向对象的原则,在Plane类中还包括对飞机位置更新的方法。

import javax.imageio.IIOException;
import javax.imageio.ImageIO;
import java.awt.*;
import java.io.File;
import java.io.IOException;

public class Plane {
    public static int x,y;//飞机坐标
    private static final int panel_width=gameFrame.WIDTH-22;//获取panel的高度宽度(22,81为与frame的差额)
    private static final int panel_height=gameFrame.HEIGHT-81;
    public static int plane_width,plane_height;//存储飞机宽度和高度的静态变量
    private Image plane;
    public static int speed=4;
    public static int count=1;//加载飞机图像标记
    public static int life_num=3;//生命数量
    public static boolean up_flag=false;
    public static boolean down_flag=false;
    public static boolean left_flag=false;
    public static boolean right_flag=false;

    public Plane(){
        try{
            plane= ImageIO.read(new File("image/plane"+count+".png"));
            plane_width=plane.getWidth(null);
            plane_height=plane.getHeight(null);
        }
        catch(IOException e){System.out.println(e.toString());}
        //将飞船坐标设为底部中央
        x=panel_width/2-plane_width/2;
        y=panel_height-plane_height;
    }
    //获取飞船的private属性
    public int getX(){return x;}
    public int getY(){return y;}
    public Image getPlane(){return plane;}
    /*
    位置更新静态方法,通过类名在paint中调用,当相关属性为真时控制玩家飞机的移动
     */
    public static void updatePosition(){
        if(up_flag&&y>0)
            y=y-speed;
        if(down_flag&&(y+plane_height)<panel_height)
            y=y+speed;
        if(left_flag&&x>0)
            x=x-speed;
        if(right_flag&&(x+plane_width)<panel_width)
            x=x+speed;

    }
    public void moveup(){
        if(y>0)
            y=y-speed;
    }
    public void movedown(){
        if((y+plane_height)<panel_height)
           y=y+speed;
    }
    public void moveleft(){
        if(x>0)
            x=x-speed;
    }
    public void moveright(){
        if((x+plane_width)<panel_width)
           x=x+speed;
    }
}

Bullets类:

用于创建玩家飞机发射子弹的对象,也是属于Plane类的属性,不过作为一个独立的类会更容易操作和设置。同时,由于子弹对象的创建是由于gamePanel中处理键盘事件来创建。所以,将其作为一个独立类。主要包括坐标,子弹的宽度和高度,速度等属性。

import java.awt.*;
import java.util.ArrayList;
import java.util.Random;

public class Bullets {
    private int x,y;//子弹的坐标
    public  static int width=15,height=15;//子弹大小常量
    public static  int speed=5;//子弹速度
    public  final Color color;

    public Bullets(int x,int y){
        //如果捕获到第二种增强道具,子弹大小加倍,否则将子弹大小重置为默认大小
        if(enhanceElement.elementCatch==2){
            width=30;
            height=30;
        }else{
            width=15;
            height=15;
        }
        this.x=x;
        this.y=y;
        //此处实现对每个子弹颜色的设置
        Random rand=new Random();
        color=new Color(rand.nextInt(255),rand.nextInt(255),rand.nextInt(255));
    }
    //玩家飞机子弹位置的更新及边界检测
    public static void updatePosition(ArrayList bulletlist){
        for(int i=0;i<bulletlist.size();i++){
            Bullets bullet=(Bullets) bulletlist.get(i);
            if(bullet.y<0)
                bulletlist.remove(i);
            else
                bullet.y-=speed;
        }
    }
    public int getX(){
        return x;
    }
    public int getY(){
        return y;
    }
}

Enemy类:

用于创建敌机对象,主要包括坐标,敌机宽度高度,速度,move_count(记录敌机移动次数,到达一定次数后发射子弹,每个对象都有这个属性),enemy_group(用于记录敌机编组,依据此属性来选择加载敌机的图像,飞机位置的设置及飞机运动模式的选择)。在此类中有updatePosition方法,它依据enemy_group属性来更新敌机编组的位置。同时,由于敌机子弹是基于move_count属性来设置,所以在此类中包含子弹这一属性,表现为用动态数组来存储EnemyBullet对象。

import javax.imageio.IIOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.ImageObserver;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;

public class Enemy {
    private Image enemy;//enemy图像
    public int x, y;//enemy坐标
    public static int enemy_width = 34, enemy_height = 24;//敌机宽度,高度静态常量
    static int panel_width = gameFrame.WIDTH - 22;
    static int panel_height = gameFrame.HEIGHT - 81;
    public static int speed = 1;
    Toolkit toolkit = Toolkit.getDefaultToolkit();
    private boolean flag;
    //敌机移动标记,true向下移动,false向上移动,第一种运动模式标记,第二种运动模式中作为开始随机移动的标记
    private int move_count;
    private int t;
    public static ArrayList enemybulletlist=new ArrayList();//所有敌机共用一个敌机子弹动态数组
    public static int enemy_group=1;//根据enemy_group来加载图像和设置位置,更新位置

    public Enemy(int i) {
        try{enemy= ImageIO.read(new File("image/enemy"+enemy_group+".png"));}
        catch(IIOException e){e.printStackTrace();}
        catch (IOException e){System.out.println(e.getMessage());}
        enemy_width=enemy.getWidth(null);
        enemy_height=enemy.getHeight(null);
        //根据i完成对飞机初始位置的设置,i为在动态数组中的位置
        if (enemy_group == 1) {
            x = panel_width + 2 * enemy_width * (i - 1);
            y = panel_height / 5 - 2 * enemy_height * (i - 1);
            //enemy = toolkit.getImage("image/enemy1.jpg");
            flag = true;
            move_count=0;
        }
        if (enemy_group == 2) {
            //enemy = toolkit.getImage("image/enemy1.jpg");
            //System.out.println(enemy.getHeight(null));
            //enemy_width = 46;
            //enemy_height = 60;
            flag = false;
            x = 3 * enemy_width * (-i);
            y = panel_height / 3;
            move_count = 0;
        }
    }

    //更新敌机位置,mark标志敌机之后的运动轨迹
    public static void updatePostion(ArrayList enemylist) {
        //System.out.println(enemylist.size());检测越界的敌机是否移出动态数组
        if (enemy_group == 1) {
            for (int i = 0; i < enemylist.size(); i++) {
                Enemy temp = (Enemy) enemylist.get(i);
                //判断敌机位置
                if (temp.y < panel_height / 6)
                    temp.flag = true;
                if (temp.y > panel_height / 3)
                    temp.flag = false;
                /*
                飞机最初在右边界
                控制敌机在gamePanel的高度1/6至1/3处移动
                当到达左边界时以3倍速度向下移动
                当到达下边界时删除这个敌机对象
                 */
                if (temp.y > panel_height) {
                    enemylist.remove(i);
                    //System.out.println(enemylist.size());
                }
                if (temp.x < 0)
                    temp.y += 3 * speed;
                else if (temp.flag) {
                    temp.x -= speed;
                    temp.y += speed;
                } else {
                    temp.x -= speed;
                    temp.y -= speed;
                }
                temp.move_count++;
                //此处是一个修正,让前面敌机产生子弹的频率较慢,以防止这一组敌机同时产生子弹
                if(temp.move_count%((20-i)*50)==0)
                    enemybulletlist.add(new EnemyBullet(temp.x+enemy_width/2-EnemyBullet.width/2,temp.y+enemy_height));
            }
        }

        if (enemy_group == 2) {
            Random rand = new Random();
            for (int i = 0; i < enemylist.size(); i++) {
                Enemy temp = (Enemy) enemylist.get(i);
                //当敌机的x移动到400处时,开始随机移动
                if (temp.x > 400)
                    temp.flag = true;
                else
                    temp.x += 3 * speed;
                //当开始随机移动后判断是否超出边界,因为初始位置有些敌机放在外面
                if (temp.flag && (temp.x < 0 || temp.x > panel_width || temp.y < 0 || temp.y > panel_height))
                    enemylist.remove(i);
                //如果move_count为300倍数且开始随机移动,则随机生成每个敌机的属性t
                if (temp.flag && temp.move_count%300== 0) {
                    temp.t = rand.nextInt(4);
                }
                /*
                随机移动时,依据每个敌机的属性t决定向哪移动
                当向某一方向移动300次后,重置move_count
                决定下一次的移动方向
                 */
                if (temp.flag) {
                    if (temp.t == 0) {
                        temp.x += 2*speed;
                        temp.y -= speed;
                    } else if (temp.t == 1) {
                        temp.x -= speed;
                        temp.y -= speed;
                    } else if (temp.t == 2) {
                        temp.x -= speed;
                        temp.y += 2*speed;
                    } else {
                        temp.x += 2*speed;
                        temp.y += 2*speed;
                    }
                    temp.move_count++;
                    if(temp.move_count%200==0)
                        enemybulletlist.add(new EnemyBullet(temp.x+enemy_width/2-EnemyBullet.width,temp.y+enemy_height));
                }
            }
        }
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public Image getImage() {
        return enemy;
    }
}

enhanceElement类:

import javax.imageio.ImageIO;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;

public class enhanceElement {
    public int x,y;
    public Image element;
    static int panel_width = gameFrame.WIDTH - 22;
    static int panel_height = gameFrame.HEIGHT - 81;
    public static int element_width,element_height;
    public static int speed=1;
    public int move_count;
    public int t;//控制移动方向
    public int elementKind;
    public static int elementCatch=0;
    Random rand = new Random();
    public enhanceElement(){
        try {
            //随机选择加载增强道具
            elementKind=rand.nextInt(2)+1;
            element = ImageIO.read(new File("image/element"+elementKind+".png"));
            element_width=element.getWidth(null);
            element_height=element.getHeight(null);
        } catch(IOException e){System.out.println(e.toString());}
        //初始位置在屏幕中上方的随机位置
        x=rand.nextInt(200)+500;
        y=rand.nextInt(100);
        move_count=0;
    }
    public static void updatePosition(ArrayList elementlist){
        Random rand = new Random();
        for (int i = 0; i < elementlist.size(); i++) {
            enhanceElement temp = (enhanceElement) elementlist.get(i);

            if ( (temp.x < 0 || temp.x > panel_width || temp.y < 0 ))
                temp.t = rand.nextInt(4);
            if(temp.y > panel_height)
                elementlist.remove(i);
            //如果move_count为300倍数且开始随机移动,则随机生成每个敌机的属性t
            if ( temp.move_count%300== 0) {
                temp.t = rand.nextInt(4);
            }
                /*
                随机移动时,依据每个敌机的属性t决定向哪移动
                当向某一方向移动300次后,重置move_count
                决定下一次的移动方向
                 */
                if (temp.t == 0) {
                    temp.x += speed;
                    temp.y += speed;
                } else if (temp.t == 1) {
                    temp.x -= 2*speed;
                    temp.y += speed;
                } else if (temp.t == 2) {
                    temp.x -= speed;
                    temp.y += 2*speed;
                } else {
                    temp.x += speed;
                    temp.y += 2*speed;
                }
                temp.move_count++;
            }
        }
    }

EnemyBullet类:

用于创建敌机子弹对象,主要包含坐标,宽度高度,速度等属性,包含更新子弹位置的方法。

import java.util.ArrayList;

public class EnemyBullet {
    private int x,y;//子弹的坐标
    private final int panel_width=gameFrame.WIDTH-22;//获取panel的高度宽度(22,81为与frame的差额)
    private static  int panel_height=gameFrame.HEIGHT-81;
    public static  int width=15,height=15;//子弹大小常量
    public static  int speed=4;//子弹速度
    public EnemyBullet(int x,int y){
        this.x=x;
        this.y=y;
    }
    public static void updatePosition(ArrayList enemybulletlist){
        for(int i=0;i<enemybulletlist.size();i++){
            EnemyBullet temp=(EnemyBullet) enemybulletlist.get(i);
            if(temp.y>panel_height)
                enemybulletlist.remove(i);
            else
                temp.y+=speed;
        }
    }
    public int getX(){
        return x;
    }
    public int getY(){
        return y;
    }
}

checkEvent类:

用于做各种碰撞检测,因此需要包括玩家飞机对象,玩家子弹对象,敌机对象,敌机子弹对象,同时还要有游戏主面板对象(在做检测时,若玩家飞机被击中,需要通过面板来重新生成飞机对象)(这里不包括边界检测,边界检查对应类的updatePosition类中来实现)。

import sun.audio.AudioPlayer;
import sun.audio.AudioStream;

import java.awt.*;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Random;

import static java.lang.Thread.sleep;

public class checkEvent {
    private Plane plane;
    private ArrayList enemylist;
    private ArrayList bulletlist;
    private gamePanel panel;
    private ArrayList enemybulletlist;
    private ArrayList elementlist;
    Random rand=new Random();

    public checkEvent(Plane plane, ArrayList enemylist, ArrayList bulletlist, ArrayList enemybulletlist,ArrayList elementlist, gamePanel panel) {
        this.plane = plane;
        this.enemylist = enemylist;
        this.bulletlist = bulletlist;
        this.enemybulletlist = enemybulletlist;
        this.elementlist=elementlist;
        this.panel = panel;
    }

    /*
    碰撞检测方法
    玩家飞机与敌机的碰撞,玩家飞机与敌机子弹的碰撞
    玩家飞机子弹与敌机的碰撞,玩家飞机与增强道具的碰撞
    同时,实现增强道具的随机添加
     */
    public void check() {
        //捕获数组越界异常
        try {
            //增强道具出现频率
            if(rand.nextInt(1000)==1&&elementlist.size()<2){
                elementlist.add(new enhanceElement());}
            //当第二组敌机从屏幕上消失时,游戏结束,玩家获胜
            if (Enemy.enemy_group == 2 && enemylist.size() == 0) {
                panel.add(gamePanel.game_win);
                GamePlay.stop_flag = true;
                //panel.repaint();
            } else {
                if (enemylist.size() == 0) {
                    Enemy.enemy_group++;
                    for (int i = 0; i < 50; i++)
                        (panel.enemylist).add(new Enemy(i));
                    enemylist = panel.enemylist;
                }

            /*
            检测子弹与敌机的碰撞
            先检测子弹数量,若为0,则不会与敌机碰撞
             */
                for (int i = 0; i < bulletlist.size(); i++) {
                    for (int j = 0; j < enemylist.size(); j++) {
                        Enemy temp1 = (Enemy) enemylist.get(j);
                        Bullets temp2 = (Bullets) bulletlist.get(i);
                        Rectangle rect1 = new Rectangle(temp1.x, temp1.y, temp1.enemy_width, temp1.enemy_height);
                        Rectangle rect2 = new Rectangle(temp2.getX(), temp2.getY(), temp2.width, temp2.height);
                        if (rect1.intersects(rect2)) {
                            bulletlist.remove(i);
                            enemylist.remove(j);
                        }
                    }
                }
            /*
            检测飞机与敌机的碰撞,在碰撞后休眠一段时间
             */
                for (int i = 0; i < enemylist.size(); i++) {
                    Enemy temp1 = (Enemy) enemylist.get(i);
                    Rectangle rect1 = new Rectangle(temp1.x, temp1.y, temp1.enemy_width, temp1.enemy_height);
                    Rectangle rect3 = new Rectangle(plane.x, plane.y, plane.plane_width, plane.plane_height);
                    if (rect1.intersects(rect3)) {
                        enemylist.remove(i);
                        sleep(1000);
                        Plane.life_num--;
                        if (Plane.life_num <= 0) {
                            panel.add(gamePanel.game_stop);
                            GamePlay.stop_flag = true;
                        } else {
                            //飞机被碰撞后,初始化为无增强道具
                            enhanceElement.elementCatch=0;
                            panel.plane = new Plane();
                            plane = panel.plane;
                        }
                    }
                }
                /*
                玩家飞机与增强道具的碰撞
                 */
                for(int i=0;i<elementlist.size();i++){
                    enhanceElement temp = (enhanceElement) elementlist.get(i);
                    Rectangle rect1 = new Rectangle(temp.x, temp.y, temp.element_width, temp.element_height);
                    Rectangle rect2 = new Rectangle(plane.x, plane.y, plane.plane_width, plane.plane_height);
                    if (rect1.intersects(rect2)) {
                        enhanceElement.elementCatch =temp.elementKind ;
                        try {
                            AudioPlayer.player.start(new AudioStream(new FileInputStream("music/pickelement.wav")));
                        } catch (Exception e1) {
                            e1.printStackTrace();
                        }
                        elementlist.remove(i);
                    }
                }
            /*
            检测敌机子弹与我的飞机碰撞,在碰撞后休眠一段时间
             */
                for (int i = 0; i < enemybulletlist.size(); i++) {
                    EnemyBullet temp = (EnemyBullet) enemybulletlist.get(i);
                    Rectangle rect1 = new Rectangle(temp.getX(), temp.getY(), temp.width, temp.height);
                    Rectangle rect2 = new Rectangle(plane.x, plane.y, plane.plane_width, plane.plane_height);
                    if (rect1.intersects(rect2)) {
                        enemybulletlist.remove(i);
                        sleep(1000);
                        Plane.life_num--;
                        if (Plane.life_num < 0) {
                            panel.add(gamePanel.game_stop);
                            GamePlay.stop_flag = true;
                        } else {
                            //飞机被碰撞后,初始化为无增强道具
                            enhanceElement.elementCatch=0;
                            panel.plane = new Plane();
                            plane = panel.plane;
                        }
                    }
                }
            }
        } catch (IndexOutOfBoundsException e) {
            System.out.println(e.toString());
        } catch (InterruptedException e) {
            System.out.println(e.toString());
        }
    }
}
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
package cn.feike.shoot; import java.awt.Graphics; import java.awt.image.BufferedImage; public abstract class FlyingObject { protected double x;//物体的x坐标 protected double y;//物体的y坐标 protected double width;//物体的宽 protected double heigth;//物体的高 protected BufferedImage image;//当前正在显示的图片 protected int index = 0;//图片数组下标序号,子类中使用 protected double step;//飞行物每次(1/24秒)移动的距离 protected int life;//命 protected int state;//飞行物的状态 public static final int ACTIVE=0;//活着状态 public static final int DEAD=1;//死亡状态 public static final int REMOVE=2;//回收状态 //默认构造器 public FlyingObject() { life = 1; state = ACTIVE; } //有参构造器 public FlyingObject(double width,double heigth){ this();//调用无参数的构造器,必须写在第一行. this.x = (int)(Math.random()*(480-width)); this.y = -heigth; this.width = width; this.heigth = heigth; step = Math.random()*3+0.8;//初始化step为[0.8,3.8)之间的数 } //重写toString方法 public String toString() { return x+","+y+","+width+","+heigth+","+image; } //重写paint,方便子类对象的使用 public void paint(Graphics g) { g.drawImage(image, (int)x, (int)y, null);//绘制图片 } //飞行物移动的move方法 /** * 重构了move,方法实现播放销毁动画功能 */ public void move(){ if(state == ACTIVE){ y += step; return ; } if(state == DEAD){ //从子类对象中获取下一张照片 BufferedImage img = nextImage(); if(img == null){ state = REMOVE;//没有照片则回收 }else{ image = img;//否则把子类的图片传给image } //越界则销毁 if(y>=825){ state = REMOVE; } } } /** * 子类中必须有的方法,返回下一个要播放的照片引用, * 如果返回null表示没有可播放的照片了. */ protected abstract BufferedImage nextImage(); /** * 飞行物被打了一下 */ public void hit(){ if(life>0){ life--; } if(life==0){ state = DEAD; } } /** * 碰撞检测的方法 * 检测物体的位置是否在碰撞的范围内. * (子弹是否在飞行物的碰撞范围内) */ public boolean duang(FlyingObject obj){ //this(x,y,w,h) //obj(x,y,w,h) double x1 = this.x - obj.width; double x2 = this.x + this.width; double y1 = this.y - obj.width; double y2 = this.y + this.heigth; return x1<obj.x&&obj;.x<x2&&y1;<obj.y&&obj;.y<y2; } /** 重构FlyingObject,添加了状态检查方法 */ /** 检查飞行物死了吗 */ public boolean isDead(){ return state == DEAD; } /** 检查飞行物是否活动的 */ public boolean isActive(){ return state == ACTIVE; } /** 检查飞行是否可以被删除*/ public boolean canRemove(){ return state == REMOVE; } /** 飞行物添加"去死"方法*/ public void goDead(){ if(isActive()){ state = DEAD; } } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值