Java实战项目二(超详细) 您所在的位置:网站首页 恐龙跑酷免费下载 Java实战项目二(超详细)

Java实战项目二(超详细)

2024-06-12 03:58| 来源: 网络整理| 查看: 265

界面图 奔跑吧小恐龙是一款简单的跑酷游戏(代码简单,适合初学者学习)。玩家控制小恐龙向前狂奔,躲避沿途出现的石头和仙人掌,跑的越远,分数越高。游戏内还增加了背景音乐、跳跃音乐和碰撞音乐。 本文的代码虽然长,但不难理解,希望大家能够耐心看完。 文中代码均可直接运行,完整代码请见github (如果觉得有帮助,记得给个star,谢谢!)

文章目录 系统结构设计游戏功能架构图项目目录结构预览 游戏模型设计恐龙类障碍类 音效模块设计音频播放器

系统结构设计 游戏功能架构图 项目目录结构预览 游戏模型设计 恐龙类

1.定义 Dinosaur类的成员属性绝大多数都是私有属性,只有少数公有属性用于游戏面板绘图使用。Dinosaur类的私有属性包含3张来回切换的跑步照片: 在这里插入图片描述 Dinosaur类的定义如下:

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;// 刷新时间--刷新帧线程 }

在Dinosaur类的构造方法中将恐龙的横坐标固定在50像素的位置,纵坐标采用落地时的坐标,具体代码如下:

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(); } }

2.踏步 游戏中恐龙的横坐标虽然一直没变,但背景的运动会造成恐龙向前移动的假象。Step()方法就是踏步动作的方法,具体代码如下:

/** * 踏步 */ private void step() { // 每过250毫秒,更换一张图片。因为共有3图片,所以除以3取余,轮流展示这三张 int tmp = stepTimer / 250 % 3; // 0、1、2 switch (tmp) { case 1 : image = image1; break; case 2 : image = image2; break; default : image = image3; } stepTimer += FREASH;// 计时器递增 }

3.跳跃 跳跃是小恐龙躲避障碍的动作,也是玩家可以控制恐龙做出的唯一动作。 具体代码如下:

/** * 跳跃 */ public void jump() { if (!jumpState) {// 如果没处于跳跃状态 Sound.jump();// 播放跳跃音效 } jumpState = true;// 处于跳跃状态 }

4.移动 move()是恐龙移动方法,move()方法不断地调用step()踏步方法 stepTimer踏步计时器会有效控制图片地切换频率 move()方法地具体代码如下:

/** * 移动 */ public void move() { step();// 不断踏步 if (jumpState) {// 如果正在跳跃 if (y == LOWEST_Y) {// 如果纵坐标大于等于最低点---(越往上坐标越小) jumpValue = -4;// 增变量为负值--向上跳 } if (y // 如果再次落地 jumpState = false;// 停止跳跃 } } }

5.边界对象 java.awt.Rectangle类是举行边界类。为恐龙的头部和足部创建矩形边界对象,用于做碰撞测试 getFootBounds()方法用于获取恐龙的足部边界对象,具体代码如下:

/** * 足部边界区域 * * @return */ public Rectangle getFootBounds() { // 获取恐龙的脚部边界对象 return new Rectangle(x + 30, y + 59, 29, 18); // 用于后续做碰撞检测 }

getHeadBounds()方法用于获取恐龙的头部边界对象,具体代码如下:

/** * 头部边界区域 * * @return */ public Rectangle getHeadBounds() { // 获取恐龙的头部边界对象 return new Rectangle(x + 66, y + 25, 32, 22); // new Rectangle(x, y, width, height) } 障碍类

游戏中的障碍有两种,一种是很矮的石头,另一种是很高的仙人掌,如下图所示。恐龙碰到任何一种障碍,都会导致游戏的结束: 在这里插入图片描述 1.定义 项目中的com.mr.modle.Obstacle类是障碍类, 因为所有的障碍都会随着背景一起移动,所以障碍的移动速度采用背景图片的速度。Obstacle类的定义如下:

public class Obstacle { public int x, y;// 横纵坐标 public BufferedImage image; private BufferedImage stone;// 石头图片---(32,26) private BufferedImage cacti;// 仙人掌图片---(32,59) private int speed;// 移动速度--图片跟着背景走 }

在Obstacle类的构造方法中,Obstacle对象会随机成为石头或者仙人掌。具体代码如下:

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中取一值,若为0 image = cacti;// 采用仙人掌图片 } else { image = stone;// 采用石头图片 } x = 800;// 初始横坐标 y = 200 - image.getHeight();// 纵坐标--使图片处在地平线上 // System.out.println(image.getWidth()); speed = BackgroundImage.SPEED;// 移动速度与背景同步--BackgroundImage=背景 }

2.移动 Obstacle类中的move()方法可以让障碍在游戏画面中移动,且移动速度与背景图片的移动速度相同。move()方法的具体代码如下:

/** * 移动 */ public void move() { x -= speed;// 横坐标递减--障碍物的速度与背景的速度一致 }

3.消除 当障碍移动出游戏画面之后,就不会再对游戏产生任何影响。 要及时将移出画面之外的障碍删除掉,isLive()方法用于获取障碍的有效状态。isLive()的具体代码如下:

/** * 是否存活 * * @return */ public boolean isLive() { // 如果移出了游戏界面 if (x if (image == cacti) {// 如果使用仙人掌图片 // 返回仙人掌的边界 return new Rectangle(x + 7, y, 15, image.getHeight()); } // 返回石头的边界 return new Rectangle(x + 5, y + 4, 23, 21); } 音效模块设计

本节介绍如何利用java代码播放音乐文件。 JDK支持播放的音乐格式非常少,本章使用的所有音乐文件均为WAVE格式。JDK支持的具体音乐格式可以参考javax.sound.sampled.AudioFileFormat.Type类

音频播放器

项目中的com.mr.service.MusicPlayer类是音频播放器类,该类使用javax.sound.sampled包提供的混音器工具实现音频播放功能。 MusicPlayer类实现了Runnerable接口,并在成员属性中定义了一个线程对象,该线程对象用于启动混音器数据行的读写业务。MusicPlayer类的定义如下:

```java /** * 音乐播放器 */ public class MusicPlayer implements Runnable { File soundFile; // 音乐文件 Thread thread;// 父线程 -- 执行run方法 boolean circulate;// 是否循环播放

MusicPlayer类的构造方法有两个参数,filepath表示音乐文件的完整文件名,circulate表示是否重复播放。MusicPlayer类构造方法的具体代码如下:

/** * 构造方法 * * @param filepath 音乐文件完整名称 * @param circulate 是否循环播放 * @throws FileNotFoundException */ // 构造方法--2 public MusicPlayer(String filepath, boolean circulate) throws FileNotFoundException { this.circulate = circulate; soundFile = new File(filepath); // File soundFile if (!soundFile.exists()) {// 如果文件不存在 throw new FileNotFoundException(filepath + "未找到"); // 抛出错误,文件未找到 } }

MusicPlayer类要实现Runnable接口,必须先实现run()方法。 在run()方法中声明了一个128K的缓冲区字节数组,程序以不断循环的方式将音乐文件以音频输入流格式读入缓冲区,再把缓冲区的数据写入混音器源数据行中,实现播放音乐的效果。run()方法的具体代码如下:

```java /** * 音乐播放器 */ public class MusicPlayer implements Runnable { File soundFile; // 音乐文件 Thread thread;// 父线程 -- 执行run方法 boolean circulate;// 是否循环播放

MusicPlayer类的构造方法有两个参数,filepath表示音乐文件的完整文件名,circulate表示是否重复播放。MusicPlayer类构造方法的具体代码如下:

/** * 构造方法 * * @param filepath 音乐文件完整名称 * @param circulate 是否循环播放 * @throws FileNotFoundException */ // 构造方法--2 public MusicPlayer(String filepath, boolean circulate) throws FileNotFoundException { this.circulate = circulate; soundFile = new File(filepath); // File soundFile if (!soundFile.exists()) {// 如果文件不存在 throw new FileNotFoundException(filepath + "未找到"); // 抛出错误,文件未找到 } }

MusicPlayer类要实现Runnable接口,必须先实现run()方法。 在run()方法中声明了一个128K的缓冲区字节数组,程序以不断循环的方式将音乐文件以音频输入流格式读入缓冲区,再把缓冲区的数据写入混音器源数据行中,实现播放音乐的效果。run()方法的具体代码如下:

/* * 在run()方法中声明一个128K的缓冲区字节数组 * 程序以不断循环的方式将音乐文件以音频输入流格式读入缓冲区 * 把缓冲区的数据写入混音器源数据行中 * */ 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(); // 获取音频格式 // System.out.println(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);// 根据循环标志判断是否循环播放 }

现在只要将MusicPlayer类放入线程中,就可以播放音乐。创建play()方法,传入参数,然后开启线程。play()方法的具体代码如下:

/** * 播放 */ public void play() { thread = new Thread(this);// 创建线程对象 thread.start();// 开启线程 }

创建stop()方法,在该方法中强制停止线程。 stop()方法的具体代码如下:

/** * 停止播放 */ public void stop() { thread.stop();// 强制关闭线程 }


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有