球球大作战JAVA小游戏

一、功能实现
游戏简介:
这是一款规则简单的球类游戏,在这个球球的世界里,大球吃小球,努力生存,努力成长是你唯一的目标。
实现方式:
首先定义一个窗口类Gameframe以及游戏面板类GamePanel去实现游戏窗口的描绘;再通过paint方法去drawPaint绘制小球。然后,再定义一个小球类Ball,将小球的x,y坐标以及小球的直径d、移动方向direction、移动速度speed、颜色ballColor等属性封装到该类中。再定义一个ArrayList容器将多个小球进行封装,并且统一管理;然后通过一个循环来创建小球并且初始化它的各项属性。还需要继承线程Thread类多线程进行移动监测敌方每个小球的移动以及碰撞结果。利用键盘监听器KeyListener和鼠标监听器MiuseMontionListener这两个接口,通过定义一个类去实现它们从而实现对玩家小球的鼠标控制和键盘控制。然后还需要定义一个BallCrash类去判断两小球相互碰撞后的结果。若是容器中小球被吃掉,则在容器ArrayList中清除该小球,若是玩家小球被吃掉则切换面板显示“GAME OVER”,若是敌方小球中的几个Boss球被吃掉了则显示游戏胜利。
二、游戏规则:
游戏规则:
1、自己的小球可以随着键盘或鼠标的移动而改变坐标;
2、敌方小球不断的在界面中移动
3、地图上会自动产生许多微粒,供给玩家球和敌方球长大。
4、当检测到两个小球相互碰撞时,
直径大的球会吃掉直径小的球。
5、当我方球吃掉了几个特定的Boss球时,我方胜利,游戏结束;当我方小球被吃掉时,我方失败,游戏结束。
实现方式:
1、定义一个Ball类,其中将玩家球和敌方球的x,y坐标,移动速度,颜色,移动方向封装起来。
2、在Ball类中实现Graphics的方法,用以绘制小球的大小、颜色以及小球上面的文字。
3、定义一个窗口类Gameframe继承JFrame,设置窗口的标题,大小,位置,各项状态。
4、在窗口类中添加背景图片,添加背景音乐,添加面板并且添加键盘KeyListener和鼠标MouseMotionLisener的监听器。
5、定义一个面板类Gamepanel继承JPanel,在面板中添加玩家小球和敌方小球。
6、在面板中实现两个Thread线程,一个控制静止小球,一个控制运动小球。在该面板中设置键盘监听和鼠标监听的事件。
7、定义一个Music类,实现背景音乐的导入、播放以及循环。
8、定义一个Png类,实现背景图片以及小球形状图片等图片的导入。
9、定义一个Otherball类,初始化静止小球和运动小球的各项属性并且实现静止小球和运动小球的自动添加。
10、在Otherball类中定义两个ArrayList容器,分别用以存储静止小球和运动小球。
三、设计思路
在这里插入图片描述
四、程序代码
关键代码一:

package Gamescreen;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
/*画小球*/
public class Gamepanel extends JPanel implements KeyListener,MouseMotionListener{
	public int cnt=10;   //计算剩余大boss的球个数
	private Color pink;
	public Ball mainball = new Ball(450, 450, 40, 30, pink);	
	OtherBall ob=new OtherBall();
	public Gamepanel(){
		ob.addBall();
	
	    startBalls();
        startBalls2();
}

public void paint(Graphics g){
	super.paint(g);
	try {
		mainball.drawBall2(g);
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}                 //绘制玩家小球
	for (int i = 0; i < ob.ballList.size(); i++) {
		Ball ball2 = ob.ballList.get(i);             //绘制敌方运动小球
		if(ball2.flag==true)  ball2.drawBall1(g);
		else ball2.drawBall(g);
		}             
	for (int i = 0; i < ob.ballList2.size(); i++) {
		Ball ball2 = ob.ballList2.get(i);         //绘制静止小球
		ball2.drawBall(g);}
}

public void startBalls(){
//启动线程-----匿名内部类
new Thread(){
	
public void run() {
	
	while (true) {
		//遍历小球集合
		for (int i = 0; i < ob.ballList.size(); i++) {
			//取出小球			
			Ball b =  ob.ballList.get(i);
			b.ballMove();
		  
			//让每一个小球进行移动
		}
		if(cnt==0) {JOptionPane.showMessageDialog(null, "You are the winner!!!\n\n\n\n你统治了整个球球世界\n\n\n\n");
		return;}
		if(ob.ballList.size()<20) {
			ob.ball2();
		}
		for (int i = 0; i < ob.ballList.size(); i++) {
			//先取第一个小球
			Crash ball=new Crash();
			Ball b1 =ob.ballList.get(i);
			for (int j = i+1; j < ob.ballList.size(); j++) {
				Ball b2 =ob. ballList.get(j);
				
				if(ball.crash(b1, b2)){
					if (b1.d >= b2.d) {
						b1.d += b2.d/5;
						ob.ballList.remove(b2);
						if(b2.flag==true)  cnt--; 
						break;
					}else if(b1.d < b2.d){
						b2.d += b1.d/5;
						ob.ballList.remove(b1);
						if(b1.flag==true)  cnt--; 
						break;
					}
				}
			}
					if ((ball.crash(b1,mainball))) {
						if (b1.d > mainball.d) {
							JOptionPane.showMessageDialog(null, "GAME OVER\n\n\n\n你被大球吃掉了\n\n\n\n请再接再厉");
							return;
						}else{
							mainball.d += b1.d/3;
							ob.ballList.remove(b1);
							if(b1.flag==true)  cnt--; 
							break;
					}
				}
			
		}
		repaint();//重绘
		try {
			Thread.sleep(25);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
};
}.start();
}	
public void startBalls2(){
	//启动线程-----匿名内部类
	new Thread(){
		
	public void run() {
		
		while (true) {
			if(ob.ballList2.size()<= 500) {
			ob.ball1();
			}
			for (int i = 0; i < ob.ballList2.size(); i++) {
				//先取第一个小球
				Ball b1 =ob.ballList2.get(i); //静止球
				Crash ball=new Crash();
				for (int j = 0; j < ob.ballList.size(); j++) {
					Ball b2 =ob. ballList.get(j); //运动球
						
				
					if(ball.crash(b1, b2)){
							b2.d +=(b1.d*1.0/b2.d)*(b1.d);
							ob.ballList2.remove(b1);
							break;
						}
					}
					if ((ball.crash(b1, mainball))) {
								mainball.d +=(b1.d*1.0/mainball.d)*(b1.d+10);
								ob.ballList2.remove(b1);
								break;
							}
					}
			repaint();//重绘
			try {
				Thread.sleep(20);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
};
}.start();
}	@Override
public void keyTyped(KeyEvent e) {
	// TODO Auto-generated method stub
	
}

@Override
public void keyPressed(KeyEvent e) {
	// TODO Auto-generated method stub
	if (e.getKeyCode() == KeyEvent.VK_UP) {
	//	System.out.println("点击了上方向键");
		mainball.y -= 10;
	}
	
	if (e.getKeyCode() == KeyEvent.VK_DOWN) {
	//	System.out.println("点击了下方向键");
		mainball.y += 10;
	}


		if (e.getKeyCode() == KeyEvent.VK_LEFT ) {
	//	System.out.println("点击了左方向键");
			mainball.x -= 12;
	}

		if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
	//	System.out.println("点击了右方向键");
			mainball.x += 12; 
	}
	if (e.getKeyCode() == KeyEvent.VK_1) {
		//	System.out.println("点击了左上方向键");
		mainball.x += 10; 
		mainball.y -= 10;
	}
	if (e.getKeyCode() == KeyEvent.VK_2) {
		//	System.out.println("点击了左下方向键");
		mainball.x -= 10; 
		mainball.y -= 10;
	}
	if (e.getKeyCode() == KeyEvent.VK_3) {
		//	System.out.println("点击了右上方向键");
		mainball.x -= 10;
		mainball.y += 10;
	}
	if (e.getKeyCode() == KeyEvent.VK_4) {
		//	System.out.println("点击了右下方向键");
		mainball.x += 10;
		mainball.y += 10;
	}
	repaint();

}


@Override
public void keyReleased(KeyEvent e) {
	// TODO Auto-generated method stub
	
}

@Override
public void mouseDragged(MouseEvent e) {
	// TODO Auto-generated method stub
	
}

@Override
public void mouseMoved(MouseEvent e) {
	// TODO Auto-generated method stub
	int x=e.getX();
	int y=e.getY();
	mainball.x=x;
	mainball.y=y;
}
}

关键代码二:

package Gamescreen;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.AttributedCharacterIterator.Attribute;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;

import java.awt.Color;
import java.awt.Font;


public  class Ball {
	
	public static final int LEFT_UP=0;
	public static final int LEFT_DOWN=1;
	public static final int RIGHT_UP=2;
	public static final int RIGHT_DOWN=3;
	Color ballColor;                //定义小球的颜色;
	public int x,y;                       //定义x,y坐标
	public int d;                         //定义球的直径
	public int speed=(int)(Math.random()*5+1);                     //定义小球的运动速度
	public int direction;                 //定义小球的运动方向
	public Boolean flag;
	public Ball() {
		
	}
	//初始化球
	public Ball(int x,int y,int direction,int d,int speeed,boolean flag,Color ballColor) {
		this.x=x;
		this.y=y;
		this.direction=direction;
		this.d=d;
		this.speed=speed;
		this.flag=flag;
		this.ballColor=ballColor;
	}
	//定义玩家球
	public Ball(int x,int y,int d,int speeed,Color ballColor) {
		this.x=x;
		this.y=y;
		this.d=d;
		this.speed=speed;
	    this.ballColor=ballColor;
	}
	public void ballMove() {
		switch(this.direction) {
		case LEFT_UP:                                //左上
			x-=speed;
			y-=speed;
			if(x<=0) {
				this.direction=RIGHT_UP;
			}
			else if(y<=0) {
				this.direction=LEFT_DOWN;
				
			}
		break;
			case LEFT_DOWN:                             //左下
			x-=speed;
			y+=speed;
			if(x<=0) {
				this.direction=RIGHT_DOWN;
			}
			else if(y>=Gameframe.HEIGHT-d) {
				this.direction=LEFT_UP;
				
			}
		    break;
			case RIGHT_UP :                           //右上
			x+=speed;
			y-=speed;
			if(x>=Gameframe.WIDTH-d) {
				this.direction=LEFT_UP;
			}
			else if(y<=0) {
				this.direction=RIGHT_DOWN;	
			}
			break;
			case RIGHT_DOWN:                               //右下
			x+=speed;
			y+=speed;
			if(x>=Gameframe.WIDTH-d) {
				this.direction=LEFT_DOWN;
			}
			else if(y>=Gameframe.HEIGHT-d) {
				this.direction=RIGHT_UP;
				
			}
			break;
		}
	}
	//画小球
	public void drawBall(Graphics g) {              //画敌方小球
		g.setColor(ballColor);
		g.fillOval(x,y,d,d);                    //画椭圆的x,y坐标以及长度和宽度
	}
	public void drawBall1(Graphics g) {              //画敌方小球
		g.setColor(ballColor);
		g.fillOval(x,y,d,d);                    //画椭圆的x,y坐标以及长度和宽度
		g.setColor(Color.RED);                   //给小球加文字
		Font font=new Font(Font.DIALOG,Font.BOLD, 20);        //设置字体显示效果(String字体  int风格  int字号)
		g.setFont(font);                         //设置组件当前使用的字体
		g.drawString("BOSS",x+d/4-40,y+d/4+10);
	}
	public void drawBall2(Graphics g) throws IOException {            //画玩家小球
		g.setColor(Color.pink);
		g.fillOval(x, y, d, d);
		g.setColor(Color.BLUE);                   //给小球加文字
		File file=new File("712dfdc794f6067845176875eaff25f4.png");
		Image img =ImageIO.read(new FileInputStream("712dfdc794f6067845176875eaff25f4.png"));
		img=ImageIO.read(file);
		g.drawImage(img, x-d, y-d, x+d, y+d, 0, 0, Gameframe.WIDTH, Gameframe.HEIGHT, null		);
		Font font=new Font(Font.DIALOG,Font.BOLD, 12);        //设置字体显示效果(String字体  int风格  int字号)
		g.setFont(font);                         //设置组件当前使用的字体
		g.drawString("伟大宇哥勇往直前",x+d/4-40,y+d/4+10);
	}

	public void paint(Graphics g) {
		// TODO Auto-generated method stub
	}

关键代码三:

package Gamescreen;
import java.awt.Component;
import java.awt.Image;
import java.awt.event.KeyListener;
import java.awt.event.MouseMotionListener;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.TargetDataLine;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class Gameframe extends JFrame{
	public static final int HEIGHT=1360;
	public static final int WIDTH=800;

	static Gamepanel ball=new Gamepanel();
	public Gameframe() {
		this.setTitle("球球大作战");                             //设置标题
		this.setSize(HEIGHT,WIDTH);                             //设置窗口大小
		this.setLocationRelativeTo(null);                       //设置窗口位置居中
		this.setResizable(false);                               //设置不允许窗口大下被改变
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);    //设置关闭程序时窗口关闭
		this.setVisible(true);
		//添加小球到窗体
		this.add(ball);
		//添加键盘的监听事件
		this.addKeyListener(ball);
		this.addMouseMotionListener(ball);
	}
	public static void main(String[] args) throws FileNotFoundException, IOException {
		Gameframe bf=new Gameframe(); 
        Music bgm=new Music("C:\\Users\\86131\\Music\\7017.wav");
        bgm.start();                         //添加背景音乐
        png bg=new png(ball,bf);            //添加背景图片
}}

四、游戏截图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

五、游戏总结
问题一:在新建的一个线程Thread内无法实现有些球静止,有些球随机运动。
解决方法:于是我创建了两个线程Thread,一个线程Thread管理静止小球,另一个线程Thread管理运动小球。

问题二:添加一张背景到我的面板,游戏运行时会出现两个面板频闪的状态。
解决方法:利用pant方法改造,先通过缓冲图片,把所有需要绘制的东西,先绘制在缓冲图中,再把缓冲图片绘制到面板上。

问题三:添加.mp3文件的背景音乐,通过一系列代码将他转化为.wav文件并用AudioPlayer实现让它播放,但却因为缺少某个插件,不能使用java.sun包。
解决方法:为了方便直接在网上找了很久这个音乐的.wav文件,导入java.sound包,通过一个音乐线程,实现音乐的播放以及循环。

问题四:在一个线程中无法实现静止小球和运动小球在一定时间后的自动添加。
解决办法:定义了一个新的小球的类addball,其中实现两个方法ball1(),ball2();通过每隔一段时间调用该方法实现给分别装静止球和运动球的容器ArrayListener再添加小球。

问题五:给游戏界面Gameframe添加一张背景图片时会覆盖游戏界面,使游戏无法进行。
解决办法:利用Jlabel组件通过java.swing中的ImageIcon导入图片实现。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐