前言
这个小游戏是参考的b站上尚学堂的视频,自己创新并且写的风格更偏向于本人。
是本人Java基础期末的项目作业,由于只花了一天,很多功能没有完善。
游戏介绍
《黄金矿工》是一款经典的塔防游戏,游戏中有多个关卡,通过收集金币、石头、物品,消灭敌人,最终过关。
项目简介
用户系统
表结构
代码,带注释
童年的味道
游戏主界面类
package com.GoldMiner.ui;
import com.GoldMiner.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import static com.GoldMiner.util.Img.*;//导入所有图片静态常量
public class GameMain extends JFrame {
private final ReentrantLock lock = new ReentrantLock();//锁
public int delay = 20; //延迟多少毫秒重新绘制
Line line = new Line(this);
public static int count = 0;//总积分
//存放物体的集合,包括金块、石头、物品
public List<Item> items = new ArrayList<>();
int level = DataBase.level; //当前关卡
int goal = DataBase.goal; //目标分数
long startTime;
long endTime;
long tim; //剩余时间
DataBase db; //数据库
public GameMain(){
}
//构造方法
public GameMain(DataBase db) {
startTime = System.currentTimeMillis();
this.db = db;
long startTime = System.currentTimeMillis();//开始时间
try {
//初始化窗口
initUI();
} catch (Exception e) {
throw new RuntimeException(e);
}
//初始化金块、石头
initItem();
//鼠标点击事件
this.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
//鼠标左键是1,右键是3,滚轮是2
if (e.getButton() == 1){
line.setState(1); //设置线条状态为1,抓取中
}
}
});
//键盘监听事件
this.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
//按下键盘上的方向键
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
line.setState(1); //设置线条状态为1,抓取中
} else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
exitGame();
}
}
});
//线程循环判断是否过关
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
lock.lock(); //获取锁
System.out.println("count:" + count + " tim:" + tim);
if (tim < 0){
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JOptionPane.showMessageDialog(null, "时间到!请重新开始游戏或者退出游戏");
//重新开始游戏
DataBase.level = 1;
DataBase.goal = 10;
//startTime = System.currentTimeMillis();
count = 0;
items.clear();
dispose();
new GameMain(db);
}
});
break;
}
if (count >= DataBase.goal){
// 过关,但不在当前线程中直接操作GUI
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JOptionPane.showMessageDialog(null, "恭喜过关!");
}
});
DataBase.level++;//升级关卡
DataBase.goal = DataBase.level * 10; //升级目标分数
count = 0;
System.out.println("level up:" + DataBase.level);
new GameMain(db);//重新开始游戏
dispose();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); //释放锁
}
}
}
}).start();
}
private void initItem() {
Gold gold;//存放当前金块
//是否可以放置
boolean isPlaced = true;
//初始化金块
for (int i = 0; i < 12; i++) {
double x = Math.random();
//随机生成不同大小金块
if (x < 0.4){
gold = new GoldMini();
}else if (x < 0.8){
gold = new Gold();
}else {
gold = new GoldPlus();
}
for (Item item : items){
if (gold.getRect().intersects(item.getRect())){
//如果金块和其他物体重叠,则重新生成金块
isPlaced = false;
}
}
if (isPlaced){
//如果可以放置,则添加到集合中
items.add(gold);
isPlaced = true;
} else {
isPlaced = true;
i--;
}
}
//初始化石头
for (int i = 0; i < 8; i++) {
Stone stone = new Stone();//存放当前石块
for (Item item : items){
if (stone.getRect().intersects(item.getRect())){
//如果石头和其他物体重叠,则重新生成
isPlaced = false;
}
}
if (isPlaced){
//如果可以放置,则添加到集合中
items.add(stone);
} else {
isPlaced = true;
i--;
}
}
}
//初始化UI
public void initUI() throws Exception {
this.setTitle("GoldMiner");
this.setIconImage(logo);
this.setSize(800, 600);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
this.setLocationRelativeTo(null);
this.setLayout(new BorderLayout());
//设置窗口不可改变大小
this.setResizable(false);
JMenuBar menuBar = new JMenuBar();
JMenu menuJMenu = new JMenu("功能");
JMenu aboutMenu = new JMenu("关于");
menuBar.add(menuJMenu);
menuBar.add(aboutMenu);
JMenuItem reLoginItem = new JMenuItem("重新登录");
JMenuItem restartItem = new JMenuItem("重新开始游戏");
JMenuItem exitGameItem = new JMenuItem("退出并保存进度");
JMenuItem aboutItem = new JMenuItem("关于作者");
JMenuItem aboutGameItem = new JMenuItem("关于游戏");
JMenuItem helpItem = new JMenuItem("游戏帮助");
menuJMenu.add(reLoginItem);
menuJMenu.add(restartItem);
menuJMenu.addSeparator();
menuJMenu.add(exitGameItem);
aboutMenu.add(aboutItem);
aboutMenu.add(aboutGameItem);
aboutMenu.addSeparator();
aboutMenu.add(helpItem);
//重新登录
reLoginItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dispose();
try {
new Login();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
});
//重新开始游戏
restartItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
DataBase.level = 1;
DataBase.goal = 10;
startTime = System.currentTimeMillis();
count = 0;
items.clear();
new GameMain(db);
dispose();
}
});
//退出游戏
exitGameItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
exitGame();
}
});
//关于作者
aboutItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null, "作者:上玄\nQQ:1421148240\n参考视频:尚学堂Java黄金矿工");
}
});
//关于游戏
aboutGameItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null, "《黄金矿工》是一款经典的塔防游戏,游戏中有多个关卡,通过收集金币、石头、物品,消灭敌人,最终过关。");
}
});
//游戏帮助
helpItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null, "1. 点击鼠标左键,开始抓取\n2. 按下方向键,开始抓取物品\n3. 按下ESC键,退出游戏");
}
});
/*// 背景图片
ImageIcon bg = new ImageIcon("src/com/GoldMiner/image/bkg.png");
ImageIcon man = new ImageIcon("src/com/GoldMiner/image/man.png");*/
// 创建自定义面板来放置组件
JPanel mainPanel = new JPanel(null) {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//绘制背景图片
g.drawImage(bg.getImage(), 0, 0, getWidth(), getHeight(), this);
g.drawImage(man.getImage(), 335, 10,145,95, this);
//绘制金块和石头
for (Item item : items) {
item.paint(g);
}
//绘制线条
line.paint(g);
//绘制积分
paintText(g,"总积分: " + count,30,30);
//绘制关卡
paintText(g,"当前关卡: " + level,30,60);
//绘制目标分数
paintText(g,"目标分数: " + goal,30,90);
//绘制时间
endTime = System.currentTimeMillis();
tim = 30-(endTime-startTime)/1000;
paintText(g,"时间:"+(tim>0?tim:0),520,30);
}
};
mainPanel.setBounds(0, 0, 710, 800);
//mainPanel.add(menuBar);
this.setJMenuBar(menuBar);
this.add(mainPanel);
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//调用repaint()方法重新绘制组件
//System.out.println("repaint");
repaint();
//重新调用paintComponent()方法
//mainPanel.paintComponents(mainPanel.getGraphics());
//line.update(mainPanel.getGraphics());
}
};
//启动定时器重新绘制
new Timer(delay,taskPerformer).start();
}
//绘制文字
private static void paintText(Graphics g,String text,int x,int y) {
g.setColor(Color.BLACK);
g.setFont(new Font("幼圆", Font.BOLD, 25));
g.drawString(text,x,y);
}
//退出游戏并保存进度
public void exitGame() {
int record = db.getMax_record();
if (DataBase.level > record){
db.setMaxRecord(DataBase.level);//更新最高关卡
}
System.exit(0);
}
}
线类
package com.GoldMiner.util;
import com.GoldMiner.ui.GameMain;
import java.awt.*;
import static com.GoldMiner.util.Img.hook;
/**
* 矿工的线
*/
public class Line {
private int x = 390;//起点x坐标
private int y = 85;//起点y坐标
private int endX = 600;//终点x坐标
private int endY = 30;//终点y坐标
private double length = 80;//线的长度
private int direction = 1;//线的方向,1为正方向,-1为负方向
private double n = 0;
private int state;//线的状态,0为摇摆,1为抓取,2为没有抓到物体收回,3为金块碰撞完成
GameMain gameMain;
public Line(GameMain gameMain) {
//空参构造函数
this.gameMain = gameMain;
}
public void paint(Graphics g) {
logic();//金块碰撞逻辑
//通过状态画线
switch (state) {
case 0: //摇摆
if (n < 0.1) {
direction = 1; //未超过180度,正方向
} else if (n > 0.9) {
direction = -1; //超过180度,反方向
}
n += 0.005 * direction;//角度转弧度
lines(g);//画线
break;
case 1: //抓取
if (length < 550) {
length += 10; //线长增加
lines(g);
} else {
state = 2; //抓取完成,收回线
}
break;
case 2: //收回
if (length > 80) {
length -= 10; //线长减少
lines(g);
} else {
state = 0; //收回线,摇摆
}
break;
case 3: //金块碰撞完成
int m = 1; //暂停时间
if (length > 80) {
length -= 10; //线长减少
//画线
lines(g);
for (Item item : this.gameMain.items) {
//是否为被抓取的金块
if (item.isIsCollected()) {
m = item.getM(); //暂停时间
//将金块位置设置为跟着线移动
item.setX(endX - item.getWidth() / 2);
item.setY(endY);
if (length <= 100) {
//将金块移出屏幕外
item.setX(-150);
item.setY(-150);
item.setIsCollected(false);//移动完毕修改回来
//增加积分
GameMain.count += item.getCount();
state = 0; //收回线,摇摆
}
}
}
}
try {
Thread.sleep(m);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
default: //摇摆
if (n < 0.1) {
direction = 1; //未超过180度,正方向
} else if (n > 0.9) {
direction = -1; //超过180度,反方向
}
n += 0.005 * direction;//角度转弧度
lines(g);
break;
}
}
/**
* 计算线的坐标并绘制
*/
private void lines(Graphics g) {
//公式计算终点坐标
endX = (int) (x + length * Math.cos(n * Math.PI));
endY = (int) (y + length * Math.sin(n * Math.PI));
g.setColor(Color.black);
g.drawLine(x, y, endX, endY);
//加粗
g.drawLine(x-1, y, endX-1, endY);
g.drawLine(x+1, y, endX+1, endY);
g.drawImage(hook,endX-25,endY-2,null);
}
/**
* 金块碰撞的逻辑
*/
public void logic() {
//逻辑处理
for (Item item : this.gameMain.items){
if (endX > item.getX() && endX < item.getX() + item.getWidth() && endY > item.getY() && endY < item.getY() + item.getHeight()) {
//物体碰撞
setState(3);//抓取状态返回3
//System.out.println(endX + " " + endY + " " + item.getX() + " " + item.getY() + " " + item.getWidth() + " " + item.getHeight());
item.setIsCollected(true);
break;
}
}
}
public void update(Graphics g){
//更新线的坐标
paint(g);
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getEndX() {
return endX;
}
public void setEndX(int endX) {
this.endX = endX;
}
public int getEndY() {
return endY;
}
public void setEndY(int endY) {
this.endY = endY;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public int getDirection() {
return direction;
}
public void setDirection(int direction) {
this.direction = direction;
}
public double getN() {
return n;
}
public void setN(double n) {
this.n = n;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public String toString() {
return "Line{x = " + x + ", y = " + y + ", endX = " + endX + ", endY = " + endY + ", length = " + length + ", direction = " + direction + ", n = " + n + ", state = " + state + "}";
}
}
物体类
package com.GoldMiner.util;
import java.awt.*;
/**
* 抓取的物体类
*/
public class Item {
//物体的坐标
private int x;
private int y;
//物体的大小
private int width;
private int height;
private Image img;//抓取的物体图片
private boolean isCollected = false; //是否已经被抓取
private int m; //物体的质量
private int count; //物体的积分
public Item() {
}
//绘制物体
public void paint(Graphics g) {
g.drawImage(img, x, y, width, height, null);
}
//检测物体矩形重合
public Rectangle getRect() {
return new Rectangle(x, y, width, height);
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public Image getImg() {
return img;
}
public void setImg(Image img) {
this.img = img;
}
public String toString() {
return "Item{x = " + x + ", y = " + y + ", width = " + width + ", height = " + height + ", img = " + img + "}";
}
public boolean isIsCollected() {
return isCollected;
}
public void setIsCollected(boolean isCollected) {
this.isCollected = isCollected;
}
public int getM() {
return m;
}
public void setM(int m) {
this.m = m;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
更多代码访问Gitee下载源代码,以上为主要功能代码,需要配套课设PPT的可以联系我
全部源码开源下载