如何保存夺旗游戏排行榜数据,实现玩家重连后数据留存?
Hey there! Let's break down how to save and retain your CTF players' stats (points, flag captures) so they persist across game sessions—this is a straightforward tweak to your existing PlayerManager script, and I'll walk you through exactly what to modify.
First, pick a storage method that fits your game's scale:
- For simple, small datasets (like just points and flag captures), Unity's built-in
PlayerPrefsis perfect—it's easy to implement and works for most single-player/lan multiplayer scenarios. - If you ever expand to more complex stats later, you can switch to saving JSON files to the
PersistentDataPath(I'll cover both options below).
Step 1: Add a Serializable Player Stats Class
First, you need a structured way to store each player's data. Add this inside or outside your PlayerManager script (just make sure it's accessible):
[System.Serializable] public class PlayerStats { public string playerId; // Unique identifier (username, UUID, etc.—use whatever you're already tracking) public int totalPoints; public int flagCaptureCount; }
This class lets you serialize the data into a format that's easy to save and load (JSON works great here).
Step 2: Add Save/Load Methods to PlayerManager
Next, add methods to save and load these stats. Let's start with PlayerPrefs since it's simpler:
// Save a player's stats to PlayerPrefs private void SavePlayerStats(PlayerStats stats) { // Convert stats to a JSON string string statsJson = JsonUtility.ToJson(stats); // Store it with a unique key to avoid conflicts between players PlayerPrefs.SetString($"CTF_Player_{stats.playerId}", statsJson); PlayerPrefs.Save(); // Force immediate write to disk to avoid data loss } // Load a player's stats from PlayerPrefs (returns default values if no save exists) private PlayerStats LoadPlayerStats(string playerId) { string savedJson = PlayerPrefs.GetString($"CTF_Player_{playerId}", string.Empty); if (!string.IsNullOrEmpty(savedJson)) { return JsonUtility.FromJson<PlayerStats>(savedJson); } // Return fresh stats if no save is found return new PlayerStats { playerId = playerId, totalPoints = 0, flagCaptureCount = 0 }; }
If you want to use file storage (better for larger datasets or if you want editable save files), replace the above with these methods (add using System.IO; at the top of your script):
private string GetPlayerSavePath(string playerId) { // Use Unity's persistent data path (works reliably across all platforms) return Path.Combine(Application.persistentDataPath, $"CTF_Player_{playerId}.json"); } private void SavePlayerStatsToFile(PlayerStats stats) { string statsJson = JsonUtility.ToJson(stats, prettyPrint: true); File.WriteAllText(GetPlayerSavePath(stats.playerId), statsJson); } private PlayerStats LoadPlayerStatsFromFile(string playerId) { string savePath = GetPlayerSavePath(playerId); if (File.Exists(savePath)) { string savedJson = File.ReadAllText(savePath); return JsonUtility.FromJson<PlayerStats>(savedJson); } return new PlayerStats { playerId = playerId, totalPoints = 0, flagCaptureCount = 0 }; }
Step 3: Modify Player Join Logic
When a player joins your game, instead of initializing their stats to 0, load their saved data first. Update your existing player join method:
public void OnPlayerJoined(string playerId) { // Your existing join logic (spawn player, register in manager, etc.) // Load saved stats PlayerStats savedStats = LoadPlayerStats(playerId); // Or LoadPlayerStatsFromFile if using files // Update your current player tracking variables with the saved data // Assuming you have dictionaries like these in your PlayerManager: playerPointsDictionary[playerId] = savedStats.totalPoints; playerFlagCapturesDictionary[playerId] = savedStats.flagCaptureCount; // Refresh the leaderboard to show the saved stats immediately UpdateLeaderboard(); }
Step 4: Modify Flag Capture Trigger Logic
Whenever a player captures a flag and gains points, save their updated stats right away. Update your flag capture method:
public void OnFlagCaptured(string playerId) { // Your existing capture logic: increment points and capture count playerPointsDictionary[playerId] += 10; // Adjust point value to match your game's rules playerFlagCapturesDictionary[playerId] += 1; // Create a PlayerStats object with the updated data PlayerStats updatedStats = new PlayerStats { playerId = playerId, totalPoints = playerPointsDictionary[playerId], flagCaptureCount = playerFlagCapturesDictionary[playerId] }; // Save the updated stats SavePlayerStats(updatedStats); // Or SavePlayerStatsToFile if using files // Update the leaderboard to reflect the new stats UpdateLeaderboard(); }
Step 5: Optional - Save On Player Exit/Game Quit
To make sure data isn't lost if the player disconnects or quits unexpectedly, add a save call when the player leaves or the game closes:
// Call this when a player leaves the game public void OnPlayerLeft(string playerId) { // Your existing leave logic // Save their final stats PlayerStats finalStats = new PlayerStats { playerId = playerId, totalPoints = playerPointsDictionary[playerId], flagCaptureCount = playerFlagCapturesDictionary[playerId] }; SavePlayerStats(finalStats); } // Save all active players when the game quits (for single-player scenarios) private void OnApplicationQuit() { foreach (var playerId in playerPointsDictionary.Keys) { PlayerStats finalStats = new PlayerStats { playerId = playerId, totalPoints = playerPointsDictionary[playerId], flagCaptureCount = playerFlagCapturesDictionary[playerId] }; SavePlayerStats(finalStats); } }
Key Parts of PlayerManager You'll Modify:
- Add the
PlayerStatsserializable class to structure your save data. - Implement save/load methods (either
PlayerPrefsor file-based, depending on your needs). - Update player join logic to load saved stats instead of starting from 0.
- Modify flag capture logic to save stats immediately after updating them.
- Optional: Add exit/leave save triggers to prevent data loss during unexpected disconnects.
If you're working on a multiplayer game with a dedicated server, you'd want to store this data server-side instead of locally, but for most small-scale CTF games, the above local storage methods work perfectly.
内容的提问来源于stack exchange,提问作者AspaeringStar7

