Java小程序之球球大作战(基于Java线程实现)

Posted ζั͡ޓއއއ 丶退休的码农

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java小程序之球球大作战(基于Java线程实现)相关的知识,希望对你有一定的参考价值。

                                                                   Java小程序之球球大作战(基于Java线程实现)

 

一、游戏基本功能:

       1、自己的小球可以随着鼠标的移动而改变坐标;

       2、敌方小球不断的在界面中移动

       3、当检测到敌方小球相互碰撞时,小球会弹开

       4、当我方小球和敌方小球碰撞时,会判断敌我双方的半径,如果我方直径大,则吃掉小球,分数累加

            若敌方小球比我方大时,转换到游戏界面,切换面板,显示游戏最终得分
 

二、游戏运行界面:

 

 

 

三、游戏实现的大概思路

        1、创建窗体

        2、创建我方小球类,并实现鼠标移动监听

        3、创建敌方小球类(继承线程Thread类,每个小球会不停的运动)

        4、实现碰撞检测(计算小球圆心与圆心之间的距离)

        5、游戏结束,切换面板

 

      难点: 

              1.多个小球实现(List封装)

                 实现机制:如果说涉及到比较多的小球移动,则我们需要通过一个容器进行统一管理

                 容器:ArrayList

 

1)通过一个循环来创建小球:代码可以定义在当前类的构造方法里面

2)绘制小球的时候,通过遍历容器对象,进行绘制

3)坐标,小球直径都可以定义在小球类中,通过小球的属性进行封装

4)paint方法中只是用于绘制图形,

5)如何计算圆心距

     1>先计算每个球的圆心坐标:x+width/2   y+width/2

     2>再算出横向的距离和纵向的距离

     3>计算斜边长度

 

 

2.双缓冲解决闪屏问题

      a) 原理:

                  1. 通过缓冲图片,把所有需要绘制的东西,先绘制在缓冲图片上

                  2. 把缓冲图片绘制到窗体/面板上

      b)  实现步骤:pant方法改造

                 1.创建一个缓冲图片

                 2.获取一只图片上的画笔

                 3.把所有的图形通过图片画笔进行绘制

                 4.把缓冲图片绘制到窗体上

 

 

3.键盘监听器控制自己小球移动:KeyListener

       a) 需要自己定义一个类,用于实现监听器接口

       b) w:87   s:83  a:65  d:68

              1、上:38  下:40  左:37  右:39

 

4.鼠标监听器控制自己小球移动:MouseMotionListener鼠标移动监听

 

5.音乐添加

      a) 把music.jar包复制到工程目录下

      b) 右击music.jar,选择build path,选择add to build path选项

 

          

 

 

四、面板切换功能代码:每隔2秒切换页面

package com.bluesky.movingball;
 
import java.awt.Color;
import java.awt.Graphics;
 
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
 
public class GameFrame extends JFrame
	
	public boolean flag=true;
	public JPanel panel,panel2;
	public Graphics g;
	
	public ImageIcon bgimg= new ImageIcon("img/bg1.jpg");
	
	public void initFrame()
		this.setTitle("移动的小球");
		this.setSize(800, 600);
		this.setDefaultCloseOperation(3);
		this.setLocationRelativeTo(null);
		panel = new JPanel();
		panel.setBackground(Color.red);
		panel2 = new JPanel();
		panel2.setBackground(Color.green);
		changePanel(this);
		this.add(panel);
		this.setVisible(true);
		g=panel.getGraphics();
		System.out.println("this:"+g);
	
	
 
	
	public void changePanel(GameFrame f)
		new Thread()
			public void run()
				while(true)
					if(!flag)
						f.remove(panel);
						f.add(panel2);
						f.repaint();
						f.setVisible(true);
					
					if(flag)
						f.remove(panel2);
						f.add(panel);
						f.repaint();
						f.setVisible(true);
					
					
					try 
						sleep(2000);
						flag=!flag;
					 catch (InterruptedException e) 
						e.printStackTrace();
					
 
				
			
			
		.start();
	
 

 

 

package com.bluesky.movingball;
 
public class Test 
	public static void main(String[] args) 
		GameFrame gf = new GameFrame();
		gf.initFrame();
 
	

 

 

五、球球大作战源代码:

     主界面类:

package com.huaxin.zhou;
 
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Stroke;
import java.util.ArrayList;
import java.util.Random;
 
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
 
public class MoveBallGame extends JFrame
	
	//敌方小球容器类
	public static ArrayList<MoveThread>list =new ArrayList<MoveThread>();
	//随机器
	public Random r = new Random();
	
	public MyBall myball;
	
	public BallMouseListener bl;
	
	public JPanel panel,overPanel;
	
	public MoveBallGame jf;
	
	public int score=0;
	
	//检测游戏是否结束的标志
	public boolean overFlag=false;
	
	//检测添加小球的线程是否结束
	public boolean over=false;
	
	public MoveBallGame()
		
		myball = new MyBall(0, 500, 1, 60);
		bl = new BallMouseListener(myball);
		//添加背景音乐
		com.huaxin.music.Util.startMusic("music/bg1.wav");
	
	
	
	//窗体初始化
	public void initFrame()
		jf=this;
		this.setSize(800,600);
		this.setDefaultCloseOperation(3);
		this.setResizable(false);
		this.setTitle("球球大作战");
		this.setLocationRelativeTo(null);
		panel= new JPanel();
		overPanel= new JPanel();
		this.add(panel);
		
		this.setVisible(true);
		
		//拿到窗体的画笔
		Graphics g =panel.getGraphics();
		//给窗体添加鼠标移动监听
		BallKeyListener kl = new BallKeyListener(myball);
		panel.addKeyListener(kl);
		panel.addMouseMotionListener(bl);
		
		checkBallCount();
		
	
	//paint方法画小球(敌方小球和我们小球),兵利用双缓冲解决闪屏问题
	public void paint(Graphics g) 
		
		//创建一张图片
		Image buffImage = this.createImage(800,600);
		//拿到这张图片的画笔
		Graphics buffg=buffImage.getGraphics();
		
		ImageIcon bgimg = new ImageIcon("img/bg1.jpg");
		//给图片画背景
		buffg.drawImage(bgimg.getImage(), 0,0, null);
		//循环将容器里面的小球画出来
		for (int i = 0; i < list.size(); i++) 
			MoveThread mt = list.get(i);
			buffg.setColor(mt.color);
			buffg.fillOval(mt.x, mt.y, mt.width, mt.width);
		
		
		//设置画笔颜色画我方的小球
		buffg.setColor(Color.ORANGE);
		
		buffg.fillOval(myball.x, myball.y, myball.width, myball.width);
		
		//利用窗体的画笔将整张图片画进窗体
		g.drawImage(buffImage, 0, 0, null);
	
	
	
	public void checkBallCount()
		//检测球是否吃完了的线程,吃完了则重新产生六个小球
		new Thread()
			public void run()
				while(!over)
					while(!overFlag)
						// 如果屏幕上没有敌方小球了,那么重新画6个敌方小球
						if (MoveBallGame.list.size() == 0) 
							for (int j = 0; j < 6; j++) 
								MoveThread mt = new MoveThread(jf);
								mt.x += 70 * j;
								mt.y += 50 * j;
								mt.xSpeed = 5;
								mt.ySpeed = 5;
								mt.width = jf.r.nextInt(20) + 50;
								mt.color = new Color(jf.r.nextInt(10000));
								MoveBallGame.list.add(mt);
								mt.start();
							
						
						try 
							Thread.sleep(100);
						 catch (InterruptedException e) 
							e.printStackTrace();
						
					
					
					if(overFlag)
						jf.remove(panel);
						jf.add(overPanel);
						jf.repaint();
						jf.setVisible(true);
//						System.out.println("面板切换");
						Graphics g=overPanel.getGraphics();
						Graphics2D g1=(Graphics2D) g;
						ImageIcon overimg= new ImageIcon("img/bg.jpg");
						g1.drawImage(overimg.getImage(), 0, 0, null);
						g1.setColor(Color.red);
						g1.setStroke(new BasicStroke(5));
						g1.drawString("游戏结束", 300,200);
						g.drawString("得分:"+score, 350, 200);
						over=true;
					
					
					try 
						Thread.sleep(100);
					 catch (InterruptedException e) 
						e.printStackTrace();
					
				
				try 
					Thread.sleep(100);
				 catch (InterruptedException e) 
					e.printStackTrace();
				
			
			
		.start();
	
	
	

 

       敌方小球类:敌方的每个小球都是一个独立的线程

package com.huaxin.zhou;
 
import java.awt.Color;
 
import javax.swing.JOptionPane;
 
public class MoveThread extends Thread 
 
	public MoveBallGame mb;
	public int x = 100, y = 100;
	public int xSpeed = 5;
	public int ySpeed = 5;
	public int width;
	public Color color;
	
	public boolean isbegin = true;
//	public boolean over =false;
	
	public MoveThread(MoveBallGame mb) 
		this.mb = mb;
	
 
	// 控制每个小球跑的线程
	public void run() 
		while(!mb.overFlag)
			while (isbegin) 
				// 控制敌方小球移动
				x += xSpeed;
				y += ySpeed;
				// 判断敌方小球是否出界
				if (this.x < 10 || this.x > 800 - this.width - 10) 
					xSpeed = -xSpeed;
				
				if (this.y < 30 || this.y > 600 - this.width - 10) 
					ySpeed = -ySpeed;
				
				// 判断我方小球是否出界
				if (mb.myball.x < 4) 
					mb.myball.x = 4;
				
				if (mb.myball.y <28) 
					mb.myball.y =28;
				
 
				if (mb.myball.x > 800 - mb.myball.width - 4) 
					mb.myball.x = 800 - mb.myball.width - 4;
				
 
				if (mb.myball.y > 600 - mb.myball.width - 4) 
					mb.myball.y = 600 - mb.myball.width - 4;
				
 
				// 碰撞检测
				isHit();
 
				mb.repaint();
				// 线程休眠
				try 
					Thread.sleep(50);
				 catch (InterruptedException e) 
					e.printStackTrace();
				
			
			// 线程休眠
			try 
				Thread.sleep(50);
			 catch (InterruptedException e) 
				e.printStackTrace();
			
		
		
//		if(over)
//			JOptionPane.showMessageDialog(null, "游戏结束");
//			mb.overFlag=true;
//		
		
		
	
 
	// 检车是否碰撞的函数
	public void isHit() 
 
		// 判断敌方小球和我方小球是否发生碰撞
		int x = ((this.x + this.width) - (mb.myball.x + mb.myball.width))
				* ((this.x + this.width) - (mb.myball.x + mb.myball.width));
		int y = ((this.y + this.width) - (mb.myball.y + mb.myball.width))
				* ((this.y + this.width) - (mb.myball.y + mb.myball.width));
		int r = (int) Math.sqrt(x + y);
 
		// 判断敌我双方谁的半径大
		if (r <= (this.width / 2 + mb.myball.width / 2)) 
			// 敌方直径比我大,则我方被吃掉,游戏结束!
			if (this.width > mb.myball.width) 
				
//				mb.overFlag=true;
//				this.setDaemon(true);
				isbegin = false;
//				MoveBallGame.list.remove(this);
				
				for (int i = 0; i <MoveBallGame.list.size(); i++) 
//					MoveBallGame.list.get(i).setDaemon(true);
					MoveBallGame.list.get(i).isbegin=false;
				
				JOptionPane.showMessageDialog(null, "你被大球吃掉了!");
				mb.overFlag=true;
				return;
			
			// 如果我方直径大,则让我方直径加2个像素,同时从容器里面移除吃掉的小球
			if (this.width <= mb.myball.width) 
				mb.myball.width += 2;
				mb.score=+this.width;
 
//				this.setDaemon(true);
				this.isbegin = false;
				MoveBallGame.list.remove(this);
				
				// 我方直径达到500,我方获胜
				if (mb.myball.width >= 300) 
					
//					mb.overFlag=true;
					isbegin = false;
					MoveBallGame.list.remove(this);
					for (int i = 0; i <MoveBallGame.list.size(); i++) 
						MoveBallGame.list.get(i).isbegin=false;
//						MoveBallGame.list.get(i).setDaemon(true);
					
					JOptionPane.showMessageDialog(null, "恭喜你赢了!");
//					over=true;
					mb.overFlag=true;
				
			
 
		
 
		// 从容器里面取出小球来
		for (int i = 0; i < MoveBallGame.list.size(); i++) 
			MoveThread mtb = MoveBallGame.list.get(i);
			// 如果是正在执行run的小球,则另外取一个小球
			if (mtb == this) 
				continue;
			 else 
 
				// 判断敌方小球是否碰撞
				int x1 = ((mtb.x + mtb.width) - (this.x + this.width)) * ((mtb.x + mtb.width) - (this.x + this.width));
				int y1 = ((mtb.y + mtb.width) - (this.y + this.width)) * ((mtb.y + mtb.width) - (this.y + this.width));
				int r1 = (int) Math.sqrt(x1 + y1);
 
				if (r1 <= (mtb.width / 2 + this.width / 2)) 
					mtb.xSpeed = -mtb.xSpeed;
					mtb.ySpeed = -mtb.ySpeed;
					this.xSpeed = -this.xSpeed;
					this.ySpeed = -this.ySpeed;
				
			
		
 
	

 

我方小球类:

package com.huaxin.zhou;
 
import java.awt.Color;
 
public class MyBall 
	
	//我方自己的球类
 
	//我方球类的属性
	public int x,y;
	public int Speed;
	public int width;
	
	//我方求球类的构造方法
	public MyBall(int x, int y, int speed, int width) 
		this.x = x;
		this.y = y;
		this.Speed = speed;
		this.width = width;
	
	
	

 

我方小球鼠标移动监听类:

package com.huaxin.zhou;
 
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
 
import javax.swing.JOptionPane;
 
public class BallMouseListener implements MouseMotionListener
	
	//我方小球鼠标移动监听器
	
	public MyBall ball;
	
	//构造函数
	public BallMouseListener(MyBall ball) 
		this.ball=ball;
	
	
	//实现鼠标移动时,小球坐标改变
	public void mouseMoved(MouseEvent e) 
		int x=e.getX();
		int y=e.getY();
		
		ball.x=x-ball.width/2;
		ball.y=y;/*-ball.width/2;*/
		
	
	public void mouseDragged(MouseEvent e) 
		
	

 

我方小球键盘移动监听类:

package com.huaxin.zhou;
 
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
 
import javafx.scene.input.KeyCode;
 
public class BallKeyListener implements KeyListener
	
	public MyBall ball;
	
	public BallKeyListener(MyBall ball)
		this.ball=ball;
	
 
	public void keyPressed(KeyEvent e) 
		
		int key=e.getKeyCode();
		
		
		if(key==37)
		ball.x-=3;
		if(key==38)
			ball.y-=3;
		if(key==39)
			ball.x+=5;
		if(key==40)
		  ball.y+=5;
		
	
 
	public void keyReleased(KeyEvent e) 
		
	
 
	public void keyTyped(KeyEvent e) 
		
	
 

 

主函数:程序入口

package com.huaxin.zhou;
 
import java.awt.Color;
 
public class MainFrame 
	
	public static void main(String[] args) 
		//程序入口
		MoveBallGame mbg = new MoveBallGame();
		mbg.initFrame();
	

 

六、总结

通过这个小项目,学到了非常多的知识、比如线程的应用、碰撞检测、双缓冲原理以及应用、如何切换面板,音乐添加等;在这个项目中遇到了很多的问题,比如内存泄漏,因为后面判断游戏结束,使用了双重循环,因为try 的位置不正确,导致内存泄漏,即陷入死循环中;

完成这个小项目花了好几天的时间,还是在有老师指导的情况下,这里面设计到了很多知识的细节,原理其实多不是很难理解,主要是如何转化成代码,还有对线程的理解等,如何为去结束一个线程;碰撞检测主要用到圆和圆之间的圆心距的计算,这里看到了数学在计算机的应用,果然,数学很重要,当然也不是那么重要,你想要往高的地方走,必须的汲取足够多的知识;个人觉得面板切换还是比较炫酷的,我也不知道为什么,可能因为终于可以不是局限在同一个面板中了吧!双缓冲原理竟然变得和以前不太一样了,以前还有用到update方法,新版JDK简化了这一过程,也变得更好理解了;音乐的切换需要用到一个架包,调用里面的一个方法就可以实现了,恩,还是期待有一天能够封装自己的音乐架包呢!

行吧,就先分享到这里了!共勉!

 

 

好了,以上是我精心为零基础以及基础好的学习者准备的精心Java大礼包,基本包含了Java的一切知识,针对一切学习者(不管有无基础),本人也在努力得提高自己的Java核心技术,有想要一起快速提升自己Java编程水平的小伙伴加下我的联系方式哦~~~,免费提供一切学习资料和本人多年的经验!

有什么问题欢迎大家提出来 ♪(´○`)o团结就是力量
 

Q:2694674917
V:asd2069696039

ALL-OUT YOUTH

以上是关于Java小程序之球球大作战(基于Java线程实现)的主要内容,如果未能解决你的问题,请参考以下文章

Java小程序之球球大作战(基于Java线程实现)

TYVJ4623 球球大作战·生存

球球大作战

球球大作战符号大全

球球大作战名字颜色代码复制

websocket实现简化版球球大作战