JAVA实现飞机大战详解

小游戏制作——飞机大战

java 实现

耗时四天,通过借鉴学习别人,到自己写代码。比较费头发。但最终也还是肝了出来。本来还想弄一个 菜单栏,用该改变战机和子弹,但迫于时间有限。能先写到这里了。等过段时间,我再来完善它!

1.首先 我将英雄机,敌机,子弹,玩家。都分别当做对象来处理。单独写.java文件。
2. 写一个窗口(GUI编程)。存放所有的对象。并行多线程,因为敌机 英雄机 子弹,都需要同时运行。不断检测敌机是否被子击中,英雄机是否碰到敌机。所以:这些对象 都要继承 Thread 重写 run 方法
3. 事件监听器也有写,在英雄机碰到敌机时触发,弹出窗口Gameover 并且关闭所有的窗口。结束进程。
4. 因为 敌机和子弹,在窗口中都会同时出现多个。我使用了vector 集合用来存放对象。 敌机和子弹都会消失,使用集合的 remove 方法就可以。

vector 和 list 的区别:
vector:连续存储结构:vector是可以实现动态增长的对象数组,支持对数组高效率的访问和在数组尾端的删除和插入操作,在中间和头部删除和插入相对不易,需要挪动大量的数据。

它与数组最大的区别就是vector不需程序员自己去考虑容量问题,库里面本身已经实现了容量的动态增长,而数组需要程序员手动写入扩容函数进形扩容。
list:非连续存储结构:list是一个双链表结构,支持对链表的双向遍历。每个节点包括三个信息:元素本身,指向前一个元素的节点(prev)和指向下一个元素的节点(next)。

因此list可以高效率的对数据元素任意位置进行访问和插入删除等操作。由于涉及对额外指针的维护,所以开销比较大。

5. 对方向键 的键值 做出了解。 玩家通过方向键来操控英雄机。需要,switch 语句进行识别 玩家按了哪个键。但同时,英雄机的移动范围也是有限的。不能移出窗口。
6. 将所有的java文件 存放在同一目录下,来自同一个包。

其余的小点:我在代码中有注释。大家多加理解吧!不理解可以私信我哦!

GameFrame.java 文件 窗口文件

package VacationTest.PlaneFight.src;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Random;
import java.util.Vector;

public class GameFrame extends JFrame {
    //对英雄机和敌机作提前声明
    HeroPlane heroplane;
    EnemyPlane enemyPlane;
    // 定义子弹集合
    Vector<bullet> bullets = new Vector<>();
    //敌机集合
    Vector<EnemyPlane> enemys = new Vector<>();

    GameFrame frame;
    public GameFrame() {

        frame = this ;// 后面 敌机的线程中要使用
        // 创建英雄机
        heroplane = new HeroPlane();
        //启动英雄机线程
        heroplane.start();
        // 设置窗体的宽高
        this.setSize(500, 760);
        this.setTitle("飞机大战---小帅制作");
        this.setResizable(false);//设置 用户是否可以调整窗口的大小   这里设置为 否
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLocationRelativeTo(null);//设置窗口 相对于屏幕的位置,null 指:处于屏幕中央
        // 窗口可见
        this.setVisible(true);
        // 新建线程,让 画笔 不断 重复
        new Thread(new Runnable() {//内部类。
            @Override
            public void run() {
                while (true) {
                    repaint();//不断重复画 
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

        //产生敌机的线程
        new Thread(new Runnable(){
            //产生随机数
            Random r = new Random();
            @Override
            //重写run 方法
            public void run(){
                while(true){
                    EnemyPlane enemyPlane = new EnemyPlane(r.nextInt(500), 0,frame);// 随机产生敌机,并创建敌机对象
                    enemyPlane.start(); // 启动线程
                    //随机产生敌机
                    enemys.add(enemyPlane); // 将 敌机对象 添加到 enemy 集合中 
                    try{
                        Thread.sleep(500);
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

    /**
     * 在窗口上画图片,需要不断重复的画,使用API中 paint 画笔 重写其中的方法
     * 
     * @param g
     */
    public void paint(Graphics g) {
        //System.out.println("绘制画板");
        // 画背景
        BufferedImage image = (BufferedImage) this.createImage(this.getSize().width, this.getSize().height);
        // 高效缓存画笔
        Graphics pen = image.getGraphics();
        pen.drawImage(new ImageIcon("G:\\Users\\Administrator\\eclipse-workspace\\test\\src\\VacationTest\\PlaneFight\\Image\\Background.jpg").getImage(),0, 0, null);
        // 画英雄机
        pen.drawImage(heroplane.img, heroplane.x, heroplane.y, heroplane.width, heroplane.height, null);
        // 飞机发射子弹
        for (int i = 0; i < bullets.size(); i++) {
            //System.out.println("bullet");
            // 实例化 子弹对象  b 
            bullet b = bullets.get(i);
            if (b.y > 0)
                pen.drawImage(b.img, b.x, b.y -= b.speed, b.width, b.height, null);
            else
                // 子弹超出上边界 移除
                bullets.remove(b);
        }
        //产生敌机
        for (int i = 0; i < enemys.size(); i++) {
            //实例化 敌机对象  ep
            EnemyPlane ep = enemys.get(i);
            
            if (ep.y < 760)
                pen.drawImage(ep.img, ep.x, ep.y += ep.speed, ep.width, ep.height, null);
            else
                enemys.remove(ep);
        }
        // 生效
        g.drawImage(image, 0, 0, null);
    }

    public static void main(String[] args) {
        GameFrame frame = new GameFrame();
        Player player = new Player(frame);
        //给 玩家注册事件监听器
        frame.addKeyListener(player);
    }
}

HeroPlane.java 文件 英雄机文件

package VacationTest.PlaneFight.src;

import java.awt.Image;
import javax.swing.ImageIcon;

public class HeroPlane extends Thread {

    int x = 230, y = 650;
    int width = 50, height = 50;
    int speed = 8;
    Image img = new ImageIcon(
            "G:\\Users\\Administrator\\eclipse-workspace\\test\\src\\VacationTest\\PlaneFight\\Image\\HeroPlane.png")
                    .getImage();

    // 定义方向键标志 up down left right
    boolean up, down, left, right;

    // 两种 构造器
    public HeroPlane() {

    }

    public HeroPlane(int x, int y, int width, int height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }

    public void run() {
        while (true) {
            // 实现 英雄机的 移动
            if (up) {
                if (y > 20) {
                    y -= speed;
                } else {
                    y -= 0;
                }
            }
            if (down) {
                if (y < 700)
                    y += speed;
                else
                    y += 0;
            }
            if (left) {
                if (x > 10)
                    x -= speed;
                else
                    x -= 0;
            }
            if (right) {
                if (x < 440)
                    x += speed;
                else
                    x += 0;
            }
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

    }
}

EnemyPlane.java 文件 敌机文件

package VacationTest.PlaneFight.src;

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

import VacationTest.PlaneFight.src.Gameover.MyFrame;// 导入 游戏结束的 包 自己写的java 文件

public class EnemyPlane extends Thread {

    public GameFrame gf;
    // 敌机的位置 大小 速度
    int x, y;
    int width = 50, height = 50;
    int speed = 3;
    Image img = new ImageIcon(
            "G:\\Users\\Administrator\\eclipse-workspace\\test\\src\\VacationTest\\PlaneFight\\Image\\EmenyPlane.png")
                    .getImage();

    // 构造器
    public EnemyPlane(int x, int y, GameFrame gf) {
        super();
        this.x = x;
        this.y = y;
        this.gf = gf;
    }

    // 构造器
    public EnemyPlane(int x, int y, int width, int height, GameFrame gf) {
        super();
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.gf = gf;
    }

    // 重写run方法 在线程启动时 执行
    public void run() {
        while (true) {
            if (hit()) {
                // System.out.println("hit.............");
                // 敌机被击毁后,速度变为0 图片更换为 爆炸图片
                this.speed = 0;
                this.img = new ImageIcon(
                        "G:\\Users\\Administrator\\eclipse-workspace\\test\\src\\VacationTest\\PlaneFight\\Image\\boom3.png")
                                .getImage();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 子弹击毁 移除敌机
                gf.enemys.remove(this);
                break;
            }
            // 敌机超出下边界 移除敌机
            if (this.y > 760) {
                gf.enemys.remove(this);
                break;
            }
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (crash()) {
                this.speed = 0;
                this.img = new ImageIcon().getImage();
                new MyFrame();	//实例化MyFrame对象
                gf.enemys.remove(this);
                gf.heroplane.img = new ImageIcon(
                        "G:\\Users\\Administrator\\eclipse-workspace\\test\\src\\VacationTest\\PlaneFight\\Image\\HeroPlaneBoom.png")
                                .getImage();
                try {
                    Thread.sleep(1500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //gf.heroplane.addActionListener(new broken());
                System.exit(0);
            }

        }
    }
    // 检测碰撞
    public boolean hit() {
        // Swing技术中,已经实现相关算法
        // 给出敌机的矩形
        Rectangle myrect = new Rectangle(this.x, this.y, this.width, this.height);
        Rectangle rect = null;// 给出子弹的矩形
        for (int i = 0; i < gf.bullets.size(); i++) {
            bullet b = gf.bullets.get(i);
            rect = new Rectangle(b.x, b.y, b.width, b.height);
            // 碰撞检测
            if (myrect.intersects(rect)) {
                return true;
            }
        }
        return false;

    }

    // 检测 英雄机和 敌机碰撞
    public boolean crash() {
        Rectangle myrect = new Rectangle(this.x, this.y, this.width, this.height);
        Rectangle rect2 = new Rectangle(gf.heroplane.x, gf.heroplane.y, gf.heroplane.width, gf.heroplane.height);
        if (myrect.intersects(rect2)) {
            return true;
        }
        return false;
    }
    
}

bullet.java文件 子弹文件

package VacationTest.PlaneFight.src;

import java.awt.Image;

import javax.swing.ImageIcon;

public class bullet {
    
    int x;
    int y;
    int width=30;
    int height=40;
    int speed = 15;

    Image img = new ImageIcon("G:\\Users\\Administrator\\eclipse-workspace\\test\\src\\VacationTest\\PlaneFight\\Image\\bullet2.png").getImage();

    public bullet(int x,int y){
        this.x = x;
        this.y = y;
    }
    public bullet(int x,int y ,int width , int height){
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }


}

Player.java 文件 玩家文件

package VacationTest.PlaneFight.src;

import java.awt.event.*;

public class Player extends KeyAdapter{
    //传入 frame 对象  也就是 整个窗体中的所有属性值  使用 对象名.方法 进行调用
    GameFrame frame;
    public Player(GameFrame frame){
        this.frame = frame;
    }
    /**
     * 定义一个玩家,操作键盘的上下左右。以及 发射子弹  空格 
     * 38 40 37 39  对应 上下左右
     * 重写 keyPressed 和 keyReleased 方法  并使用监听器  判断玩家按哪个键 
     */
    public void keyPressed(KeyEvent e){
        int keycode = e.getKeyCode();
        //System.out.println(keycode);//利用该语句 可以 知道 键盘上的按键 值是多少。
        switch(keycode){
            case 38: frame.heroplane.up = true;break;
            case 40: frame.heroplane.down = true;break;
            case 37: frame.heroplane.left = true;break;
            case 39:frame.heroplane.right = true;break;
            case 32:addBullet();break;
        }
    }
    public void keyReleased(KeyEvent e){
        int keycode = e.getKeyCode();
        switch(keycode){
            case 38: frame.heroplane.up = false;break;
            case 40: frame.heroplane.down = false;break;
            case 37: frame.heroplane.left = false;break;
            case 39:frame.heroplane.right = false;break;
        }
    }
    // 发射子弹方法 在 键值为  32  时 触发
    public void addBullet(){
        frame.bullets.add(new bullet(frame.heroplane.x+15, frame.heroplane.y-20));
    }
}

Gameover.java文件 游戏结束文件

package VacationTest.PlaneFight.src;

import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.WindowConstants;

public class Gameover{
    static GameFrame frame;
    
public static class MyFrame extends JFrame {	//创建新类,继承自JFrame
	private  static final long serialVersionUID = 1L;
	public MyFrame() {
		Container container = getContentPane();	//创建一个容器
		container.setLayout(null);
		//JLabel jl = new JLabel("这是一个JFrame窗体");	//在窗体中设置标签
		//jl.setHorizontalAlignment(SwingConstants.CENTER);	//将标签的文字至于标签中间的位置 
		//container.add(jl);	//将标签添加到容器中
		JButton jb = new JButton("");	//定义一个按钮
        ImageIcon img = new ImageIcon("G:\\Users\\Administrator\\eclipse-workspace\\test\\src\\VacationTest\\PlaneFight\\Image\\Gameover.jpg");
        img.setImage(img.getImage().getScaledInstance(350,150,0));
		jb.setBounds(0, 0, 350, 150);	//设置按钮的大小
        jb.setIcon(img);
		jb.addActionListener(new ActionListener() {	//为按钮添加点击事件
 
			@Override
			public void actionPerformed(ActionEvent e){
                    try {
                        Thread.sleep(1500);
                    } catch (InterruptedException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                System.exit(0);
			}		
		});
		container.add(jb);
		setSize(360,180);
		setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
		setVisible(true);
        setLocationRelativeTo(null);//设置窗口 相对于屏幕的位置,null 指:处于屏幕中央
	}

}
}

在代码中使用的图片,以及素材,已经放在百度网盘里了。
注意: 使用的图片路径 要改。
https://pan.baidu.com/s/1L70YtfqrBg8iWqFxmxB1jA
提取码:p6o2

你可能感兴趣的:(课程设计,java,游戏)