学得线程后应该就可以进行“雷霆战机”的制作了,这个拖了好久了。
首先进行界面设计,如图设计:
主要使用JFrame、JPanel和JButton组件,及添加一些监听器。
package 最_雷霆战机;
/**
* 游戏界面设计
* @author asus
*/
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class LeidianUI extends JFrame {
public static void main(String[] arg) {
new LeidianUI().initUI();
}
public void initUI() {
this.setTitle("雷电");
this.setSize(400, 600);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new BorderLayout());
// 添加游戏界面
final GamePanel jp1 = new GamePanel();
jp1.setPreferredSize(new Dimension(380, 500));
jp1.setBackground(Color.BLACK);
// 添加操作界面
JPanel jp2 = new JPanel();
jp2.setBackground(Color.WHITE);
this.add(jp1, BorderLayout.NORTH);
this.add(jp2, BorderLayout.CENTER);
final JButton start = new JButton("start");
final JButton pause = new JButton("pause");
final JButton over = new JButton("over");
pause.setEnabled(false);
over.setEnabled(false);
jp2.add(start);
jp2.add(pause);
jp2.add(over);
this.setVisible(true);
ActionListener alis = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String s = e.getActionCommand();
if (s.equals("start")) {
jp1.initGamePanel(15);
// 禁用开始按钮,其他按钮启动
start.setEnabled(false);
pause.setEnabled(true);
over.setEnabled(true);
} else if (s.equals("pause")) {
pause.setText("continue");
GamePanel.pauseThread();
} else if (s.equals("continue")) {
pause.setText("pause");
GamePanel.continueThread();
} else if (s.equals("over")) {
pause.setText("pause");
start.setEnabled(true);
pause.setEnabled(false);
over.setEnabled(false);
// 停止敌机
for (int i = 0; i < jp1.airList.size(); i++) {
jp1.airList.get(i).stopThread();
}
jp1.airList.clear();
// 停掉子弹线程
// 停止敌机
for (int i = 0; i < jp1.myAir.bulletList.size(); i++) {
jp1.myAir.bulletList.get(i).stopThread();
}
jp1.myAir.bulletList.clear();
// 自己的飞机
jp1.myAir.stopThread();
jp1.myAir = null;
}
}
};
start.addActionListener(alis);
pause.addActionListener(alis);
over.addActionListener(alis);
start.setFocusable(false);
pause.setFocusable(false);
over.setFocusable(false);
//添加键盘监听器(GamePanel实现了KeyListener的接口,所以他就是一个监听器)
this.addKeyListener(jp1);
}
}
将一个JPanel写成一个监听器,implements KeyListener。
package 最_雷霆战机;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import javax.swing.JPanel;
/***
* 重写paint方法绘制
*
* @author asus
*
*/
public class GamePanel extends JPanel implements KeyListener {
public static boolean isRun = true; // 游戏是否终止
ArrayList<EAir> airList = new ArrayList<EAir>();// 敌机对象个体存储的动态数组
MyAir myAir;
private BackgroundThread bgThread;
public void initGamePanel(int num) {
myAir = new MyAir(this);
myAir.start();
for (int i = 0; i < num; i++) {
EAir air = new EAir(this);
air.start();
airList.add(air);
}
}
@Override
public void paint(Graphics g) {
super.paint(g);
if (bgThread != null) {
bgThread.draw(g);
}
// 绘制战机
if (myAir != null) {
if (myAir.isLive) {
myAir.draw(g);
}
for (int i = 0; i < myAir.bulletList.size(); i++) {
BulletThread but = myAir.bulletList.get(i);
// 如果活着就绘制,否则就删除掉
if (but.isLive) {
but.draw(g);
} else {
myAir.bulletList.remove(i);
}
}
}
// 绘制敌机
for (int i = 0; i < airList.size(); i++) {
EAir air = airList.get(i);
if (air.isLive) {
air.draw(g);
} else {
airList.remove(i);
}
}
this.repaint();
}
@Override
public void keyTyped(KeyEvent e) {
}
public static void pauseThread() {
isRun = false;
}
public static void continueThread() {
isRun = true;
}
@Override
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
switch (code) {
case KeyEvent.VK_LEFT:
MyAir.left = true;
break;
case KeyEvent.VK_RIGHT:
MyAir.right = true;
break;
case KeyEvent.VK_UP:
MyAir.up = true;
break;
case KeyEvent.VK_DOWN:
MyAir.down = true;
break;
}
}
@Override
public void keyReleased(KeyEvent e) {
int code = e.getKeyCode();
switch (code) {
case KeyEvent.VK_LEFT:
MyAir.left = false;
break;
case KeyEvent.VK_RIGHT:
MyAir.right = false;
break;
case KeyEvent.VK_UP:
MyAir.up = false;
break;
case KeyEvent.VK_DOWN:
MyAir.down = false;
break;
}
}
}
新建自己的战机的类MyAir,作为一个线程。
package 最_雷霆战机;
/**
*
* 战机的类
*
* @author asus
*/
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.net.URL;
import java.util.ArrayList;
import javax.swing.ImageIcon;
public class MyAir extends Thread {
// 飞机属性
int x = 10, y = 10;
int width = 70;
int height = 70;
int xc = 2;
int yc = 2;
int blood = 20;
Image img;
private int panelWidth;
private int panelHeight;
private GamePanel panel;
boolean isLive = true;// 线程是否活着
// 方向指令
public static boolean up, down, left, right;
// 装子弹的队列
ArrayList<BulletThread> bulletList = new ArrayList<BulletThread>();
public MyAir(GamePanel gamePanel) {
this.panel = gamePanel;
Dimension dim = gamePanel.getPreferredSize();
panelWidth = dim.width;
panelHeight = dim.height;
// 获取战机图片
URL url = EAir.class.getResource("feiji.png");
img = new ImageIcon(url).getImage();
x = (panelWidth - width) / 2;
y = panelHeight - height;
}
// 绘制战机
public void draw(Graphics g) {
g.drawImage(img, x, y, width, height, null);
}
public void stopThread() {
isLive = false;
}
public void fire() {
BulletThread bullet = new BulletThread(panel, x + width / 2, y);
bullet.start();
bulletList.add(bullet);
}
@Override
public void run() {
while (isLive) {
if (GamePanel.isRun) {
if (left) {
xc = -2;
} else if (right) {
xc = 2;
} else {
xc = 0;
}
if (up) {
yc = -2;
} else if (down) {
yc = 2;
} else {
yc = 0;
}
x += xc;
y += yc;
// 战机不出边界
if (x <= 0) {
x = 0;
}
if (y <= 0) {
y = 0;
}
if (x >= panelWidth - width) {
x = panelWidth - width;
}
if (y >= panelHeight - height) {
y = panelHeight - height;
}
}
num++;
if (num % 20 == 0) {
this.fire();
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
int num = 0;
}
新建敌机类,extends Thread。存储到GamePanel中的动态数组里。
package 最_雷霆战机;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.net.URL;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.ImageIcon;
/**
* 敌机的属性
*
* @author asus
*
*/
public class EAir extends Thread {
// 敌机
int x = 10, y = 10;
int width = 50, height = 50;
int xc = 2, yc = 2;
int blood = 5;
Image img;
Random rd = new Random();
int[] c = { 5, 4, 3, 2, 1 };
ArrayList<EAir> airList;
private int panelWidth;
private int panelHeight;
private GamePanel panel;
boolean isLive = true; // 线程是否还存在
// static boolean isRun = true; // 线程是否还在执行逻辑处理-->进行数据的交换
public EAir(GamePanel gamePanel) {
this.panel = gamePanel;
this.airList = gamePanel.airList;
Dimension dim = gamePanel.getPreferredSize();
panelWidth = dim.width;
panelHeight = dim.height;
URL url = EAir.class.getResource("diji.png");
img = new ImageIcon(url).getImage();
initDiji();
}
// 敌机动作命令初始化
public void initDiji() {
yc = c[rd.nextInt(c.length)];
x = rd.nextInt(panelWidth - width);
y = -height;
}
// 绘制自身
public void draw(Graphics g) {
g.drawImage(img, x, y, width, height, null);
}
@Override
public void run() {
while (isLive) {
check();
if (GamePanel.isRun) {
if (y >= panelHeight - height) {
initDiji();
}
y += yc;
}
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void stopThread() {
isLive = false;
}
// 检测两个小球是否相碰
public void check() {
// 获得玩家飞机
MyAir myAir = panel.myAir;
if (myAir != null) {
// 检测玩家飞机和敌机是否碰撞
// 计算敌机的圆心
int xa = this.x + this.width / 2;
int ya = this.y + this.width / 2;
// 计算玩家的圆心
int xb = myAir.x + myAir.width / 2;
int yb = myAir.y + myAir.width / 2;
// 计算斜边
int c2 = Math.abs(xa - xb) * Math.abs(xa - xb) + Math.abs(ya - yb)
* Math.abs(ya - yb);
// 计算半径之和
int r = this.width / 2 + this.width / 2;
// 碰撞到了
if (c2 <= r * r) {
if (this.blood < myAir.blood) {
myAir.blood -= this.blood;
this.blood = 0;
} else {
myAir.stopThread();
}
this.stopThread();
}
for (int i = 0; i < myAir.bulletList.size(); i++) {
// 取出一个子弹
BulletThread bullet = myAir.bulletList.get(i);
int xc = bullet.x + bullet.width / 2;
int yc = bullet.y + bullet.width / 2;
// 计算斜边
int c3 = Math.abs(xa - xc) * Math.abs(xa - xc)
+ Math.abs(ya - yc) * Math.abs(ya - yc);
// 计算半径之和
int r3 = this.width / 2 + this.width / 2;
// 碰撞到了
if (c3 <= r3 * r3) {
this.blood -= bullet.blood;
bullet.blood = 0;
if (this.blood <= 0) {
// 敌机Over
this.stopThread();
}
// 子弹OVer
bullet.stopThread();
}
}
}
}
}
设置子弹类,由战机发射子弹。
package 最_雷霆战机;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
public class BulletThread extends Thread{
int x, y;
int width = 5, height = 5;
int xc = 0, yc = -5;
boolean isLive = true;
int blood = 1;
int screenWidth, screenHeight;
public BulletThread(GamePanel gamePanel, int a, int b) {
Dimension dim = gamePanel.getPreferredSize();
screenWidth = dim.width;
screenHeight = dim.height;
this.x = a - width / 2;
this.y = b - height;
}
public void run() {
while (isLive) {
if (GamePanel.isRun) {
if (y <= -height) {
stopThread();
}
// 子弹于飞出屏幕终止
x += xc;
y += yc;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void stopThread() {
isLive = false;
}
public void draw(Graphics g){
g.setColor(Color.green);
g.fillOval(x, y, width, height);
}
}
注意isRun和isLive是否为静态,这里容易出错。并且over时各个线程要确定关闭。