Java小白-如何用线程做飞机大战?


前言

本人Java开发小白一枚,从0开始学开发。
本文将从头记录如何开发出自己的飞机大战,也供日后复习参考。
本文仅供参考,可能存在不少漏洞,望请指教。


提示:以下是本篇文章正文内容,下面案例可供参考

一、飞机大战一共需要哪几个类?

1. 界面类 2. 游戏监听器 3. 游戏主线程 4. 飞机对象类 5. 自动化线程

二、各类详细讲解

1.界面类

顾名思义,GameUI 是用于创建游戏界面,包括设置界面属性,添加游戏中涉及到的监听器。一般需要在最开始就写出来。

代码如下(示例):

package feijidazhan.java0302;

import java.awt.Graphics;

import javax.swing.JFrame;

public class GameUI extends JFrame{
	public static void main(String[] args) {
		GameUI gameui= new GameUI();
		gameui.initUI();
	}
	public void initUI() {
		setTitle("飞机大战");
		setSize(700,700);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setVisible(true);
		Graphics g = getGraphics(); //获取画笔
		GameListener gl= new GameListener(g);
		addMouseListener(gl);//添加鼠标监听器 
		addKeyListener(gl);//添加键盘监听器
		addMouseMotionListener(gl); //添加鼠标拖拽监听器
	}
}

2.游戏监听器

在这个类中需要把飞机大战中涉及到的监听器方法重写。
可以想一下,飞机大战需要哪些监听器呢?
首先,我们可以尝试添加一个鼠标监听器,当我们按下鼠标的时候就可以产生一个飞机。

代码如下(示例):

public void mousePressed(MouseEvent e){
	Plane plane = new Plane(e.getX(), e.getY(), 100, 0, 1, 1, 1);//获取飞机的坐标 
	gl.planes[index++]= plane;//将飞机依次存入planes 队列

这里重写了鼠标监听器的方法,plane对象需要在Plane飞机类里写。

除此之外,我们还需要键盘监听器,我们可以通过键盘来控制飞机运动,从而实现友机和敌机的区分。

在最后,还引入了一个MouseMotionListener,这个监听器可以实现通过拖拽鼠标控制飞机。

在引入这些监听器之后,我们不着急先去写监听器中的方法,我们先去想一下如何写游戏主线程。

3.游戏主线程

可以想一下,这个主线程中,我们需要做些什么事?
1.画飞机 2.让飞机移动。

该如何画飞机呢?
在游戏中,应该是会有无数个敌机从上方飞下来,所以我们首先需要定义一个队列,把产生的飞机存到这个队列里面。然后从这个队列里面一个一个的取出来我们的飞机并画出来然后让飞机自己移动。

Plane[] planes= new Plane[1000];//创建队列 监听器获取飞机坐标后存入队列
while (true) {
			g2d.drawImage(background, 0, 0, 700, 700,null); //在缓冲画布上绘制背景
			for (int i =0; i<planes.length; i++) {
				if (planes[i]!=null) {

					//飞机绘制 移动 碰撞 
					Plane plane= planes[i];//依次读取队列中飞机 
					plane.drawplane(g2d);
					plane.moveplane();
//					plane.crashplane(planes);
				}
			}
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
		}

此时,我们已经把敌机取出来并且可以画出来了,为了让敌机的飞行更流畅,我们选择先将飞机画在缓存画布上,然后在将缓存画布完整画出来,同时我们也将提前选好的飞机大战背景图片先画在缓存画布上面。

完整代码如下:

package feijidazhan.java0302;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

import javax.swing.ImageIcon;


//绘制游戏主线程
public class GameThread  implements Runnable{
	Plane[] planes= new Plane[1000];//创建队列 监听器获取飞机坐标后存入队列
	Graphics gui;
	Plane goodplane;//声明变量 goodplane
	@Override
	public void run() {
		// TODO Auto-generated method stub
		BufferedImage buffimg=new BufferedImage(700, 700,BufferedImage.TYPE_INT_ARGB); //缓存画布
		Graphics g= buffimg.getGraphics();
		// g 绘制的内容显示在 buffimg上  -- 过程: 内存中  先绘制一个实心矩形  在绘制飞机
		// gui 绘制 buffimg  负责将每张buffimg都绘制出来 
		Graphics2D g2d = (Graphics2D)g;
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		Image background = new ImageIcon("飞机大战/background.jpeg").getImage();//声明背景并获取背景图片
		while (true) {
//			g2d.setColor(Color.white);
//			g2d.fillRect(0, 0, 700, 700);
			g2d.drawImage(background, 0, 0, 700, 700,null); //在缓冲画布上绘制背景
			goodplane.drawplane(g2d);//画友机
			
			for (int i =0; i<planes.length; i++) {
				if (planes[i]!=null) {
//					System.out.println(planes[i]);
					//飞机绘制 移动 碰撞 
					Plane plane= planes[i];//依次读取队列中飞机 
					plane.drawplane(g2d);
					plane.moveplane();
					if(plane.crashplane(goodplane)) {
						planes[i]= null;  //碰撞后消除敌机	
					};
					
				}
				
			}
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			gui.drawImage(buffimg, 0, 0, null);
		}
	}
	
}


4.飞机对象类

我们将在飞机对象类里面定义飞机如何画出、如何飞行、如何碰撞。

飞行方法:

我们在自动化线程类中定义了敌机的初始化 speedx,speedy,我们可以在飞行方法中让 飞机的 x,y坐标分别每次增加speedx,speedy,这样敌机就可以横纵向飞啦!

碰撞方法:

首先我们需要先明确一个问题,好飞机一次性碰撞几个飞机?换句话说,是好飞机碰撞一个敌机就消失呢,还是碰撞完所有的敌机敌机才消失呢?
这里我写的是碰撞一个敌机,敌机就会消失。

第二个问题,如何检测飞机碰撞?
可以很容易想到,当两个飞机的横纵坐标之差小于飞机本身的大小,那么就会发生碰撞。

在这里我们引用了 布尔值 ,在发生碰撞之后,返回true,否则返回false。

同时,在调用碰撞方法的游戏主线程中,需要将碰撞后的敌机进行擦出,做法为将数组中这个位置的敌机改为null,则在下一次绘制中就无法绘制出来,从而实现擦出效果。

package feijidazhan.java0302;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.util.Random;

import javax.swing.ImageIcon;

public class Plane {
	int x,y,size;
	double speedx,speedy;
	int identity,status;
	Image goodplane = new ImageIcon("飞机大战/goodplane.png").getImage();//获取好飞机图像
	Image badplane = new ImageIcon("飞机大战/badplane.png").getImage();//获取敌机图像
	Random ran=new Random();
	//飞机构造方法
	public Plane(int x, int y, int size, double speedx, double speedy, int identity, int status) {
		this.x = x;
		this.y = y;
		this.size = size;
		this.speedx = speedx;
		this.speedy = speedy;
		this.identity = identity;
		this.status = status;
	}
	
	
	
	

	public boolean crashplane(Plane planes) {
		// TODO Auto-generated method stub

				if(Math.abs(planes.x - this.x)<size) {//检测是否碰撞 planes -->goodplane this -->敌机
					if(Math.abs(planes.y - this.y)<size) {
						return true;
					}
				}
				return false;
		
	}

	public void moveplane() {
		// TODO Auto-generated method stub
		y+=speedy;
		x+= speedx;
		
	}

	public void drawplane(Graphics g) {
		// TODO Auto-generated method stub
		//判断飞机身份
		if(identity == 1) {
			g.drawImage(goodplane, x, y, size, size, null); //绘制敌机
		}
		else{
			g.drawImage(badplane, x, y, size, size, null);//绘制好飞机
			
		}
	}

}

5.自动化线程

由于之前写到的飞机队列,我们将飞机依次从队列中取出,但是在游戏中,我们需要让敌机自动产生,而非我们手动点击产生,并且敌机的位置是随机的。

所以我们需要添加一个自动化线程类,通过该线程,我们可以调用plane方法,并且随机给飞机定义一个位置,并存入飞机队列中。

package feijidazhan.java0302;

import java.util.Random;

public class AutoThread implements Runnable {
	Random random = new Random();
	Plane planes[];
	int index=0;
	public void run() {
		while(true) {
			Plane plane = new Plane(random.nextInt(700), random.nextInt(100),50, 0, 3, 1, 1);//获取飞机的坐标 
	    	planes[index++]= plane;//将飞机依次存入planes 队列
	    	
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}


6.完整代码

GameUI:

package feijidazhan.java0302;

import java.awt.Graphics;

import javax.swing.JFrame;

public class GameUI extends JFrame{
	public static void main(String[] args) {
		GameUI gameui= new GameUI();
		gameui.initUI();
	}
	public void initUI() {
		setTitle("飞机大战");
		setSize(700,700);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setVisible(true);
		Graphics g = getGraphics(); //获取画笔
		GameListener gl= new GameListener(g);
		addMouseListener(gl);//添加鼠标监听器 
		addKeyListener(gl);//添加键盘监听器
		addMouseMotionListener(gl); //添加鼠标拖拽监听器
		
		
	}
}

GameListener:

package feijidazhan.java0302;

import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

public class GameListener  implements MouseListener,KeyListener,MouseMotionListener{
	
	Graphics g;
	GameThread gt = new GameThread();//创建游戏主线程的对象
	AutoThread at= new AutoThread();//创建自动出现敌机的线程对象
	int index=0;//定义数组中飞机存放位置
	Plane goodplane= new Plane(350, 350, 100, 0, 0, 0, 0); //x,y,size,speedx,speedy,identity,status,蓝色飞机
	public GameListener (Graphics g) {
		this.g =g;
		gt.gui=g;
		gt.goodplane= goodplane;
		Thread thread = new Thread(gt);
		at.planes= gt.planes;//让自动线程的planes 队列 得到 planes 队列中的飞机 ,从而自动产生飞机
		Thread autothread = new Thread(at);
		thread.start();
		autothread.start();
	}
	public void mouseClicked(MouseEvent e) {}

    
    public void mousePressed(MouseEvent e){
//    	Plane plane = new Plane(e.getX(), e.getY(), 100, 0, 1, 1, 1);//获取飞机的坐标 
//    	gl.planes[index++]= plane;//将飞机依次存入planes 队列
    	
    }
    
    public void mouseReleased(MouseEvent e) {}
    public void mouseEntered(MouseEvent e){}
    public void mouseExited(MouseEvent e) {}
    
    public void keyTyped(KeyEvent e) {}
    public void keyPressed(KeyEvent e) {
    	if(e.getKeyCode()==KeyEvent.VK_UP) {
    		goodplane.y-=5;
    	}
    	if(e.getKeyCode()==KeyEvent.VK_DOWN) {
    		goodplane.y+=5;
    	}
    	if(e.getKeyCode()==KeyEvent.VK_LEFT) {
    		goodplane.x-=5;
    	}
    	if(e.getKeyCode()==KeyEvent.VK_RIGHT) {
    		goodplane.x+=5;
    	}
    }
    public void keyReleased(KeyEvent e) {}
    public void mouseDragged(MouseEvent e) {
    	//鼠标拖动飞机移动-按下
    	goodplane.x=e.getX();
    	goodplane.y=e.getY();
    }
    public void mouseMoved(MouseEvent e) {}

}

GameThread:

package feijidazhan.java0302;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

import javax.swing.ImageIcon;


//绘制游戏主线程
public class GameThread  implements Runnable{
	Plane[] planes= new Plane[1000];//创建队列 监听器获取飞机坐标后存入队列
	Graphics gui;
	Plane goodplane;//声明变量 goodplane
	@Override
	public void run() {
		// TODO Auto-generated method stub
		BufferedImage buffimg=new BufferedImage(700, 700,BufferedImage.TYPE_INT_ARGB); //缓存画布
		Graphics g= buffimg.getGraphics();
		// g 绘制的内容显示在 buffimg上  -- 过程: 内存中  先绘制一个实心矩形  在绘制飞机
		// gui 绘制 buffimg  负责将每张buffimg都绘制出来 
		Graphics2D g2d = (Graphics2D)g;
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		Image background = new ImageIcon("飞机大战/background.jpeg").getImage();//声明背景并获取背景图片
		while (true) {
//			g2d.setColor(Color.white);
//			g2d.fillRect(0, 0, 700, 700);
			g2d.drawImage(background, 0, 0, 700, 700,null); //在缓冲画布上绘制背景
			goodplane.drawplane(g2d);//画友机
			
			for (int i =0; i<planes.length; i++) {
				if (planes[i]!=null) {
//					System.out.println(planes[i]);
					//飞机绘制 移动 碰撞 
					Plane plane= planes[i];//依次读取队列中飞机 
					plane.drawplane(g2d);
					plane.moveplane();
					if(plane.crashplane(goodplane)) {
						planes[i]= null;  //碰撞后消除敌机	
					};
					
				}
				
			}
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			gui.drawImage(buffimg, 0, 0, null);
		}
	}
	
}


Plane:

package feijidazhan.java0302;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.util.Random;

import javax.swing.ImageIcon;

public class Plane {
	int x,y,size;
	double speedx,speedy;
	int identity,status;
	Image goodplane = new ImageIcon("飞机大战/goodplane.png").getImage();//获取好飞机图像
	Image badplane = new ImageIcon("飞机大战/badplane.png").getImage();//获取敌机图像
	Random ran=new Random();
	//飞机构造方法
	public Plane(int x, int y, int size, double speedx, double speedy, int identity, int status) {
		this.x = x;
		this.y = y;
		this.size = size;
		this.speedx = speedx;
		this.speedy = speedy;
		this.identity = identity;
		this.status = status;
	}
	
	
	
	

	public boolean crashplane(Plane planes) {
		// TODO Auto-generated method stub

				if(Math.abs(planes.x - this.x)<size) {//检测是否碰撞 planes -->goodplane this -->敌机
					if(Math.abs(planes.y - this.y)<size) {
						return true;
					}
				}
				return false;
		
	}

	public void moveplane() {
		// TODO Auto-generated method stub
		y+=speedy;
		x+= speedx;
		
	}

	public void drawplane(Graphics g) {
		// TODO Auto-generated method stub
		//判断飞机身份
		if(identity == 1) {
			g.drawImage(goodplane, x, y, size, size, null); //绘制敌机
		}
		else{
			g.drawImage(badplane, x, y, size, size, null);//绘制好飞机
			
		}
	}

}

AutoThread:

package feijidazhan.java0302;

import java.util.Random;

public class AutoThread implements Runnable {
	Random random = new Random();
	Plane planes[];
	int index=0;
	public void run() {
		while(true) {
			Plane plane = new Plane(random.nextInt(700), random.nextInt(100),50, 0, 3, 1, 1);//获取飞机的坐标 
	    	planes[index++]= plane;//将飞机依次存入planes 队列
	    	
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

总结

以上就是如何通过线程制作一个简单的飞机大战游戏,总共涉及了5个类,各类之间的关系也并不复杂。但目前还未完成发射子弹部分,后续会继续更新。

如有问题,欢迎批评指出。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值