Java小程序之球球大作战(基于Java线程实现)
发布日期:2021-06-30 21:46:24 浏览次数:2 分类:技术文章

本文共 9960 字,大约阅读时间需要 33 分钟。

                                                                   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
list =new ArrayList
(); //随机器 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 
= 300) { // mb.overFlag=true; isbegin = false; MoveBallGame.list.remove(this); for (int i = 0; i

 

我方小球类:

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

转载地址:https://longjiedasheng.blog.csdn.net/article/details/116838920 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:日常Java练习题(方舟SS系列)
下一篇:Java基础视频教程大全,2021年最新最强的大佬自学路线图

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2024年04月06日 06时52分02秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

金山云张斯聪:探索沉浸式解决方案 提升教育云上体验 2019-05-01
高防弹性IP 金山云荣获“可信云技术最佳实践--网络安全”奖 2019-05-01
一周拿下百度Offer!211本+985硕+计算机专业~ 2019-05-01
闭关三月!猛男逆道而行,四杀斩获阿里 / 腾讯 / 京东 / 百度等大厂 offer 2019-05-01
花了3个达不溜!让隔壁小姐姐从圈内大佬手中拿到“阿里面试官手册”,看完之后我大呼“不亏”! 2019-05-01
上线三天获 22w 浏览量!2021 最新一线大厂 Java 高级架构师面试题总结~ 2019-05-01
电信物联网平台SOTA升级(软件升级)的全流程说明 2019-05-01
电信物联网平台插件开发相关总结 2019-05-01
ARM之一 分散加载文件(scatter)详述 2019-05-01
centos6 python3.6 安装配置jupyer 2019-05-01
CDH5.14 spark2.4.0配置python3 以及读取hive表 2019-05-01
VMware安装centos7.2后配置网络并设置固定ip 2019-05-01
在 centos7.2安装docker 并设置阿里云源 2019-05-01
centos7.2 将mysql添加到服务中 2019-05-01
【nifi数据采集】nifi给kafka打数据遇到的坑 - kafka2.1 的listeners配置 2019-05-01
【linux用户模块】/etc/passwd的字段含义 2019-05-01
【linux用户模块】用户/用户组的管理 2019-05-01
【spark2】【源码学习】【环境编译】在idea导入spark源码,执行example并debug 2019-05-01
【spark2】【源码学习】【分区数】spark读取 本地/可分割/单个 的文件时是如何划分分区 2019-05-01
【大数据】【调度】Airflow 和 Azkaban的选型 2019-05-01