文章目录

  • 现奔跑吧!小恐龙
    • 效果
    • 源码
      • main包
      • modle包
      • service包
      • view包

现奔跑吧!小恐龙

项目结构

效果



源码

main包

package main;import view.MainFrame;// 游戏开始类
public class Start {public static void main(String[] args) {MainFrame frame = new MainFrame();// 创建主窗体frame.setVisible(true);// 显示主窗体}
}

modle包

package modle;import service.FreshThread;
import service.Sound;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;// 恐龙类
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_HIGHT = 100; // 跳起最大高度private final int LOWEST_Y = 120; // 落地最低坐标private final int FREASH = FreshThread.FREASH; // 刷新时间--刷新帧线程public Dinosaur() {x = 50;         // 恐龙的横坐标y = LOWEST_Y;   // 恐龙的纵坐标try {image1 = ImageIO.read(new File("image/恐龙1.png")); // 读取恐龙的图片image2 = ImageIO.read(new File("image/恐龙2.png"));image3 = ImageIO.read(new File("image/恐龙3.png"));} catch (IOException e) {e.printStackTrace();}}// 踏步private void step() {// 每过250毫秒,更换一张图片。因为共有3图片,所以除以3取余,轮流展示这三张int tmp = stepTimer / 250 % 3;switch (tmp) {case 1 :image = image1;break;case 2 :image = image2;break;default :image = image3;}stepTimer += FREASH; // 计时器递增}// 跳跃public void jump() {if (!jumpState) { // 如果没处于跳跃状态Sound.jump(); // 播放跳跃音效}jumpState = true; // 处于跳跃状态}// 移动public void move() {step(); // 不断踏步if (jumpState) { // 如果正在跳跃if (y == LOWEST_Y) { // 如果纵坐标大于等于最低点---(越往上坐标越小)jumpValue = -4; // 增变量为负值--向上跳}if (y <= LOWEST_Y - JUMP_HIGHT) {// 如果跳过最高点jumpValue = 4; // 增变量为正值--向下跳}y += jumpValue; // 纵坐标发生变化if (y == LOWEST_Y) { // 如果再次落地jumpState = false; // 停止跳跃}}}public Rectangle getFootBounds() { // 获取恐龙的脚部边界对象return new Rectangle(x + 30, y + 59, 29, 18); // 用于后续做碰撞检测}public Rectangle getHeadBounds() { // 获取恐龙的头部边界对象return new Rectangle(x + 66, y + 25, 32, 22);}}
package modle;import view.BackGroundImage;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;// 障碍类
public class Obstacle {public int x, y; // 横纵坐标public BufferedImage image;private BufferedImage stone; // 石头图片---(32,26)private BufferedImage cacti; // 仙人掌图片---(32,59)private int speed; // 移动速度--图片跟着背景走public Obstacle() {try {stone = ImageIO.read(new File("image/石头.png")); // 石头图片cacti = ImageIO.read(new File("image/仙人掌.png")); // 仙人掌图片} catch (IOException e) {e.printStackTrace();}Random r = new Random(); // 创建随机对象if (r.nextInt(2) == 0) { // 从0和1中取一值,若为0image = cacti; // 采用仙人掌图片} else {image = stone; // 采用石头图片}x = 800; // 初始横坐标y = 200 - image.getHeight(); // 纵坐标--使图片处在地平线上speed = BackGroundImage.SPEED; // 移动速度与背景同步--BackgroundImage=背景}// 移动public void move() {x -= speed; // 横坐标递减--障碍物的速度与背景的速度一致}public boolean isLive() {// 如果移出了游戏界面if (x <= -image.getWidth()) {return false; // 消亡}return true; // 存活}// 通过getBounds()方法返回边界对象public Rectangle getBounds() {if (image == cacti) { // 如果使用仙人掌图片// 返回仙人掌的边界return new Rectangle(x + 7, y, 15, image.getHeight());}// 返回石头的边界return new Rectangle(x + 5, y + 4, 23, 21);}}

service包

package service;import view.GamePanel;
import view.MainFrame;
import view.ScoreDialog;import java.awt.*;// 刷新帧线程类
public class FreshThread extends Thread{public static final int FREASH = 20;GamePanel p; // 游戏面板public FreshThread(GamePanel p) {this.p = p;}public void run() {while (!p.isFinish()) { // 如果游戏未结束p.repaint(); // 重绘游戏面板try {Thread.sleep(FREASH); // 按照刷新时间休眠} catch (InterruptedException e) {e.printStackTrace();}}Container c = p.getParent(); // 获取面板父容器while (!(c instanceof MainFrame)) { // 如果父容器不是主窗体类c = c.getParent(); // 继续获取父容器的父容器}MainFrame frame = (MainFrame) c; // 将容器强制转换为主窗体类new ScoreDialog(frame); // 弹出得分记录对话框frame.restart(); // 主窗体重载开始游戏}
}
package service;import javax.sound.sampled.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;// 音乐播放器类
public class MusicPlayer implements Runnable {// 音乐文件File soundFile;// 父线程Thread thread;// 是否循环播放boolean circulate;public MusicPlayer(String filepath,boolean circulate) throws FileNotFoundException {this.circulate = circulate;soundFile = new File(filepath);if(!soundFile.exists()){ // 如果文件不存在throw  new FileNotFoundException(filepath + "未找到");}}@Overridepublic void run() {byte[] auBuffer = new byte[1024 * 128]; // 创建128k缓冲区do{AudioInputStream audioInputStream = null; // 创建音频输入流对象SourceDataLine auline = null; // 混频器源数据行try {// 从音乐文件中获取音频输入流audioInputStream = AudioSystem.getAudioInputStream(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的数据byteCount = audioInputStream.read(auBuffer, 0,auBuffer.length);if (byteCount >= 0) { // 如果读出有效数据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();}public void stop(){// 强制关闭线程thread.stop();}
}
package service;import java.io.*;
import java.util.Arrays;// 分数记录器类
public class ScoreRecorder {private static final String SCOREFILE = "data/soure"; // 得分记录文件private static int scores[] = new int[3]; // 当前得分最高前三名// 分数初始化public static void init() {File f = new File(SCOREFILE); // 创建记录文件if (!f.exists()) { // 如果文件不存在try {f.createNewFile(); // 创建新文件} catch (IOException e) {e.printStackTrace();}return; // 停止方法}FileInputStream fis = null;InputStreamReader isr = null;BufferedReader br = null;try {fis = new FileInputStream(f); // 文件字节输入流isr = new InputStreamReader(fis); // 字节流转字符流br = new BufferedReader(isr); // 缓冲字符流String value = br.readLine(); // 读取一行if (!(value == null || "".equals(value))) { // 如果不为空值String vs[] = value.split(","); // 分割字符串if (vs.length < 3) { // 如果分割结果小于3Arrays.fill(scores, 0); // 数组填充0} else {for (int i = 0; i < 3; i++) {// 将记录文件中的值赋给当前分数数组scores[i] = Integer.parseInt(vs[i]);}}}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally { // 依次关闭流try {br.close();} catch (IOException e) {e.printStackTrace();}try {isr.close();} catch (IOException e) {e.printStackTrace();}try {fis.close();} catch (IOException e) {e.printStackTrace();}}}// 保存分数public static void saveScore() {// 拼接得分数组String value = scores[0] + "," + scores[1] + "," + scores[2];FileOutputStream fos = null;OutputStreamWriter osw = null;BufferedWriter bw = null;try {fos = new FileOutputStream(SCOREFILE); // 文件字节输出流osw = new OutputStreamWriter(fos); // 字节流转字符流bw = new BufferedWriter(osw); // 缓冲字符流bw.write(value); // 写入拼接后的字符串bw.flush(); // 字符流刷新} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally { // 依次关闭流try {bw.close();} catch (IOException e) {e.printStackTrace();}try {osw.close();} catch (IOException e) {e.printStackTrace();}try {fos.close();} catch (IOException e) {e.printStackTrace();}}}// 添加分数。如果新添加的分数比排行榜分数高,则会将新分数记入排行榜。static public void addNewScore(int score) {// 在得分组数基础上创建一个长度为4的临时数组int tmp[] = Arrays.copyOf(scores, 4);tmp[3] = score; // 将新分数赋值给第四个元素Arrays.sort(tmp); // 临时数组降序排列scores = Arrays.copyOfRange(tmp, 1, 4); // 将后三个元素赋值给得分数组}// 获取分数static public int[] getScores() {return scores;}
}
package service;import java.io.FileNotFoundException;// 音效类
public class Sound {// 音乐文件夹public static final String DIR = "music\\";// 背景音乐public static final String BACKGROUND = "background.wav";// 跳跃音效public static final String JUMP = "jump.wav";// 撞击音效public static final String HIT = "hit.wav";// flag是否播放mp3格式音频public static void play(String file,boolean circulate){MusicPlayer player = null;try {// 创建播放器player = new MusicPlayer(file, circulate);// 播放器开始播放player.play();} catch (FileNotFoundException e) {e.printStackTrace();}}public static void jump(){// 播放跳跃音效(不循环播放)play(DIR + JUMP,false);}public static void hit(){// 播放第撞击音效(不循环播放)play(DIR + HIT, false);}public static void background(){// 播放背景音效(循环播放)play(DIR + BACKGROUND,true);}
}

view包

package view;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;// 滚动背景
public class BackGroundImage {public BufferedImage image; // 背景图片private BufferedImage image1, image2; // 滚动的两个图片private Graphics2D g; // 背景图片的绘图对象public int x1, x2; // 两个滚动图片的坐标public static final int SPEED = 4; // 滚动速度public BackGroundImage() {try {image1 = ImageIO.read(new File("image/背景.png"));image2 = ImageIO.read(new File("image/背景.png"));} catch (IOException e) {e.printStackTrace();}// 主图片采用宽800高300的彩色图片image = new BufferedImage(800, 300, BufferedImage.TYPE_INT_RGB);g = image.createGraphics(); // 获取主图片绘图对象x1 = 0; // 第一幅图片初始坐标为0x2 = 800; // 第二幅图片初始横坐标为800g.drawImage(image1, x1, 0, null);}// 滚动public void roll() {x1 -= SPEED; // 第一幅图片左移x2 -= SPEED; // 第二幅图片左移if (x1 <= -800) { // 如果第一幅图片移出屏幕x1 = 800; // 回到屏幕右侧}if (x2 <= -800) { // 如果第二幅图片移出屏幕x2 = 800; // 回到屏幕右侧}g.drawImage(image1, x1, 0, null); // 在主图片中绘制两幅图片g.drawImage(image2, x2, 0, null);}
}
package view;import modle.Dinosaur;
import modle.Obstacle;import service.FreshThread;
import service.ScoreRecorder;
import service.Sound;import java.awt.event.KeyListener;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;import javax.swing.JPanel;// 游戏主面板
public class GamePanel extends JPanel implements KeyListener {private BufferedImage image; // 主图片private BackGroundImage background; // 背景图片private Dinosaur golden; // 恐龙private Graphics2D g2; // 主图片绘图对象private int addObstacleTimer = 0; // 添加障碍计时器private boolean finish = false; // 游戏结束标志private ArrayList<Obstacle> list = new ArrayList<Obstacle>(); // 障碍集合private final int FREASH = FreshThread.FREASH; // 刷新时间int score = 0; // 得分int scoreTimer = 0; // 分数计时器public GamePanel() {// 主图片采用宽800高300的彩色图片image = new BufferedImage(800, 300, BufferedImage.TYPE_INT_BGR);g2 = image.createGraphics(); // 获取主图片绘图对象background = new BackGroundImage(); // 初始化滚动背景golden = new Dinosaur(); // 初始化小恐龙list.add(new Obstacle()); // 添加第一个障碍FreshThread t = new FreshThread(this); // 刷新帧线程t.start(); // 启动线程}// 绘制主图片private void paintImage() {background.roll(); // 背景图片开始滚动golden.move(); // 恐龙开始移动g2.drawImage(background.image, 0, 0, this); // 绘制滚动背景if (addObstacleTimer == 1300) { // 每过1300毫秒if (Math.random() * 100 > 40) { // 60%概率出现障碍list.add(new Obstacle());}addObstacleTimer = 0; // 重新计时}for (int i = 0; i < list.size(); i++) { // 遍历障碍集合Obstacle o = list.get(i); // 获取障碍对象if (o.isLive()) { // 如果是有效障碍o.move(); // 障碍移动g2.drawImage(o.image, o.x, o.y, this); // 绘制障碍// 如果恐龙头脚碰到障碍if (o.getBounds().intersects(golden.getFootBounds())|| o.getBounds().intersects(golden.getHeadBounds())) {Sound.hit(); // 播放撞击声音gameOver(); // 游戏结束}} else { // 如果不是有效障碍list.remove(i); // 删除此障碍i--; // 循环变量前移}}g2.drawImage(golden.image, golden.x, golden.y, this); // 绘制恐龙if (scoreTimer >= 500) { // 每过500毫秒score += 10; // 加十分scoreTimer = 0; // 重新计时}g2.setColor(Color.BLACK); // 使用黑色g2.setFont(new Font("黑体", Font.BOLD, 24)); // 设置字体g2.drawString(String.format("%06d", score), 700, 30); // 绘制分数addObstacleTimer += FREASH; // 障碍计时器递增scoreTimer += FREASH; // 分数计时器递增}// 重写绘制组件方法public void paint(Graphics g) {paintImage(); // 绘制主图片内容g.drawImage(image, 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) { // 如果是空格golden.jump(); // 恐龙跳跃}}@Overridepublic void keyReleased(KeyEvent e) {}@Overridepublic void keyTyped(KeyEvent e) {}
}
package view;import service.ScoreRecorder;
import service.Sound;import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;// 主窗体
public class MainFrame extends JFrame {public MainFrame() {restart(); // 开始setBounds(340, 150, 821, 260); // 设置横纵坐标和宽高setTitle("奔跑吧!小恐龙!"); // 标题Sound.background(); // 播放背景音乐ScoreRecorder.init(); // 读取得分记录addListener(); // 添加监听setDefaultCloseOperation(EXIT_ON_CLOSE); // 关闭窗体则停止程序}// 重新开始public void restart() {Container c = getContentPane(); // 获取主容器对象c.removeAll(); // 删除容器中所有组件GamePanel panel = new GamePanel(); // 创建新的游戏面板c.add(panel);addKeyListener(panel); // 添加键盘事件c.validate(); // 容器重新验证所有组件}// 添加监听private void addListener() {addWindowListener(new WindowAdapter() { // 添加窗体监听public void windowClosing(WindowEvent e) { // 窗体关闭前ScoreRecorder.saveScore(); // 保存比分}});}
}
package view;import service.ScoreRecorder;import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;// 成绩对话窗
public class ScoreDialog extends JDialog {public ScoreDialog(JFrame frame) {super(frame, true); // 调用父类构造方法,阻塞父窗体int scores[] = ScoreRecorder.getScores(); // 获取当前前三名成绩JPanel scoreP = new JPanel(new GridLayout(4, 1)); // 成绩面板,4行1列scoreP.setBackground(Color.WHITE); // 白色背景JLabel title = new JLabel("得分排行榜", JLabel.CENTER); // 标题标签,居中title.setFont(new Font("黑体", Font.BOLD, 20)); // 设置字体title.setForeground(Color.RED); // 红色体字JLabel first = new JLabel("第一名:" + scores[2], JLabel.CENTER); // 第一名标签JLabel second = new JLabel("第二名:" + scores[1], JLabel.CENTER); // 第二名标签JLabel third = new JLabel("第三名:" + scores[0], JLabel.CENTER); // 第三名标签JButton restart = new JButton("重新开始"); // 重新开始按钮restart.addActionListener(new ActionListener() { // 按钮添加事件监听@Overridepublic void actionPerformed(ActionEvent e) { // 当点击时dispose(); // 销毁对话框}});scoreP.add(title); // 成绩面板添加标签scoreP.add(first);scoreP.add(second);scoreP.add(third);Container c = getContentPane(); // 获取主容器c.setLayout(new BorderLayout()); // 使用边界布局c.add(scoreP, BorderLayout.CENTER); // 成绩面板放中间c.add(restart, BorderLayout.SOUTH); // 按钮放底部setTitle("游戏结束"); // 对话框标题int width, height; // 对话框宽高width = height = 200; // 对话框宽高均为200// 获得主窗体中居中位置的横坐标int x = frame.getX() + (frame.getWidth() - width) / 2;// 获得主窗体中居中位置的纵坐标int y = frame.getY() + (frame.getHeight() - height) / 2;setBounds(x, y, width, height); // 设置坐标和宽高setVisible(true); // 显示对话框}}

源码、图片和音效下载-下载地址

java实现-现奔跑吧小恐龙-小游戏相关推荐

  1. python小游戏毕设 仿谷歌浏览器小恐龙小游戏设计与实现 (源码)

    文章目录 0 项目简介 1 游戏介绍 2 实现效果 3 Pygame介绍 4 原理和实现 4.1 环境配置 4.2 游戏初始化 4.3 创建游戏类 4.4 云.路面以及仙人掌类 4.5 计分板 4.6 ...

  2. python小游戏 仿谷歌浏览器小恐龙小游戏设计与实现

    文章目录 0 项目简介 1 游戏介绍 2 实现效果 3 Pygame介绍 4 原理和实现 4.1 环境配置 4.2 游戏初始化 4.3 创建游戏类 4.4 云.路面以及仙人掌类 4.5 计分板 4.6 ...

  3. 用Python写个超级小恐龙跑酷游戏,上班摸鱼我能玩一天

    目录 啥也不多说,先来一个效果图展示 工具使用 游戏思路解析 项目整体的框架搭建 创建小恐龙对象 创建障碍物对象 创建地板对象 游戏的基本配置信息 啥也不多说,先来一个效果图展示 工具使用 开发环境: ...

  4. 2022-用Python写个超级小恐龙跑酷游戏,上班摸鱼我能玩一天10-22

    啥也不多说,先来一个效果图展示 **工具使用 ** ** 开发环境:win10.python3.7** ** 开发工具:pycharm 工具包:pygame** 游戏思路解析 准备相对应的游戏图片 准 ...

  5. C++ 谷歌小恐龙#1 游戏制作实录

    版本号:1.0 嗨,我是一块铌金属,新年快乐呀! 之前不是说啃了EGE库嘛,所以我打算做一个项目练练手. 做什么呢--?谷歌小恐龙! 谷歌小恐龙就是一款谷歌浏览器内置的小游戏--多的我就不说了,在谷歌 ...

  6. 生活记录:挑战制作谷歌小恐龙的游戏

    挑战制作小恐龙游戏 开始工作 目标 动机 设定的开始时间 后面大体要做的工作 结语 开始工作 今天突发奇想,挑战试着制作谷歌浏览器断网后的那只小恐龙游戏.专门整一个专栏,记录下每一天的的制作进度,看多 ...

  7. Phaser(二):小恐龙跑酷游戏

    效果展示 资源 图片资源 地图资源 src/GameScenes/Scene02/Tilemaps/map.json { "compressionlevel":-1,"h ...

  8. Python谷歌小恐龙--Pygame

    文章目录 Python谷歌小恐龙(持续更新,未完结) 前言 正文 创建窗口 添加静态背景图 添加静态小恐龙 让小恐龙动起来 程序小优化(增加小知识) 背景动起来 小恐龙跳跃(代码大改,做好心理准备) ...

  9. Java实战项目二(超详细)---奔跑吧小恐龙

    奔跑吧小恐龙是一款简单的跑酷游戏(代码简单,适合初学者学习).玩家控制小恐龙向前狂奔,躲避沿途出现的石头和仙人掌,跑的越远,分数越高.游戏内还增加了背景音乐.跳跃音乐和碰撞音乐. 本文的代码虽然长,但 ...

最新文章

  1. 自然语言处理中文本的token和tokenization
  2. 如何在ARM开发板上从源码编译安装OpenCV和OpenCV contrib
  3. 0.0 目录-深度学习第二课《改善神经网络》-Stanford吴恩达教授
  4. 最受欢迎的男友职业排行榜 Top10 ,程序员排第 3
  5. getElementByClassName()不兼容的解决办法
  6. 在.NET Core下的机器学习--学习笔记
  7. 【LeetCode笔记】剑指 Offer 57- II. 和为 s 的连续正数序列(Java、滑动窗口、二刷)
  8. git保存账号密码_Altium Designer 通过Git实现版本控制
  9. java提高代码效率_提高java代码运行效率
  10. javascript中特殊数值常量
  11. html文件变成巨大,在巨大的html文件中选择两个patern之间的文本?
  12. 百位云计算专家齐聚湖畔大学,阿里云MVP全球闭门会聚焦数字化转型
  13. 2020 年前端技术发展盘点
  14. 腾讯地图基于 WebGL实现自定义栅格图层踩坑实录
  15. 微软邮箱(@outlook.com/@hotmail.com):双重验证+应用密码
  16. 「视频」重磅 | Magic Leap再发Demo,凯文·凯利万字长文揭秘
  17. 自媒体创作没思路?这4款内容创作爆文神器助你摆脱内容瓶颈!
  18. Photoshop文字之——制作晶莹剔透胶体特效
  19. C++ 域名转IP地址
  20. 2019年下半年系统架构设计师上午真题及答案解析

热门文章

  1. IDEA 2018.3.3 有效期至 2100
  2. 实现一个简单的抽奖系统
  3. 联筑赚赋能传统模架产业链数字化 促进产业发展互利共赢
  4. nodejs和php性能,Nodejs 和PHP 性能测试结果
  5. STM32F4 RTC详解
  6. 新兴实践_新兴文件系统简介
  7. 二分查找时间复杂度及其Python实现
  8. SpringBoot项目没有@RunWith注解
  9. visual assistant x 破解版使用方法及下载地址
  10. 《系统集成项目管理》第三章 信息系统集成专业技术知识