Java小项目——飞机大战(一、实现线程绘制背景和我方飞机,键盘控制飞机运动)
1 总体需求分析
1.1 类
1、主类
2、我方飞机类
3、线程类
2.2 效果图
2 实现
2.1 飞机类 MyPlane
飞机类包括以下参数:
位置x、y
速度vx、vy
图片图标myicom:设置为飞机的图片
飞机类包括以下方法:
有参构造方法:初始化x、y,保证第一次绘制飞机能够有坐标
public MyPlane(int x, int y) { this.x = x; this.y = y; }
绘制飞机方法:用参数画笔g来绘制飞机,再更新vx和vy,
public void drawPlane(Graphics g) { g.drawImage(myicon.getImage(), x, y, null); x += vx; y += vy; }
代码:
package com.java8.planewarsV1;
import javax.swing.*;
import java.awt.*;
public class MyPlane {
private int x, y;
private int vx, vy;
private ImageIcon myicon = new ImageIcon(this.getClass().getResource("PaperPlane.png"));
/**
* 我方飞机的构造函数
* @param x:绘制坐标x
* @param y:绘制坐标y
*/
public MyPlane(int x, int y) {
this.x = x;
this.y = y;
}
/**
* 绘制飞机对象的函数,每次调用,则绘制一次飞机
* @param g:画笔
*/
public void drawPlane(Graphics g) {
g.drawImage(myicon.getImage(), x, y, null);
x += vx;
y += vy;
}
/**
* setVx
* setVy
* 用于在按键后,设置其每次移动的大小,并在释放的时候清0
* @param vx
*/
public void setVx(int vx) {
this.vx = vx;
}
public void setVy(int vy) {
this.vy = vy;
}
}
2.2 主界面类 GameUI
界面类和监听器类:两个写在一个类中,方便参数的传入和传出
界面类:主要实现一个面板JFrame jf,jf上添加键盘监听器,jf上获取画笔g
监听器类:KeyListener。按space空格开始游戏,按上下左右控制飞机运动。
GameUI类的参数为:
private JFrame jf; private Graphics g; private MyPlane myPlane; private MyThread myThread; private ImageIcon bgicon = new ImageIcon(this.getClass().getResource("bg.jpeg")); private int speed = 5;
空格 VK_SPACE:
1.创建飞机对象,初始化飞机的x和y;2.若线程为null,则创建myThread线程,传入mayplane飞机、g画笔、jf对象; 3.使用Thread()方法,运行myThread线程,开始不断绘制飞机类
// 按下空格,开启线程 // 线程每隔0.02s就绘制背景图、飞机 if(myThread == null){ //1.创建飞机对象 myPlane = new MyPlane((jf.getWidth() - 150) / 2, jf.getHeight() - 150); //2.创建myThread线程 myThread = new MyThread(myPlane,g,jf); //3.使用Thread()方法,运行myThread线程 new Thread(myThread).start(); }
左右上下 KeyEvent.VK_LEFT:
设置飞机类的x/y速度为+speed或者-speed
case KeyEvent.VK_LEFT: myPlane.setVx(-speed); break;
代码:
package com.java8.planewarsV1;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class GameUI implements KeyListener {
private JFrame jf;
private Graphics g;
private MyPlane myPlane;
private MyThread myThread;
private ImageIcon bgicon = new ImageIcon(this.getClass().getResource("bg.jpeg"));
private int speed = 5;
public static void main(String arg[]) {
GameUI gameUI = new GameUI();
gameUI.showUI();
}
private void showUI() {
jf = new JFrame();
jf.setTitle("飞机大战1.0");
jf.setSize(800, 800);
jf.setLocationRelativeTo(null);
jf.setDefaultCloseOperation(3);
jf.setVisible(true);
g = jf.getGraphics();
g.drawImage(bgicon.getImage(),0,0,null);
jf.addKeyListener(this);
}
public void keyTyped(KeyEvent e) {
}
/***
* 按下对应按钮,获取按钮的值e.getKeyCode(),进行不同操作
* 空格:开始游戏;上下左右:对应移动
* @param e
*/
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
switch (key) {
case KeyEvent.VK_LEFT:
myPlane.setVx(-speed);
break;
case KeyEvent.VK_RIGHT:
myPlane.setVx(speed);
break;
case KeyEvent.VK_UP:
myPlane.setVy(-speed);
break;
case KeyEvent.VK_DOWN:
myPlane.setVy(speed);
break;
case KeyEvent.VK_SPACE:
// 按下空格,开启线程
// 线程每隔0.02s就绘制背景图、飞机
if(myThread == null){
//1.创建飞机对象
myPlane = new MyPlane((jf.getWidth() - 150) / 2,
jf.getHeight() - 150);
//2.创建myThread线程
myThread = new MyThread(myPlane,g,jf);
//3.使用Thread()方法,运行myThread线程
new Thread(myThread).start();
}
break;
}
}
/**
* 清空上一次操作的speed
* @param e
*/
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
switch (key) {
case KeyEvent.VK_LEFT:
myPlane.setVx(0);
break;
case KeyEvent.VK_RIGHT:
myPlane.setVx(0);
break;
case KeyEvent.VK_UP:
myPlane.setVy(0);
break;
case KeyEvent.VK_DOWN:
myPlane.setVy(0);
break;
}
}
}
2.3 MyThread
重写线程run():
线程暂停0.02s绘制一次;在bufferedImage内绘制背景+绘制飞机(bg);将bufferedImage绘制到jf上(g)
绘制飞机线程构造函数:
需要传入飞机、画笔g、面板jf
/** * 绘制飞机线程构造函数 */ public MyThread(MyPlane myPlane, Graphics g,JFrame jf){ this.myPlane = myPlane; this.g = g; this.jf = jf; }
缓存技术bufferedImage:
使用bufferedImage的画笔bg,来绘制背景、绘制飞机。解决了画面交替绘制闪烁问题。
/** * 使用缓存技术bufferedImage,解决画面交替绘制闪烁问题 * 1 首先将所有物体绘制于bufferedImage内 * 2 再将bufferedImage绘制于JFrame内 */ //1.创建bufferedImage对象:大小为jf大小,类型为RGB BufferedImage bufferedImage = new BufferedImage(jf.getWidth(),jf.getHeight(),BufferedImage.TYPE_INT_BGR); //2.获取bufferedImage对象的画笔:bg Graphics bg = bufferedImage.createGraphics(); //3.绘制背景和飞机,于bufferedImage对象上 bg.drawImage(bgicon.getImage(),0,0,null); myPlane.drawPlane(bg); //4.绘制bufferedImage,到JFrame上 g.drawImage(bufferedImage,0,0,null);
代码:
package com.java8.planewarsV1;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
public class MyThread implements Runnable{
private MyPlane myPlane;
private Graphics g;
private JFrame jf;
private ImageIcon bgicon = new ImageIcon(this.getClass().getResource("bg.jpeg"));
/**
* 绘制飞机线程构造函数
*/
public MyThread(MyPlane myPlane, Graphics g,JFrame jf){
this.myPlane = myPlane;
this.g = g;
this.jf = jf;
}
/**
* 不使用线程,每次绘制之间间隔过长;
* 使用线程,加速绘制飞机移动轨迹。
*/
public void run() {
while(true) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
/**
* 使用缓存技术bufferedImage,解决画面交替绘制闪烁问题
* 1 首先将所有物体绘制于bufferedImage内
* 2 再将bufferedImage绘制于JFrame内
*/
//1.创建bufferedImage对象:大小为jf大小,类型为RGB
BufferedImage bufferedImage = new BufferedImage(jf.getWidth(),jf.getHeight(),BufferedImage.TYPE_INT_BGR);
//2.获取bufferedImage对象的画笔:bg
Graphics bg = bufferedImage.createGraphics();
//绘制背景和飞机,于bufferedImage对象上
bg.drawImage(bgicon.getImage(),0,0,null);
myPlane.drawPlane(bg);
//绘制bufferedImage,到JFrame上
g.drawImage(bufferedImage,0,0,null);
}
}
}