如何在Unity中借助Firebase实时数据库实现在线状态检测?
嘿,这个需求我之前做多人游戏的时候刚好折腾过,用Firebase的实时数据库就能完美搞定在线/离线状态的实时同步,下面给你一步步拆解怎么在Unity里实现:
在Unity中用Firebase实现玩家在线/离线状态展示
1. 前置准备
- 确保你的Unity项目已经集成Firebase Authentication和Firebase Realtime Database(如果偏好Firestore也可以,不过实时数据库对状态同步的支持更直接)
- 每个玩家登录后会拿到唯一的
User ID,这是后续标识玩家身份的核心依据
2. 实现玩家在线状态自动上报
当玩家成功登录后,我们需要把他的在线状态写入数据库,并且利用Firebase的OnDisconnect特性,实现断开连接(包括退出游戏、网络中断)时自动标记为离线,不用手动处理各种异常场景。
核心代码示例(C#)
using Firebase; using Firebase.Auth; using Firebase.Database; using UnityEngine; public class PlayerPresenceManager : MonoBehaviour { private FirebaseAuth _auth; private FirebaseUser _currentUser; private DatabaseReference _playerPresenceRef; void Start() { // 初始化Firebase Auth并监听登录状态变化 _auth = FirebaseAuth.DefaultInstance; _auth.StateChanged += OnAuthStateChanged; OnAuthStateChanged(this, null); } void OnAuthStateChanged(object sender, System.EventArgs eventArgs) { if (_auth.CurrentUser != _currentUser) { bool isSignedIn = _currentUser != _auth.CurrentUser && _auth.CurrentUser != null; if (!isSignedIn && _currentUser != null) { Debug.Log("玩家已登出"); } _currentUser = _auth.CurrentUser; if (isSignedIn) { Debug.Log($"玩家 {_currentUser.UserId} 已登录"); SetupPresenceTracking(); } } } void SetupPresenceTracking() { // 指向数据库中存储玩家状态的节点,比如 /presences/{userId} _playerPresenceRef = FirebaseDatabase.DefaultInstance.GetReference($"presences/{_currentUser.UserId}"); // 先标记当前状态为在线 _playerPresenceRef.SetValueAsync(true); // 设置断开连接时自动将状态改为离线 _playerPresenceRef.OnDisconnect().SetValueAsync(false); } void OnDestroy() { if (_auth != null) { _auth.StateChanged -= OnAuthStateChanged; } // 主动登出时手动标记离线(可选,OnDisconnect也会处理) if (_currentUser != null && _playerPresenceRef != null) { _playerPresenceRef.SetValueAsync(false); } } }
3. 监听其他玩家的状态变化
接下来需要监听数据库中所有玩家的状态节点,实时获取在线/离线更新,然后同步到游戏UI上。
监听与UI更新代码示例
void StartListeningToPlayerPresences() { DatabaseReference presencesRoot = FirebaseDatabase.DefaultInstance.GetReference("presences"); // 监听所有玩家状态的变化(新增、修改、删除) presencesRoot.ValueChanged += (sender, args) => { if (args.DatabaseError != null) { Debug.LogError($"监听状态出错: {args.DatabaseError.Message}"); return; } // 遍历所有玩家的状态数据 foreach (var playerSnapshot in args.Snapshot.Children) { string userId = playerSnapshot.Key; bool isOnline = playerSnapshot.Value as bool? ?? false; // 这里可以根据userId拉取玩家的昵称、头像等信息(假设你有/user/{userId}节点存储这些数据) // 然后更新UI,比如给在线玩家头像加绿色标识,或者维护在线玩家列表 UpdatePlayerPresenceUI(userId, isOnline); } }; } // 示例:更新玩家状态UI的方法 void UpdatePlayerPresenceUI(string userId, bool isOnline) { // 假设你有一个字典存储玩家对应的UI元素,或者根据userId找到对应的UI对象 // PlayerStatusUI statusUI = PlayerUIMap[userId]; // statusUI.SetOnlineIndicator(isOnline); Debug.Log($"玩家 {userId} 当前状态: {(isOnline ? "在线" : "离线")}"); }
4. 实用优化建议
- 关联玩家信息:建议在数据库中单独创建
/users/{userId}节点存储玩家昵称、头像URL等信息,这样展示状态时可以显示真实玩家信息,而不是冷冰冰的ID - 权限控制:一定要在Firebase控制台设置数据库规则,避免恶意修改状态。示例规则:
{ "rules": { "presences": { "$userId": { ".read": true, ".write": "$userId === auth.uid" } }, "users": { "$userId": { ".read": true, ".write": "$userId === auth.uid" } } } }
- 网络异常处理:可以添加数据库连接状态监听,当网络恢复时重新同步状态,提升稳定性
- Firestore替代方案:如果用Firestore,可以用
FieldValue.ServerTimestamp()记录最后在线时间,通过判断时间差来识别在线状态,但实时性不如Realtime Database的OnDisconnect直接
内容的提问来源于stack exchange,提问作者Uzoigwe Clement Ikechukwu
相关产品推荐
相关产品推荐

