线程的游戏的制作,其实在做这个小项目的时候还是很无语的,做什么游戏呢??这个困扰了我很久,做飞机大战?做的人太多了,做坦克大战?没新意。后来就迁就了一下,做一个大球吃小球吧(其实觉得逼格还不如前两个),哈哈。
那首先介绍一下这个游戏吧,就是在一个界面,初始有几个小球,大小随机,自己控制一个小球,用点击鼠标的方式控制这个小球的移动轨迹,当碰到比自己小的球时就会吃掉它,并且自己的半径变成自己原来的半径加上吃掉的小球的半径。当然如果遇到比自己大的球时,那就悲剧了,被吃掉了,GAME OVER!
其实这个游戏不难是不是,恩,听着确实很简单,但是还是有一点小问题值得注意的,要不我也不会费力气写这篇博客对不对。
首先老规矩——添加一个界面,贴出代码:
package Thread;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Thread_JFrame
{
private Ball_Init ballinit;
public static void main(String[] args)
{
Thread_JFrame jframe = new Thread_JFrame();
jframe.Init();
}
public void Init()
{
JFrame frame = new JFrame();
frame.setSize(1000,700);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(3);
frame.setTitle("thread");
frame.setResizable(false);
//区别,setBackGround
frame.getContentPane().setBackground(Color.black);
frame.setLayout(new BorderLayout());
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(65,0));
panel.setBackground(Color.gray);
//初始化每个小球的坐标
ballinit = new Ball_Init();
ballinit.init();
//设置暂停按钮
JButton but1 = new JButton("暂停");
JButton but2 = new JButton("开始");
//添加监听器
DrawListener listener = new DrawListener(frame);
but1.addActionListener(listener);
but2.addActionListener(listener);
panel.add(but1);
panel.add(but2);
frame.add(panel,BorderLayout.EAST);
frame.setVisible(true);
frame.addMouseListener(listener);
}
}
似乎还是有点说反了,第一步应该考虑的是不变的因素,那我们就再补上吧。什么东西不变呢?比如我们要控制界面上球的数量,储存每个球的半径,因为球要运动,所以还要设置球的运动方向的方向向量等等,直接贴出代码:
package Thread;
import java.awt.Color;
import java.awt.Point;
public interface point {
//设置数组下标的初始值
public static final int num = 0;
//设置储存点坐标的值
public static final int Length = 25;
public static final Point[] points = new Point[Length];
//设置圆的大小
public static final int[] radius = new int[Length];
// public static final int Size = 36;
//设置圆的颜色
public static final Color[] colors = new Color[Length];
//设置方向向量
public static final double[] X = new double[Length];
public static final double[] Y = new double[Length];
}
好了,现在说一下要注意的东西,因为现有的代码都是经过修改的,当时也忘了储存有问题的代码了,现在只能口述了,不过我尽量说的清楚点。其实很容易理解的,接触过编程的同学都知道,程序运行的时候是顺序运行的,就是说,按照你写的程序的顺序来运行的,这就出现了一个问题——一开始我不是直接写这个游戏的,一开始我是先写的是要实现很多球在屏幕上运动的效果,因为这是写这个游戏必须具备的技能。话说到这里大家可以思考一下怎么才能实现这个效果?用平时简单的for循环是不是很难做到这一点?也就是说用平常我们顺序写的程序的方法是不能实现这个效果的。这时候就要用到一个东西——线程。什么是线程呢?举个例子,比如我要点击屏幕一下就能画出一个运动的圆,再点击一下还会再画出一个运动的圆,以此类推,所有的圆都能同时运动。那么如果不用线程这是不可能用平常的程序实现的,在这里我们可以把每个运动的圆当做一个独立的线程,每个线程都会控制这个圆移动,他们之间“不受影响”。一个进程可以包含很多线程。如果对这几个概念不是太清楚的就自行百度吧哈哈。
贴出Listener的代码:
package Thread;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
public class DrawListener extends MouseAdapter implements point,ActionListener{
private JFrame frame;
private DrawThread thread;
private int Num;
private Suspend suspend;
public DrawListener(JFrame frame)
{
this.frame = frame;
this.Num = num;
suspend = new Suspend();
//声明进程
thread = new DrawThread(this.frame,this.suspend);
thread.start();
}
public void mouseReleased(MouseEvent e)
{
//取点
int x = e.getX();
int y = e.getY();
//改变小球的方向
x = x-points[0].x;
y = y-points[0].y;
X[0] = (double)(x)/Math.sqrt(x*x+y*y);
Y[0] = (double)(y)/Math.sqrt(x*x+y*y);
}
public void actionPerformed(ActionEvent e)
{
//每次判断是否暂停
suspend.update();
}
}
现在来看看怎么实现一个线程类的,贴出代码:
package Thread;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class DrawThread extends Thread implements point{
private Graphics g;
private JFrame frame;
private int x,y;
private Judge judge;
private Suspend suspend;
private Hang hg;
private int pp;
public DrawThread(JFrame frame,Suspend suspend)
{
this.frame = frame;
frame.setVisible(true);
hg = new Hang(this.frame);
judge = new Judge(suspend);
this.g = this.frame.getGraphics();
this.suspend = suspend;
pp = 0;
}
public void run()
{
while(true)//一直循环
{
if(suspend.j())
{
try{
Thread.sleep(5);
}catch(Exception ef){}
if(pp == 0) hg.hang();
pp = 1;
continue;
}
judge.judge();
try{
Thread.sleep(30);
}catch(Exception ef){}
Image image = new ImageIcon(this.getClass().getResource("11.jpg")).getImage();
BufferedImage buff = new BufferedImage(935, 800, BufferedImage.TYPE_INT_ARGB);
Graphics gg = buff.getGraphics();
//画一个图像使能够动起来
//待完成
gg.drawImage(image,0,0,935,700,0,0,image.getWidth(null),image.getHeight(null),null);
for(int i = 0;i < points.length; i++)
{
if(points[i] != null)
{
if(points[i].x+radius[i]/2 <= 935)
{
x = points[i].x;
y = points[i].y;
gg.setColor(colors[i]);
gg.fillOval(x,y,radius[i],radius[i]);
//通过方向向量改变这个小球的路径
points[i].x = (int)(points[i].x + 1.5*X[i]);
points[i].y = (int)(points[i].y + 1.5*Y[i]);
}
}else break;
}
//将缓冲器里的东西画到原来的画板上
g.drawImage(buff,0,0,null);
}
}
}
那么剩下的就非常容易了,核心的东西都讲完了,其他的贴出代码大家自己看着玩玩吧。
球的初始化:
package Thread;
import java.awt.Color;
import java.awt.Point;
import java.util.Random;
//初始化小球的位置和速度矢量(状态)以及半径
public class Ball_Init implements point{
private int num;
public Ball_Init()
{
num = 0;
}
public void init()
{
double x,y;
double dir_x,dir_y;
int r;
Random ran = new Random();
while(num<25)
{
boolean p = true;
//产生小球的坐标
x = 18+ran.nextInt(900);
y = 18+ran.nextInt(764);
//产生方向矢量
dir_x = 1+ran.nextInt(50);
dir_y = 1+ran.nextInt(50);
// System.out.println(dir_x+" "+dir_y);
//保证每次移动是单位长度
if(num%2 == 0)
dir_x = -dir_x/(Math.sqrt(dir_x*dir_x+dir_y*dir_y));
else
dir_x = dir_x/(Math.sqrt(dir_x*dir_x+dir_y*dir_y));
dir_y = dir_y/(Math.sqrt(dir_x*dir_x+dir_y*dir_y));
//产生小球的半径
r = 1+ran.nextInt(34);
radius[num] = r;
double x1 = x-radius[num]/2;
double y1 = y-radius[num]/2;
//如果不相交就可以添加这个点
for(int i = 0; i < points.length; i++)
{
if(points[i] != null)
{
if(Math.sqrt((x1-points[i].x)*(x1-points[i].x)+(y1-points[i].y)*(y1-points[i].y)) < (radius[i]+radius[num]))
{
p = false;
break;
}
}else break;
}
if(p)
{
Random rann=new Random();
int rr = rann.nextInt(225);
int bb = rann.nextInt(225);
int gg = rann.nextInt(30);
colors[num] = new Color(rr,bb,gg);
//在数组中添加这个点
if(num == 0)
{
x1 = 350; y1 = 350;
points[num] = new Point((int)x1,(int)y1);
X[num] = 1;
Y[num] = 0;
radius[num] = 20;
colors[num] = Color.black;
}else
{
points[num] = new Point((int)x1,(int)y1);
X[num] = dir_x;
Y[num] = dir_y;
}
num++;
}
}
}
}
判断输赢和暂停的原理:
package Thread;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
//画出初始时的状态
public class Hang implements point{
private JFrame frame;
private Graphics g;
public Hang(JFrame frame)
{
this.frame = frame;
g = this.frame.getGraphics();
}
public void hang()
{
int x,y;
Image image1 = new ImageIcon(this.getClass().getResource("11.jpg")).getImage();
g.drawImage(image1,0,0,935,700,0,0,image1.getWidth(null),image1.getHeight(null),null);
for(int i = 0;i < points.length; i++)
{
if(points[i] != null)
{
if(points[i].x+radius[i]/2 <= 935)
{
x = points[i].x;
y = points[i].y;
g.setColor(colors[i]);
g.fillOval(x,y,radius[i],radius[i]);
}
}else break;
}
}
}
package Thread;
import java.awt.Dimension;
import java.awt.Font;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Judge implements point{
private Suspend suspend;
private JFrame frame;
public Judge(Suspend suspend)
{
frame = new JFrame();
frame.setSize(400,300);
frame.setDefaultCloseOperation(3);
frame.setLocationRelativeTo(null);
JLabel label = new JLabel("Game Over!!!");
label.setPreferredSize(new Dimension(380,280));
label.setFont(new Font("楷体",1,50));
frame.add(label);
this.suspend = suspend;
}
public void judge()
{
for(int i = 0;i < points.length; i++)
{
//遍历所有小球,找出越出边界的小球并更新这些小球
if(points[i] != null)
{
Random ran = new Random();
double dir_x = 1+ran.nextInt(50);
double dir_y = 1+ran.nextInt(50);
dir_x = dir_x/(Math.sqrt(dir_x*dir_x+dir_y*dir_y));
dir_y = dir_y/(Math.sqrt(dir_x*dir_x+dir_y*dir_y));
if((int)(dir_y)%2==1) dir_x = -dir_x;
if((points[i].x+radius[i])<=0)
{
points[i].y = 0;
points[i].x = 20+ran.nextInt(890);
X[i] = dir_x;
Y[i] = dir_y;
}else if((points[i].x-radius[i])>=935)
{
points[i].y = 0;
points[i].x = 20+ran.nextInt(890);
X[i] = dir_x;
Y[i] = dir_y;
}else if((points[i].y-radius[i]) >= 1000)
{
points[i].y = 0;
points[i].x = 20+ran.nextInt(890);
X[i] = dir_x;
Y[i] = dir_y;
}
}
}
//通过边界判断操控的小球是否越界,如果越界,结果为输
if(points[0].x-radius[0] <= 0)
{
suspend.setcount(1);
frame.setVisible(true);
}
if(points[0].x+radius[0] >= 935)
{
suspend.setcount(1);
frame.setVisible(true);
}
if(points[0].y+radius[0]>= 700)
{
suspend.setcount(1);
frame.setVisible(true);
}
//遍历每个小球,如果相撞,大的小球就合并小的小球
for(int i = 0; i < points.length; i++)
{
if(points[i] != null)
{
for(int j = i+1; j < points.length; j++)
{
if(points[i] != null)
{
//如果两个小球相撞,那么就可开始合并连个小球
if(Math.sqrt((points[j].x-points[i].x)*(points[j].x-points[i].x)+(points[j].y-points[i].y)*(points[j].y-points[i].y)) <= (int)(radius[i]+radius[j]))
{
if(radius[i] >= radius[j])
{
radius[i] += radius[j];
Random ran = new Random();
points[j].y = 0;
points[j].x = 20+ran.nextInt(890);
radius[j] = 1+ran.nextInt(34);
}else
{
if(i == 0)
{
suspend.setcount(1);
frame.setVisible(true);
}
radius[j] += radius[i];
Random ran = new Random();
points[i].y = 0;
points[i].x = 20+ran.nextInt(890);
radius[i] = 1+ran.nextInt(34);
}
}
}
}
}
}
}
}