Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions messages.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

# Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
# Click nbfs://nbhost/SystemFileSystem/Templates/Other/properties.properties to edit this template


25 changes: 25 additions & 0 deletions resources/messages.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

# Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
# Click nbfs://nbhost/SystemFileSystem/Templates/Other/properties.properties to edit this template

# Mainframe.java
mainframe.closing.animating=\u8bf7\u7b49\u5f85\u5f53\u524d\u79fb\u52a8\u52a8\u753b\u7ed3\u675f
mainframe.closing.confirm.save=\u662f\u5426\u4fdd\u5b58\u6e38\u620f\uff1f
mainframe.closing.confirm.exit=\u9000\u51fa\u6e38\u620f
dialog.loadaudio=\u8df3\u8fc7\u7f3a\u5931\u7684\u80cc\u666f\u97f3\u4e50:

# AISolveCoordinator
aisolve.stop=\u505c\u6b62\u63a8\u6f14

label.username=\u7528\u6237\u540d
label.password=\u5bc6\u7801
button.login=\u767b\u5f55
button.register=\u6ce8\u518c
button.guest=\u6e38\u5ba2\u767b\u5f55
dialog.emptyfield=\u7528\u6237\u540d\u6216\u5bc6\u7801\u4e0d\u80fd\u4e3a\u7a7a
dialog.syntax=\u7528\u6237\u540d\u53ea\u80fd\u5305\u542b\u6570\u5b57\u3001\u6c49\u5b57\u548c\u5927\u5c0f\u5199\u5b57\u6bcd\\n\u5bc6\u7801\u53ea\u80fd\u5305\u542b\u6570\u5b57\u548c\u5927\u5c0f\u5199\u5b57\u6bcd
dialog.invalid_login=\u7528\u6237\u540d\u6216\u5bc6\u7801\u9519\u8bef
dialog.fail_login=\u8bfb\u53d6\u73a9\u5bb6\u6570\u636e\u5931\u8d25\uff1a
dialog.register_success=\u672c\u5730\u73a9\u5bb6\u521b\u5efa\u6210\u529f
dialog.register_taken=\u8be5\u7528\u6237\u540d\u5df2\u88ab\u6ce8\u518c
dialog.register_fail=\u4fdd\u5b58\u73a9\u5bb6\u6570\u636e\u5931\u8d25\uff1a
25 changes: 25 additions & 0 deletions resources/messages_en.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

# Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
# Click nbfs://nbhost/SystemFileSystem/Templates/Other/properties.properties to edit this template


# Mainframe.java
mainframe.closing.animating=Please wait for the current animation to finish.
mainframe.closing.confirm.save=Save
mainframe.closing.confirm.exit=Exit
dialog.loadaudio=Skipping missing background music:

# AISolveCoordinator
aisolve.stop=\u505c\u6b62\u63a8\u6f14
label.username=username
label.password=password
button.login=login
button.register=register
button.guest=guest login
dialog.emptyfield=Username or password cannot be empty.
dialog.syntax=Usernames may only contain numbers, Chinese characters, and uppercase and lowercase letters.\\nPasswords may only contain numbers and uppercase and lowercase letters.
dialog.invalid_login=Incorrect username or password
dialog.fail_login=Failed to load player data
dialog.register_success=Local player successfully created
dialog.register_taken=This username has already been registered
dialog.register_fail=Failed to save player data:
25 changes: 25 additions & 0 deletions resources/messages_zh_CN.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

# Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
# Click nbfs://nbhost/SystemFileSystem/Templates/Other/properties.properties to edit this template


# Mainframe.java
mainframe.closing.animating=\u8bf7\u7b49\u5f85\u5f53\u524d\u79fb\u52a8\u52a8\u753b\u7ed3\u675f
mainframe.closing.confirm.save=\u662f\u5426\u4fdd\u5b58\u6e38\u620f\uff1f
mainframe.closing.confirm.exit=\u9000\u51fa\u6e38\u620f
dialog.loadaudio=\u8df3\u8fc7\u7f3a\u5931\u7684\u80cc\u666f\u97f3\u4e50:

# AISolveCoordinator
aisolve.stop=\u505c\u6b62\u63a8\u6f14
label.username=\u7528\u6237\u540d
label.password=\u5bc6\u7801
button.login=\u767b\u5f55
button.register=\u6ce8\u518c
button.guest=\u6e38\u5ba2\u767b\u5f55
dialog.emptyfield=\u7528\u6237\u540d\u6216\u5bc6\u7801\u4e0d\u80fd\u4e3a\u7a7a
dialog.syntax=\u7528\u6237\u540d\u53ea\u80fd\u5305\u542b\u6570\u5b57\u3001\u6c49\u5b57\u548c\u5927\u5c0f\u5199\u5b57\u6bcd\\n\u5bc6\u7801\u53ea\u80fd\u5305\u542b\u6570\u5b57\u548c\u5927\u5c0f\u5199\u5b57\u6bcd
dialog.invalid_login=\u7528\u6237\u540d\u6216\u5bc6\u7801\u9519\u8bef
dialog.fail_login=\u8bfb\u53d6\u73a9\u5bb6\u6570\u636e\u5931\u8d25\uff1a
dialog.register_success=\u672c\u5730\u73a9\u5bb6\u521b\u5efa\u6210\u529f
dialog.register_taken=\u8be5\u7528\u6237\u540d\u5df2\u88ab\u6ce8\u518c
dialog.register_fail=\u4fdd\u5b58\u73a9\u5bb6\u6570\u636e\u5931\u8d25\uff1a
8 changes: 8 additions & 0 deletions src/main/java/Main.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import java.util.Locale;
import view.MainFrame;

import javax.swing.*;
import util.AppResources;

// 游戏的主类,负责启动游戏
public class Main {
public static void main(String[] args) {
for (String arg : args) {
if (arg.equals("en")) {
AppResources.setLocale(Locale.ENGLISH);
}
}

SwingUtilities.invokeLater(() -> new MainFrame(1532, 864).setVisible(true));
}
}
19 changes: 19 additions & 0 deletions src/main/java/util/AppResources.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;

/** Resolves bundled resources both from the classpath/JAR and a source checkout. */
public final class AppResources {
private static ResourceBundle messageBundle =
ResourceBundle.getBundle("resources/messages", Locale.SIMPLIFIED_CHINESE);

private AppResources() {
}

Expand Down Expand Up @@ -36,4 +42,17 @@ public static URL url(String path) {
public static ImageIcon icon(String path) {
return new ImageIcon(url(path));
}

public static void setLocale(Locale locale) {
messageBundle = ResourceBundle.getBundle("resources/messages", locale);
}

public static String get(String key) {
return messageBundle.getString(key);
}

// For strings with placeholders like {0}
public static String get(String key, Object... args) {
return MessageFormat.format(messageBundle.getString(key), args);
}
}
13 changes: 10 additions & 3 deletions src/main/java/view/MainFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

// 游戏的主窗口,负责显示登录界面和游戏控制面板
public class MainFrame extends JFrame implements WindowListener {
Expand Down Expand Up @@ -73,10 +74,16 @@ public void windowOpened(WindowEvent e) {
public void windowClosing(WindowEvent e) {
if (controlPanel != null && controlPanel.isVisible() && controlPanel.controller != null && controlPanel.controller.user != null) {
if (controlPanel.controller.isAnimating()) {
JOptionPane.showMessageDialog(this, "请等待当前移动动画结束");
JOptionPane.showMessageDialog(this, AppResources.get("mainframe.closing.animating"));
return;
}
int choice = JOptionPane.showConfirmDialog(this, "是否保存游戏?", "退出游戏", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
int choice = JOptionPane.showConfirmDialog(
this,
AppResources.get("mainframe.closing.confirm.save"),
AppResources.get("mainframe.closing.confirm.exit"),
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE
);
if (JOptionPane.YES_OPTION == choice) {
controlPanel.controller.saveGame();
exitApplication();
Expand Down Expand Up @@ -144,7 +151,7 @@ private List<URL> loadAudioFiles() {
try {
audioResources.add(AppResources.url(path));
} catch (IllegalArgumentException exception) {
System.out.println("跳过缺失的背景音乐: " + path);
System.out.println(AppResources.get("dialog.loadaudio") + path);
}
}
return audioResources;
Expand Down
24 changes: 12 additions & 12 deletions src/main/java/view/login/LoginPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,16 @@ public LoginPanel(MainFrame mainFrame, int width, int height) {
// 创建用户名和密码输入框
username = ViewUtil.createJTextField(contentPanel, new Point(width / 2 - 40, height / 2 - 100), 160, 30);
password = ViewUtil.createJPasswordField(contentPanel, new Point(width / 2 - 40, height / 2 - 50), 160, 30);
ViewUtil.createJLabel(contentPanel, new Point(width / 2 - 110, height / 2 - 100), 70, 30, 16, "用户名:"); // 用户名标签
ViewUtil.createJLabel(contentPanel, new Point(width / 2 - 110, height / 2 - 50), 70, 30, 16, "密码:"); // 密码标签
ViewUtil.createJLabel(contentPanel, new Point(width / 2 - 110, height / 2 - 100), 70, 30, 16, AppResources.get("label.username").concat(":")); // 用户名标签
ViewUtil.createJLabel(contentPanel, new Point(width / 2 - 110, height / 2 - 50), 70, 30, 16, AppResources.get("label.password").concat(":")); // 密码标签
ViewUtil.createJLabel(contentPanel, new Point(width / 2 - 110, height / 2 - 300), 240, 120, 60, "华 容 道"); // 游戏标题

// 登录注册按钮
Color btnColor = new Color(139, 69, 19); // 按钮颜色
Font btnFont = new Font("楷体", Font.PLAIN, 16); // 按钮字体
JButton loginBtn = ViewUtil.createStyledButton(contentPanel, "登录", new Point(width / 2 - 80, height / 2 + 30), 80, 30, btnColor, btnFont);
JButton registerBtn = ViewUtil.createStyledButton(contentPanel, "注册", new Point(width / 2 + 20, height / 2 + 30), 80, 30, btnColor, btnFont);
JButton guestLoginBtn = ViewUtil.createStyledButton(contentPanel, "游客登录", new Point(width / 2 - 80, height / 2 + 80), 180, 32, btnColor, btnFont);
JButton loginBtn = ViewUtil.createStyledButton(contentPanel, AppResources.get("button.login"), new Point(width / 2 - 80, height / 2 + 30), 80, 30, btnColor, btnFont);
JButton registerBtn = ViewUtil.createStyledButton(contentPanel, AppResources.get("button.register"), new Point(width / 2 + 20, height / 2 + 30), 80, 30, btnColor, btnFont);
JButton guestLoginBtn = ViewUtil.createStyledButton(contentPanel, AppResources.get("button.guest"), new Point(width / 2 - 80, height / 2 + 80), 180, 32, btnColor, btnFont);
loginBtn.addActionListener(event -> handleLogin()); // 登录按钮事件
registerBtn.addActionListener(event -> handleRegister()); // 注册按钮事件
guestLoginBtn.addActionListener(event -> mainFrame.showControl(null)); // 游客登录事件
Expand All @@ -63,11 +63,11 @@ protected void paintComponent(Graphics graphics) {
// 验证用户名和密码
public boolean isValidCredentials(String user, String pass) {
if (user.isEmpty() || pass.isEmpty()) { // 检查是否为空
JOptionPane.showMessageDialog(this, "用户名或密码不能为空");
JOptionPane.showMessageDialog(this, AppResources.get("dialog.emptyfield"));
} else if (Pattern.matches("^[a-zA-Z0-9一-龥]+$", user) && Pattern.matches("^[a-zA-Z0-9]+$", pass)) {
return true; // 验证通过
} else {
JOptionPane.showMessageDialog(this, "用户名只能包含数字、汉字和大小写字母\n密码只能包含数字和大小写字母");
JOptionPane.showMessageDialog(this, AppResources.get("dialog.syntax"));
}
return false;
}
Expand All @@ -81,11 +81,11 @@ private void handleLogin() {
if (users != null && users.verify(user, pass)) {
mainFrame.showControl(user); // 显示控制面板
} else {
JOptionPane.showMessageDialog(this, "用户名或密码错误");
JOptionPane.showMessageDialog(this, AppResources.get("dialog.invalid_login"));
}
}
} catch (IOException exception) {
JOptionPane.showMessageDialog(this, "读取玩家数据失败:" + exception.getMessage());
JOptionPane.showMessageDialog(this, AppResources.get("dialog.fail_login") + exception.getMessage());
} finally {
Arrays.fill(pass, '\0');
}
Expand All @@ -98,14 +98,14 @@ private void handleRegister() {
try {
if (isValidCredentials(user, new String(pass))) {
if (users != null && users.register(user, pass)) {
JOptionPane.showMessageDialog(this, "本地玩家创建成功");
JOptionPane.showMessageDialog(this, AppResources.get("dialog.register_success"));
mainFrame.showControl(user);
} else {
JOptionPane.showMessageDialog(this, "该用户名已被注册");
JOptionPane.showMessageDialog(this, AppResources.get("dialog.register_taken"));
}
}
} catch (IOException exception) {
JOptionPane.showMessageDialog(this, "保存玩家数据失败:" + exception.getMessage());
JOptionPane.showMessageDialog(this, AppResources.get("dialog.register_fail") + exception.getMessage());
} finally {
Arrays.fill(pass, '\0');
}
Expand Down