学习本文需要先准备的知识:窗体编写、窗体元素添加、鼠标监听器的使用、线程的使用(可以查看我的上一篇博客:“java线程 、键盘监听器——教你写自己的球球大作战”)
1、 前期准备(知识点讲解)
(1)、java ArrayList
a、什么是ArrayList
ArrayList可以说是一个动态数组,它的容量可以随时调整。
b、怎样使用ArrayList
定义语法:
ArrayList<类名> ArrayList名= new ArrayList<类名>(); //<>里面必须是除了基本数据类型外的自定义数据类型(类)
给ArrayList<>添加内容:ArrayList对象名.add(对象名);
从ArrayList<>删除内容:
ArrayList对象名.remove(i); //删除第i个ArrayList成员
ArrayList对象名.remove(对象名); //如果ArrayList中存在此对象,则删除
ArrayList对象名.removeAll(ArrayList对象名); //移除所有ArrayList对象
例:
ArrayList things = new ArrayList();
StoreThings sts = new StoreThings(image, (jsf.getWidth() - 90) / 2, jsf.getHeight() - 90, 90, 90, 0, g, "m_p",jsf, things);
things.add(sts);
(2)、Image对象的使用
a、 Image对象的用途:用于储存图片
b、 Image对象的用法
Image image对象名 = new ImageIcon(this.getClass().getResource("图片名,包括后缀名")).getImage(); //图片必须和代码文件放在同一根目录下
c、 将Image在窗体里绘制出来
Graphics对象名. drawImage(Image对象名, 图片左上角X坐标, 图片左上角Y坐标, 图片的宽度(可选), 图片的高度(可选), 需要绘制图片的窗体对象名);
例:
Image BackGround = new ImageIcon(this.getClass().getResource("BackGround.jpg")).getImage();
g.drawImage(BackGround, 100, 0, jsf.getWidth(), jsf.getHeight(), jsf);
2、 开发飞机大战
提示:可以从网上寻找飞机图片、子弹图片以及背景图片
(1)、游戏规则
玩家控制一架飞机,窗口最上方会不断地出现敌方飞机,同时我方飞机和地方飞机都会自动发子弹,我方的飞机子弹速度稍微快一些。当我方的子弹碰到敌机后敌机消失,敌方的子弹碰到我方飞机,我方死亡,结束游戏。
(2)、代码思路
a、背景、飞机和子弹的绘制:
写一个类储存飞机和子弹的信息,要能够保存飞机和子弹的位置、大小、对应的图片、移动速度等信息,当然一定要添加一个属性区分地方和我方、飞机和子弹,同时还需要有将该图片绘制出来的方法。
import java.awt.Graphics;
import java.awt.Image;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class StoreThings {
private int x, y, width, heigth;
private Graphics g;
private Image image;
private String type;
private JFrame jsf;
private int speed = 0;
private ArrayList things;
public StoreThings(Image image, int x, int y, int width, int heigth, int speed, Graphics g, String type, JFrame jsf,
ArrayList things) {
this.image = image;
this.x = x;
this.y = y;
this.width = width;
this.heigth = heigth;
this.speed = speed;
this.g = g;
this.type = type;
this.jsf = jsf;
this.things = things;
}
public void setX(int x) {
this.x = x;
}
public int getWidth() {
return width;
}
public void setY(int y) {
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public String getType() {
return type;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public void showThings() { //绘制图片的方法
g.drawImage(image, x, y, width, heigth, jsf);
}
}
定义一个上述类的ArrayList对象,用来保存出现的各个飞机和子弹;
ArrayList things = new ArrayList();
写一个专门负责绘制的线程,里面的内容包括:绘制背景,然后执行ArrayList对象里每个成员的绘制方法,最后将每一个对象的X坐标加上他的速度,然后在此等待一段时间。以上这些内容可以放在一个while(true)循环里面。
while (true) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (pause) {
g.drawImage(BackGround, 100, 0, jsf.getWidth(), jsf.getHeight(), jsf);
for (int i = 0; i < things.size(); i++) {
StoreThings temp = things.get(i);
temp.showThings();
temp.setY(temp.getY()+temp.getSpeed());
}
}
}
b、敌机的出现:
敌机的出现的位置纵坐标为0,横坐标可以是窗体0到窗体宽度范围的随机数,可以写一个继承了线程的对象用于生成敌机(定时创建敌机对象,并添加到一个ArrayList对象里面):
public void run() {
while (start) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (pause) {
x = 100 + rand.nextInt(jsf.getWidth());
Image image = new ImageIcon(this.getClass().getResource("EnemyPlane.png")).getImage();
StoreThings st = new StoreThings(image, x, y, 80, 80, 10, g, "e_p", jsf, things);
things.add(st);
}
}
}
c、我方飞机的出现:可在监听器类的构造函数里写,建立一个Image对象,用Graphics的drawImage方法绘制出来。
public PlaneListener(Graphics g, JFrame jsf) {
this.g = g;
this.jsf = jsf;
st = new ShowThread(g, jsf, things);
mpt = new MyPlaneThread(jsf, things, g);
et = new EnemyThread(g, jsf, things);
Image image = new ImageIcon(this.getClass().getResource("MyPlane.png")).getImage(); //我方飞机的图片
StoreThings sts = new StoreThings(image, (jsf.getWidth() - 90) / 2, jsf.getHeight() - 90, 90, 90, 0, g, "m_p", jsf, things); //将我方飞机绘制出来
}
c、子弹的出现:
创建子弹对象,位置在各个飞机的中间位置,同时注意速度属性应该要比飞机快一点,同时,我方子弹的速度和地方子弹的速度方向相反,可以单独放在一个线程里面。
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (pause) {
x = 100 + rand.nextInt(jsf.getWidth());
Image image = new ImageIcon(this.getClass().getResource("EnemyPlane.png")).getImage();
StoreThings st = new StoreThings(image, x, y, 80, 80, 10, g, "e_p", jsf, things);
things.add(st);
image = new ImageIcon(this.getClass().getResource("bullet1.png")).getImage();
for (int i = 0; i < things.size(); i++) {
StoreThings temp = things.get(i);
if (temp.getType().equals("e_p")) {
StoreThings Bullet = new StoreThings(image, temp.getX() + 28, temp.getY() + 40, 25, 25, 20, g,
"e_b", jsf, things);
things.add(Bullet);
}
}
}
d、被子弹击中后
可以用飞机与子弹的距离和宽度等信息判断二者是否相碰,当我方飞机碰到敌方子弹时,或者地方飞机碰到我方子弹时应当爆炸消失(从ArrayList里面移除该对象,此方法建议放在储存这些信息的类里的绘制方法里执行,这样可以保证能及时判断二者的位置):
public void crash(StoreThings st) {
if (st.getType().equals("e_p")) {
for (int i = 0; i < things.size(); i++) {
StoreThings temp = things.get(i);
if (temp.getType().equals("m_b")) {
double cx = temp.getX() - st.getX();
double cy = temp.getY() - st.getY();
double cw = temp.getWidth() + st.getWidth();
if (Math.sqrt(cx * cx + cy * cy) <= cw / 2) {
things.remove(st);
}
}
}
}
if (st.getType().equals("m_p")) {
for (int i = 0; i < things.size(); i++) {
StoreThings temp = things.get(i);
if (temp.getType().equals("e_b")) {
double cx = temp.getX() - st.getX();
double cy = temp.getY() - st.getY();
double cw = temp.getWidth() + st.getWidth()-40; //经测试有偏差,此处减去40以减小判断误差
if (Math.sqrt(cx * cx + cy * cy) <= cw / 2) {
things.remove(st);
JOptionPane.showMessageDialog(null, "玩家死亡,游戏结束!");
System.exit(0);
}
}
}
}
}
e、暂停和继续游戏的实现
在界面添加继续游戏和暂停游戏按钮,为其添加事件监听器。在每个线程while循环里加一个if(boolean类型数据)的判断,为这个boolean类型数据写一个set方法,点击暂停时将其改成false,点击继续将其改成true。
注意:while和if之间最好放上几句代码,不然可能无法实现暂停功能,可以把延时的语句(Thread.sleep())放在此处。
case "暂停游戏":
st.setPause(false);
mpt.setPause(false);
et.setPause(false);
break;
case "继续游戏":
st.setPause(true);
mpt.setPause(true);
et.setPause(true);
break;
3、全部的代码
–ShowFrame.java–
package com.antony.PlaneBattle0916;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class ShowFrame {
public static void main(String[] args) {
showUI();
}
public static void showUI() {
JFrame jsf = new JFrame();
jsf.setDefaultCloseOperation(3);
jsf.setSize(700, 910);
jsf.setLocationRelativeTo(null);
BorderLayout boder = new BorderLayout();
FlowLayout flow = new FlowLayout();
jsf.setLayout(boder);
JPanel jp = new JPanel();
jp.setLayout(flow);
Dimension d = new Dimension(100, 910);
jp.setPreferredSize(d);
jp.setBackground(Color.GREEN);
JLabel jsl_place = new JLabel();
Dimension dl = new Dimension(100,300);
jsl_place.setPreferredSize(dl);
Dimension db = new Dimension(80, 26);
Font fb = new Font("宋体",Font.PLAIN, 11);
JButton jsb_start = new JButton("开始游戏");
jsb_start.setFont(fb);
jsb_start.setPreferredSize(db);
JButton jsb_pause = new JButton("暂停游戏");
jsb_pause.setFont(fb);
jsb_pause.setPreferredSize(db);
JButton jsb_continue = new JButton("继续游戏");
jsb_continue.setFont(fb);
jsb_continue.setPreferredSize(db);
JButton jsb_exit = new JButton("停止游戏");
jsb_exit.setFont(fb);
jsb_exit.setPreferredSize(db);
jp.add(jsl_place);
jp.add(jsb_start);
jp.add(jsb_pause);
jp.add(jsb_continue);
jp.add(jsb_exit);
jsf.getContentPane().add("West", jp);
jsf.setVisible(true);
Graphics g = jsf.getGraphics();
PlaneListener pl = new PlaneListener(g, jsf);
jsf.addMouseListener(pl);
jsf.addMouseMotionListener(pl);
jsb_start.addActionListener(pl);
jsb_pause.addActionListener(pl);
jsb_continue.addActionListener(pl);
jsb_exit.addActionListener(pl);
}
}
–PlaneListener.java–
package com.antony.PlaneBattle0916;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class PlaneListener extends MouseAdapter implements ActionListener {
private Graphics g;
private JFrame jsf;
private ArrayList things = new ArrayList();
private ShowThread st = new ShowThread(g, jsf, things);
private MyPlaneThread mpt = new MyPlaneThread(jsf, things, g);
private EnemyThread et = new EnemyThread(g, jsf, things);
public PlaneListener(Graphics g, JFrame jsf) {
this.g = g;
this.jsf = jsf;
st = new ShowThread(g, jsf, things);
mpt = new MyPlaneThread(jsf, things, g);
et = new EnemyThread(g, jsf, things);
Image BackGround = new ImageIcon(this.getClass().getResource("BackGround.jpg")).getImage();
g.drawImage(BackGround, 100, 0, jsf.getWidth(), jsf.getHeight(), jsf);
}
public void mouseMoved(MouseEvent e) {
int x = e.getX();
int y = e.getY();
for (int i = 0; i < things.size(); i++) {
StoreThings temp = things.get(i);
if (x < 145) {
x = 145;
}
if (temp.getType().equals("m_p")) {
temp.setX(x - 45);
temp.setY(y - 45);
}
}
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
String BT = e.getActionCommand();
switch (BT) {
case "开始游戏":
if (!(mpt.isAlive() || st.isAlive() || st.isAlive())) {
mpt.start();
et.start();
st.start();
}
things.removeAll(things);
Image image = new ImageIcon(this.getClass().getResource("MyPlane.png")).getImage();
StoreThings sts = new StoreThings(image, (jsf.getWidth() - 90) / 2, jsf.getHeight() - 90, 90, 90, 0, g, "m_p",
jsf, things);
things.add(sts);
break;
case "暂停游戏":
st.setPause(false);
mpt.setPause(false);
et.setPause(false);
break;
case "继续游戏":
st.setPause(true);
mpt.setPause(true);
et.setPause(true);
break;
case "停止游戏":
System.exit(0);
break;
}
}
}
–StoreThings.java–
package com.antony.PlaneBattle0916;
import java.awt.Graphics;
import java.awt.Image;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class StoreThings {
private int x, y, width, heigth;
private Graphics g;
private Image image;
private String type;
private JFrame jsf;
private int speed = 0;
private ArrayList things;
public StoreThings(Image image, int x, int y, int width, int heigth, int speed, Graphics g, String type, JFrame jsf,
ArrayList things) {
this.image = image;
this.x = x;
this.y = y;
this.width = width;
this.heigth = heigth;
this.speed = speed;
this.g = g;
this.type = type;
this.jsf = jsf;
this.things = things;
}
public void crash(StoreThings st) {
if (st.getType().equals("e_p")) {
for (int i = 0; i < things.size(); i++) {
StoreThings temp = things.get(i);
if (temp.getType().equals("m_b")) {
double cx = temp.getX() - st.getX();
double cy = temp.getY() - st.getY();
double cw = temp.getWidth() + st.getWidth();
if (Math.sqrt(cx * cx + cy * cy) <= cw / 2) {
things.remove(st);
}
}
}
}
if (st.getType().equals("m_p")) {
for (int i = 0; i < things.size(); i++) {
StoreThings temp = things.get(i);
if (temp.getType().equals("e_b")) {
double cx = temp.getX() - st.getX();
double cy = temp.getY() - st.getY();
double cw = temp.getWidth() + st.getWidth()-40;
if (Math.sqrt(cx * cx + cy * cy) <= cw / 2) {
things.remove(st);
JOptionPane.showMessageDialog(null, "玩家死亡,游戏结束!");
System.exit(0);
}
}
}
}
}
public void setX(int x) {
this.x = x;
}
public int getWidth() {
return width;
}
public void setY(int y) {
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public String getType() {
return type;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public void showThings() {
for (int i = 0; i < things.size(); i++) {
StoreThings temp = things.get(i);
crash(temp);
}
g.drawImage(image, x, y, width, heigth, jsf);
}
}
–EnemyThread.java–
package com.antony.PlaneBattle0916;
import java.awt.Graphics;
import java.awt.Image;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class EnemyThread extends Thread {
private int x, y = 0;
private Graphics g;
private JFrame jsf;
private ArrayList things;
private Random rand = new Random();
private boolean start = true;
private boolean pause = true;
public EnemyThread(Graphics g, JFrame jsf, ArrayList things) {
this.g = g;
this.jsf = jsf;
this.things = things;
}
public void setStart(boolean start){
this.start = start;
}
public void setPause(boolean pause){
this.pause =pause;
}
public void run() {
while (start) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (pause) {
x = 100 + rand.nextInt(jsf.getWidth());
Image image = new ImageIcon(this.getClass().getResource("EnemyPlane.png")).getImage();
StoreThings st = new StoreThings(image, x, y, 80, 80, 10, g, "e_p", jsf, things);
things.add(st);
image = new ImageIcon(this.getClass().getResource("bullet1.png")).getImage();
for (int i = 0; i < things.size(); i++) {
StoreThings temp = things.get(i);
if (temp.getType().equals("e_p")) {
StoreThings Bullet = new StoreThings(image, temp.getX() + 28, temp.getY() + 40, 25, 25, 20, g,
"e_b", jsf, things);
things.add(Bullet);
}
}
}
}
}
}
–MyPlaneThread.java–
package com.antony.PlaneBattle0916;
import java.awt.Graphics;
import java.awt.Image;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class MyPlaneThread extends Thread {
private boolean start = true;
private JFrame jsf;
private ArrayList things;
private Image image;
private Graphics g;
private boolean pause = true;
public MyPlaneThread(JFrame jsf, ArrayList things, Graphics g) {
this.jsf = jsf;
this.things = things;
this.g = g;
image = new ImageIcon(this.getClass().getResource("bullet2.png")).getImage();
}
public void setStart(boolean start){
this.start = start;
}
public void setPause(boolean pause){
this.pause =pause;
}
public void run() {
while (start) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (pause) {
for (int i = 0; i < things.size(); i++) {
StoreThings temp = things.get(i);
if (temp.getType().equals("m_p")) {
StoreThings Bullet = new StoreThings(image, temp.getX() + 31, temp.getY(), 30, 30, -40, g,
"m_b", jsf, things);
things.add(Bullet);
}
}
}
}
}
}
–ShowThread.java–
package com.antony.PlaneBattle0916;
import java.awt.Graphics;
import java.awt.Image;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class ShowThread extends Thread {
private Graphics g;
private Image BackGround = new ImageIcon(this.getClass().getResource("BackGround.jpg")).getImage();
private JFrame jsf;
private boolean start = true;
private boolean pause = true;
private ArrayList things;
public ShowThread(Graphics g, JFrame jsf, ArrayList things) {
this.g = g;
this.jsf = jsf;
this.things = things;
}
public void setStart(boolean start){
this.start = start;
}
public void setPause(boolean pause){
this.pause =pause;
}
public void run() {
while (start) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (pause) {
g.drawImage(BackGround, 100, 0, jsf.getWidth(), jsf.getHeight(), jsf);
for (int i = 0; i < things.size(); i++) {
StoreThings temp = things.get(i);
temp.showThings();
temp.setY(temp.getY()+temp.getSpeed());
}
}
}
}
}