- 浏览: 53050 次
- 性别:
- 来自: 长沙
最新评论
-
huyuancai1010:
Eclipse中配置Struts2并实现HelloWorld -
zl544434558:
领教了。很久没用struts了,记得不是很清楚了
Eclipse中配置Struts2并实现HelloWorld -
Wuaner:
楼主 你这里的 reHash, 是个什么概念? HashMap ...
挂链式Hash表的实现 -
jadethao:
作者辛苦了。
关于P2P的简单总结 -
剑&箫:
oolala 写道也买了一本,可是看了二章坚持不下去了。
本人 ...
《TCP/IP详解,卷1:协议》读书笔记之概述总结
前几天学习了多线程,现在总结自己做的一个打砖块的游戏,以此来加深对多线程的理解(如有不正确的地方欢迎指正!)。首先来看游戏的效果图:
首先要有一个界面,界面的实现在前面已经作过很多次了,具体代码如下:
/**
* 初始化窗体
*/
public void initFrame(){
this.setTitle("喷怒的小球");//设置窗体的标题
this.setSize(500, 750);//设置窗体的大小
//this.getContentPane().setBackground(Color.BLACK);
this.setLayout(new FlowLayout());//设置流式布局管理器
JButton bt = new JButton("开始");
JButton bt1 = new JButton("停止");
JPanel panel = new JPanel ();
Dimension d = new Dimension(495,650);
panel.setBackground(Color.BLACK);
panel.setPreferredSize(d);
this.add(bt);
this.add(bt1);
this.add(panel);
this.setResizable(false);//设置窗体的大小不可变
this.setDefaultCloseOperation(3);//点击关闭时退出窗体
this.setVisible(true);//将窗体显示在屏幕上
//设置焦点
bt.setFocusable(false);
bt1.setFocusable(false);
panel.setFocusable(true);
final Graphics g = panel.getGraphics();//得到画布
}
得到窗体之后,需要一个挡板,所以定义一个挡板类,并且这个挡板能够在窗体底部水平移动,所以这里是定义的挡板类是实现MouseMotionListener的接口,使得画出的挡板能够随着鼠标的移动而移动,然后在这个类里面定义挡板的属性和实现画挡板的方法。挡板的属性有左上角的坐标,长,宽以及颜色等,为了美观,这里是直接画挡板的一张图片,具体代码如下所示:
public class Fender implements MouseMotionListener{
public static int x = 0;
public static int getX() {
return x;
}
public int y = 630;
public int width = 100;
private int height = 20;
private JPanel panel;
private Graphics g;
public Fender(){}
public Fender(netjava.wxh0807pm1.BallFrame.mypanel panel){
this.panel = panel;
g = panel.getGraphics();
}
//重写父类的方法
public void mouseMoved(MouseEvent e){
//清除图像
g.setColor(panel.getBackground());
g.fillRect(x, y, width, height);
x = e.getX();
//g.setColor(Color.RED);
if(x>=400){
x=400;
}
//画挡板
createFender(g,x,y,width,height);
}
//画挡板的方法
public void createFender(Graphics g,int x,int y,int width,int height){
javax.swing.ImageIcon icon = new javax.swing.ImageIcon("src\\netjava\\wxh0807pm1\\image\\5.png");
g.drawImage(icon.getImage(), x, y, width, height, null);
}
public void mouseDragged(MouseEvent e){
}
}
然后需要画出自己设计的砖块,这里是直接以地图的形式画砖块的。首先是准备几张砖块的图片,然后是把要画得区域看成一个二维数组,二维数组中的元素为零的地方表示该区域没有画砖块,以不同数字表示不同的砖块,然后在另外一个文件中设计二维数组的元素以画出自己想要画得地图。二维数组设计好之后,首先要定义一个方法来把文件读取到内存中,这时就用到了输入输出流的知识,在前面已经总结过,这里不再罗嗦了。但是读取到的是字符串,所以还需要定义一个方法将字符串转化为数组,然后还要定义一个得到图片的静态方法,最后要定义一个根据得到的数组和图片创建地图的方法。将前面三个方法写成一个类,具体代码如下所示:
public class MapTest {
/**
* 读取文件中的地图数据
*
* @param path
* @return
*/
public static int[][] readMap(String path) {
try {
// 创建文件输入流
FileInputStream fis = new FileInputStream(path);
BufferedInputStream bis = new BufferedInputStream(fis);
byte[] bs = new byte[bis.available()];
// 将数据从流中读取到数组中
bis.read(bs);
String str = new String(bs);
// 对字符串进行处理
// System.out.println(str);
int[][] arr = changeToArray(str);
return arr;
} catch (Exception ef) {
ef.printStackTrace();
}
return null;
}
/**
* 将字符串转化为数组
*
* @param str
* @return
*/
private static int[][] changeToArray(String str) {
// 根据回车换行符将字符串分割为字符串数组
String[] strs = str.split("\r\n");
int[][] array = new int[strs.length][strs[0].length()];
// 遍历字符串数组
for (int i = 0; i < strs.length; i++) {
String s = strs[i];
// 对字符串进行解析
char[] cs = s.toCharArray();
for (int j = 0; j < cs.length; j++) {
char c = cs[j];
// 将字符串转成数字
int num = Integer.parseInt(c + "");
array[i][j] = num;
}
}
return array;
}
//根据路径得到图片对象的方法
public static ImageIcon createImageIcon(String path) {
java.net.URL url = MapTest.class.getResource(path);
ImageIcon icon = new ImageIcon(url);
return icon;
}
}
最后一个方法的代码如下:
/**
* 根据地图数组创建地图
* @param array
*/
public static void createMap(int[][] array,Graphics g){
for(int i=0;i<array.length;i++){
for(int j=0;j<array[i].length;j++){
if(array[i][j]!=0){
int num = array[i][j];
String path = "image/"+num+".png";
//根据路径构造图片对象
ImageIcon icon = MapTest.createImageIcon(path);
g.drawImage(icon.getImage(), 35*j, 15*i, null);
}
}
}
}
上面的方法都写成之后只要调用就可以实现砖块的绘制了。现在还需要绘制一个小球,这个小球是一个线程,所以定义一个小球类,在该类里面定义小球的属性和画得方法,在小球的移动过程中还要判断小球与界面的左右以及上边的碰撞反弹以及小球与砖块的碰撞。小球与砖块的碰撞主要分别从砖块的四条边考虑与小球的碰撞,因为根据上面的方法得到数组可以得到每个砖块的位置,然后在遍历数组,判断数组中的每一个砖块是否与小球相撞,然后在做相应的反弹,砖块碰到小球之后要把砖块消掉,所谓消掉就是把砖块画成与背景一样的颜色,把数组中对应的元素变为零。然后在判断小球是否与挡板碰撞,如果碰撞,则弹回,如果挡板没有接住小球,则游戏结束。然后在写一个方法判断是否赢了,同样是遍历上面得到的数组,如果数组的元素全为零,则说明砖块全被打完了,则赢了。具体点的代码如下所示:
/**
* 小球类
* @author lenovo
*
*/
public class Ball extends Thread{
java.util.Random rd = new java.util.Random();
public static int x0=240;
public static int y0=605;
private int width=20;
private int height=20;
private int x1;
private int y1;
private JPanel panel;
private Graphics g;
private Fender fd;
public static boolean isStop=false;
public static boolean isPause=false;
public Ball(){}
public Ball(JPanel panel,Fender fd){
this.fd = fd;
this.panel = panel;
g = panel.getGraphics();
//小球的增量
x1 = 8;
y1 = -8;
}
public void run(){
draw();
}
public void draw(){
Fender fd = new Fender();
while(!isStop){
while(!isPause){
//javax.swing.ImageIcon icon = new javax.swing.ImageIcon("src\\netjava\\wxh0807pm1\\image\\6.png");
//清除图像
g.setColor(panel.getBackground());
g.fillRect(x0, y0, width, height);
//遍历数组,判断是否与砖块相撞
//int[][] array = MapTest.readMap("src\\netjava\\wxh0806\\image\\map");
for (int i=0;i<BallFrame.arr.length;i++){
for (int j=0;j<BallFrame.arr[i].length;j++){
if(BallFrame.arr[i][j]!=0){
if (x0>=35*j-1&&x0<=35*j+10&&y0<=15*i+15&&y0>=15*i){//砖块左边碰撞
g.setColor(panel.getBackground());
g.fillRect(35*j, 15*i, 36, 15);
//System.out.println("11");
BallFrame.arr[i][j] = 0;
x1=-x1;
}else if (y0>=15*i-1&&y0<=15*i+15&&x0<=35*j+35&&x0>=35*j){//砖块上边判断
g.setColor(panel.getBackground());
g.fillRect(35*j, 15*i, 36, 15);
//System.out.println("12");
BallFrame.arr[i][j]=0;
y1=-y1;
}else if (y0<=15*i+15+1&&y0>=15*i&&x0<=35*j+35&&x0>=35*j){//砖块下边判断
g.setColor(panel.getBackground());
g.fillRect(35*j, 15*i, 36, 15);
//System.out.println("13");
BallFrame.arr[i][j]=0;
y1=-y1;
}else if(x0>=35*j+35+1&&x0<=35*j+35-10&&y0<=15*i+15&&y0>=15*i){//砖块右边判断
g.setColor(panel.getBackground());
g.fillRect(35*j, 15*i, 36, 15);
//System.out.println("14");
BallFrame.arr[i][j]=0;
x1=-x1;
}
}
}
}
isWin(BallFrame.arr);
if (x1!=0){
if (x0<=0||x0>=470){//左右两壁
x1=-x1;
//System.out.println("1");
}else if (y0<=0){//上下两壁
y1=-y1;
//System.out.println("2");
}else if ((x0<=0&&y0<=0)||x0<=0||(x0>=470&&y0<=0)||x0>=470){//垂直碰撞四壁
x1=-x1;y1=-y1;
//System.out.println("3");
}
else if (y0>=630-20&&y0<=630-20+10&&x0<=Fender.getX()+100-10&&x0>=Fender.getX()-10){
//System.out.println("------------");
y1=-y1;
//System.out.println("0");
}else if (y0>640&&y0<650){
javax.swing.JOptionPane.showMessageDialog(null, "加油哦!");
}
x0+=x1;
y0+=y1;
//画球
createBall(g,x0,y0);
// g.drawImage(icon.getImage(), x0+=x1, y0+=y1, null);
// g.setColor(Color.RED);
// g.fillOval(x0+=x1,y0+=y1,width,height);
}
try{
Thread.sleep(40);
}catch(Exception ep){
ep.printStackTrace();
}
}
try{
Thread.sleep(1);
}catch(Exception ef){
ef.printStackTrace();
}
}
}
//画球的方法
public void createBall(Graphics g,int x,int y){
javax.swing.ImageIcon icon = new javax.swing.ImageIcon("src\\netjava\\wxh0807pm1\\image\\6.png");
g.drawImage(icon.getImage(), x, y, null);
}
/**
* 判断输赢的方法
* @param chars
*/
public void isWin(int[][]array){
int count=0;
for(int m=0;m<array.length;m++){
for(int n=0;n<array[m].length;n++){
if(array[m][n]!=0){
count++;
}
}
}
System.out.println(count);
if(count==0){
JOptionPane.showMessageDialog(null, "YOU WIN!!!");
stopThread();
}
}
}
然后再在小球类里面定义暂停、继续等的方法来控制小球的线程,具体代码如下所示:
//暂停的方法
public static void pauseThread(){
isPause=true;
}
//继续的方法
public static void resumeThread(){
isPause=false;
}
//停止的方法
public static void stopThread(){
isPause=true;
isStop=true;
}
//初始的方法
public static void initThread(){
isPause=false;
isStop=false;
}
然后再在初始化窗体的方法里面定义一个内部匿名类,来启动线程,但是在这个类里面用到的不在此类里的变量都要定义成final,具体代码如下:
//匿名内部类
ActionListener alt = new ActionListener(){
public void actionPerformed(ActionEvent e){
String command = e.getActionCommand();
if (command.equals("开始")){
//读取文件
int[][] array = MapTest.readMap("src\\netjava\\wxh0807pm1\\image\\map");
arr = array;
//画图片
createMap(array,g);
Ball b = new Ball(panel,fd);
b.start();
bt.setText("暂停");
}
if (command.equals("暂停")){
Ball.pauseThread();
bt.setText("继续");
}
if (command.equals("继续")){
Ball.resumeThread();
bt.setText("暂停");
}
if (command.equals("停止")){
Ball.stopThread();
bt.setText("开始");
}
}
};
//添加监听器
bt.addActionListener(alt);
bt1.addActionListener(alt);
Fender fd = new Fender(panel);
panel.addMouseMotionListener(fd);
然后再重绘挡板、小球以及砖块就可以了,重绘代码如下所示:
//重绘
class mypanel extends JPanel{
public void paint(Graphics g){
//重写父类的方法
super.paint(g);
//遍历砖块数组,实现重绘
for(int i=0;i<arr.length;i++){
for(int j=0;j<arr[i].length;j++){
if(arr[i][j]!=0){
int num=arr[i][j];
String path = "image/"+num+".png";
ImageIcon icon = MapTest.createImageIcon(path);
g.drawImage(icon.getImage(), 35*j, 15*i, 35, 15, null);
}
}
}
//重绘挡板
Fender f=new Fender(this);
f.createFender(g,Fender.x,630,100,20);
//重绘小球
Ball ball=new Ball();
ball.createBall(g, Ball.x0 , Ball.y0);
}
}
到这里基本的游戏已成型了,但是发现砖块消掉不完全或则还没被碰到的砖块已经被擦掉了,所以要重新启动一个线程来不停的对画图区域进行刷新,具体代码如下所示:
//刷新画布监听线程
class PaintThread extends Thread{
public void run(){
while(!Ball.isStop){
while(!Ball.isPause){
//重绘
repaint();
try{
Thread.sleep(1);
}catch(Exception ef){
ef.printStackTrace();
}
}
try{
Thread.sleep(1);
}catch(Exception ef){
ef.printStackTrace();
}
}
}
}
这样弄之后把上面的问题解决了,但是又发现挡板 、小球在不停的闪动,这时就需要根据双缓冲原理在swing中实现消除闪烁,所以上面重绘的代码改动如下:
//重绘
class mypanel extends JPanel{
public void paint(Graphics g){
//重写双缓冲机制
offSreenImage = this.createImage(495, 650);
//获得截取图片的画布
Graphics gImage = offSreenImage.getGraphics();
//获取画布的底色并且使用这种颜色填充画布,如果没有填充效果的话,则会出现拖动的效果
gImage.setColor(gImage.getColor());
//有清楚上一步图像的功能,相当于gImage.clearRect(0, 0, WIDTH, HEIGHT)
gImage.fillRect(0, 0, 495, 650);
//重写父类的方法
super.paint(gImage);
//遍历砖块数组,实现重绘
for(int i=0;i<arr.length;i++){
for(int j=0;j<arr[i].length;j++){
if(arr[i][j]!=0){
int num=arr[i][j];
String path = "image/"+num+".png";
ImageIcon icon = MapTest.createImageIcon(path);
gImage.drawImage(icon.getImage(), 35*j, 15*i, 35, 15, null);
}
}
}
//重绘挡板
Fender f=new Fender(this);
f.createFender(gImage,Fender.x,630,100,20);
//重绘小球
Ball ball=new Ball();
ball.createBall(gImage, Ball.x0 , Ball.y0);
// 将接下来的图片加载到窗体画布上去,才能考到每次画的效果
g.drawImage(offSreenImage, 0, 0, null);
}
}
到此,一个打砖块的游戏已基本实现,但是这个游戏还很简单,还有很多问题,还需要很大得改进。但这里主要目的是深刻理解多线程以及在这个过程中的收获。
首先要有一个界面,界面的实现在前面已经作过很多次了,具体代码如下:
/**
* 初始化窗体
*/
public void initFrame(){
this.setTitle("喷怒的小球");//设置窗体的标题
this.setSize(500, 750);//设置窗体的大小
//this.getContentPane().setBackground(Color.BLACK);
this.setLayout(new FlowLayout());//设置流式布局管理器
JButton bt = new JButton("开始");
JButton bt1 = new JButton("停止");
JPanel panel = new JPanel ();
Dimension d = new Dimension(495,650);
panel.setBackground(Color.BLACK);
panel.setPreferredSize(d);
this.add(bt);
this.add(bt1);
this.add(panel);
this.setResizable(false);//设置窗体的大小不可变
this.setDefaultCloseOperation(3);//点击关闭时退出窗体
this.setVisible(true);//将窗体显示在屏幕上
//设置焦点
bt.setFocusable(false);
bt1.setFocusable(false);
panel.setFocusable(true);
final Graphics g = panel.getGraphics();//得到画布
}
得到窗体之后,需要一个挡板,所以定义一个挡板类,并且这个挡板能够在窗体底部水平移动,所以这里是定义的挡板类是实现MouseMotionListener的接口,使得画出的挡板能够随着鼠标的移动而移动,然后在这个类里面定义挡板的属性和实现画挡板的方法。挡板的属性有左上角的坐标,长,宽以及颜色等,为了美观,这里是直接画挡板的一张图片,具体代码如下所示:
public class Fender implements MouseMotionListener{
public static int x = 0;
public static int getX() {
return x;
}
public int y = 630;
public int width = 100;
private int height = 20;
private JPanel panel;
private Graphics g;
public Fender(){}
public Fender(netjava.wxh0807pm1.BallFrame.mypanel panel){
this.panel = panel;
g = panel.getGraphics();
}
//重写父类的方法
public void mouseMoved(MouseEvent e){
//清除图像
g.setColor(panel.getBackground());
g.fillRect(x, y, width, height);
x = e.getX();
//g.setColor(Color.RED);
if(x>=400){
x=400;
}
//画挡板
createFender(g,x,y,width,height);
}
//画挡板的方法
public void createFender(Graphics g,int x,int y,int width,int height){
javax.swing.ImageIcon icon = new javax.swing.ImageIcon("src\\netjava\\wxh0807pm1\\image\\5.png");
g.drawImage(icon.getImage(), x, y, width, height, null);
}
public void mouseDragged(MouseEvent e){
}
}
然后需要画出自己设计的砖块,这里是直接以地图的形式画砖块的。首先是准备几张砖块的图片,然后是把要画得区域看成一个二维数组,二维数组中的元素为零的地方表示该区域没有画砖块,以不同数字表示不同的砖块,然后在另外一个文件中设计二维数组的元素以画出自己想要画得地图。二维数组设计好之后,首先要定义一个方法来把文件读取到内存中,这时就用到了输入输出流的知识,在前面已经总结过,这里不再罗嗦了。但是读取到的是字符串,所以还需要定义一个方法将字符串转化为数组,然后还要定义一个得到图片的静态方法,最后要定义一个根据得到的数组和图片创建地图的方法。将前面三个方法写成一个类,具体代码如下所示:
public class MapTest {
/**
* 读取文件中的地图数据
*
* @param path
* @return
*/
public static int[][] readMap(String path) {
try {
// 创建文件输入流
FileInputStream fis = new FileInputStream(path);
BufferedInputStream bis = new BufferedInputStream(fis);
byte[] bs = new byte[bis.available()];
// 将数据从流中读取到数组中
bis.read(bs);
String str = new String(bs);
// 对字符串进行处理
// System.out.println(str);
int[][] arr = changeToArray(str);
return arr;
} catch (Exception ef) {
ef.printStackTrace();
}
return null;
}
/**
* 将字符串转化为数组
*
* @param str
* @return
*/
private static int[][] changeToArray(String str) {
// 根据回车换行符将字符串分割为字符串数组
String[] strs = str.split("\r\n");
int[][] array = new int[strs.length][strs[0].length()];
// 遍历字符串数组
for (int i = 0; i < strs.length; i++) {
String s = strs[i];
// 对字符串进行解析
char[] cs = s.toCharArray();
for (int j = 0; j < cs.length; j++) {
char c = cs[j];
// 将字符串转成数字
int num = Integer.parseInt(c + "");
array[i][j] = num;
}
}
return array;
}
//根据路径得到图片对象的方法
public static ImageIcon createImageIcon(String path) {
java.net.URL url = MapTest.class.getResource(path);
ImageIcon icon = new ImageIcon(url);
return icon;
}
}
最后一个方法的代码如下:
/**
* 根据地图数组创建地图
* @param array
*/
public static void createMap(int[][] array,Graphics g){
for(int i=0;i<array.length;i++){
for(int j=0;j<array[i].length;j++){
if(array[i][j]!=0){
int num = array[i][j];
String path = "image/"+num+".png";
//根据路径构造图片对象
ImageIcon icon = MapTest.createImageIcon(path);
g.drawImage(icon.getImage(), 35*j, 15*i, null);
}
}
}
}
上面的方法都写成之后只要调用就可以实现砖块的绘制了。现在还需要绘制一个小球,这个小球是一个线程,所以定义一个小球类,在该类里面定义小球的属性和画得方法,在小球的移动过程中还要判断小球与界面的左右以及上边的碰撞反弹以及小球与砖块的碰撞。小球与砖块的碰撞主要分别从砖块的四条边考虑与小球的碰撞,因为根据上面的方法得到数组可以得到每个砖块的位置,然后在遍历数组,判断数组中的每一个砖块是否与小球相撞,然后在做相应的反弹,砖块碰到小球之后要把砖块消掉,所谓消掉就是把砖块画成与背景一样的颜色,把数组中对应的元素变为零。然后在判断小球是否与挡板碰撞,如果碰撞,则弹回,如果挡板没有接住小球,则游戏结束。然后在写一个方法判断是否赢了,同样是遍历上面得到的数组,如果数组的元素全为零,则说明砖块全被打完了,则赢了。具体点的代码如下所示:
/**
* 小球类
* @author lenovo
*
*/
public class Ball extends Thread{
java.util.Random rd = new java.util.Random();
public static int x0=240;
public static int y0=605;
private int width=20;
private int height=20;
private int x1;
private int y1;
private JPanel panel;
private Graphics g;
private Fender fd;
public static boolean isStop=false;
public static boolean isPause=false;
public Ball(){}
public Ball(JPanel panel,Fender fd){
this.fd = fd;
this.panel = panel;
g = panel.getGraphics();
//小球的增量
x1 = 8;
y1 = -8;
}
public void run(){
draw();
}
public void draw(){
Fender fd = new Fender();
while(!isStop){
while(!isPause){
//javax.swing.ImageIcon icon = new javax.swing.ImageIcon("src\\netjava\\wxh0807pm1\\image\\6.png");
//清除图像
g.setColor(panel.getBackground());
g.fillRect(x0, y0, width, height);
//遍历数组,判断是否与砖块相撞
//int[][] array = MapTest.readMap("src\\netjava\\wxh0806\\image\\map");
for (int i=0;i<BallFrame.arr.length;i++){
for (int j=0;j<BallFrame.arr[i].length;j++){
if(BallFrame.arr[i][j]!=0){
if (x0>=35*j-1&&x0<=35*j+10&&y0<=15*i+15&&y0>=15*i){//砖块左边碰撞
g.setColor(panel.getBackground());
g.fillRect(35*j, 15*i, 36, 15);
//System.out.println("11");
BallFrame.arr[i][j] = 0;
x1=-x1;
}else if (y0>=15*i-1&&y0<=15*i+15&&x0<=35*j+35&&x0>=35*j){//砖块上边判断
g.setColor(panel.getBackground());
g.fillRect(35*j, 15*i, 36, 15);
//System.out.println("12");
BallFrame.arr[i][j]=0;
y1=-y1;
}else if (y0<=15*i+15+1&&y0>=15*i&&x0<=35*j+35&&x0>=35*j){//砖块下边判断
g.setColor(panel.getBackground());
g.fillRect(35*j, 15*i, 36, 15);
//System.out.println("13");
BallFrame.arr[i][j]=0;
y1=-y1;
}else if(x0>=35*j+35+1&&x0<=35*j+35-10&&y0<=15*i+15&&y0>=15*i){//砖块右边判断
g.setColor(panel.getBackground());
g.fillRect(35*j, 15*i, 36, 15);
//System.out.println("14");
BallFrame.arr[i][j]=0;
x1=-x1;
}
}
}
}
isWin(BallFrame.arr);
if (x1!=0){
if (x0<=0||x0>=470){//左右两壁
x1=-x1;
//System.out.println("1");
}else if (y0<=0){//上下两壁
y1=-y1;
//System.out.println("2");
}else if ((x0<=0&&y0<=0)||x0<=0||(x0>=470&&y0<=0)||x0>=470){//垂直碰撞四壁
x1=-x1;y1=-y1;
//System.out.println("3");
}
else if (y0>=630-20&&y0<=630-20+10&&x0<=Fender.getX()+100-10&&x0>=Fender.getX()-10){
//System.out.println("------------");
y1=-y1;
//System.out.println("0");
}else if (y0>640&&y0<650){
javax.swing.JOptionPane.showMessageDialog(null, "加油哦!");
}
x0+=x1;
y0+=y1;
//画球
createBall(g,x0,y0);
// g.drawImage(icon.getImage(), x0+=x1, y0+=y1, null);
// g.setColor(Color.RED);
// g.fillOval(x0+=x1,y0+=y1,width,height);
}
try{
Thread.sleep(40);
}catch(Exception ep){
ep.printStackTrace();
}
}
try{
Thread.sleep(1);
}catch(Exception ef){
ef.printStackTrace();
}
}
}
//画球的方法
public void createBall(Graphics g,int x,int y){
javax.swing.ImageIcon icon = new javax.swing.ImageIcon("src\\netjava\\wxh0807pm1\\image\\6.png");
g.drawImage(icon.getImage(), x, y, null);
}
/**
* 判断输赢的方法
* @param chars
*/
public void isWin(int[][]array){
int count=0;
for(int m=0;m<array.length;m++){
for(int n=0;n<array[m].length;n++){
if(array[m][n]!=0){
count++;
}
}
}
System.out.println(count);
if(count==0){
JOptionPane.showMessageDialog(null, "YOU WIN!!!");
stopThread();
}
}
}
然后再在小球类里面定义暂停、继续等的方法来控制小球的线程,具体代码如下所示:
//暂停的方法
public static void pauseThread(){
isPause=true;
}
//继续的方法
public static void resumeThread(){
isPause=false;
}
//停止的方法
public static void stopThread(){
isPause=true;
isStop=true;
}
//初始的方法
public static void initThread(){
isPause=false;
isStop=false;
}
然后再在初始化窗体的方法里面定义一个内部匿名类,来启动线程,但是在这个类里面用到的不在此类里的变量都要定义成final,具体代码如下:
//匿名内部类
ActionListener alt = new ActionListener(){
public void actionPerformed(ActionEvent e){
String command = e.getActionCommand();
if (command.equals("开始")){
//读取文件
int[][] array = MapTest.readMap("src\\netjava\\wxh0807pm1\\image\\map");
arr = array;
//画图片
createMap(array,g);
Ball b = new Ball(panel,fd);
b.start();
bt.setText("暂停");
}
if (command.equals("暂停")){
Ball.pauseThread();
bt.setText("继续");
}
if (command.equals("继续")){
Ball.resumeThread();
bt.setText("暂停");
}
if (command.equals("停止")){
Ball.stopThread();
bt.setText("开始");
}
}
};
//添加监听器
bt.addActionListener(alt);
bt1.addActionListener(alt);
Fender fd = new Fender(panel);
panel.addMouseMotionListener(fd);
然后再重绘挡板、小球以及砖块就可以了,重绘代码如下所示:
//重绘
class mypanel extends JPanel{
public void paint(Graphics g){
//重写父类的方法
super.paint(g);
//遍历砖块数组,实现重绘
for(int i=0;i<arr.length;i++){
for(int j=0;j<arr[i].length;j++){
if(arr[i][j]!=0){
int num=arr[i][j];
String path = "image/"+num+".png";
ImageIcon icon = MapTest.createImageIcon(path);
g.drawImage(icon.getImage(), 35*j, 15*i, 35, 15, null);
}
}
}
//重绘挡板
Fender f=new Fender(this);
f.createFender(g,Fender.x,630,100,20);
//重绘小球
Ball ball=new Ball();
ball.createBall(g, Ball.x0 , Ball.y0);
}
}
到这里基本的游戏已成型了,但是发现砖块消掉不完全或则还没被碰到的砖块已经被擦掉了,所以要重新启动一个线程来不停的对画图区域进行刷新,具体代码如下所示:
//刷新画布监听线程
class PaintThread extends Thread{
public void run(){
while(!Ball.isStop){
while(!Ball.isPause){
//重绘
repaint();
try{
Thread.sleep(1);
}catch(Exception ef){
ef.printStackTrace();
}
}
try{
Thread.sleep(1);
}catch(Exception ef){
ef.printStackTrace();
}
}
}
}
这样弄之后把上面的问题解决了,但是又发现挡板 、小球在不停的闪动,这时就需要根据双缓冲原理在swing中实现消除闪烁,所以上面重绘的代码改动如下:
//重绘
class mypanel extends JPanel{
public void paint(Graphics g){
//重写双缓冲机制
offSreenImage = this.createImage(495, 650);
//获得截取图片的画布
Graphics gImage = offSreenImage.getGraphics();
//获取画布的底色并且使用这种颜色填充画布,如果没有填充效果的话,则会出现拖动的效果
gImage.setColor(gImage.getColor());
//有清楚上一步图像的功能,相当于gImage.clearRect(0, 0, WIDTH, HEIGHT)
gImage.fillRect(0, 0, 495, 650);
//重写父类的方法
super.paint(gImage);
//遍历砖块数组,实现重绘
for(int i=0;i<arr.length;i++){
for(int j=0;j<arr[i].length;j++){
if(arr[i][j]!=0){
int num=arr[i][j];
String path = "image/"+num+".png";
ImageIcon icon = MapTest.createImageIcon(path);
gImage.drawImage(icon.getImage(), 35*j, 15*i, 35, 15, null);
}
}
}
//重绘挡板
Fender f=new Fender(this);
f.createFender(gImage,Fender.x,630,100,20);
//重绘小球
Ball ball=new Ball();
ball.createBall(gImage, Ball.x0 , Ball.y0);
// 将接下来的图片加载到窗体画布上去,才能考到每次画的效果
g.drawImage(offSreenImage, 0, 0, null);
}
}
到此,一个打砖块的游戏已基本实现,但是这个游戏还很简单,还有很多问题,还需要很大得改进。但这里主要目的是深刻理解多线程以及在这个过程中的收获。
发表评论
-
Java动态加载小结
2012-03-04 01:15 2933上一节课老师讲了java类的动态装载与反射,上课时听的 ... -
挂链式Hash表的实现
2011-11-23 22:10 1931最基本的 ... -
String类常用方法总结
2011-08-30 14:34 1456自己对字符串的各种方法不太熟悉,今天把主要的方法都试了一遍,简 ... -
哈夫曼树小结
2011-08-12 00:44 3045所谓哈夫曼树,又称为最优二叉树,要了解哈夫曼树,首先先来了解几 ... -
线索二叉树小结
2011-08-11 23:52 1464在前面总结的链表是一种一对一的关系,而有一种一对多的关系就是树 ... -
Java中自定义链表总结
2011-08-10 01:15 1845在C/C++中可知链表是一种物理存储单元上非顺序的线性存储结构 ... -
多线程总结
2011-08-03 01:26 13921.进程,程序的区别 在上一篇总结中总结了进程与线程的区别, ... -
多线程入门总结
2011-08-02 01:35 1163什么是线程 提到线程,首先要了解进程。每个程序都有一个入口,在 ... -
画图板数据的存取
2011-07-31 13:40 1149前段时间作了个简单的画图板,能够画直线,矩形,椭圆,三角形四种 ... -
异常机制小结
2011-07-31 13:31 869什么是异常 异常是指程序运行时,可能由于外部系统的条件的变更而 ... -
输入输出流的总结
2011-07-30 15:40 1486我们都知道在电脑上对数据的存储有三种方式,一种是外存,一种是内 ... -
Java中文件的操作
2011-07-30 12:21 2084文件可分为目录文件、 ... -
JAVA常用集合框架
2011-07-25 00:40 1266Java中集合类定义主要是在java.util.*包下面,常用 ... -
java中常用关键字总结
2011-07-24 01:15 1362关键字的定义 所谓关键 ... -
Java基础之登陆界面开发入门
2011-06-21 00:40 2120在前面学了继承,就可 ... -
Java基础知识总结
2011-06-15 21:56 541这学期在学校初步接触了Java,感觉对Java挺有兴趣的。于是 ...
相关推荐
c#打砖块游戏源码c#打砖块游戏源码c#打砖块游戏源码c#打砖块游戏源码
java写的简单的打砖块游戏。实现了一些简单的道具功能
这是华中科技大学硬件课设的脑电波控制的游戏系统的代码,我们实现的是打砖块的游戏。该游戏基于微软的.NET 平台开发,使用C#语言,通过眨眼强度来控制挡板的左右移动,已通过验收
基于Java Swing的打砖块游戏.zip基于Java Swing的打砖块游戏.zip 基于Java Swing的打砖块游戏.zip基于Java Swing的打砖块游戏.zip 基于Java Swing的打砖块游戏.zip基于Java Swing的打砖块游戏.zip 基于Java Swing的...
自己做的打砖块代码,基本功能都实现了,希望大家喜欢
html5实现经典打砖块游戏源码下载 html5实现经典打砖块游戏源码下载
游戏功能:有关卡 有图片 打到相应物体会有不同的功能
课堂资源,这是老师上课教做的一个简单的打砖块游戏,用lua编的,挺有趣的一个小东西
原创c++代码,qt打砖块游戏,初学者可以学习
这可不是普通的打砖块游戏,这可是越打越上头的的打砖块游戏,玩起来很带劲~~还不快来试试。 复刻自 Steam 游戏 ManyBricksBeater(原游戏 Steam 售价 15¥) 编译环境 Visual Studio 2022 & EasyX_20220901 想自制...
2. **打砖块:** 用球撞击砖块来消除它们。每次成功消除一个砖块,你将获得分数,并且球将反弹回来。 3. **发射速度增加:** 游戏的难度在每次成功接球后都会上升,发射速度将变得更快,需要你更快的反应时间。 4....
包括各种方块,道具的掉落以及发射导弹功能,简单的打砖块游戏,C#开发
用Java编写的一款很小的打砖块游戏,游戏非常简单,是初学Java编程的不错选择。
打砖块 java游戏+源码下载打砖块 java游戏+源码下载打砖块 java游戏+源码下载
一个基于Java Swing的打砖块游戏.zip一个基于Java Swing的打砖块游戏.zip 一个基于Java Swing的打砖块游戏.zip一个基于Java Swing的打砖块游戏.zip 一个基于Java Swing的打砖块游戏.zip一个基于Java Swing的打砖块...
基于Android Studio的打砖块游戏,点开直接进入游戏界面,单击开始游戏,砖块颜色随机产生,小球消除砖块有音效。特点就是挡板随手机传感器变化而变化。有兴趣可以学习下。
基于Android Studio平台开发的经典打砖块游戏,包括游戏开始菜单选择界面、第一关、第二关、第三关。每一关砖块排列颜色都不同,掉落的宝物数量也有所不同,难度依次提升,拾取不同宝物,实现不同功能。有兴趣的可以...
使用vb6编写的打砖块游戏源码,有需要的伙伴可以参考参考