Unity中从Firestore读取Map的实现方法:获取名为Statistics的Map数据
Hey there! I’ve tackled this exact problem multiple times when building Unity games with Firestore, so let me break down the process clearly for you.
Prerequisites
First, make sure you’ve got the basics sorted:
- The Firebase Firestore SDK is installed in your Unity project (via Package Manager or Firebase Console’s setup wizard).
- Firebase is initialized correctly in your project (you should have the
google-services.jsonfile in yourAssetsfolder for Android, orGoogleService-Info.plistfor iOS).
Step 1: Define a C# Class for Your Statistics Map
The cleanest way to work with Firestore Maps is to map them to a strongly-typed C# class. This makes your code type-safe and way easier to maintain.
Let’s say your Statistics map in Firestore has fields like total_score (number), play_time_hours (number), and total_wins (number). Here’s how to define the corresponding class:
using UnityEngine; using Firebase.Firestore; [Serializable] public class UserStatistics { // Use [FirestoreProperty] if your Firestore keys use snake_case (common in Firestore) [FirestoreProperty("total_score")] public int TotalScore { get; set; } [FirestoreProperty("play_time_hours")] public float PlayTimeHours { get; set; } [FirestoreProperty("total_wins")] public int TotalWins { get; set; } // If your Firestore keys match the C# property names exactly (e.g., "TotalScore"), // you can skip the [FirestoreProperty] attribute entirely }
Step 2: Fetch and Deserialize the Map Data
Firestore operations are asynchronous, so we’ll use async/await for clean code. Here’s a complete example of a MonoBehaviour that fetches the Statistics map:
using Firebase; using Firebase.Firestore; using UnityEngine; using System.Threading.Tasks; using System.Collections.Generic; public class StatsReader : MonoBehaviour { private FirebaseFirestore _firestoreDb; void Start() { // Initialize Firebase first FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(task => { if (task.Result == DependencyStatus.Available) { _firestoreDb = FirebaseFirestore.DefaultInstance; Debug.Log("Firebase ready to go!"); // Fetch stats for a specific user (replace with your user ID logic) FetchUserStats("player_456"); } else { Debug.LogError("Failed to initialize Firebase: " + task.Result); } }); } private async void FetchUserStats(string userId) { try { // Get reference to the user's document (adjust collection/document paths to match your setup) DocumentReference userDoc = _firestoreDb.Collection("players").Document(userId); DocumentSnapshot snapshot = await userDoc.GetSnapshotAsync(); if (snapshot.Exists) { // Method 1: Deserialize directly to your custom class (RECOMMENDED) UserStatistics stats = snapshot.GetValue<UserStatistics>("Statistics"); if (stats != null) { Debug.Log($"Loaded Stats: Score={stats.TotalScore}, Play Time={stats.PlayTimeHours}h, Wins={stats.TotalWins}"); // Use these stats in your game (e.g., update UI, save to player data) UpdateGameUI(stats); } else { Debug.LogWarning("Statistics field exists but couldn't be deserialized. Check field types!"); } // Method 2: Read as a Dictionary (for dynamic/unknown map structures) Dictionary<string, object> statsDict = snapshot.GetValue<Dictionary<string, object>>("Statistics"); if (statsDict != null) { foreach (var entry in statsDict) { Debug.Log($"Stats Entry: {entry.Key} = {entry.Value}"); } } } else { Debug.LogError($"User document {userId} doesn't exist in Firestore!"); } } catch (System.Exception ex) { Debug.LogError($"Error fetching stats: {ex.Message}"); } } // Example method to update your game's UI with the stats private void UpdateGameUI(UserStatistics stats) { // Replace with your actual UI logic // scoreText.text = stats.TotalScore.ToString(); // playTimeText.text = $"{stats.PlayTimeHours:F1}h"; } }
Key Notes & Troubleshooting
- Field Type Matching: Make sure the data types in your C# class match exactly what’s stored in Firestore. For example, a Firestore
Numbercan map toint,float, ordouble—but mismatches will cause deserialization failures. - Nested Maps: If your
Statisticsmap contains other nested maps, just create nested C# classes and mirror the structure. Firestore will handle deserializing nested objects automatically. - Main Thread Updates: If you’re updating UI elements with the fetched stats, remember that Firestore callbacks run on a background thread. Use
UnityMainThreadDispatcher(or wrap your UI code inUnityEngine.WaitForEndOfFrame) to switch back to the main thread. - Firestore Rules: Double-check your Firestore security rules to ensure your app has permission to read the document. If you get permission errors, adjust the rules temporarily for testing (but lock them down for production!).
内容的提问来源于stack exchange,提问作者MarlonDSC

