900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > Java游戏项目——仿4399小游戏《黄金矿工》

Java游戏项目——仿4399小游戏《黄金矿工》

时间:2020-04-16 15:23:12

相关推荐

Java游戏项目——仿4399小游戏《黄金矿工》

简介

作者简介:青铜码农,和大多数同学一样从零开始一步步学习,一步步积累。期待您的关注,让我们一起成长~注:本人学疏才浅,文章如有错误之处,敬请指正~

内容简介:实现4399《黄金矿工》小游戏

目录

功能预览:

游戏中一些对象的介绍 :

实现步骤:

1.创建Game类继承JFrame

2.创建图片Background类,以便绘制地图

3.绘制绳索

4.绳索的延长与收回

5.双缓存技术

6.创建金块

7.抓取判定

8.抓取返回

9.多个金块

10.创建石头

11.设置不同的回收速度

12.解决物体位置重叠

13.设置多种金块

14.绳索的钩爪

16.添加快速抓取功能

17.设置关卡

18.设置游戏状态

19.倒计时效果:

20.失败状态:

21.成功状态:

22.重置游戏

23.游戏商店:

功能预览:

《黄金矿工》

游戏中一些对象的介绍 :

实现步骤:

1.创建Game类继承JFrame

在类中创建一个Game方法,以便初始化窗口

void Game() {setVisible(true);setSize(800, 824);// 窗口大小setLocationRelativeTo(null);// 窗口将放置在屏幕中央setTitle("CodeDragons黄金矿工");// 设置标题setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 关闭程序}

2.创建图片Background类,以便绘制地图

import java.awt.*;/*** @author WayLon* @create -07-15 19:19* 备注:*/public class Background {// 背景图片初始化Image bg= Toolkit.getDefaultToolkit().getImage("src/images/土壤.jpg");Image people=Toolkit.getDefaultToolkit().getImage("src/images/人物.png");public void BackgroundPaint(Graphics g){g.drawImage(bg, 0, 0, null);g.drawImage(people, 380, 190, null);}}

再返回Game类中创建一个paint()方法

Background bg = new Background();/*** 绘制游戏地图** @param g*/public void paint(Graphics g) {bg.BackgroundPaint(g);}

在Game类中创建一个main()方法以便启动程序

/*** 启动程序*/public static void main(String[] args) {Game frame = new Game();frame.Game();}

运行效果如图:

3.绘制绳索

说明:绳索会左右摇摆且可以收回来。

创建一个绳索Rope类,并初始化绳索的起点坐标和终点坐标以及绳索的长度,绳索摆动的角度

绳索的终点坐标算法如图:

import java.awt.*;/*** @author WayLon* @create -07-15 19:14* 备注:*/public class Rope {// 绳索的起点坐标int x = 505;int y = 253;// 绳索的终点坐标int endx = 400;int endy = 700;// 初始化绳索的长度double length = 200;// 初始化绳索的角度double angle = 0;public void Ropepaint(Graphics g) {angle=angle+0.005;// 每次调用这个方法就将绳索的角度加0.005,以便实现绳索的不停转动endx = (int) (x + length * Math.cos(angle*Math.PI));endy = (int) (y + length * Math.sin(angle*Math.PI));Graphics2D g2d=(Graphics2D) g;g2d.setStroke(new BasicStroke(2));// 设置绳索粗细g2d.drawLine(x, y, endx, endy);// 画绳索}}

运行效果如图:

如果想让绳索不停的转动,只需要在Game类中的Game()方法添加以下代码:

void Game() {// 此处为不做改变的代码while (true) {repaint();try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}

效果如图:

先别着急,此时的绳索是360°旋转, 而绳索只能在X轴下方来回摆动,所以可以设置绳索的角度取值范围的为0-π。(且此时的整个画面是不停的闪动的,需要用到双缓存技术去解决,后面再讲这个问题),这里我们只讨论绳索需要在X轴下方来回摆动,则需要在Rope类添加以下代码:

public class Rope {// 绳索的起点坐标// 绳索的终点坐标// 初始化绳索的长度// 初始化绳索的角度// 以下为新增代码// 初始化方向.1表示顺时针0~180度,-1表示逆时针0~180度int dir = 1;public void Ropepaint(Graphics g) {if (angle <= 0) {dir = 1;} else if (angle >= 1) {dir = -1;}// 此处省略原有代码}}

效果如图:

眼尖的同学在这里会发现,绳索还是超越了地平线。这个问题很好解决,只需要将新增代码修饰为以下代码:

public class Rope {// 绳索的起点坐标// 绳索的终点坐标// 初始化绳索的长度// 初始化绳索的角度// 以下为新增代码// 初始化方向.1表示顺时针0~180度,-1表示逆时针0~180度int dir = 1;public void Ropepaint(Graphics g) {if (angle <= 0.1) {dir = 1;} else if (angle >= 0.9) {dir = -1;}// 此处省略原有代码}}

再来看一下效果:

嗯,这就完美许多了。

4.绳索的延长与收回

实现思路:

首先给绳索定义一个状态state,0表示摇摆,1表示抓取,2表示收回。

初始化状态state为0,=,当玩家按下键盘向下键时, 令state=1,当state=1时,延长绳索,且当绳索的长度小于500时,延长绳索的长度,直到绳索的长度等于500,此时再令state=2,收回绳索,当state=2且绳索的长度大于130时,收回绳索直到绳索长度等于130,也就是原始的绳索长度。当收回绳索的长度等于原始的长度时,令state=0恢复原来摆动的状态,以此循环类推。

为了代码整洁,下面我们将Ropepaint()方法里的这几行代码单独用一个方法封装起来。

void Rope(Graphics g) {endx = (int) (x + length * Math.cos(angle * Math.PI));endy = (int) (y + length * Math.sin(angle * Math.PI));Graphics2D g2d = (Graphics2D) g;g2d.setStroke(new BasicStroke(2));// 设置绳索粗细g2d.drawLine(x, y, endx, endy);// 画绳索}

在Game类中的Game()方法添加键盘事件,如下:

addKeyListener(new KeyAdapter() {@Overridepublic void keyPressed(KeyEvent e) {if (e.getKeyCode() == KeyEvent.VK_DOWN) {rope.state = 1;}}});

绳索的延长已收回完整代码如下:

public class Rope {// 绳索的起点坐标// 绳索的终点坐标// 初始化绳索的长度// 初始化绳索的角度// 初始化方向.1表示顺时针0~180度,-1表示逆时针0~180度// 初始化绳索的状态,0表示摇摆,1表示抓取,2表示收回int state = 0;void Rope(Graphics g) {endx = (int) (x + length * Math.cos(angle * Math.PI));endy = (int) (y + length * Math.sin(angle * Math.PI));Graphics2D g2d = (Graphics2D) g;g2d.setStroke(new BasicStroke(2));// 设置绳索粗细g2d.drawLine(x, y, endx, endy);// 画绳索}public void Ropepaint(Graphics g) {switch (state) {case 0:// 当state=0时,摆动绳索if (angle <= 0.1) {dir = 1;} else if (angle >= 0.9) {dir = -1;}angle += 0.005 * dir;Rope(g);break;case 1:// 当state=1时,延长绳索抓取if (length < 650) {// 当绳索的长度小于650时,延长绳索的长度直到绳索的长度等于650length += 10;Rope(g);} else {state = 2;// 绳索长度等于650时,令state=2}break;case 2:// 当state=2时,收回绳索if (length > 130) {// 当state=2且绳索的长度大于130时,收回绳索直到绳索长度等于130,也就是原始的绳索长度length -= 10;Rope(g);} else {state = 0;// 当收回绳索的长度等于原始的长度时,令state=0恢复原来摆动的状态}break;}}}

效果图如下:

代码敲到这里,相信很多同学已经被这个闪动的画面闪得不想再继续码下去了,那好,现在我们就来解决这个烦人的问题。

5.双缓存技术

原理讲解:双缓冲技术在很多动画中被采用。主要原理是创建一幅BufferedImage图像,将每一帧画入图像,然后调用drawImage方法,将整个BufferedImage图像一次画到屏幕上去。

代码实现:

首先在Game类中创建一个画布offFlickerImage;再将Game类中的paint方法改写成以下代码:

public void paint(Graphics g) {offFlickerImage=this.createImage(800,824);Graphics gImage=offFlickerImage.getGraphics();bg.BackgroundPaint(gImage);rope.Ropepaint(gImage);g.drawImage(offFlickerImage,0,0,null);}

运行一下,是不是更加完美了呢?

6.创建金块

因为金块都有一些相同的属性,例如宽高度。所以我们可以创建一个Object类作为Gold类的父类。

Object类:

import java.awt.*;/*** @author WayLon* @create -07-15 22:01* 备注:*/public class Object {// 物体的坐标int x;int y;// 物体的宽高int width;int height;// 图片Image image;// 标记是否能移动boolean flag;public void goldPaint(Graphics g) {g.drawImage(image, x, y, null);}public int getWidth() {return width;}}

Gold类:

import java.awt.*;/*** @author WayLon* @create -07-15 22:19* 备注:*/public class Gold extends Object {public Gold() {this.x = (int) (Math.random() * 750);this.y = (int) (Math.random() * 300 + 400);this.width = 55;this.height = 55;this.flag = false;this.image = Toolkit.getDefaultToolkit().getImage("src/images/金元宝.png");}}

在Game类中new一个Gold类对象,再往paint()方法中调用Gold类的drawImage()方法。

public class Game extends JFrame {Gold gold = new Gold();public Game() {// 此处省略不做改变的代码}/*** 启动程序*/public static void main(String[] args) {// 此处省略不做改变的代码}/*** 绘制游戏地图** @param g*/public void paint(Graphics g) {// 此处省略不做改变的代码gold.goldPaint(gImage);g.drawImage(offFlickerImage, 0, 0, null);}}

运行效果如图:

7.抓取判定

此模块运用的是Java游戏中的碰撞检测,查看相关知识点可点击→矩形碰撞检测 & 圆形和像素碰撞检测。

修改Rope类中的代码:

public class Rope {// 绳索的起点坐标// 绳索的终点坐标// 初始化绳索的长度// 初始化绳索的角度// 初始化方向.1表示顺时针0~180度,-1表示逆时针0~180度// 初始化绳索的状态,0表示摇摆,1表示抓取,2表示收回Game frame;Rope(Game frame) {this.frame = frame;}void judge() {if (endx > this.frame.gold.x && endx < this.frame.gold.x + this.frame.gold.width &&endy > this.frame.gold.y && endy < this.frame.gold.y + this.frame.gold.height) {System.out.println("抓到啦!");}}void Rope(Graphics g) {// 此处省略不做修改的代码}public void Ropepaint(Graphics g) {judge();switch (state) {// 此处省略不做修改的代码}}

效果如图:

8.抓取返回

之前的state状态新增一个3,用来表示抓取返回。

public class Rope {// 绳索的起点坐标// 绳索的终点坐标// 初始化绳索的长度// 初始化绳索的角度// 初始化方向.1表示顺时针0~180度,-1表示逆时针0~180度// 初始化绳索的状态,0表示摇摆,1表示抓取,2表示收回Game frame;Rope(Game frame) {this.frame = frame;}void judge() {if (endx > this.frame.gold.x && endx < this.frame.gold.x + this.frame.gold.width &&endy > this.frame.gold.y && endy < this.frame.gold.y + this.frame.gold.height) {state = 3;this.frame.gold.flag = true;}}void Rope(Graphics g) {// 此处省略不做修改的代码}public void Ropepaint(Graphics g) {judge();switch (state) {case 0:// 此处省略不做修改的代码break;case 1:// 此处省略不做修改的代码break;case 2:// 此处省略不做修改的代码break;case 3:if (length > 130) {length -= 10;Rope(g);this.frame.gold.x = endx - this.frame.gold.getWidth() / 2;this.frame.gold.y = endy;} else {// 直接移到屏幕外this.frame.gold.x = -100;this.frame.gold.y = -100;state = 0;}break;}}}

效果如图:

9.多个金块

利用list集合存储金块。在Game类中添加以下新代码,并删除两行代码(别漏删了,要不然后面会出现其中某一个金块钓不起来的糟糕情况):

public class Game extends JFrame {// 此处省略不做改变的代码Gold gold = new Gold();// 删除此行代码List<Object> goldList = new ArrayList<Object>();// 储存金块,有这个集合后,上面一行代码可删除{for (int i = 0; i < 5; i++) {goldList.add(new Gold());}}public Game() {// 此处省略不做改变的代码}/*** 启动程序*/public static void main(String[] args) {// 此处省略不做改变的代码}/*** 绘制游戏地图** @param g*/public void paint(Graphics g) {// 此处省略不做改变的代码for (Object o : goldList) {o.goldPaint(gImage);}gold.goldPaint(gImage);// 删除此行代码g.drawImage(offFlickerImage, 0, 0, null);// 此处行是不做改变的代码}}

修改Rope类中的judge()方法和Ropepaint()方法:

public class Rope {// 此处为不做修改的代码块void judge() {for (Object o : this.frame.goldList) {if (endx > o.x && endx < o.x + o.width &&endy > o.y && endy < o.y + o.height) {state = 3;o.flag=true;}}}void Rope(Graphics g) {// 此处为不做修改的代码块}public void Ropepaint(Graphics g) {judge();switch (state) {case 0:// 此处为不做修改的代码块case 1:// 此处为不做修改的代码块case 2:// 此处为不做修改的代码块case 3:if (length > 130) {// 当state=2且绳索的长度大于130时,收回绳索直到绳索长度等于130,也就是原始的绳索长度length -= 10;Rope(g);for (Object o : this.frame.goldList) {if (o.flag) {o.x = endx - o.getWidth() / 2;o.y = endy;if (length <= 130) {// 直接移到屏幕外o.x = -100;o.y = -100;o.flag = false;state = 0;// 当收回绳索的长度等于原始的长度时,令state=0恢复原来摆动的状态}}}}break;}}}

效果如图:

10.创建石头

首先创建一个石头类Stone继承Object类。

import java.awt.*;/*** @author WayLon* @create -07-16 9:56* 备注:*/public class Stone extends Object {public Stone() {this.x = (int) (Math.random() * 750);this.y = (int) (Math.random() * 300 + 400);this.width = 70;this.height = 70;this.flag = false;this.image = Toolkit.getDefaultToolkit().getImage("src/images/石头.png");}}

再修改Game类:

public class Game extends JFrame {// 此处省略不做修改的代码块{// 生成金块for (int i = 0; i < 5; i++) {// 此处省略不做修改的代码块}// 生成石头for (int i = 0; i < 2; i++) {goldList.add(new Stone());}}public Game() {// 此处省略不做修改的代码块}/*** 启动程序*/public static void main(String[] args) {// 此处省略不做修改的代码块}/*** 绘制游戏地图** @param g*/public void paint(Graphics g) {// 此处省略不做修改的代码块}}

效果如图:

11.设置不同的回收速度

给Object类添加一个变量m,用于表示物体的质量。

public class Object {// 物体的坐标// 物体的宽高// 图片// 标记是否能移动// 物体的质量int m;public void goldPaint(Graphics g) {// 此处省略不做改变的代码块}public int getWidth() {// 此处省略不做改变的代码块}}

再到Gold类和Stone类中给物体的质量赋值(石头的质量要明显大于金块的质量)。

public class Gold extends Object {public Gold() {// 此处省略不做修改的代码块this.m=35;}}

public class Stone extends Object {public Stone() {// 此处省略不做改变的代码块this.m=100;}}

再到Rope类中新增以下代码:

public class Rope {// 此处为不做修改的代码块Rope(Game frame) {// 此处为不做修改的代码块}void judge() {// 此处为不做修改的代码块}void Rope(Graphics g) {// 此处为不做修改的代码块}public void Ropepaint(Graphics g) {// 此处为不做修改的代码块switch (state) {case 0: // 此处为不做修改的代码块case 1: // 此处为不做修改的代码块case 2: // 此处为不做修改的代码块case 3:int m=0;if (length > 130) { // 此处为不做修改的代码块}try {Thread.sleep(m);} catch (InterruptedException e) {e.printStackTrace();}break;}}}

效果如图:

12.解决物体位置重叠

在Object类中添加获取矩形的方法:

// 获取矩形public Rectangle getR() {return new Rectangle(x, y, width, height)}

import java.awt.*;/*** @author WayLon* @create -07-15 22:01* 备注:*/public class Object {// 物体的坐标int x;int y;// 物体的宽高int width;int height;// 图片Image image;// 标记是否能移动boolean flag;// 物体的质量int m;public void goldPaint(Graphics g) {g.drawImage(image, x, y, null);}public int getWidth() {return width;}}

13.设置多种金块

在Gold类中添加以下代码:

public class Gold extends Object {public Gold() {// 此处为不做修改的代码块}}class GoldTwo extends Gold {public GoldTwo() {this.width = 55;this.height = 37;this.m = 110;this.image = Toolkit.getDefaultToolkit().getImage("src/images/金条.png");}}class GoldThree extends Gold {public GoldThree() {this.width = 55;this.height = 55;this.m = 65;this.image = Toolkit.getDefaultToolkit().getImage("src/images/戒指.png");}}

且不同的金块按照不同的概率出现。元宝占50%,戒指占35%,金条占15%。

在Game的第一个循环中替换为以下代码:

public class Game extends JFrame {// 此处为不做修改的代码块{for (int i = 0; i < 8; i++) {double probability = Math.random();if (probability < 0.15) {goldList.add(new GoldThree());} else if (probability < 0.35 && probability > 0.15) {goldList.add(new GoldTwo());} else if (probability > 0.35) {goldList.add(new Gold());}}for (int i = 0; i < 3; i++) {// 此处为不做修改的代码块}}public Game() {// 此处为不做修改的代码块}/*** 启动程序*/public static void main(String[] args) {// 此处为不做修改的代码块}/*** 绘制游戏地图** @param g*/public void paint(Graphics g) {// 此处为不做修改的代码块}}

运行效果:

14.绳索的钩爪

public class Rope {// 此处为不做修改的代码块// 钩爪的图片Image hook = Toolkit.getDefaultToolkit().getImage("src/images/钳子.png");Rope(Game frame) {// 此处为不做修改的代码块}void judge() {// 此处为不做修改的代码块}void Rope(Graphics g) {// 此处为不做修改的代码块g2d.drawImage(hook,endx-35,endy-3,null);}public void Ropepaint(Graphics g) {// 此处为不做修改的代码块}}

15.金钱设置

先在Object类中设定一个cost变量;

// 物体的金钱数int cost;

再到Stone类和Gold类进行初始化。

元宝价值为50;金条为550;戒指为250;石头为11;

再到Background类中,将总钱数写入:

public class Background {// 总钱数static int count = 0;// 背景图片初始化Image bg = Toolkit.getDefaultToolkit().getImage("src/images/土壤.jpg");Image people = Toolkit.getDefaultToolkit().getImage("src/images/人物.png");public static void drawText(Graphics g, int size, Color color, String s, int x, int y) {g.setColor(color);g.setFont(new Font("楷体", Font.BOLD, 24));g.drawString(s, x, y);}public void BackgroundPaint(Graphics g) {g.drawImage(bg, 0, 0, null);g.drawImage(people, 380, 190, null);drawText(g, 24, new Color(143, 112, 1), "金钱:$" + count, 30, 250);}}

再到Rope类中的case 3:添加一行代码实现加钱:

public class Rope {Rope(Game frame) {this.frame = frame;}void judge() {}void Rope(Graphics g) {}public void Ropepaint(Graphics g) {judge();switch (state) {case 0:case 1:case 2:case 3:// 此处为不做改变的代码if (length <= 130) {// 直接移到屏幕外o.x = -100;o.y = -100;o.flag = false;Background.count += o.cost;// 增加此行代码state = 0;}}}}// 此处为不做改变的代码}}}

效果如图:

16.添加快速抓取功能

在物体被抓取的时候,按下键盘的向上键也就是使用魔法水物品,物体将迅速被拉回。

首先需要在Background类中添加魔法水。

public class Background {// 总钱数// 此处为不做改变的代码// 爆竹的数量static int firecrackersNum = 3;// 爆竹的状态static boolean fcFlag = false;// 背景图片初始化// 此处为不做改变的代码Image firecrackers = Toolkit.getDefaultToolkit().getImage("src/images/魔法水.png");public static void drawText(Graphics g, int size, Color color, String s, int x, int y) {// 此处为不做改变的代码}public void BackgroundPaint(Graphics g) {// 此处为不做改变的代码g.drawImage(firecrackers, 580, 250, null);drawText(g, 24, new Color(143, 112, 1), "*" + firecrackersNum, 630, 290);}}

效果如图:

接下来在Game类中的Game()方法添加新的键盘事件:

public Game() {// 此处为不做改变的代码addKeyListener(new KeyAdapter() {@Overridepublic void keyPressed(KeyEvent e) {if (e.getKeyCode() == KeyEvent.VK_DOWN) {// 此处为不做改变的代码}if (e.getKeyCode() == KeyEvent.VK_UP && rope.state == 3 && Background.firecrackersNum > 0) {// 当按下向上键且绳索的状态为3时和有魔法水的情况下Background.firecrackersNum--;Background.fcFlag = true;}}});}

再修改Rope()类中Ropepaint()方法中的case 3:

public void Ropepaint(Graphics g) {judge();switch (state) {case 0:// 此处为不做改变的代码case 1:// 此处为不做改变的代码case 2:// 此处为不做改变的代码case 3:// 此处为不做改变的代码if (length <= 130) {// 直接移到屏幕外// 此处为不做改变的代码Background.count += o.cost;// 新增此行代码state = 0;Background.fcFlag = false;// 新增此行代码}if (Background.fcFlag) {// 新增此行代码m = 1;}}}}// 此处为不做改变的代码}}

效果图如下:

17.设置关卡

当达到目标钱数后,将进入下一关。

在Backgound类中添加以下两个变量:

public class Background {// 总钱数// 爆竹的数量// 爆竹的状态// 关卡数static int level = 1;// 目标钱数int goal = level * 100;// 背景图片初始化public static void drawText(Graphics g, int size, Color color, String s, int x, int y) {// 此处为不做改变的代码}public void BackgroundPaint(Graphics g) {// 此处为不做改变的代码}}

再到Game类中添加新代码:

public class Game extends JFrame {// 此处为不做改变的代码/*** 启动程序*/public static void main(String[] args) {// 此处为不做改变的代码}void Game() {// 此处为不做改变的代码while (true) {repaint();nextLevel();// 此行为新增代码// 此处为不做改变的代码}}/*** 下一关*/private void nextLevel() {// 此代码块为新增代码if (Background.count >= bg.goal) {Background.level++;dispose();Game game1 = new Game();game1.Game();}}/*** 绘制游戏地图** @param g*/public void paint(Graphics g) {// 此处为不做改变的代码}}

再到Background类中绘制相应的面板以便显示目前关数和目标钱数:

public class Background {// 总钱数// 爆竹的数量// 爆竹的状态// 关卡数static int level = 1;// 目标钱数int goal = level * 100;// 背景图片初始化public static void drawText(Graphics g, int size, Color color, String s, int x, int y) {// 此处为不做改变的代码}public void BackgroundPaint(Graphics g) {// 此处为不做改变的代码// 关卡数drawText(g, 20, new Color(143, 112, 1), "第" + level+"关", 370, 60);// 目标钱数drawText(g, 24, new Color(143, 112, 1), "目标钱数:$" + goal, 27, 280);}}

public void BackgroundPaint(Graphics g) {g.drawImage(bg, 0, 0, null);switch (Game.start) {case 0:drawText(g, 110, new Color(0,0,0), "按空格键以开始游戏", 200, 400);break;case 1:g.drawImage(people, 380, 190, null);drawText(g, 24, new Color(143, 112, 1), "金钱:$" + count, 30, 250);g.drawImage(firecrackers, 580, 250, null);drawText(g, 24, new Color(143, 112, 1), "*" + firecrackersNum, 630, 290);// 关卡数drawText(g, 20, new Color(143, 112, 1), "第" + level + "关", 370, 60);// 目标钱数drawText(g, 24, new Color(143, 112, 1), "目标钱数:$" + goal, 27, 280);break;case 2:break;case 3:break;case 4:break;default:}}

18.设置游戏状态

游戏的最基本的三种状态:游戏开始前、游戏中、游戏结束,游戏结束又分为以失败结束和以通关结束

接下来是根据游戏的状态进行绘制组件:

先在Game类中添加一个游戏状态的变量:

static int start;// 0未开始 1游戏中 2商店 3游戏失败 4游戏成功

并修改该类中的Game()方法:

void Game() {// 此处为不做改变的代码addKeyListener(new KeyAdapter() {@Overridepublic void keyPressed(KeyEvent e) {switch (start) {case 0:if (e.getKeyCode() == KeyEvent.VK_SPACE) {start = 1;}break;case 1:if (e.getKeyCode() == KeyEvent.VK_DOWN) {rope.state = 1;}if (e.getKeyCode() == KeyEvent.VK_UP && rope.state == 3 && Background.firecrackersNum > 0) {// 当按下向上键且绳索的状态为3时Background.firecrackersNum--;Background.fcFlag = true;}break;case 2:break;case 3:break;case 4:break;default:}}});while (true) {// 此处为不做改变的代码}}

背景是在任何时候都会绘制,代码不需要根据start的值进行变化。

魔法水,关卡数,目标钱数都是在游戏开始才绘制,所以将Background类中的BackgroundPaint()方法修改为以下代码:

public void BackgroundPaint(Graphics g) {g.drawImage(bg, 0, 0, null);switch (Game.start) {case 0:drawText(g, 30, new Color(252, 25, 68), "按空格键以开始游戏", 280, 120);break;case 1:g.drawImage(people, 380, 190, null);drawText(g, 24, new Color(143, 112, 1), "金钱:$" + count, 30, 250);g.drawImage(firecrackers, 580, 250, null);drawText(g, 24, new Color(143, 112, 1), "*" + firecrackersNum, 630, 290);// 关卡数drawText(g, 20, new Color(143, 112, 1), "第" + level + "关", 370, 60);// 目标钱数drawText(g, 24, new Color(143, 112, 1), "目标钱数:$" + goal, 27, 280);break;case 2:break;case 3:break;case 4:break;default:}}

19.倒计时效果:

在Background类中创建两个变量:

// 游戏开始时间long startTime = 40;// 游戏结束时间long endTime;

并在case 1:中添加以下代码:

// 倒计时endTime = System.currentTimeMillis();long t = 40 - (endTime - startTime) / 1000;drawText(g, 24, new Color(143, 112, 1), "时间:" + t, 30, 220);

返回Game类中Game()方法中的case 0 :初始化startTime:

void Game() {// 此处为不做改变的代码addKeyListener(new KeyAdapter() {@Overridepublic void keyPressed(KeyEvent e) {switch (start) {case 0:if (e.getKeyCode() == KeyEvent.VK_SPACE) {start = 1;bg.startTime = System.currentTimeMillis();// 游戏开始时顺便给起始时间赋值}break;case 1:// 此处为不做改变的代码break;case 2:break;case 3:break;case 4:break;default:}}});while (true) {// 此处为不做改变的代码}}

运行效果:

20.失败状态:

先在Background类中创建一个gameTime()方法,以便判断游戏开始后,游戏时间是否大于所设时间,如果是,则代表已经超时了,游戏结束,反之游戏还有剩余时间。

/*** 倒计时** @return true代表倒计时完成,false表示正在倒计时*/boolean gameTime() {long tim = (endTime - startTime) / 1000;if (tim > 40) {return true;}return false;}

在Game类中的nextLevel()方法中修改通关成功的条件:

private void nextLevel() {if (start == 1 && bg.gameTime()) {// 通过成功就进入下一关if (Background.count >= bg.goal) {Background.level++;dispose();Game game1 = new Game();game1.Game();} else {start = 3;// 不成功则进入失败状态}}}

返回 Background类中的BackgroundPaint()方法的case 3:添加以下代码:

case 3:drawText(g, 80, new Color(252, 25, 68), "游戏失败,再接再厉!", 280, 120);// 显示失败信息drawText(g, 50, new Color(12, 207, 103), "所得金钱:$" + count, 305, 150);// 显示所得钱数break;

运行效果:

21.成功状态:

修改Game类中的nextLevel()方法:

private void nextLevel() {if (start == 1 && bg.gameTime()) {// 通过成功就进入下一关if (Background.count >= bg.goal) {if (Background.level == 5) {start = 4;} else {Background.level++;}dispose();Game game1 = new Game();game1.Game();} else {start = 3;// 不成功则进入失败状态}}}

返回 Background类中的BackgroundPaint()方法的case 4:添加以下代码:

case 4:drawText(g, 80, new Color(120, 157, 210), "恭喜你,成功过关!", 280, 120);// 显示失败信息drawText(g, 50, new Color(174, 164, 162), "所得金钱:$" + count, 305, 150);// 显示所得钱数break;

运行效果:

22.重置游戏

在Rope类中添加Reset()方法:

/*** 重置绳索*/void Reset() {angle = 0;length = 130;}

在Background类中添加以下方法:

/*** 重置游戏*/void Reset() {// 总钱数count = 0;// 爆竹的数量firecrackersNum = 3;// 爆竹的状态fcFlag = false;// 关卡数level = 1;// 目标钱数goal = level * 100;}

金块石头的重置实在Game类中的nextLevel中,同时,在进入下一关的时候需要重置时间:

private void nextLevel() {if (start == 1 && bg.gameTime()) {// 通过成功就进入下一关if (Background.count >= bg.goal) {if (Background.level == 5) {start = 4;} else {Background.level++;bg.startTime = System.currentTimeMillis();// 重置时间}} else {start = 3;// 不成功则进入失败状态}dispose();Game game1 = new Game();game1.Game();}}

接下来在Game类中Game()方法的case 4:添加以下代码:

void Game() {// 此处为不做改变的代码addKeyListener(new KeyAdapter() {@Overridepublic void keyPressed(KeyEvent e) {switch (start) {case 0:// 此处为不做改变的代码break;case 1:// 此处为不做改变的代码break;case 2:break;case 3:break;case 4:if (e.getKeyCode()==KeyEvent.VK_SPACE){start=0;bg.Reset();rope.Reset();}break;default:}}});while (true) {// 此处为不做改变的代码}}

运行效果:

23.游戏商店:

修改Background类:

public class Background {// 总钱数static int count = 0;// 爆竹的数量static int firecrackersNum = 3;// 爆竹的状态// 关卡数// 目标钱数// 游戏开始时间// 游戏结束时间// 魔法水价格int price = 150;// 是否进入商店boolean enter = false;// 背景图片初始化public static void drawText(Graphics g, int size, Color color, String s, int x, int y) {// 此处为不做改变的代码}public void BackgroundPaint(Graphics g) {g.drawImage(bg, 0, 0, null);switch (Game.start) {case 0:// 此处为不做改变的代码case 1:// 此处为不做改变的代码case 2:g.drawImage(firecrackers, 220, 70, null);drawText(g, 50, new Color(252, 25, 68), "价格:" + price, 280, 100);if (count < 150) {drawText(g, 50, new Color(174, 164, 162), "余额不足", 260, 165);} else {drawText(g, 50, new Color(12, 207, 103), "是否购买?", 280, 130);drawText(g, 50, new Color(174, 164, 162), "是:空格键 否:Esc键", 260, 165);}if (enter) {count = count - price;firecrackersNum++;enter = false;Game.start = 1;startTime = System.currentTimeMillis();}break;case 3:// 此处为不做改变的代码case 4:// 此处为不做改变的代码default:}}/*** 倒计时** @return true代表倒计时完成,false表示正在倒计时*/boolean gameTime() {// 此处为不做改变的代码}/*** 重置游戏*/void Reset() {// 此处为不做改变的代码}}

在Game类中的Game()方法添加键盘事件:

void Game() {// 此处为不做改变的代码addKeyListener(new KeyAdapter() {@Overridepublic void keyPressed(KeyEvent e) {switch (start) {case 0:// 此处为不做改变的代码case 1:// 此处为不做改变的代码case 2:if (e.getKeyCode() == KeyEvent.VK_SPACE) {bg.enter = true;}if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {start = 1;bg.startTime = System.currentTimeMillis();}break;case 3:case 4:// 此处为不做改变的代码default:}}});while (true) {// 此处为不做改变的代码}}

运行效果:

至此,此小游戏完美结束。有脑洞的同学可自行添加功能。

我是码龙,如果我的文章对你有帮助,请点个👍🏻 支持我一下,谢谢~

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。