经过一段时间的学习,掌握了基本的多线程、双缓冲等知识要点,通过这些知识点简单实现一个项目,即飞机大战。
线程与进程
1、程序
是一份存在存储里的文件,固定的文件包含 (代码,素材,配置文件…)
2、进程
一个程序从载入内存,程序启动、运行、结束的整个过程。
3、线程
可简单理解为进程 > 线程,如CPU双核四线程、六核六线程。
一般来说,一个进程,可以有多个线程。
进程:游戏 - 王者荣耀
包括代码、图片素材等
运行时图片需要在屏幕上绘制出来,数据的变化
4、Java如何实现线程
(1)Thread 类
1.继承Thread 类
2.重写run方法
3.使用线程 -启动方法 - start
(2)Runnable 接口
1.实现Runnable接口
2.重写run方法
3.在构造方法中,实例化Thread类的对象(包含了实现了Runnable接口的类的对象)
4.使用Thread类的对象启动,通过start方法。
双缓冲
作用:防止绘制时图像卡顿
原来绘制JFrame,得到一个Graphcis对象来绘制时:
一个一个来绘制
1.背景 – 全尺寸的图片,整个JFrame
2.画球 – 根据球的坐标改变这个球大小范围内的像素
双缓冲绘图:
一次绘制
1.先找个地方,把下一帧要显示的东西都画好变成一张图,
2.再把这张图整个绘制一遍
1.一个Ball类,一个球=一个对象,可用此作为飞船和子弹的基本类(球的数据(坐标、大小、颜色、速度),球的方法(绘制、移动),球的不同(插入不同的飞机,子弹图片))
2.一个界面类
3.一个监听器类
4.通过Ball类构建一个飞船生成类和一个子弹生成类
package NewBallV2;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
public class Ball {
//球的属性
int x,y,size,speedx,speedy;
int width,height;
Color color;
int r;
ArrayList<Ball> balls;
ArrayList<Plane> ships;
BufferedImage img;
//飞船和子弹的构造函数
public Ball(ArrayList<Ball> balls,int x,int y,int speedx,int speedy,BufferedImage img){
this.balls=balls;
this.x=x;
this.y=y;
this.speedx=speedx;
this.speedy=speedy;
this.img=img;
this.height=img.getHeight(null);
this.width=img.getWidth(null);
}
//另一种构造函数,用于己方飞船
public Ball(ArrayList<Plane> ships,int x,int y,BufferedImage img){
this.ships=ships;
this.x=x;
this.y=y;
this.img=img;
this.height=img.getHeight(null);
this.width=img.getWidth(null);
}
// 画飞船和子弹的函数
public void drawball(Graphics g) throws IOException{
img.getGraphics();
g.drawImage(img, x, y, null);
}
public void drawSelf(Graphics g){
//用于之后扩展的Plane类继承
}
// 画小球
public void drawBall(Graphics g) {
g.fillOval(x, y, size, size);
g.setColor(color);
}
// 移动小球 改变小球的坐标
public void moveBall() {
if(x>1800||x<0||y>1000||y<0) {
speedx=-speedx;
speedy=-speedy;
}
x+=speedx;
y+=speedy;
}
public void collision(ArrayList<Ball> balls){
for(int i=0;i<balls.size();++i){
Ball ball = balls.get(i);//获取小球对象
if(ball != this){
//判断两个小球是否碰撞
if((ball.x - x) * (ball.x - x) + (ball.y - y) * (ball.y - y) < (ball.r + r)
* (ball.r + r)){
//交换移动速度
int tempX = ball.speedx;
ball.speedx = speedx;
speedx = tempX;
int tempY = ball.speedy;
ball.speedy = speedy;
speedy = tempY;
}
}
}
}
// paint 整体擦除背景
public void cleanBall(Graphics g) {
g.setColor(new Color(238,238,238));
g.fillOval(x-size, y-size, size, size);
}
}
package NewBallV2;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class BallFrame extends JFrame implements Runnable{
ArrayList<Ball> balls = new ArrayList<Ball>(); //敌方飞船队列
ArrayList<Plane> ships = new ArrayList<Plane>(); //己方飞船队列
ArrayList<Ball> bullets=new ArrayList<Ball>(); //敌方子弹队列
ArrayList<Ball> bullets1=new ArrayList<Ball>(); //己方子弹队列
Boolean game=true; //游戏开始按钮
KeyEvent e;
// 初始化界面
public void initUI() {
this.setTitle("Ball");
this.setSize(1800, 1000);
this.setResizable(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 注册鼠标监听器
BallListen ballListen = new BallListen(this,balls,bullets1,ships,game);
this.addMouseListener(ballListen);
this.addKeyListener(ballListen);
this.setVisible(true);
ballListen.g=this.getGraphics();
// 生成飞船和子弹
BallAI ballAI = new BallAI(balls,bullets,ships);
ballAI.start();
}
@Override
public void paint(Graphics bg) {
// 休眠
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 需要绘制的对象 都通缓冲画布来绘制到缓冲图片上
// bg.setColor(Color.BLUE);
// bg.fillRect(0, 0, this.getWidth(), this.getHeight());
//使用绝对路径
ImageIcon icon = new ImageIcon("F:\\Java\\学习\\线程飞机大战\\飞机大战\\background\\back.jpg");
//获取图片
Image bjImg = icon.getImage();
//每次重画一次图片,避免飞机出现残影
bg.drawImage(bjImg,0,0,this.getWidth(),this.getHeight(),null);
for (int i = 0; i < balls.size(); i++) {
//绘制己方飞机
if (i==0){
ships.get(i).drawSelf(bg);
ships.get(i).moveBall();
//ships.get(i).addDirection(e);
}
//绘制敌方飞机
if (balls.get(i) != null) {
try {
balls.get(i).drawball(bg);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
balls.get(i).moveBall();
if(balls.get(i).y>1000||balls.get(i).x>1800||balls.get(i).x<0) {
balls.remove(i);
}
}
}
//绘制敌方子弹
for (int i = 0; i < bullets.size(); i++) {
if (bullets.get(i) != null) {
try {
bullets.get(i).drawball(bg);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
bullets.get(i).moveBall();
if(bullets.get(i).y>1000) {
bullets.remove(i);
}
}
}
//绘制己方子弹
for (int i = 0; i < bullets1.size(); i++) {
if (bullets1.get(i) != null) {
try {
bullets1.get(i).drawball(bg);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
bullets1.get(i).moveBall();
if(bullets1.get(i).y<0) {
bullets1.remove(i);
}
}
}
System.out.println("已经生成的敌方飞船:"+balls.size());
System.out.println("已经生成的子弹:"+bullets.size());
}
// 重写run
public void run() {
// 添加双缓存技术,解决游戏画面闪烁问题
// 得到一张缓冲图片
Graphics g = this.getGraphics();
BufferedImage bfimg = new BufferedImage(this.getWidth(), this.getHeight(),
BufferedImage.TYPE_INT_ARGB);
// 通过缓冲图片对象取到一张缓冲画布
Graphics bg = bfimg.getGraphics();
//System.out.println(game);
while (game==true) {
paint(bg);
//将缓冲图片通过窗体的画布绘制到窗体上
g.drawImage(bfimg, 0, 0, this);
}
}
// 主函数
public static void main(String[] args) {
BallFrame bf = new BallFrame();
bf.initUI();
Thread t1= new Thread(bf);
t1.start();
}
}
package NewBallV2;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import javax.imageio.ImageIO;
public class BallListen implements MouseListener,KeyListener,ActionListener{
Graphics g;
String action;
String shapeTypeStr = "";
ArrayList<Ball> balls = new ArrayList<Ball>();
ArrayList<Ball> bullets1 = new ArrayList<Ball>();
ArrayList<Plane> ships = new ArrayList<Plane>();
BallFrame ballFrame;
Boolean game;
public BallListen(BallFrame ballFrame,ArrayList<Ball> balls,ArrayList<Ball> bullets1,ArrayList<Plane> ships,Boolean game){
this.ballFrame = ballFrame;
this.balls=balls;
this.ships=ships;
this.bullets1=bullets1;
this.game=game;
}
public void actionPerformed(ActionEvent e){
action = e.getActionCommand();
shapeTypeStr = action;
}
public void keyTyped(KeyEvent e){
}
public void keyPressed(KeyEvent e){
//键盘控制飞机
switch(e.getKeyCode()){
case 0x25 :
ships.get(0).x-=5;
break;
case 0x26 :
ships.get(0).y-=5;
break;
case 0x27 :
ships.get(0).x+=5;
break;
case 0x28 :
ships.get(0).y+=5;
break;
}
}
public void keyReleased(KeyEvent e){
}
public void mouseClicked(MouseEvent e) {
}
Random random = new Random();
public void mousePressed(MouseEvent e) {
//按下鼠标操作
//if("开始".equals(shapeTypeStr)){
//game=true;
//准备己方子弹数据
int x=ships.get(0).x + 49;
int y=ships.get(0).y - 10;
int speedx = 0;
int speedy = -25;
BufferedImage img = null;
try {
//子弹图片
img = ImageIO.read(new File("F:\\Java\\学习\\线程飞机大战\\飞机大战\\myplane\\bullet1.png"));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//生成己方子弹
Ball mybullet= new Ball(bullets1, x, y, speedx, speedy, img);
bullets1.add(mybullet);
// System.out.println("按下鼠标");
//
// int speedx = random.nextInt(10);
// int speedy = random.nextInt(10);
// int r = random.nextInt(255);
// int g = random.nextInt(255);
// int b = random.nextInt(255);
// Color color = new Color(r,g,b);
//
//
// Ball ball = new Ball(balls,e.getX(),e.getY(),50,speedx,speedy,color);
// balls.add(ball);
//}
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
}
package NewBallV2;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import javax.imageio.ImageIO;
public class BallAI extends Thread{
ArrayList<Ball> balls;
ArrayList<Ball> bullets;
ArrayList<Plane> ships;
Random random = new Random();
public BallAI(ArrayList<Ball> balls,ArrayList<Ball> bullets,ArrayList<Plane> ships) {
this.balls=balls;
this.bullets=bullets;
this.ships=ships;
}
@Override
public void run() {
// 休眠
try {
Thread.sleep(300);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//己方飞船的图片文件
BufferedImage img1 = null;
try {
img1 = ImageIO.read(new File("F:\\Java\\学习\\线程飞机大战\\飞机大战\\myplane\\hero12.png"));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//生成己方飞船
Plane ship= new Plane(ships, 800, 900, img1);
ships.add(ship);
while (true) {
//准备敌方飞船数据
int x=random.nextInt(1800);
int y=10;
int speedx = random.nextInt(18) - 8;
int speedy = random.nextInt(5) + 5;
BufferedImage img = null;
try {
img = ImageIO.read(new File("F:\\Java\\学习\\线程飞机大战\\飞机大战\\enemyplane\\enemy1.png"));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//生成敌方飞船
Ball ball= new Ball(balls, x, y, speedx, speedy, img);
balls.add(ball);
//启动这个飞船自动生成子弹的线程
BulletAI bulletAI = new BulletAI(bullets, ball);
bulletAI.start();
// 生成飞船间隔时间
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
package NewBallV2;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import javax.imageio.ImageIO;
public class BulletAI extends Thread {
Random random = new Random();
ArrayList<Ball> bullets;
Ball ball;
public BulletAI(ArrayList<Ball> bullets, Ball ball) {
this.bullets=bullets;
this.ball=ball;
}
@Override
public void run() {
while (true) {
// 准备子弹数据
int x = ball.x + 25;
int y = ball.y + 35;
//int size = 15;
int speedx = 0;
int speedy = 8;
BufferedImage img = null;
try {
//子弹图片
img = ImageIO.read(new File("F:\\Java\\学习\\线程飞机大战\\飞机大战\\enemyplane\\bullet2.png"));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//生成子弹
Ball ball = new Ball(bullets, x, y, speedx, speedy, img);
bullets.add(ball);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}