2018.8.8
前言:学习Java也有好长一段时间了,前几天搞了一下线程游戏,借此写篇博客留点东西供日后回来学习,也希望能帮到刚入门线程的小伙伴。
一、先看看游戏界面:有点不美观,23333。暂时还没有太多的时间去考虑细节,红色的为飞机的血量,没有血量的飞机是玩家的,hhh无敌有点作弊。
二、具体实现:
其实这个就是根据那个多线程弹跳小球改过来了。我本来想用多线程来实现,但无奈空指针错误多得我改不过来。(期待大佬指正)所以我就用了简单的循环+队列数组和一个单线程。循环主要是产生随机的敌机,线程用来控制飞机的绘制和移动。为了更好的理解游戏的结构,我新建了四个类,分别是主界面、监听、产生飞机、产生子弹。每个类干好自己的事情就好了,需要共用的数据就传一下,emmm就是这么简单。在写的时候可能会遇到空指针的错误,这是类对象在传递的时候的错误,简单的说就是当年需要用这个对象的时候,但这个对象还没有被传递过来,如果使用它就会产生空指针错误,所以线程的启动时间需要特别注意!给各位朋友的建议就是在所有数据都到位后在启动绘制飞机的线程,这样百分百不会产生空指针错误。
三、详细代码分析:
为了更方便管理我们的代码,我们将代码分成四个部分:1、主界面类 ; 2、负责画飞机的类 ; 3、负责画子弹的类; 4、监听器类;详细说明已在代码加注释。
1.主界面类:
package com.Lzh_20180727;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import com.zn.ArrayList0720.*; //自定义的数组队列,用系统自带的会发生空指针异常
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import java.awt.Image;
;public class MainFrame extends JFrame implements Runnable{
public static void main(String[] args) {
MainFrame mf = new MainFrame();
mf.Init();
}
public ArrayListlist = new ArrayList();//存储小球的
public ArrayListbulletlist = new ArrayList();//存储子弹的
public volatile boolean StopFlag = false;//是否开始游戏的标志
public volatile boolean PauseFlag = true;//是否处于游戏暂停状态
public int Count = 0;
public JLabel s ,Time;//游戏剩余时间
//BallAI ballai = new BallAI(this,5);//将窗体和要生成的小球数量传过去
public void Init()
{
this.setTitle("飞机大战2`.0");
this.setSize(1400, 1000);
this.setResizable(false);
this.setLocationRelativeTo(null);
this.getContentPane().setBackground(Color.black);
this.setDefaultCloseOperation(3);
String type[]={"启动","暂停","恢复","停止"};
this.setLayout(null);
AllListener AL = new AllListener(StopFlag,PauseFlag,this,bulletlist);//建立监听器对象
ImageIcon IMG = new ImageIcon("src\\1285.gif");
JLabel score = new JLabel();
score.setIcon(IMG);
score.setBounds(950, 20, 150, 50);
score.setFont(new Font("宋体",Font.BOLD,30));
this.add(score);
ImageIcon MMG = new ImageIcon("src\\1313.gif");
JLabel time = new JLabel();
time.setIcon(MMG);
time.setBounds(60, 20, 150, 50);
time.setFont(new Font("宋体",Font.BOLD,30));
this.add(time);
Time = new JLabel();
Time.setBounds(250,20, 50, 50);
Time.setFont(new Font("宋体",Font.BOLD,30));
this.add(Time);
s = new JLabel("0");
s.setText(Count+" ");
s.setBounds(1150, 20, 150, 50);
s.setFont(new Font("宋体",Font.BOLD,30));
this.add(s);
for(int i=0;i=0;t--)//倒计时,时间结束后GameOver
{
Time.setText(t+"");
}
pan.drawImage(img, 0, 0, this.getWidth(), this.getHeight(), null);
pan.fillRect(list.get(0).x-3*list.get(0).r, list.get(0).y-2*list.get(0).r,
this.list.get(0).blood*10, 10);//飞机当前的生命值
this.list.get(0).drawBall(pan);
this.list.get(0).moveBall();
//this.list.get(0).Iscrash(0);
for(int i=1;i
2.负责保存飞机信息的类:
package com.Lzh_20180727;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import com.zn.ArrayList0720.*;
import java.util.Random;
import javax.swing.ImageIcon;
public class Ball {
public int x=30,y=30,r=5,speedX=5,speedY=7,num=0;//初始化一些数据,防止空指针错误
public int blood =0;//飞机的生命值
private Color c = Color.black;//这个没用到
private Image img ;//飞机的图片对象
public MainFrame mf;//将主界面传过来
private Graphics g;//绘制需要的画笔类
private ArrayListlist;//存储飞机所有信息的队列数组
private Random random = new Random();//随机数,主要用于产生敌机的位置和生命值
public Ball(int x, int y, int r, int speedX, int speedY,int num, Color c, MainFrame mf,
Graphics g, ArrayList list,int blood,Image img) {//构造函数
super();
this.x = x;
this.y = y;
this.r = r;
this.speedX = speedX;
this.speedY = speedY;
this.c = c;
this.mf = mf;
this.g = g;
this.list = list;
this.num = num;
this.blood = blood;
this.img = img ;
}
// public Ball(int x,int y,int r,int speedX,int speedY)
// {
// this.x = x;
// this.y = y;
// this.r = r;
// this.speedX = speedX;
// this.speedY = speedY;
// }
public void drawBall(Graphics gg)
{
// int i = random.nextInt(255);
// int j = random.nextInt(255);
// int k = random.nextInt(255);
// g.setColor(new Color(i,j,k));//设不设置颜色都无所谓了,因为我们画的是图片
gg.setColor(Color.blue);
// gg.fillOval(x-r, y-r, 2*r, 2*r);
gg.drawImage(img, x-r, y-r, null);//绘制飞机
}
public void moveBall()//飞机移动的方法
{
if(x+r>=mf.getWidth())//到达右边界
{
speedX*=-1;
}
else if(x+r<0)
{
speedX*=-1;
}
if(y+r>=mf.getHeight())
{
speedY*=-1;
}
else if(y+r<0)
{
speedY*=-1;
}
x+=speedX;
y+=speedY;
}
public void clearBall()//清除飞机的,现在不需要了,用remove就好了。
{
g.setColor(Color.black);
g.fillOval(x-r-speedX, y-r-speedY, 2*r, 2*r);
}
// public void Iscrash(int i)//此方法原来是判断飞机间是否碰撞的,但现在判断子弹和飞机,故注释
// {
// for(int j=0;jmf.list.get(j).x) {
// speedX*=1;
// blood-=1;
// }
// else
// {
// speedX*=-1;
// blood-=1;
// }
// if(y>mf.list.get(j).y) {
// speedY*=1;
// blood-=1;
// }
// else
// {
// speedY*=-1;
// blood-=1;
// }
//
// }
//
// }
// }
public void Craeat_Ball()//生成绘制飞机所需要的信息,并存入队列数组
{
ImageIcon image = new ImageIcon("src\\飞机1.png");
Image img = image.getImage();
Ball myball = new Ball(400,400,30,0,0,num,Color.red,mf,g,list,0,img);
list.add(myball);
System.out.println("生成球的方法被调用!");
for(int i=0;i
3.绘制子弹类:
package com.Lzh_20180727;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import com.zn.ArrayList0720.*;
import java.util.Random;
import javax.swing.JOptionPane;
public class DrawBullet {
//public ArrayListbulletlist;
public int x,y,r,speedX,speedY; //定义绘制子弹需要的信息
public Color c ;
private Random random = new Random();
public boolean IsFire = false;是否开火的标志
public MainFrame mf;
private Image img ;
public DrawBullet(int x,int y,int r,int speedX,int speedY,Color c,MainFrame mf ,
Image img )//构造函数,传入需要的数据
{
this.mf = mf ;
this.x = x;
this.y = y;
this.r = r;
this.speedX = speedX;
this.speedY = speedY;
this.c = c;
this.img = img;
}
public void drawbullet(Graphics gg)//根据拿到的信息绘制子弹
{
//gg.setColor(Color.red);
// gg.fillOval(x, y, 2*r, 2*r);
gg.drawImage(img, x+10, y-50, 40,80,null);
}
public void movebullet()//子弹移动
{
// if(x+r>=mf.getWidth())
// {
// speedX*=-1;
// }
// else if(x+r<0)
// {
// speedX*=-1;
// }
// if(y+r>=mf.getHeight())
// {
// speedY*=-1;
// }
// else if(y+r<0)
// {
// speedY*=-1;
// }
y+=speedY;
}
public void Ishit()//子弹是否击中飞机,遍历所有的子弹和飞机,计算两者的距离,小于某个值则碰撞,飞机生命值减少。
{
for(int i=1;i
4.监听器类:
package com.Lzh_20180727;
import java.awt.Color;
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 com.zn.ArrayList0720.*;
import javax.swing.ImageIcon;
public class AllListener extends MouseAdapter implements ActionListener {
public volatile boolean StopFlag ,PauseFlag;
public MainFrame mf ;
public ArrayListbulletlist;
private boolean Isfire = false;
public AllListener( boolean StopFlag, boolean PauseFlag,MainFrame mf,ArrayListbulletlist)
{
this.StopFlag = StopFlag;
this.PauseFlag = PauseFlag;
this.mf = mf;
this.bulletlist = bulletlist;
}
public void actionPerformed(ActionEvent e)
{
if(e.getActionCommand().equals("启动"))
{
mf.StopFlag = true;
System.out.println("启动!"+StopFlag);
Thread t = new Thread(mf);
t.start();
}
else if(e.getActionCommand().equals("暂停"))
{
mf.PauseFlag = false;
}
else if(e.getActionCommand().equals("恢复"))
{
mf.PauseFlag = true;
}
else if(e.getActionCommand().equals("停止"))
{
mf.StopFlag = false;
}
}
public void mousePressed(MouseEvent e) {
// bulletlist.clear();
Isfire = true;
int x = mf.list.get(0).x+5;
int y = mf.list.get(0).y-30;
Isfire = true;
ImageIcon IMG = new ImageIcon("src\\bullet2.png");
Image img = IMG.getImage();
DrawBullet mybullet = new DrawBullet(x,y,5,0,-10,Color.red,mf,img);
bulletlist.add(mybullet);
}
public void mouseReleased(MouseEvent e) {
Isfire = false;
}
public void mouseMoved(MouseEvent e){
int x = e.getX();
int y = e.getY()-150;
mf.list.get(0).x = x-mf.list.get(0).r;
mf.list.get(0).y = y-mf.list.get(0).r;
}
public void mouseDragged(MouseEvent e){
}
}
我有罪啊。。8.8就写的博客现在才完成。。请鞭策我。。。下次绝对不懒了!!