本文共 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 ArrayListlist =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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!