目录
一、项目介绍
1.项目描述
项目为游戏类,推箱子小游戏,拥有登陆系统,注册系统,游戏主题,游戏目录,游戏关卡选择功能
2.功能架构图
3.个人任务简述
序号 | 完成功能与任务 | 描述 |
1 | 登录功能 | 通过gui技术绘制登陆界面并且根据一些要求判定是否登陆成功 |
2 | 注册功能 | 通过gui技术绘制注册界面并且根据一些要求判定是否注册成功,注册成功之后重新登陆 |
3 | 文件读写 | 通过Scanner和writer字符流对文件进行读和写 |
4 | 游戏界面设计 | 给游戏界面添加背景色,菜单 |
5 | 游戏实现 | 通过图片的替换进行游戏实现 |
6 | 游戏目录 | 通过读取文件进行关卡选择 |
二、功能介绍
1.登陆系统
通过继承JFrame,使用其中的类来给登陆界面添加文字说明,文本框,按钮,再通过按钮的监听事件来判断是否登陆成功。
关键代码:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;
import javax.swing.*;
public class LoginJFame extends JFrame implements ActionListener {
private JLabel account = new JLabel("请输入您的账号");
private JTextField account2 = new JTextField(20);
private JLabel password = new JLabel("请输入您的密码");
private JTextField password2 = new JTextField(20);
private JButton login = new JButton("登陆");
private JButton register = new JButton("注册");
private JButton exit = new JButton("退出");
private JFrame a = new JFrame("登陆");
private File file = new File("用户信息.txt");
private File file2 = new File("关卡.txt");
public LoginJFame() {
// 登陆界面
a.setLayout(new FlowLayout());
a.add(account);
a.add(account2);
a.add(password);
a.add(password2);
a.add(login);
a.add(register);
a.add(exit);
a.setSize(300, 150);
a.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
a.setLocationRelativeTo(null);
a.setResizable(false);
a.setVisible(true);
login.addActionListener(this);
register.addActionListener(this);
exit.addActionListener(this);
}
private String ac;
// 登陆界面按钮的监听事件
@Override
public void actionPerformed(ActionEvent e) {
int t = 0, d = 0;
if (e.getSource() == login) {
ac = account2.getText();
String pa = password2.getText();
try {
Scanner sc = new Scanner(file);
while (sc.hasNext()) {
t = 0;
d = 0;
String ac2 = sc.next();
String pa2 = sc.next();
if (ac.equals(ac2)) {
t = 1;
}
if (pa.equals(pa2)) {
d = 1;
}
if (t == 1 && d == 1) {
break;
}
}
if (t == 0 || d == 0) {
JOptionPane.showMessageDialog(this, "用户名或密码错误");
sc.close();
a.dispose();
new LoginJFame();
return;
}
sc.close();
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
int h = 0;
int j = 0;
String b = null;
try {
Scanner sc2 = new Scanner(file2);
while (sc2.hasNext()) {
b = sc2.next();
h = sc2.nextInt();
if (b.equals(ac)) {
j = h;
break;
}
}
sc2.close();
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
JOptionPane.showMessageDialog(this, "登陆成功");
a.dispose();
new GameList(b, j);
}
if (e.getSource() == register) {
a.dispose();
new RegisterJFrame();
}
if (e.getSource() == exit) {
JOptionPane.showMessageDialog(this, "谢谢");
System.exit(0);
}
}
}
2.注册系统
通过输入的用户名判断用户名是否已存在,通过确认密码来确定密码是否输入正确,如果注册成功就再用户信息.txt中写入信息,并且在关卡.txt中写入用户名以及关卡1.
关键代码:
public class RegisterJFrame extends JFrame implements ActionListener {
private JLabel account = new JLabel("请输入您的账号");
private JTextField account2 = new JTextField(20);
private JLabel password = new JLabel("请输入您的密码");
private JTextField password2 = new JTextField(20);
private JLabel password3 = new JLabel("请确认您的密码");
private JTextField password4 = new JTextField(20);
private JFrame a = new JFrame("注册");
private JButton register = new JButton("注册");
private JButton exit = new JButton("退出");
private File file = new File("用户信息.txt");
private File file2 = new File("关卡.txt");
//注册界面
public RegisterJFrame() {
a.setLayout(new FlowLayout());
a.add(account);
a.add(account2);
a.add(password);
a.add(password2);
a.add(password3);
a.add(password4);
a.add(register);
a.add(exit);
a.setSize(300, 200);
a.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
a.setLocationRelativeTo(null);
a.setResizable(false);
a.setVisible(true);
register.addActionListener(this);
exit.addActionListener(this);
}
//注册界面的监听事件
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == register) {
String ac = account2.getText();
String pa = password2.getText();
String pa2 = password4.getText();
if (!pa.equals(pa2)) {
JOptionPane.showMessageDialog(this, "密码不一致,请重新输入");
a.dispose();
new RegisterJFrame();
return;
}
if (ac.isEmpty()) {
JOptionPane.showMessageDialog(this, "账号不能为空,请重新输入");
a.dispose();
new RegisterJFrame();
return;
}
Scanner sc;
int t = 0;
try {
sc = new Scanner(file);
while (sc.hasNext()) {
String s = sc.next();
if (ac.equals(s)) {
JOptionPane.showMessageDialog(this, "用户名已存在,请重新输入");
t = 1;
sc.close();
break;
}
}
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
if (t == 1) {
a.dispose();
new RegisterJFrame();
return;
}
try {
FileWriter fileWriter2 = new FileWriter(file2, true);
try (PrintWriter writer2 = new PrintWriter(fileWriter2)) {
writer2.print(ac);
writer2.print(' ');
writer2.println(1);
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
FileWriter fileWriter = new FileWriter(file, true);
PrintWriter writer = new PrintWriter(fileWriter);
writer.print(ac);
writer.print(' ');
writer.println(pa);
writer.close();
a.dispose();
JOptionPane.showMessageDialog(this, "注册成功,请重新登陆");
new LoginJFame();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
if (e.getSource() == exit) {
JOptionPane.showMessageDialog(this, "谢谢");
System.exit(0);
}
}
}
3.文件读写
在登陆界面和注册界面通过文件的读写来判断登陆是否成功,用户名和密码是否错误,注册时的用户名是否为空,密码是否确认,是否一致。
关键代码:
try {
FileWriter fileWriter2 = new FileWriter(file2, true);
try (PrintWriter writer2 = new PrintWriter(fileWriter2)) {
writer2.print(ac);
writer2.print(' ');
writer2.println(1);
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
FileWriter fileWriter = new FileWriter(file, true);
PrintWriter writer = new PrintWriter(fileWriter);
writer.print(ac);
writer.print(' ');
writer.println(pa);
writer.close();
a.dispose();
JOptionPane.showMessageDialog(this, "注册成功,请重新登陆");
new LoginJFame();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
if (e.getSource() == login) {
ac = account2.getText();
String pa = password2.getText();
try {
Scanner sc = new Scanner(file);
while (sc.hasNext()) {
t = 0;
d = 0;
String ac2 = sc.next();
String pa2 = sc.next();
if (ac.equals(ac2)) {
t = 1;
}
if (pa.equals(pa2)) {
d = 1;
}
if (t == 1 && d == 1) {
break;
}
}
if (t == 0 || d == 0) {
JOptionPane.showMessageDialog(this, "用户名或密码错误");
sc.close();
a.dispose();
new LoginJFame();
return;
}
sc.close();
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
4.游戏界面设计
使用MenuBar,Menu,MenuItem来优化菜单栏,并且添加监听事件重新本关。
关键代码:
public GameFrame(String ac, int n) {
this.ac = ac;
this.t = n;
// 给游戏界面添加菜单栏
MenuBar menuBar = new MenuBar();
Menu menu = new Menu("重新本关");
MenuItem back = new MenuItem("重新开始");
menu.add(back);
menuBar.add(menu);
back.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dispose();
new GameFrame(ac, t);
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'actionPerformed'");
}
});
// 游戏界面设置
setSize(600, 600);
setVisible(true);
setTitle("推箱子");
setMenuBar(menuBar);
setLocationRelativeTo(null);
setResizable(false);
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
5.游戏实现
通过keyevent来监听键盘输入的上下左右,通过Rectangle来绘制人物以及墙体的矩形,再通过intersects方法来判断人物与墙是否发生碰撞。
关键代码:
public void draw(Graphics g, GamePeople gamePeople, int check) {
if (chenumm) {
box = che(check);
chenumm = false;
}
for (int j = 0; j < box.length; j++) {
for (int i = 0; i < box[0].length; i++) {
switch (box[j][i]) {
case 0:
x = (i + 1) * 50;
y = 50 + j * 50;
break;
case 1:
x = (i + 1) * 50;
y = 50 + j * 50;
g.drawImage(wall, x, y, null);
save(x, y, g);
break;
case 2:
x = (i + 1) * 50;
y = 50 + j * 50;
g.drawImage(brick, x, y, null);
break;
case 3:
x = (i + 1) * 50;
y = 50 + j * 50;
g.drawImage(end, x, y, null);
break;
case 4:
x = (i + 1) * 50;
y = 50 + j * 50;
if (gamePeople.x == x && gamePeople.y == y) {
if (gamePeople.up2) {
if (box[j - 1][i] != 1 && box[j - 1][i] != 4) {
if (box[j - 1][i] == 3) {
blk1++;
}
if (blk2.contains((j + 1) * 10 + i)) {
box[j][i] = 3;
box[j - 1][i] = 4;
} else {
box[j][i] = 2;
box[j - 1][i] = 4;
}
} else {
gamePeople.y += 50;
}
} else if (gamePeople.down2) {
if (box[j + 1][i] != 1 && box[j + 1][i] != 4) {
if (box[j + 1][i] == 3) {
blk1++;
}
if (blk2.contains((j + 1) * 10 + i)) {
box[j][i] = 3;
box[j + 1][i] = 4;
} else {
box[j][i] = 2;
box[j + 1][i] = 4;
}
} else {
gamePeople.y -= 50;
}
} else if (gamePeople.right2) {
if (box[j][i + 1] != 1 && box[j][i + 1] != 4) {
if (box[j][i + 1] == 3) {
blk1++;
}
if (blk2.contains((j + 1) * 10 + i)) {
box[j][i] = 3;
box[j][i + 1] = 4;
} else {
box[j][i] = 2;
box[j][i + 1] = 4;
}
} else {
gamePeople.x -= 50;
}
} else if (gamePeople.left2) {
if (box[j][i - 1] != 1 && box[j][i - 1] != 4) {
if (box[j][i - 1] == 3) {
blk1++;
}
if (blk2.contains((j + 1) * 10 + i)) {
box[j][i] = 3;
box[j][i - 1] = 4;
} else {
box[j][i] = 2;
box[j][i - 1] = 4;
}
} else {
gamePeople.x += 50;
}
}
}
g.drawImage(crate, x, y, null);
break;
}
}
}
coll(gamePeople);
// 用于下一关的判定
if (blk == blk1 && checkpoint == 1) {
w = 2;
checkpoint = 2;
chenumm = true;
} else if (blk == blk1 && checkpoint == 2) {
w = 3;
checkpoint = 3;
chenumm = true;
} else if (blk == blk1 && checkpoint == 3) {
w = 4;
checkpoint = 4;
chenumm = true;
} else if (blk == blk1 && checkpoint == 4) {
w = 5;
checkpoint = 5;
chenumm = true;
} else if (blk == blk1 && checkpoint == 5) {
w = 6;
checkpoint = 6;
chenumm = true;
}
}
// 给墙体绘画矩形用来判断是否与人发生碰撞
public void save(int x, int y, Graphics g) {
if (filesize > 0) {
GameBox gameBox = new GameBox();
gameBox.rect.x = x;
gameBox.rect.y = y;
gameBox.rect.width = 50;
gameBox.rect.height = 50;
rects.add(gameBox.rect);
filesize--;
}
g.setColor(Color.red);
g.drawRect(rect.x, rect.y, rect.width, rect.height);
}
int filesize = 0;
// 用于统计墙的个数以及终点的个数
public int[][] che(int check) {
switch (check) {
case 1:
for (int i = 0; i < box1.length; i++) {
for (int j = 0; j < box1[0].length; j++) {
if (box1[i][j] == 1) {
filesize++;
}
if (box1[i][j] == 3) {
blk++;
}
}
}
return box1;
case 2:
blk2.clear();
rects.clear();
for (int i = 0; i < box2.length; i++) {
for (int j = 0; j < box2[0].length; j++) {
if (box2[i][j] == 1) {
filesize++;
}
if (box2[i][j] == 3) {
blk++;
blk2.add((i + 1) * 10 + j);
}
}
}
return box2;
case 3:
rects.clear();
blk2.clear();
for (int i = 0; i < box3.length; i++) {
for (int j = 0; j < box3[0].length; j++) {
if (box3[i][j] == 1) {
filesize++;
}
if (box3[i][j] == 3) {
blk++;
blk2.add((i + 1) * 10 + j);
}
}
}
return box3;
case 4:
rects.clear();
blk2.clear();
for (int i = 0; i < box4.length; i++) {
for (int j = 0; j < box4[0].length; j++) {
if (box4[i][j] == 1) {
filesize++;
}
if (box4[i][j] == 3) {
blk++;
blk2.add((i + 1) * 10 + j);
}
}
}
return box4;
case 5:
rects.clear();
blk2.clear();
for (int i = 0; i < box5.length; i++) {
for (int j = 0; j < box5[0].length; j++) {
if (box5[i][j] == 1) {
filesize++;
}
if (box5[i][j] == 3) {
blk++;
blk2.add((i + 1) * 10 + j);
}
}
}
return box5;
}
return null;
}
// 用于判断人物是否与墙体发生碰撞,如发生人物就不动
public void coll(GamePeople gamePeople) {
for (int i = 0; i < rects.size(); i++) {
Rectangle rectangle = rects.get(i);
if (gamePeople.rect.intersects(rectangle)) {
if (gamePeople.up2) {
gamePeople.y += 50;
} else if (gamePeople.down2) {
gamePeople.y -= 50;
} else if (gamePeople.left2) {
gamePeople.x += 50;
} else if (gamePeople.right2) {
gamePeople.x -= 50;
}
}
}
}
6.游戏目录
通过文件读写来判断用户上次的游戏是进行到了哪一关,通过文件的修改来重新开始游戏。
关键代码:
public class GameList extends JFrame implements ActionListener {
// 登陆成功后的游戏目录
private JButton con = new JButton("继续游戏");
private JButton back = new JButton("重新开始");
private JButton exit = new JButton("退出");
private JFrame a = new JFrame();
private String ac;
private int n;
public GameList(String ac, int n) {
this.ac = ac;
this.n = n;
// 目录界面
a.add(con);
a.add(back);
a.add(exit);
a.setLayout(new FlowLayout());
a.setSize(50, 150);
a.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
a.setLocationRelativeTo(null);
a.setResizable(false);
a.setVisible(true);
con.addActionListener(this);
back.addActionListener(this);
exit.addActionListener(this);
}
// 事件监听器,对照着目录界面的三种按钮
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == con) {
a.dispose();
new GameFrame(this.ac, this.n);
}
if (e.getSource() == back) {
a.dispose();
List<String> lines = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new FileReader("关卡.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
lines.add(line);
}
} catch (IOException e2) {
e2.printStackTrace();
}
for (int i = 0; i < lines.size(); i++) {
String[] parts = lines.get(i).split(" ");
if (parts.length == 2 && parts[0].equals(this.ac)) {
parts[1] = String.valueOf(1);
lines.set(i, parts[0] + " " + parts[1]);
break;
}
}
try (BufferedWriter writer = new BufferedWriter(new FileWriter("关卡.txt"))) {
for (String line : lines) {
writer.write(line);
writer.newLine();
}
} catch (IOException e1) {
e1.printStackTrace();
}
this.n = 1;
new GameFrame(this.ac, this.n);
}
}
}
三、游戏的运行
首先进入登陆界面:
如没有账户则点击注册按钮进入注册界面:
账号已存在或者密码确认有误会弹窗并且重新注册:
注册成功后可重新登陆:
登陆成功进入游戏目录:
继续游戏则从上次完成的关卡继续,重新开始则从第一关开始,新注册的用户只能从第一关开始:
如果游戏进入死局可以点击菜单栏中的重新开始,重新本关游戏:
完成本关后会提示消息,并且创建一个小窗口询问是否下一关或者重新本关或退出:
当全部通关时会出现消息:
四、小结
通过这次java课设,我明白了Java程序设计具有广泛的应用领域和强大的功能,可以帮助我们实现各种类型的应用程序开发。通过学习和掌握Java程序设计,我们可以更好地实现代码的重用和模块化,提高代码的可维护性和可扩展性。