Java--奔跑的小恐龙游戏(详细注释)

奔跑的小恐龙游戏是一款非常简单的跑酷游戏,玩家通过控制小恐龙向前狂奔,通过空格键进行跳跃躲避沿途出现的牛仔、木桶和飞行的老鹰,使用上下箭头控制奔跑的速度,跑的越远,得分越高。游戏内添加有背景音乐、跳跃音效和撞击音效。代码虽然较长,但结构简单,易于理解,适合初学者进行学习。

文章目录

详细代码:

一、启动包

1.开始类 Start

二、模型包

1.恐龙类 Dinosaur

2.障碍物类 Obstacle

三、服务包

1.刷新帧线程类 FreshThread

2.音乐播放器类 MusicPlayer

3.分数记录器类 ScoreRecorder

4.音效类 Sound

四、视图包

1.背景图像类 BackgroundImage

2.游戏面板类 GamePanel

3.主窗体类 MainFrame

4.成绩对话框类 ScoreDialog

五、其它

1、data文件夹数据:

2、music文件音效:

3、image文件图像:


总体代码架构:

详细代码:

一、启动包

       游戏开始类调用游戏主窗体类。而游戏面板类对开始界面进行了窗体,窗口设计并调用了游戏主体窗口类启动游戏。

1.开始类 Start

Start.java

package pers.wu.main; //启动包
 
import pers.wu.view.MainFrame;
 
//启动类
public class Start
{
 
	public static void main(String[] args)
	{
		MainFrame m1 = new MainFrame();//创建主窗体
		m1.setVisible(true);//显示主窗体
 
	}
 
}
二、模型包

       模型包类中对恐龙类和障碍物类进行了基本定义,恐龙类中包含对象恐龙的图片,坐标,恐龙跳跃的变量与状态与刷新时间。之后设置了如踏步,跳跃,加减速,移动和边界获取的方法。而在障碍物类中包含对对象牛仔、对象木桶和对象老鹰的图片,坐标和图片移动的速度,也设置了与之对应的方法,有移动,移除和边界获取的基本定义。

1.恐龙类 Dinosaur

Dinosaur.java 

package pers.wu.modles;//模型包
 
import java.awt.Rectangle;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
//import javax.xml.crypto.dsig.keyinfo.RetrievalMethod;

import pers.wu.service.FreshThread;
import pers.wu.service.Sound;
 

//恐龙类
public class Dinosaur
{
	public BufferedImage image; 						//主图片
	private BufferedImage image1,image2,image3; 		//跑步图片
	public int x,y; 									//坐标
	private int jumpValue = 0; 							//跳跃的增变量
	private boolean jumpState = false; 					//跳跃状态
	private int stepTimer = 0; 							//踏步计时器
	private final int JUMP_HEIGHT = 130;				//跳起最大高度 
	private final int LOWEST_Y = 180; 	            	//落地最低坐标
	private final int FREASH = FreshThread.FREASH; 		//刷新时间
 
	
	public Dinosaur()
	{
		this.x = 50;//恐龙的横坐标   固定的横位置50
		this.y = LOWEST_Y;//恐龙的纵坐标
		try
		{
			image1 = ImageIO.read(new File("image/konglong1.png"));//读取恐龙的图片
			image2 = ImageIO.read(new File("image/konglong2.png"));
			image3 = ImageIO.read(new File("image/konglong3.png"));
			
		} catch (IOException e)
		{
			e.printStackTrace();
		}
	}
	
	
	//实现图片的切换
	private void step()
	{
		//每过250毫秒,更换一张图片。因为有3张,所以除以3取余,轮流
		
		int temp = (stepTimer / 250) % 3;  //取余数
		switch (temp)
		{
		case 1:
			image = this.image1;
			break;
		case 2:
			image = this.image2;
			break;
		default:
			image = this.image3;
			break;
		}
		
		stepTimer += FREASH;//计时器递增
	}
	
	
	//实现恐龙的跳跃
	public void jump()
	{
		if (!jumpState)//!false 
		{
			Sound.jump(); //播放跳跃的音效
		}
		jumpState = true; //开始跳跃
	}
	
	
    //实现恐龙跳起后的落地
	public void move()        //x=50  y最低  也是向下的最大坐标
	{
		step();//不断踏步
		if (jumpState)//如果正在跳跃     最上面为0  越往下坐标越大
		{
			if (y >= LOWEST_Y)//如果纵坐标大于等于最低点---(越往上坐标越小)
			{
				jumpValue = -4;//增变量为负值--向上跳
			}
			if (y <= LOWEST_Y - JUMP_HEIGHT)//如果跳过最高点
			{
				jumpValue = 4; //增变量变为正值--向下跳
			}
			y+= jumpValue;//纵坐标发生变化
			if (y >= LOWEST_Y)//如果再次落地
			{
				jumpState = false; //停止跳跃
			}
		}
	}
	
	//恐龙头和脚部都画一个矩形 已所取矩形的左上角为基础获得恐龙的边界 来用于后面的碰撞检测
	public Rectangle getFootBounds()//获取恐龙的脚步边界对象    x,y左上角坐标
	{
		return new Rectangle(x+30,y+59,29,18);//用于后续做碰撞检测
	}
	
	public Rectangle getHeadBounds()//获取恐龙的头部边界对象
	{
		return new Rectangle(x+66,y+25,32,22);//new Rectangle(x,y,width,height)
	}
}
2.障碍物类 Obstacle

Obstacle.java

package pers.wu.modles;//模型包
 
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;
 
import javax.imageio.ImageIO;

import pers.wu.view.GamePanel;
 
//障碍类
public class Obstacle
{
	public int x,y; //横纵坐标
	public BufferedImage image;   //主图片
	private BufferedImage cask;   //木桶
	private BufferedImage cowboy;//牛仔
	private BufferedImage eagle;//老鹰
	private int speed;//障碍的横坐标移动速度
	
	
	public Obstacle()
	{
		try
		{
			cask = ImageIO.read(new File("image/cask.png"));//木桶图片
			cowboy = ImageIO.read(new File("image/cowboy.png"));//牛仔图片
		    eagle = ImageIO.read(new File("image/eagle.png"));//读取老鹰的图片
		} catch (IOException e)
		{
			e.printStackTrace();
		}

		Random r1 = new Random();//创建随机对象
		if (r1.nextInt(3) == 0)//从0、1、2中取一值   [0,3)
		{
			image = cowboy; //为0,采用牛仔图片
		}
		else if(r1.nextInt(3) == 1)
		{
			image = cask; //为1,采用木桶图片
		}
		else 
		{
			image = eagle;//采用老鹰图片
		}
	
		x = 800;//障碍初始横坐标
		if(image==cowboy||image==cask)
		{
		    y = 280 - image.getHeight();//纵坐标--使牛仔和木桶处于地平线上
		}else
		{
			y = 250 - image.getHeight();//纵坐标--使老鹰飞在空中
		}

		//speed = GamePanel.SPEED1;
	}
	
	
	//障碍物的横坐标移动
	public void move()
	{
		speed = GamePanel.SPEED1;
		x -=speed;//横坐标递减--障碍物的速度与背景的速度一致
	}
	
	//实现障碍物移出游戏界面的操作
	public boolean isLive()//如果移出了游戏界面
	{
		if (x <= -image.getWidth())
		{
			return false;//消亡
		}
		return true;//存活
	}
	
	//实现障碍边界的获取  用于和小恐龙的碰撞检测
	public Rectangle getBounds()
	{
		if (image == cowboy)//如果使用牛仔图片
		{
			return new Rectangle(x+7,y,15,image.getHeight()); //返回牛仔的边界
		}else if(image==cask)
		{
		    return new Rectangle(x+5,y+4,23,21); //返回木桶的边界(x+5,y+4,23,21)
		}
	    else
	    {
	    	return new Rectangle(x+5,y+4,23,21); //返回老鹰的边界
	    }	
	
	}
}
三、服务包

       服务包中刷新帧线程类是对游戏的刷新。分数记录类实现对新分数的记录,如果新分数大于前三名则显示到排行榜中。音乐播放器类是对音乐播放器的创建,寻找音乐文件并在进行播放与停止。而在新一轮游戏中通过重写方法来播放音乐。而音效类是读取指定文件中的音效,并在条件下播放。

1.刷新帧线程类 FreshThread

FreshThread.java

package pers.wu.service;//服务包
 
import java.awt.Container;

import pers.wu.view.GamePanel;
import pers.wu.view.MainFrame;
import pers.wu.view.ScoreDialog;
 

//刷新帧线程类
public class FreshThread extends Thread
{
	public static final int FREASH = 20; //刷新时间20
	GamePanel panel; //游戏面板
	
	public FreshThread(GamePanel p)
	{
		this.panel = p;
	}
	
	public void run()
	{
		while (!panel.isFinish())//如果游戏未结束
		{
			panel.repaint();//重绘游戏面板
			try
			{
				Thread.sleep(FREASH);//按照刷新时间休眠
			} catch (InterruptedException e)
			{
				e.printStackTrace();
			}
		}
		Container container1 = panel.getParent();//获取面板父容器
		while (!(container1 instanceof MainFrame))//如果父容器不是主窗体类
		{
			container1 = container1.getParent();//继续获取父容器的父容类
		}
		MainFrame frame = (MainFrame)container1;//将容器强制转换为主窗体类
		new ScoreDialog(frame);//弹出得分记录对话框
		frame.restart();//主窗体重载开始游戏
	}
}
2.音乐播放器类 MusicPlayer

MusicPlayer.java

package pers.wu.service;//服务包
 
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
 
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;
 
//音乐播放器类
public class MusicPlayer implements Runnable
{
	File soundFile; //音乐文件
	Thread thread;  //父线程--执行run方法
	boolean circulate; //是否循环播放
	
	public MusicPlayer(String filePath,boolean circulate) throws FileNotFoundException
	{
		this.circulate = circulate;
		soundFile  = new File(filePath);
		if (!soundFile.exists())//如果文件不存在
		{
			throw new FileNotFoundException(filePath + "未找到");//抛出错误,文件未找到
		}
	}
 
	public void run()//重写线程执行方法
	{
		byte[] auBuffer = new byte[1024 * 128]; //创建128k缓冲区
		do
		{    //从音乐文件中获取音频输入流
			AudioInputStream audioInputStream = null; //创建音频输入流对象
			SourceDataLine auLine = null; //混频器源数据行
			try
			{
				audioInputStream = AudioSystem.getAudioInputStream(soundFile);//soundFile--音乐文件
				AudioFormat format = audioInputStream.getFormat();//获取音频格式
				//按照源数据行类型和指定音频格式创建数据行对象
				DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);//获取音乐格式
				//利用音频系统类获得与指定Line.Info 对象中的描述匹配的行,并转换为源数据行对象
				auLine = (SourceDataLine)AudioSystem.getLine(info);
				auLine.open(format);//按照指定格式打开源数据行
				auLine.start();//源数据行开启读写活动
				int byteCount = 0;//记录音频输入流读出的字节数
				while (byteCount != -1)//如果音频输入流中读取的字节数不为-1
				{   //从音频数据流中读出128K的数据--auBuffer=128K缓冲区
					byteCount = audioInputStream.read(auBuffer,0,auBuffer.length);
					if (byteCount >= 0)//如果读出有效数据--auLine=混频器源数据行
					{
						auLine.write(auBuffer, 0, byteCount);//将有效数据写入数据行中
					}
				}
			}catch (IOException e)
			{
				e.printStackTrace();
			}
			catch (UnsupportedAudioFileException e) 
			{
				e.printStackTrace();
			}
			catch (LineUnavailableException e) 
			{
				e.printStackTrace();
			}finally
			{
				auLine.drain();//清空数据行
				auLine.close();//关闭数据行
			}
		} while (circulate);//根据循环标志判断是否循环播放
	}
 
	public void play()//播放
	{
		thread = new Thread(this);//创建线程对象
		thread.start();//开启线程
	}
	
	@SuppressWarnings("deprecation")
	public void stop()//停止播放
	{
		thread.stop();//强制关闭线程
	}
}
3.分数记录器类 ScoreRecorder

ScoreRecorder.java

package pers.wu.service;//服务包
 
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Arrays;
 
//分数记录器类
public class ScoreRecorder
{
	private static final String SCOREFILE = "data/source"; //成绩记录文件
	private static int scroes[] = new int[3]; //当前得分最高前三名
	
	
	public static void init()
	{
		File file1 = new File(SCOREFILE);//创建记录文件
		if (!file1.exists())//如果文件不存在
		{
			try
			{
				file1.createNewFile();//创建新文件
			} catch (IOException e)
			{
				e.printStackTrace();
			}
			return;//停止方法
		}
		
		
		FileInputStream fileInputStream1 = null;//文件字节
		InputStreamReader inputStreamReader1 = null;//字符流
		BufferedReader bufferedReader1 = null;//缓冲字符流
		try
		{
			fileInputStream1 = new FileInputStream(file1); //文件字节输入流
			inputStreamReader1 = new InputStreamReader(fileInputStream1); //字节流转字符流
			bufferedReader1 = new BufferedReader(inputStreamReader1); //缓冲字节流
			String value = bufferedReader1.readLine(); //读取一行
			if (!(value ==null || "".equals(value))) //如果不为空
			{
				String vs[] = value.split(","); //分隔字符串
				if (vs.length < 3) //如果分割结果小于3
				{
					Arrays.fill(scroes, 0); //数组成绩填充0
				}
				else 
				{
					for (int i = 0; i < 3; i++)
					{   //将记录文件中的值赋给当前分数数组
						scroes[i] = Integer.parseInt(vs[i]);
					}
				}
			}
		} catch (FileNotFoundException e)
		{
			e.printStackTrace();
		}
		catch (IOException e) 
		{
			e.printStackTrace();
		}
		finally //依次关闭流
		{
			try
			{
				bufferedReader1.close();
			} catch (IOException e2)
			{
				e2.printStackTrace();
			}
			try
			{
				inputStreamReader1.close();
			} catch (IOException e2)
			{
				e2.printStackTrace();
			}
			try
			{
				fileInputStream1.close();
			} catch (IOException e2)
			{
				e2.printStackTrace();
			}
		}
	}
	
	
	//保存分数
	public static void saveScore()
	{
		String value = scroes[0] + "," + scroes[1] + "," + scroes[2]; //拼接得分数组
		FileOutputStream fileOutputStream1 = null;//文件字节
		OutputStreamWriter outputStreamWriter1 = null;//字符流
		BufferedWriter bufferedWriter1 = null;//缓冲字符流
		try
		{
			fileOutputStream1 = new FileOutputStream(SCOREFILE);//文件字节输出流
			outputStreamWriter1 = new OutputStreamWriter(fileOutputStream1);//字符流转字符流 
			bufferedWriter1 = new BufferedWriter(outputStreamWriter1);//缓冲字符流 
			bufferedWriter1.write(value);//写入拼接后的字符串
			bufferedWriter1.flush();//字符流刷新
		} catch (FileNotFoundException e)
		{
			e.printStackTrace();
		}
		catch (IOException e) 
		{
			e.printStackTrace();
		}
		finally //依次关闭流
		{
			try
			{
				bufferedWriter1.close();
			} catch (IOException e2)
			{
				e2.printStackTrace();
			}
			
			try
			{
				outputStreamWriter1.close();
			} catch (IOException e2)
			{
				e2.printStackTrace();
			}
			
			try
			{
				fileOutputStream1.close();
			} catch (IOException e2)
			{
				e2.printStackTrace();
			}
		}
	}
	
	
    //新分数 添加分数,如果新添加的分数比排行榜分数高,则会将新分数记入排行榜
	static public void addNewScore(int score)
	{   //在得分组数基础上创建一个长度为4的临时数组
		int temp[] = Arrays.copyOf(scroes, 4);
		temp[3] = score;//将新分数赋值给第四个元素
		Arrays.sort(temp);//临时数组降序排列
		scroes = Arrays.copyOfRange(temp, 1, 4);//将后三个元素赋值给得分数组
	}
	
	
	//获取分数
	static public int[] getScores()
	{
		return scroes;
	}
}
4.音效类 Sound

Sound.java

package pers.wu.service;//服务包
 
import java.io.FileNotFoundException;
 
//音效类
public class Sound
{
	static final String DIR = "music/";//音乐文件夹
	static final String BACKGROUD = "background.wav";//背景音乐
	static final String JUMP = "jump.wav";//跳跃音效
	static final String HIT = "hit.wav";//撞击音效
	
	
	//播放声音,参数1(file)音乐文件完整名称,参数2(circulate)是否循环播放
	private static void play(String file,boolean circulate)
	{
		try
		{
			MusicPlayer player = new MusicPlayer(file, circulate);//创建播放器
			player.play();//播放器开始播放
		} catch (FileNotFoundException e)
		{
			e.printStackTrace();
		}
	}
	
	
	//播放跳跃音效
	static public void jump()
	{
		play(DIR+JUMP, false);//播放一次跳跃音效
	}
	
	
	//播放撞击音效
	static public void hit()
	{
		play(DIR+HIT, false);//播放一次撞击音效
	}
	
	
	//播放背景音乐
	static public void backgroud()
	{
		play(DIR+BACKGROUD, true);//循环播放背景音乐
	}
}
四、视图包

       视图包包括游戏背景类,游戏面板类,主体窗口类,计分面板类类。游戏背景类中设置了背景图的滚动。游戏面板类中设置了对背景图的载入,调用实体类,背景类和音效类中的音效并对各类赋予了图片绘制方法,初始化恐龙和障碍物以及启动线程方法,遍历障碍方法,计分方法,游戏结束判定方法和恐龙跳跃输入方法。游戏主体窗口类对游戏窗体与窗口进行设计并对重新开始方法进行设计与监听。计分面板类对计分面板窗体与窗口进行设计。

1.背景图像类 BackgroundImage

BackgroundImage.java

package pers.wu.view;//视图包
 
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
 
import javax.imageio.ImageIO;
 

//滚动背景
public class BackgroundImage
{
	public BufferedImage image;//背景图片
	private BufferedImage image1,image2;//滚动的两张图片
	private Graphics2D g2d;//背景图片的绘图对象
	public int x1,x2;//两个滚动图片的坐标
	
	public BackgroundImage()
	{
		try
		{
			image1 = ImageIO.read(new File("image/beijing.png"));//读取背景图片
			image2 = ImageIO.read(new File("image/beijing.png"));
			
		} catch (IOException e)
		{
			e.printStackTrace();
		}
		//主图片采用宽2000高500的彩色图片
		image = new BufferedImage(2000, 500, BufferedImage.TYPE_INT_RGB);
		g2d = image.createGraphics(); //获取主图片绘图对象
		x1 = 0; //第一幅图片初始横坐标为0
		x2 = 800;//第二副图初始横坐标为800
		g2d.drawImage(image1, x1, 0, null);
	}
	
	
    //实现背景的图片滚动
	public void roll()
	{
		int SPEED = GamePanel.SPEED1;
		x1 -= SPEED;//第一幅图片左移
		x2 -= SPEED;//第二幅图片左移
		if (x1 <= -800)//如果第一幅图片移出屏幕
		{
			x1 = 800;//回到屏幕右侧
		}
		if (x2 <= -800)//如果第二幅图片移出屏幕
		{
			x2 = 800;//回到屏幕右侧
		}
		g2d.drawImage(image1, x1, 0, null);//在主图片中绘制两幅图片
		g2d.drawImage(image2, x2, 0, null);
	}
}
2.游戏面板类 GamePanel

GamePanel.java

package pers.wu.view;//视图包
 
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
 
import javax.swing.JPanel;
//import javax.xml.crypto.dsig.keyinfo.RetrievalMethod;

import pers.wu.modles.Dinosaur;
import pers.wu.modles.Obstacle;
import pers.wu.service.FreshThread;
import pers.wu.service.ScoreRecorder;
import pers.wu.service.Sound;

 
//游戏面板
public class GamePanel extends JPanel implements KeyListener
{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private BufferedImage image1; //主图片
	private BackgroundImage background1;//背景图片
	private Dinosaur golden1; //恐龙
	private Graphics2D g2d; //主图片绘图对象
	private int addObstacleTimer = 0; //添加障碍计时器
	private boolean finish = false; //游戏结束标志
	private List<Obstacle> list1 = new ArrayList<>(); //障碍集合
	private final int FREASH = FreshThread.FREASH; //刷新时间
	int score = 0; //得分
	int scoreTimer = 0; //分数计时器
	int scores[] = ScoreRecorder.getScores();//获取当前前三名成绩
	int Maxscore=0;//最高分数

	public static  int SPEED1 = 6;
	
	public GamePanel()
	{   //主图片采用宽2000高500的彩色图片
		image1 = new BufferedImage(2000, 500, BufferedImage.TYPE_INT_BGR);//2000, 500,
		g2d = image1.createGraphics();//获取主图片绘图对象
		background1 = new BackgroundImage();//初始化滚动背景
		golden1 = new Dinosaur();//初始化小恐龙
		FreshThread thread1 = new FreshThread(this);//刷新帧线程
		thread1.start();//启动线程
	}
 
    //绘制图片
	private void paintImage()
	{
		background1.roll();//背景图片开始滚动
		golden1.move();//恐龙开始滚动
		g2d.drawImage(background1.image, 0, 0, this);//绘制滚动背景
		addObstacleTimer += FREASH;//障碍计时器递增
		scoreTimer += FREASH;//分数计时器递增
		
		if (addObstacleTimer == 1300)//每过1300毫秒
		{
			if (Math.random() * 100 > 40)//60%概率出现障碍
			{
				list1.add(new Obstacle());
			}
			addObstacleTimer = 0;//重新计时
		}
		
		for (int i = 0; i < list1.size(); i++)//遍历障碍集合
		{
			Obstacle o1 = list1.get(i);//获取障碍对象
			if (o1.isLive())//如果是有效障碍
			{
				o1.move();//障碍移动
				g2d.drawImage(o1.image, o1.x, o1.y, this);//绘制障碍
				
				
				//如果恐龙头脚碰到障碍   先获得障碍边界对象   intersects方法:判断两个矩形是否交汇
				if (o1.getBounds().intersects(golden1.getFootBounds())|| o1.getBounds().intersects(golden1.getHeadBounds()))
				{
					Sound.hit();//播放撞击声音
					gameOver();//游戏结束
				}
			}
			else //如果不是有效障碍
			{
				list1.remove(i);//删除障碍
				i--;//循环变量前移
			}
		}
		g2d.drawImage(golden1.image, golden1.x, golden1.y, this);//绘制恐龙
		
		
		
		//遍历数组集合 找最大分数
		for(int i=0;i<3;i++)
		{
			if(scores[i]>scores[0])
				Maxscore=scores[i];
		}
		g2d.drawString(String.format("MAX%06d",Maxscore), 540, 30);//绘制最大分数
		if (scoreTimer >= 500)//每过500毫秒
		{
			score += 10;//加十分
			scoreTimer = 0;//重新计时
		}
		g2d.setColor(Color.BLACK);//使用黑色
		g2d.setFont(new Font("黑体",Font.BOLD,24));//设置字体
		g2d.drawString(String.format("NOW%06d", score), 670, 30);//绘制分数
		g2d.drawString(String.format("SPEED/%02d",SPEED1), 420, 30);//绘制最大分数  越小越往左
	}
	//重写绘制组件方法
	public void paint(Graphics g)
	{
		paintImage();//绘制主图片内容
		g.drawImage(image1, 0, 0, this);
		
	}
	
	//游戏是否结束
	public boolean isFinish()
	{
		return finish;
	}
	//使游戏结束
		public void gameOver()
		{
			ScoreRecorder.addNewScore(score);//记录当前分数
			finish = true;
		}
		
		
		//键盘事件
		public void keyPressed(KeyEvent e)
		{
			int code = e.getKeyCode();//获取按下的按键值
			if (code == KeyEvent.VK_SPACE)//如果是空格
			{
				golden1.jump();//恐龙跳跃
			}else if(code == KeyEvent.VK_UP)//如果是↑
			{
				SPEED1=SPEED1+1;//速度加1
			}else if(code == KeyEvent.VK_DOWN)//如果是↓
			{
				if(SPEED1-1<4)//定义了一个最小速度4
				{
					SPEED1=SPEED1-0;//速度不变
				}else
				SPEED1=SPEED1-1;//速度减1
			}
			
			
		}
			
	
	@Override
	public void keyTyped(KeyEvent e)
	{
		
	}
 
 
	@Override
	public void keyReleased(KeyEvent e)
	{
		// TODO Auto-generated method stub
		
	}
}
3.主窗体类 MainFrame

MainFrame.java

package pers.wu.view;//视图包
 
//import java.awt.Component;
import java.awt.Container;
//import java.awt.Dimension;
//import java.awt.Font;
//import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.WindowConstants;

import pers.wu.service.ScoreRecorder;
import pers.wu.service.Sound;
 

//import javax.swing.*;
//import java.awt.event.*;
//主窗体
public class MainFrame extends JFrame
{
 
	private static final long serialVersionUID = 1L;

	public MainFrame()
	{   
		//窗口设置
		restart(); //开始
		//设置窗口的横纵坐标和宽高
		this.setBounds(350,150,820,330);//350,150,820,330  setBounds(x,y,width,height)
		this.setTitle("奔跑吧!小恐龙!     游戏按键:space 实现跳跃  ↑ 增快移动速度  ↓ 减缓移动速度");//标题
		Sound.backgroud(); //播放背景音乐
		ScoreRecorder.init(); //读取得分记录
		addListener(); //添加监听
		this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);//关闭窗体则停止程序
		this.setLocationRelativeTo(null);//窗口居中
		this.setResizable(false);//大小窗口不不变
		
	}
	public void restart()
	{
		Container container1 = this.getContentPane();
		container1.removeAll(); //删除容器中所有组件
		GamePanel panel1 = new GamePanel(); //创建游戏面板
		container1.add(panel1);
		addKeyListener(panel1); //添加键盘事件
		container1.validate(); //验证组件
	}
	
	private void addListener()
	{
		addWindowListener(new WindowAdapter()
		{
			public void windowClosing(WindowEvent e)
			{
				ScoreRecorder.saveScore();
			}
		});
		
	}
}
4.成绩对话框类 ScoreDialog

ScoreDialog.java

package pers.wu.view;//视图包
 
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
 
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

import pers.wu.service.ScoreRecorder;
 
//成绩对话框
public class ScoreDialog extends JDialog  //JDialog窗体为对话框 从一个窗体弹出另一个窗体
{
     /**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	//构造方法 frame 父窗体
	public ScoreDialog(JFrame frame)
	{
		super(frame,true);//调用父类构造方法,阻塞父窗体
		int scores[] = ScoreRecorder.getScores();//获取当前前三名成绩
		JPanel scorePanel = new JPanel(new GridLayout(4,1));//成绩面板,4行1列
		scorePanel.setBackground(Color.WHITE);//白色背景
		JLabel label1 = new JLabel("得分排行榜",JLabel.CENTER);//标题标签,居中
		label1.setFont(new Font("黑体",Font.BOLD,20));//设置字体
		label1.setForeground(Color.BLUE);//蓝色字体blue
		
		JLabel label2 = new JLabel("第1名:" + scores[2],JLabel.CENTER);//第一名标签
		JLabel label3 = new JLabel("第2名:" + scores[1],JLabel.CENTER);//第二名标签
		JLabel label4 = new JLabel("第3名:" + scores[0],JLabel.CENTER);//第三名标签
		JButton button1 = new JButton("重新开始");//重新开始按钮
		button1.addActionListener(new ActionListener()//按钮添加事件监听
		{
			
			@Override
			public void actionPerformed(ActionEvent e)//当点击时
			{
				dispose();//销毁对话框
				
			}
		});
		
		scorePanel.add(label1);//成绩面板添加标签
		scorePanel.add(label2);
		scorePanel.add(label3);
		scorePanel.add(label4);
		
		Container container1 = this.getContentPane();//获取主容器
		container1.setLayout(new BorderLayout());//使用边界布局
		container1.add(scorePanel,BorderLayout.CENTER);//成绩面板放中间
		container1.add(button1,BorderLayout.SOUTH);//按钮放底部
		
		this.setTitle("游戏结束");//对话框标题
		int width,height;//对话框宽高
		width = 200;//对话框宽高均为200
		height = 200;
		int x = frame.getX() + (frame.getWidth() - width)/2;//获得主窗体中居中位置的横坐标
		int y = frame.getY() + (frame.getHeight() - height)/2;//获得主窗体中居中位置的纵坐标
		setBounds(x,y,width,height);//设置横纵坐标和宽高
		setVisible(true);//显示对话框
	}
 
}
五、其它
1、data文件夹数据:

2、music文件音效:

链接:https://pan.baidu.com/s/1gzrE_hJxu-uy5BCz1t5hYQ 
提取码:3110

3、image文件图像:

konglong1.png

konglong2.png

konglong3.png

eagle.png

cask.png

cowboy.png