简介

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

内容简介:实现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 2021-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 2021-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 2021-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 2021-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 2021-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 2021-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) {// 此处为不做改变的代码}}

运行效果:

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

我是码龙,如果我的文章对你有帮助,请点个 

Java游戏项目——仿4399小游戏《黄金矿工》相关推荐

  1. C/C++项目:4399小游戏黄金矿工编译教程

    <黄金矿工中文版>是一款休闲益智小游戏,游戏中你需要看准时机出钩子勾取金子或者砖石来获得金钱的累加,达到一定的金钱数才能够闯关成功,游戏十分经典,强烈推荐大家学会编写这款游戏,休闲时没网也 ...

  2. java小游戏-java小游戏-黄金矿工

    java小游戏-java小游戏-黄金矿工 1 窗口绘制 2 绘制图片 3 红线绘制 4 红线摇摆 5 红线抓取 6 创建金块 7 双缓存技术 8 抓取判断 9 抓取返回 10 多个金块 11 Bug金 ...

  3. 【Java基础项目】经典小游戏黄金矿工制作

    Java初学者的小伙伴们,相信大家肯定缺少很多的练手项目吧!今天就给大家推荐一款特别好上手的一个Java小游戏--黄金矿工. 大家听到这个名字的时候,童年的回忆肯定一下子,涌上心头,那如果让大家制作一 ...

  4. Java练手小游戏---黄金矿工

    你玩过4399曾经最火的黄金矿工小游戏吗,黄金矿工小游戏是一款休闲娱乐的一个挖宝游戏,在游戏中地下会有许多的宝藏,你得想办法把它们都挖出来,作为矿工的你,对你来说是轻车熟路的,能不能挖到宝,看你抓取的 ...

  5. 用Java写个小游戏--黄金矿工代码实现

    黄金矿工 项目结构 前期准备 Stone类 Gold类(包含Gold类,GoldMini类,GoldPlus类) GameWin类 Line类 Parent类 Sky类 项目结构 GameWin类,游 ...

  6. JAVA小游戏——黄金矿工

    Day 1:窗口绘制并导入背景图片 public class mygame extends JFrame {bj b=new bj();void launch() throws Interrupted ...

  7. 基于Java+Swing实现雷电小游戏

    基于Java+Swing实现雷电小游戏 一.系统介绍 二.功能展示 三.其他系统 四.获取源码 一.系统介绍 基于java的雷电游戏基本功能包括:敌方飞机随机飞行.我方飞机手动控制飞行,射击比拼,游戏 ...

  8. 用Java开发贪食蛇小游戏

    用Java开发贪食蛇小游戏 一.实验内容 1.实现贪吃蛇游戏基本功能,屏幕上随机出现一个"食物",称为豆子,上下左右控制"蛇"的移动,吃到"豆子&qu ...

  9. java简单通讯录的实现02person类_用java实现简单的小游戏(你一定玩过)

    用java实现简单的小游戏(你一定玩过) 对于java初学者来说,通过一些学习小游戏来对swing学习以及对java基础的学习是一个好的方法,同时也给学习带来了很多的乐趣,接下来就给大家分享一个jav ...

最新文章

  1. 如何使窗体不重复被打开
  2. 算法 求两个自然数的最大公约数 C++
  3. 大规模数据中心如何重塑整个IT
  4. 爬虫实战:CentOS安装JDK,部署Java程序,利用screen使其保持在前台运行
  5. urllib.error.URLError:urlopen error unknown url type:https 解决办法
  6. Direct3D学习_绘制
  7. C#中判断字符串相等的方法
  8. projecteuler_介绍#ProjectEuler100挑战:编码成就的“黑暗灵魂”
  9. 转:[kipmi0]进程导致系统负载高
  10. Python学习-类的继承
  11. 互联网流量劫持的背后:黑客月入至少三万
  12. 学习scala03 控制结构
  13. 魔百盒CM311-1_S905L3芯片_YST代工_红外蓝牙语音_安卓9.0_线刷固件包
  14. android 5.1一键root工具箱,最新的安卓5.1.1 ROOT教程(不需要刷第三方内核)
  15. 陈佩斯曾受邀喜剧综艺:被酬劳吓的恍惚好几天
  16. Windows中redis设置密码
  17. Android 3D滑动菜单完全解析,实现推拉门式的立体特效
  18. 数据库|ALTER命令
  19. 【国家局发布】医疗器械注册流程及相关法规大全
  20. TensorFlow学习笔记12----Creating Estimators in tf.contrib.learn

热门文章

  1. CAD的一些常用命令
  2. VEEAM 7 tape还原的各类小麻烦
  3. 数字资产存在万圣节效应吗?
  4. java连接智能电表_智能电表的四种读取方法
  5. 中年程序员被裁其实是件好事!
  6. 博奥智源:企业信息系统风险评估有哪些?
  7. 【软件工程专业】被撤销!包含上海交通大学/西安交通大学/北京师范大学等学校!...
  8. Hexo-Next主题优化
  9. 你知道2023年堡垒机报价是多少吗?谁能回答!
  10. 图像为什么糊了(MATLAB)