项目简介:黄金矿工游戏项目
项目采用技术:Java变量及数据类型,判断语句,循环结构,Java集合,简单窗口创建,图形图片绘制,鼠标事件,双缓存技术,流式布局
功能需求分析:
1. 游戏基本设计:
- 设计游戏场景,包括金矿、岩石、矿石等元素以及它们的外观和分布。
2. 资源管理:
- 设计金矿的生成、存储和收集机制,玩家通过挖掘获得金矿资源。
- 创建资源管理系统,跟踪玩家的金矿数量和存储情况。
3. 游戏进度与挑战:
- 设定不同的关卡目标和挑战任务,例如在规定时间内挖掘一定量的黄金或完成特定任务。
4. 道具与技能系统:
- 提供各种道具和技能供玩家购买或解锁,比如生命药水等。
- 实现道具和技能的购买和出售系统。
5. 用户界面与用户体验:
- 设计直观易懂的用户界面
项目亮点:
1.简单易上手:游戏操作简单直观,玩家只需简单的点击操作
2.策略性挖掘体验:玩家需合理规划挖矿路线
3.重新游戏选项:使用流式布局,添加菜单栏,失败后可选择重新游戏或退出
团队成员 | 负责内容 |
郭忆微 | 创建金块,设置多种金块,解决物体堆叠,红线完善,力量与爆破关卡设置,添加鼠标事件,整合GameWin类,添加菜单栏 |
李夏冉 | 绘制图片及窗口,红线绘制及状态,双缓存技术,抓取状态,药水设置,积分设置,游戏重置,计时效果,失败与成功状态 |
package sxt;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import static java.awt.Color.black;
import static sxt.Bg.waterNum;
public class GameWin extends JFrame {
/*
设置静态变量,表示整个游戏的状态
0表示游戏未开始
1表示游戏进行中
2表示商店选购中
3表示游戏失败
4表示游戏胜利
*/
static int state;
/*
创建集合存储金块,石块
*/
List<Object> objectList = new ArrayList<>();
/*
载入图片
*/
Bg bg = new Bg();
Line line = new Line(this);
{
/*
布尔类型变量,判断是否可以放置物块
*/
boolean isPlace = true;
/*
三种金块按照一定概率添加
*/
for (int i = 0; i < 15; i++) {
/*
生成随机数计算不同金块生成概率,数值在0-1之间
*/
double random = Math.random();
/*
每次生成物块时,需要判断是否与已生成物块堆叠,如果没有堆叠,则添加在集合中
成员变量gold用来存放已经生成的物块
*/
Gold gold;
if (random < 0.4) {
gold = new GoldMini();
} else if (random < 0.75) {
gold = new Gold();
} else {
gold = new GoldPlus();
}
/*
增强for循环判断生成的金块是否和集合中存在的物块重叠
*/
for (Object obj : objectList) {
if (gold.getRec().intersects(obj.getRec())) {
/*
不可放置,需要重新生成
*/
isPlace = false;
}
}
/*
循环结束后,如果可以放置,则添加到链表中
*/
if (isPlace) {
objectList.add(gold);
} else {
isPlace = true;
i--;
}
}
for (int i = 0; i < 5; i++) {
/*
同以上方法,循环判断石块是否和已经存在的物块堆叠
*/
Rock rock = new Rock();
for (Object obj : objectList) {
if (rock.getRec().intersects(obj.getRec())) {
isPlace = false;
}
}
if (isPlace) {
objectList.add(rock);
} else {
isPlace = true;
i--;
}
}
}
/*
解决闪动问题,新定义一张画布,双缓存缓存图像数据
*/
Image offScreenImage;
/*
创建方法来初始化窗口信息
*/
void launch() {
Image icon = Toolkit.getDefaultToolkit().getImage("C:\\Users\\86185\\Desktop\\imgs\\gold-miner-\\src\\peo.png");
JMenuBar jMenuBar = new JMenuBar();
JMenu fuctionJMenu = new JMenu("功能");
fuctionJMenu.setFont(new Font("黑体", Font.BOLD, 18));
JMenuItem replay = new JMenuItem("重新开始");
JMenuItem close = new JMenuItem("关闭游戏");
replay.setFont(new Font("黑体", Font.BOLD, 18));
close.setFont(new Font("黑体", Font.BOLD, 18));
close .addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
replay.addActionListener(new ReplayGame());
jMenuBar.add(fuctionJMenu);
fuctionJMenu.add(replay);
fuctionJMenu.add(close);
this.setJMenuBar(jMenuBar);
add(drawingPanek,BorderLayout.CENTER);
this.setIconImage(icon);
this.setVisible(true);
this.setSize(768, 1000);
this.setLocationRelativeTo(null);
this.setTitle("黄金矿工");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
/*
添加鼠标事件
*/
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
switch (state) {
case 0:
/*
点击鼠标右键,进入游戏
*/
if (e.getButton() == 3) {
state = 1;
/*
进入游戏的同时给开始时间赋值
赋值为系统时间
*/
bg.startTime = System.currentTimeMillis();
}
break;
case 1:
/*
游戏进行中时
左右摇摆,点击左键
*/
if (e.getButton() == 1 && line.state == 0) {
line.state = 1;
} /*
抓取返回,点击右键
*/
if ((e.getButton() == 3 && line.state == 3) && (waterNum > 0)) {
Bg.waterFlag = true;
waterNum--;
}
break;
case 3:
case 4:
if (e.getButton() == 1) {
/*
返回准备开始
*/
state = 0;
/*
重置背景和线中的元素
*/
bg.reGame();
line.reGame();
}
break;
default:
}
}
}
);
/*
不停的创建repaint对象使线不停地摇摆
*/
while (true) {
/*
刷新组件外观
*/
repaint();
/*
刷新关卡
*/
nextLevel();
/*
判断关卡
*/
if (Bg.count >= bg.goal) {
System.out.println("过关");
}
try {
Thread.sleep(8);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/*
刷新,进入下一关
*/
public void nextLevel() {
/*
游戏运行中才会进入下一关
*/
if (bg.gameTime() && state == 1) {
if (Bg.count >= bg.goal) {
/*
关卡数加一
*/
if (Bg.level == 5) {
state = 4;
}
/*
如果满足条件并且还没有到成功的时候,就进入商店
*/
else {
state = 2;
Bg.level++;
}
/*
释放之前的窗体
*/
dispose();
GameWin gameWin1 = new GameWin();
gameWin1.launch();
} else {
state = 3;
}
}
}
public JPanel drawingPanek = new JPanel() {
public void paint(Graphics g) {
/*
背景在任何游戏状态下都需要绘制
*/
offScreenImage = this.createImage(768, 1000);
Graphics gImage = offScreenImage.getGraphics();
bg.paintSelf(gImage);
/*
在游戏运行中的状态下
绘制物体和线
*/
if (state == 1) {
for (Object obj : objectList) {
obj.paintSelf(gImage);
}
line.paintSelf(gImage);
}
g.drawImage(offScreenImage, 0, 0, null);
}
};
public static void main(String[] args) {
GameWin gameWin = new GameWin();
gameWin.launch();
}
}
package sxt;
import java.awt.*;
public class Rock extends Object{
Rock(){
this.x=(int)(Math.random()*700);
this.y=(int)(Math.random()*550+300);
this.height=71;
this.width=71;
this.flag=false;
this.m=50;
this.type =2;
this.img= Toolkit.getDefaultToolkit().getImage("imgs/rock1.png");
}
}
package sxt;
import java.awt.*;
import static java.awt.Color.black;
public class Bg {
/*
载入图片
*/
Image bg = Toolkit.getDefaultToolkit().getImage("imgs/bg.jpg");
Image bg1 = Toolkit.getDefaultToolkit().getImage("imgs/bg1.jpg");
Image peo = Toolkit.getDefaultToolkit().getImage("imgs/peo.png");
Image water = Toolkit.getDefaultToolkit().getImage("imgs/water.png");
/*
关卡数
*/
static int level = 1;
/*
目标分数(达到后方可进入下一关)
*/
int goal = level * 15;
/*
总分
*/
static int count = 0;
/*
药水数量
*/
static int waterNum = 5;
/*
药水状态,默认false,true表示正在使用
*/
static boolean waterFlag = false;
/*
定义变量
设置游戏开始时间和结束时间
*/
long startTime;
long endTime;
/*
药水数量
*/
int price=(int)Math.random()*10;
/*设置是否进入商店
f 不购买
*/
boolean shop=false;
/*
绘制组件外观
*/
void paintSelf(Graphics g) {
/*
背景块在任何游戏状态下都需要绘制
*/
g.drawImage(bg1, 0, 0, null);
g.drawImage(bg, 0, 200, null);
/*
矿工,积分块,药水组件,关卡数,关卡目标积分都需要在游戏进行状态下绘制
*/
switch (GameWin.state) {
case 0:
/*
准备开始
*/
drawWord(g,Color.GREEN ,80,"准备开始",200,400) ;
break;
case 1:
/*
绘制矿工
*/
g.drawImage(peo, 310, 50, null);
/*
绘制积分块
*/
drawWord(g, Color.BLACK, 30, "积分:" + count, 30, 150);
/*
添加药水组件
*/
g.drawImage(water, 450, 40, null);
drawWord(g, Color.CYAN, 30, "*" + waterNum, 510, 80);
/*
绘制关卡数
*/
drawWord(g, Color.BLACK, 20, "第" + level + "关", 30, 60);
/*
绘制关卡目标积分
*/
drawWord(g, Color.BLACK, 30, "目标:" + goal, 30, 110);
/*
时间组件
实时赋值
*/
endTime =System .currentTimeMillis() ;
/*
每一关限时20秒,超时即为失败
定义局部变量,用来计算倒计时
将时间单位从毫秒换算成秒
并将其进行打印
*/
long tim=30-(endTime -startTime )/1000;
drawWord(g, Color.BLACK, 30, "时间:" + (tim>0?tim:0), 520, 150);
break;
case 2:
g.drawImage(water,300,400,null);
drawWord(g,Color.black,30,"价格"+waterNum,300,500);
drawWord(g,Color.black,30,"是否购买?"+waterNum,300,550);
/*
买药水
*/
if(shop){
count=count-price;
waterNum++;
/*释放商店状态
*/
shop=false;
GameWin.state=1;
/*
同时重新计时
*/
startTime=System.currentTimeMillis();
}
break;
case 3:
/*
失败状态
*/
drawWord(g, Color.cyan, 80, "失败" , 250, 350);
drawWord(g, Color.cyan, 80, "积分:" + count, 200, 450);
break;
case 4:
drawWord(g, Color.RED, 80, "成功" , 250, 350);
drawWord(g, Color.RED, 80, "积分:" + count, 200, 450);
break;
default :
}
}
/*
添加判断倒计时的方法
返回值为true,表示倒计时完成
false,正在倒计时
*/
boolean gameTime(){
long tim=30-(endTime -startTime )/1000;
if(tim<0){
return true;
}
else {
return false ;
}
}
/*重置元素
*/
void reGame(){
level = 1;
/*
目标分数(达到后方可进入下一关)
*/
goal = level * 15;
/*
总分
*/
count = 0;
/*
药水数量
*/
waterNum = 3;
waterFlag=false;
}
/*
为简化代码,将打印字符串方法进行封装
*/
public static void drawWord(Graphics g, Color color, int size, String str, int x, int y) {
/*
字体颜色
*/
g.setColor(color);
/*
字体类型(加粗)
*/
g.setFont(new Font("黑体", Font.BOLD, size));
/*
打印字符串
*/
g.drawString(str, x, y);
}
}
package sxt;
import com.sun.javafx.tk.Toolkit;
import java.awt.*;
public class Line<frame> {
/*
起点坐标
*/
int x=380;
int y=180;
/*
终点坐标
*/
int endx=500;
int endy=500;
/*
线长
*/
double length=100;
double n=0;
/*
添加方向
*/
int dir=1;
/*
状态为0就左右摇摆
状态为1就向下抓取
状态为2就收回
状态为3时抓取返回
*/
int state;
/*
让红线类接收到主窗口中的元素
线长最小值
*/
double MinLength=100;
/*
线长最大值
*/
double MaxLength=750;
/*
给红线添加钩爪图片
*/
Image hook=java.awt.Toolkit .getDefaultToolkit() .getImage("imgs/hook.png");
/*
有参构造
*/
GameWin frame;
Line(GameWin frame){
this.frame=frame;
}
/*
检测物块是否被抓取
*/
void logic(){
for(Object obj:this.frame.objectList){
if(endx>obj.x && endx<obj.x+obj.width
&&endy>obj.y && endy<obj.y+obj.height){
state=3;
obj.flag=true;
}
}
}
/*
绘制方法
*/
void lines(Graphics g){
logic();
endx=(int)(x+length*Math.cos(n*Math.PI));
endy=(int)(y+length*Math.sin(n*Math.PI));
g.setColor(Color.red);
/*
以下两部分是绘制红线部分的完善
加粗红线,绘制三条平行线
*/
g.drawLine(x-1,y,endx-1,endy);
g.drawLine(x,y,endx,endy);
g.drawLine(x+1,y,endx+1,endy);
/*
保证红线终点在钩爪的中心
*/
g.drawImage(hook ,endx-36 ,endy-2 ,null) ;
}
void paintSelf(Graphics g) {
switch (state) {
case 0:
if (n < 0.1) {
dir = 1;
} else if (n > 0.9) {
dir = -1;
}
n = n + 0.005 * dir;
lines(g);
break;
case 1:
if (length < MaxLength) {
/*
通过调整线长来调整绳子返回速度
*/
length = length + 5;
lines(g);
} else {
state = 2;
}
break;
case 2:
if (length > MinLength) {
length = length - 5;
lines(g);
} else {
state = 0;
}
break;
/*
此状态为红线碰到金块立即返回
*/
case 3:
/*
金块石块都在3状态中,不能仅仅通过线长来调整
需要为金块和石块添加质量属性
*/
int m = 1;
if (length > MinLength) {
length = length - 5;
lines(g);
for (Object obj : this.frame.objectList) {
/*
判断金块能否移动再让它移动
*/
if (obj.flag) {
/*
判断金块能否移动再让它移动
*/
if (obj.flag) {
m = obj.m;
obj.x = endx - obj.getWidth() / 2;
obj.y = endy;
if (length <= MinLength) {
/*
移至屏幕外
*/
obj.x = -150;
obj.y = -150;
obj.flag = false;
Bg.count += obj.count;
state = 0;
/*
释放药水
*/
Bg.waterFlag = false;
}
/*
判断抓取时是否使用了药水
*/
if ((Bg.waterFlag == true) && (Bg.waterNum > 0)) {
/*
为判断抓取的是石块还是金块,需要再返回两个物块类做标记
若抓取的是石块,点击鼠标右键石块消除
若抓取的是金块,点击鼠标右键快速拉取
*/
if (obj.type == 1) {
/*
降低质量,提高刷新频率,加快抓取速度
*/
m = 1;
}
if (obj.type == 2) {
/*
直接移除石块
*/
obj.x = 750;
obj.y = 750;
obj.flag = false;
/*
刷新药水状态
*/
Bg.waterFlag = false;
/*
线立即返回
*/
state = 2;
}
} else if (Bg.waterNum <= 0) {
Bg.waterNum = 0;
Bg.waterFlag = false;
}
}
/*
会出现抓一个金块其他金块都消失的现象
为解决此问题,去给金块打一个标记flag
*/
}
}
/*
添加延时来降低刷新速度,达到缓慢的效果
*/
try {
Thread.sleep(m);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
default:
}
}
//重置线
void reGame(){
n=0;
length=100;
}
}
package sxt;
import java.awt.*;
public class Object {
int x,y;
int height;
int width;
Image img;
/*
标记是否能移动
*/
boolean flag;
/*
质量属性
*/
int m;
/*
积分
*/
int count;
/*
类型为1是金块,类型为2是石块
用来判断抓取的物块种类
*/
int type;
void paintSelf(Graphics g){
g.drawImage(img,x,y,null);
}
public int getWidth(){
return width;
}
/*
为了防止物块堆叠,需要通过判断物块矩形是否重合来判断物块是否堆叠
获取矩形
*/
public Rectangle getRec(){
return new Rectangle(x,y,width ,height);
}
}
package sxt;
import java.awt.*;
public class Gold extends Object {
Gold(){
this.x=(int)(Math.random()*700);
this.y=(int)(Math.random()*550+300);
this.height=52;
this.width=52;
this.flag=false;
this.m=30;
this.count =4;
this.type =1;
this.img= Toolkit.getDefaultToolkit().getImage("imgs/gold1.gif");
}
}
/*
构造多种金块
*/
class GoldMini extends Gold{
GoldMini (){
/*
重置与原有金块类不同的参数
*/
this.height =36;
this.width =36;
this.m=15;
this.count =2;
this.img =Toolkit.getDefaultToolkit().getImage("imgs/gold0.gif");
}
}
class GoldPlus extends Gold{
GoldPlus (){
this.x=(int)(Math.random()*650);
/*
宽度比普通金块宽出很多,因此重置横坐标
*/
this.height =105;
this.width =105;
this.m=60;
this.count =8;
this.img =Toolkit.getDefaultToolkit().getImage("imgs/gold2.gif");
}
}
package sxt;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ReplayGame implements ActionListener {
GameWin gameWin;
@Override
public void actionPerformed(ActionEvent e) {
try{
GameWin.state = 0;
/*
重置背景和线中的元素
*/
Bg.count =0;
Bg.waterNum=5;
Bg.waterFlag=false ;
gameWin. bg.reGame();
gameWin.line.reGame();
gameWin.launch();
}catch (NullPointerException e1){
e1.printStackTrace();
}
}
}
项目Git地址:
https://gitee.com/guoyiwei_1_0/gold-miner-