【发布时间】:2017-10-08 05:34:37
【问题描述】:
我正在使用 Unity 创建一个简单的 2D 多人游戏,我选择使用 Firebase 作为后端。在尝试使用 Firebase Cloud 功能填满房间时,我遇到了一些问题。我计划它的工作方式如下:
- 玩家点击“加入房间”按钮
- 唯一的设备 ID 被发送到“玩家搜索房间”下的实时数据库,并且事件监听器被添加到该 ID
- “onWrite”事件发生时将触发云函数。然后函数将检查房间数组是否为空。如果房间数组为空,云函数会将新房间推送到实时数据库。
- 云功能在“玩家搜索房间”中将房间ID推送到玩家ID下
- 由于玩家已经在“玩家搜索房间”下监听自己的ID,当房间ID被推到自己的ID下时会运行一个函数。这将告诉玩家云功能已成功为他找到了房间。
下面是云功能:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
// Create and Deploy Your First Cloud Functions
// https://firebase.google.com/docs/functions/write-firebase-functions
var room = [];
// ID for the room we are filling at the moment
var room_currentID;
// This functions triggers each time something is added or deleted to "Players Searching For Room"
exports.findRoom = functions.database
.ref('/Players Searching For Room/{pushId}')
.onWrite(event => {
// Check if data exists (if not, this was triggered by delete -> return)
if(!event.data.exists())
{
return;
}
// If this player already has a room, we want to return
if(event.data.val().inRoom != "none")
return;
// Store data under changed pushId (if player was added to waiting players then data is -> "size" : 4)
const data = event.data.val();
// Name of the player. We get this from the pushId of the item we pushed ("container" for data pushed).
var name = event.params.pushId;
// Size of the room the player wants to join
var size = data.size;
// With IF-statements check which room_size_n object array we want to loop through
console.log("Player called " + name + " is waiting for room that has maxium of " + size + " players")
// We can push the user to the room array since it can never be full
// (we clear the array before allowing next guy to join)
room.push(name);
// If this was the first guy
// we need to create new room
if(room.length == 1)
{
admin.database().ref('/Rooms').push({
onGoing: false // We need to set something, might aswell set something usefull
}).then(snapshot => {
// because this function is triggered by changes in firebase realtime database
// we can't return anything to the player. BUT we can inform player about the room
// he's been attached to by adding roomID to the playername in the "Players Searching For Room"
// then players device will handle removing
// Store ID of the room so that we can send it to later joiners in this room
room_currentID = snapshot.key;
data.inRoom = room_currentID;
return event.data.ref.set(data);
});
}
// If there already exists a suitable room with space on it
else if(room.length > 1)
{
// We can attach the stored roomID to the player so he knows which rooms onGoing flag to watch for.
data.inRoom = room_currentID;
// Attach roomID to the player and then check if room is full
// waiting roomID to attach to player before setting onGoing TRUE
// prevents other player to get a head start
event.data.ref.set(data).then(snapshot => {
// If roomId was attached to the player we can check the room size
if(room.length == size)
{
// ...and if the room became full we need to set onGoing to true
admin.database().ref('/Rooms/'+room_currentID).set({
onGoing: true
}).then(snapshot => {
room = [];
});
}
});
}
});
问题是,如果多个用户在短时间内点击Join Game-button,则会导致系统混乱。在“搜索房间的玩家”下添加玩家 ID 似乎每次都有效,但有时 Cloud 功能从不将房间 ID 附加到玩家 ID,有时 Cloud 功能会创建比应有的更多房间。我只是通过在每次单击“玩家搜索房间”下附加随机 ID 的按钮来测试这一点。然后我迅速点击了那个按钮 10 次。那应该将 5 个不同的房间 ID 附加到这 10 个随机 ID 上,并生成 5 个新房间。相反,它生成了 7 个房间并将房间 ID 添加到仅 8 个随机 ID 而不是 10 个。
问题是,我认为:
- Abe 在 12.00.00 点击加入游戏按钮
- 云功能启动(执行需要 5 秒)
- Rob 在 12.00.02 点击加入游戏按钮
- 在完成 Abe 的请求之前再次触发云功能
- 一切都搞砸了
firebase 是否可以更改此设置,以便如果 Rob 在 Abe 的请求完成之前触发 Cloud 功能,Rob 将在 Abe 完成时被搁置。当安倍完成时,轮到罗布了。呃,非常长的解释希望有人会读到这个:)
【问题讨论】:
-
您需要使用事务来维护数据库中游戏的一致状态。详细说明这一点可能比这里的答案更复杂。
-
你能给我一些教程视频或API链接吗?我似乎无法找到有关交易的任何信息,甚至从 Firebase API 也找不到(或者我可能只是错过了它)。
标签: firebase google-cloud-functions