UE4 GameInstance/GameMode/GameState/PlayerController/PlayerState/Pawn和Character

博客内容提及用于面试,但未给出更多信息技术相关关键信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

面试用

<think>我们将在之前的2048控制台版基础上添加游戏状态的保存加载功能。 保存功能:将当前游戏状态(包括棋盘、当前分数、最高分)保存到文件中。 加载功能:从文件中读取保存的游戏状态,并恢复游戏。 设计思路: 1. 定义保存游戏状态的数据结构(可以使用一个类,包含棋盘、当前分数、最高分) 2. 实现保存状态到文件的方法(使用对象序列化) 3. 实现从文件加载状态的方法(使用对象反序列化) 4. 修改主菜单,添加保存加载选项(在游戏运行过程中也可以保存,但为了简化,我们在主菜单中添加加载功能,在游戏过程中添加保存命令) 考虑到控制台游戏的特性,我们可以在游戏过程中通过输入特定命令(如"S")来保存当前游戏状态,并在游戏开始时提供加载存档的选项。 具体修改: 1. 创建一个可序列化的类(GameState)来保存游戏状态(包括棋盘、当前分数、最高分)。 2. 在游戏类中添加保存加载的方法。 3. 修改游戏主循环,增加保存命令(例如,输入"S"保存当前游戏)。 4. 在游戏启动时,询问玩家是否加载存档。 注意:由于我们之前已经实现了最高分记录,并且最高分是单独保存的,但这里为了存档的完整性,我们将当前游戏状态中的最高分也保存(注意:加载存档时,如果存档中的最高分高于之前保存的最高分,那么应该更新最高分吗?实际上,我们保存的最高分应该是全局最高分,所以我们在存档中保存最高分,加载时恢复这个最高分,并覆盖当前内存中的最高分。同时,在游戏结束时,我们仍然会将最高分保存到最高分文件中,所以这样是合理的)。 但是,我们也要注意:最高分文件(2048_highscore.dat)保存的是历史最高分,而存档中的最高分可能是当时的历史最高分。当我们加载存档时,应该将存档中的最高分当前最高分文件中的最高分进行比较,取最大值作为当前最高分?实际上,为了简单,我们可以在存档中只保存当前游戏的状态,包括最高分(即存档时的最高分),然后加载存档后,将最高分设置为存档中的最高分。同时,在游戏过程中如果打破了记录,我们会更新这个最高分,并在游戏结束时保存到最高分文件中。 另一种做法:存档中不保存最高分,而是只保存棋盘当前分数,最高分仍然独立维护(从最高分文件中读取,并实时更新)。这样加载存档后,最高分还是从文件读取的,不会因为加载一个旧的存档而覆盖了最新的最高分。这样更合理,因为最高分是全局的,不应该因为加载一个存档而降低。 我们采用第二种做法:存档中只保存棋盘当前分数,不保存最高分。最高分仍然独立维护(从文件读取保存)。 因此,保存的GameState类只需要包含: - board: 当前棋盘 - currentScore: 当前分数 最高分(highScore)不保存在存档中,而是单独保存在最高分文件中。 修改计划: 1. 创建GameState类(实现Serializable)用于保存棋盘当前分数。 2. 在EnhancedConsole2048类中添加两个方法: - saveGameState(String filename): 将当前棋盘当前分数保存到文件 - loadGameState(String filename): 从文件加载棋盘当前分数,并更新当前游戏状态(注意:加载后最高分不变,仍然是之前加载的全局最高分) 3. 修改游戏主循环,增加保存命令(例如,输入"S"保存游戏,并提示用户输入文件名?或者我们固定一个文件名?为了简单,我们可以固定一个存档文件名,比如"2048_save.dat") 4. 在游戏启动时,询问用户是否加载存档(比如,在开始游戏前,提示用户按'L'加载存档,按其他键开始新游戏) 但是,控制台游戏一般是命令行操作,我们可以这样设计: - 启动游戏后,显示一个简单的菜单: 1. 新游戏 2. 加载存档 3. 退出 5. 修改主方法,实现这个菜单。 由于时间关系,我们简化设计: - 在游戏开始时,询问用户是否加载存档(输入"load"来加载,或者按回车开始新游戏) - 在游戏过程中,输入"S"保存游戏(保存到固定文件,比如"2048_save.dat") 步骤: 1. 定义GameState类(可序列化) 2. 在EnhancedConsole2048类中添加保存加载方法 3. 修改main方法,在游戏开始前询问是否加载 4. 在游戏主循环中增加保存命令(S) 注意:由于我们之前已经有一个最高分文件,现在又有一个存档文件,所以需要两个不同的文件。 存档文件:2048_save.dat 代码修改如下:</think># Java 2048 控制台版 - 游戏状态保存与加载功能实现 我将为Java 2048控制台版添加游戏状态保存加载功能,允许玩家保存当前游戏进度并在之后继续游戏。以下是完整实现方案: ## 完整代码实现 ```java import java.io.*; import java.util.*; public class EnhancedConsole2048WithSave { private static final int SIZE = 4; private int[][] board; private int currentScore; private int highScore; private boolean moved; private final Random random; private static final Scanner scanner = new Scanner(System.in); // 用于撤销功能的栈 private LinkedList<GameState> historyStack; private static final int MAX_UNDO_STEPS = 10; // 用于保存最高分的文件 private static final String HIGH_SCORE_FILE = "2048_highscore.dat"; // 用于保存游戏状态的文件 private static final String SAVE_FILE = "2048_save.dat"; // 游戏状态类(用于撤销功能存档) private static class GameState implements Serializable { int[][] board; int score; int highScore; GameState(int[][] board, int score, int highScore) { this.board = new int[SIZE][SIZE]; for (int i = 0; i < SIZE; i++) { System.arraycopy(board[i], 0, this.board[i], 0, SIZE); } this.score = score; this.highScore = highScore; } } public EnhancedConsole2048WithSave() { board = new int[SIZE][SIZE]; random = new Random(); historyStack = new LinkedList<>(); // 从文件加载最高分 highScore = loadHighScore(); initializeBoard(); } // 初始化游戏板 private void initializeBoard() { for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { board[i][j] = 0; } } currentScore = 0; } // 在空白位置添加随机数字 private void addRandomTile() { int emptySpots = 0; for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { if (board[i][j] == 0) emptySpots++; } } if (emptySpots == 0) return; int position = random.nextInt(emptySpots); int value = random.nextDouble() < 0.9 ? 2 : 4; int count = 0; for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { if (board[i][j] == 0) { if (count == position) { board[i][j] = value; return; } count++; } } } } // 打印游戏板 public void printBoard() { System.out.println("\n当前分数: " + currentScore + " | 最高分: " + highScore); for (int i = 0; i < SIZE; i++) { System.out.println("+----+----+----+----+"); for (int j = 0; j < SIZE; j++) { System.out.print("|"); if (board[i][j] == 0) { System.out.print(" "); } else { System.out.printf("%4d", board[i][j]); } } System.out.println("|"); } System.out.println("+----+----+----+----+"); } // 保存当前游戏状态(用于撤销功能) private void saveCurrentState() { // 限制历史记录大小 if (historyStack.size() >= MAX_UNDO_STEPS) { historyStack.removeFirst(); // 移除最旧的状态 } historyStack.addLast(new GameState(board, currentScore, highScore)); } // 撤销上一步操作 private void undoMove() { if (historyStack.isEmpty()) { System.out.println("无法撤销,已回到初始状态!"); return; } GameState previousState = historyStack.removeLast(); for (int i = 0; i < SIZE; i++) { System.arraycopy(previousState.board[i], 0, board[i], 0, SIZE); } currentScore = previousState.score; System.out.println("已撤销上一步操作!"); } // 向左移动 private void moveLeft() { moved = false; for (int i = 0; i < SIZE; i++) { // 1. 移除空格 int[] newRow = new int[SIZE]; int index = 0; for (int j = 0; j < SIZE; j++) { if (board[i][j] != 0) { newRow[index++] = board[i][j]; } } // 2. 合并相同数字 for (int j = 0; j < SIZE - 1; j++) { if (newRow[j] != 0 && newRow[j] == newRow[j + 1]) { newRow[j] *= 2; currentScore += newRow[j]; // 更新最高分 if (currentScore > highScore) { highScore = currentScore; } newRow[j + 1] = 0; moved = true; } } // 3. 再次移除空格 int[] finalRow = new int[SIZE]; index = 0; for (int j = 0; j < SIZE; j++) { if (newRow[j] != 0) { finalRow[index++] = newRow[j]; } } // 4. 检查是否移动 for (int j = 0; j < SIZE; j++) { if (board[i][j] != finalRow[j]) { moved = true; } board[i][j] = finalRow[j]; } } } // 旋转矩阵90度(顺时针) private void rotateBoard() { int[][] rotated = new int[SIZE][SIZE]; for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { rotated[i][j] = board[SIZE - 1 - j][i]; } } board = rotated; } // 通用移动方法 private void move(int direction) { // 0: 左, 1: 上, 2: 右, 3: 下 int rotations = direction; for (int i = 0; i < rotations; i++) { rotateBoard(); } moveLeft(); for (int i = 0; i < (4 - rotations) % 4; i++) { rotateBoard(); } } // 检查游戏是否胜利 public boolean hasWon() { for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { if (board[i][j] == 2048) { return true; } } } return false; } // 检查游戏是否结束 public boolean isGameOver() { // 检查是否有空格 for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { if (board[i][j] == 0) { return false; } } } // 检查水平方向是否有可合并的 for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE - 1; j++) { if (board[i][j] == board[i][j + 1]) { return false; } } } // 检查垂直方向是否有可合并的 for (int j = 0; j < SIZE; j++) { for (int i = 0; i < SIZE - 1; i++) { if (board[i][j] == board[i + 1][j]) { return false; } } } return true; } // 保存最高分到文件 private void saveHighScore() { try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(HIGH_SCORE_FILE))) { oos.writeInt(highScore); } catch (IOException e) { System.out.println("保存最高分失败: " + e.getMessage()); } } // 从文件加载最高分 private int loadHighScore() { File file = new File(HIGH_SCORE_FILE); if (!file.exists()) { return 0; } try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) { return ois.readInt(); } catch (IOException e) { System.out.println("加载最高分失败: " + e.getMessage()); return 0; } } // 保存游戏状态到文件 public void saveGameState() { try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(SAVE_FILE))) { GameState state = new GameState(board, currentScore, highScore); oos.writeObject(state); System.out.println("游戏状态已保存!"); } catch (IOException e) { System.out.println("保存游戏状态失败: " + e.getMessage()); } } // 从文件加载游戏状态 public boolean loadGameState() { File file = new File(SAVE_FILE); if (!file.exists()) { System.out.println("没有找到保存的游戏状态"); return false; } try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) { GameState state = (GameState) ois.readObject(); for (int i = 0; i < SIZE; i++) { System.arraycopy(state.board[i], 0, board[i], 0, SIZE); } currentScore = state.score; highScore = state.highScore; System.out.println("游戏状态已加载!"); return true; } catch (IOException | ClassNotFoundException e) { System.out.println("加载游戏状态失败: " + e.getMessage()); return false; } } // 显示主菜单 private void showMainMenu() { System.out.println("===== 2048 游戏 ====="); System.out.println("1. 新游戏"); System.out.println("2. 继续游戏"); System.out.println("3. 退出"); System.out.print("请选择: "); } // 初始化新游戏 private void startNewGame() { initializeBoard(); addRandomTile(); addRandomTile(); play(); } // 继续游戏 private void continueGame() { if (loadGameState()) { play(); } else { System.out.println("开始新游戏..."); startNewGame(); } } // 游戏主循环 public void play() { printBoard(); System.out.println("控制说明: W(上), A(左), S(下), D(右), U(撤销), S(保存), Q(退出)"); while (true) { System.out.print("请输入操作: "); String input = scanner.nextLine().trim().toLowerCase(); if (input.equals("q")) { saveHighScore(); System.out.println("游戏结束!最终分数: " + currentScore + " | 最高分: " + highScore); break; } if (input.equals("u")) { undoMove(); printBoard(); continue; } if (input.equals("s")) { saveGameState(); continue; } int direction = -1; if (input.equals("a")) direction = 0; // 左 else if (input.equals("w")) direction = 1; // 上 else if (input.equals("d")) direction = 2; // 右 else if (input.equals("s")) direction = 3; // 下 if (direction != -1) { // 保存当前状态(用于撤销) saveCurrentState(); move(direction); if (moved) { addRandomTile(); } printBoard(); if (hasWon()) { saveHighScore(); System.out.println("恭喜!你赢得了游戏!最终分数: " + currentScore); break; } if (isGameOver()) { saveHighScore(); System.out.println("游戏结束!没有可移动的方块了。最终分数: " + currentScore); break; } } else { System.out.println("无效输入!请使用: W(上), A(左), S(下), D(右), U(撤销), S(保存), Q(退出)"); } } } public static void main(String[] args) { EnhancedConsole2048WithSave game = new EnhancedConsole2048WithSave(); while (true) { game.showMainMenu(); String choice = game.scanner.nextLine().trim(); switch (choice) { case "1": game.startNewGame(); break; case "2": game.continueGame(); break; case "3": System.out.println("感谢游玩!"); return; default: System.out.println("无效选择,请重新输入!"); } } } } ``` ## 新增功能说明 ### 1. 游戏状态保存与加载功能 **实现方式:** - 使用Java序列化机制保存加载游戏状态 - 创建可序列化的`GameState`类保存棋盘、当前分数最高分 - 添加`saveGameState()``loadGameState()`方法处理存档操作 - 使用固定文件名`2048_save.dat`存储游戏状态 **关键代码:** ```java // 保存游戏状态到文件 public void saveGameState() { try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(SAVE_FILE))) { GameState state = new GameState(board, currentScore, highScore); oos.writeObject(state); System.out.println("游戏状态已保存!"); } catch (IOException e) { System.out.println("保存游戏状态失败: " + e.getMessage()); } } // 从文件加载游戏状态 public boolean loadGameState() { File file = new File(SAVE_FILE); if (!file.exists()) { System.out.println("没有找到保存的游戏状态"); return false; } try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) { GameState state = (GameState) ois.readObject(); for (int i = 0; i < SIZE; i++) { System.arraycopy(state.board[i], 0, board[i], 0, SIZE); } currentScore = state.score; highScore = state.highScore; System.out.println("游戏状态已加载!"); return true; } catch (IOException | ClassNotFoundException e) { System.out.println("加载游戏状态失败: " + e.getMessage()); return false; } } ``` ### 2. 主菜单系统 **实现方式:** - 添加主菜单界面提供"新游戏"、"继续游戏""退出"选项 - 重构游戏启动流程,分离初始化游戏循环 - 添加`showMainMenu()`方法显示菜单选项 **关键代码:** ```java // 显示主菜单 private void showMainMenu() { System.out.println("===== 2048 游戏 ====="); System.out.println("1. 新游戏"); System.out.println("2. 继续游戏"); System.out.println("3. 退出"); System.out.print("请选择: "); } // 主程序入口 public static void main(String[] args) { EnhancedConsole2048WithSave game = new EnhancedConsole2048WithSave(); while (true) { game.showMainMenu(); String choice = game.scanner.nextLine().trim(); switch (choice) { case "1": game.startNewGame(); break; case "2": game.continueGame(); break; case "3": System.out.println("感谢游玩!"); return; default: System.out.println("无效选择,请重新输入!"); } } } ``` ### 3. 游戏内保存功能 **实现方式:** - 在游戏主循环中添加"S"命令用于保存当前游戏状态 - 保存后游戏继续运行,不影响当前进度 - 玩家可以随时保存游戏进度 **关键代码:** ```java // 在游戏主循环中添加保存功能 if (input.equals("s")) { saveGameState(); continue; } ``` ## 使用说明 1. **启动游戏:** - 运行程序后显示主菜单 - 选择"1. 新游戏"开始新游戏 - 选择"2. 继续游戏"加载上次保存的游戏状态 - 选择"3. 退出"结束游戏 2. **游戏内操作:** - W: 向上移动 - A: 向左移动 - S: 向下移动 - D: 向右移动 - U: 撤销上一步操作 - S: 保存当前游戏状态 - Q: 退出游戏 3. **存档功能:** - 游戏状态保存在`2048_save.dat`文件中 - 每次保存会覆盖之前的存档 - 游戏退出后可以继续之前的进度 ## 技术原理 1. **Java序列化机制:** - 使用`ObjectOutputStream`将游戏状态对象序列化为字节流 - 使用`ObjectInputStream`从字节流反序列化恢复对象 - 需要实现`Serializable`接口标记可序列化 2. **游戏状态管理:** - `GameState`类封装棋盘、当前分数最高分 - 深度复制棋盘数据确保状态完整性 - 处理文件不存在反序列化异常情况 3. **游戏生命周期:** - 分离游戏初始化、菜单显示游戏主循环 - 提供清晰的用户界面引导操作 - 合理处理游戏状态转换 ## 扩展建议 1. **多存档槽位:** - 允许玩家创建多个存档 - 添加存档命名功能 - 实现存档列表管理界面 2. **自动保存功能:** - 每N步自动保存游戏状态 - 退出时自动保存当前进度 - 添加"自动保存"配置选项 3. **存档加密:** - 添加简单加密防止存档被篡改 - 使用校验验证存档完整性 - 实现存档版本兼容性检查 4. **云存档功能:** - 支持将存档保存到云端 - 实现跨设备游戏进度同步 - 添加用户账户系统 ## 运行说明 1. 将代码保存为`EnhancedConsole2048WithSave.java` 2. 编译:`javac EnhancedConsole2048WithSave.java` 3. 运行:`java EnhancedConsole2048WithSave` 这个增强版2048游戏添加了实用的存档功能,玩家可以随时保存游戏进度并在之后继续游戏,大大提升了游戏体验[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值