我一直在跟踪这个教程,并试图在游戏中添加第三个玩家。下面是为两位玩家工作的源代码。以下是我的数据结构:
"matchmaking" : {
"32idNK8OndcujN8CFNe3VBTxsXL2" : {
"gameId" : "placeholder"
},
"LnMnOtdLJYbsRuTeUpeHfaAhpX32" : {
"gameId" : "placeholder"
},
"plpISHWWtuNJvhSlFwfik6DOHR53" : {
"gameId" : "placeholder"
}
}我有一个云函数,每当用户加入婚介室时,都会调用它。根据可用的两个用户的不同,该功能为所有三个用户生成一个独特的游戏室。我对Javascript不太熟悉,所以我已经在这方面挣扎了一段时间。
如何在事务期间检索gameId值并将其分配给三个参与者?
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
var database = admin.database();
exports.matchmaker = functions.database.ref('matchmaking/{playerId}')
.onCreate((snap, context) => {
var gameId = generateGameId();
database.ref('matchmaking').once('value').then(snapshot => {
var secondPlayer = null;
var thirdPlayer = null;
// add two players into the queue
snapshot.forEach(child => { // check that its not the playerId who just joined
var playerId = child.key
var gameId = child.val().gameId
if (gameId === "placeholder" && playerId !== context.params.playerId) {
secondPlayer = child;
}
});
snapshot.forEach(child => { // check that its not the playerId who just joined
var playerId = child.key
var gameId = child.val().gameId
if (gameId === "placeholder" && playerId !== secondPlayer.key && playerId !== context.params.playerId) {
thirdPlayer = child;
}
});
if (secondPlayer === null || thirdPlayer === null) return null; // one room needs three players
database.ref("matchmaking").transaction(function (matchmaking) {
console.log(matchmaking)
// ================================================
// PROBLEM STARTS HERE
// ================================================
console.log("playerId gameId:",context.params.playerId.gameId) // returns undefined
// If any of the players gets into another game during the transaction, abort the operation
if (matchmaking === null ||
context.params.playerId.gameId !== "placeholder" ||
matchmaking[secondPlayer.key].gameId !== "placeholder" ||
matchmaking[thirdPlayer.key].gameId !== "placeholder") return matchmaking;
// matchmaking.forEach(player => { // check that its not the playerId that just joined
// var playerId = player.key
// var gameId = player.val().gameId
// if (gameId !== "placeholder") {
// player["gameId"] = gameId;
// }
// });
context.params.playerId.gameId = gameId; // assign game id to player
matchmaking[secondPlayer.key].gameId = gameId;
matchmaking[thirdPlayer.key].gameId = gameId;
return matchmaking;
}).then(result => {
if (result.snapshot.child(context.params.playerId).val() !== gameId) return;
// ENDS HERE
// ================================================
var game = {
gameInfo: {
gameId: gameId,
playersIds: [context.params.playerId, secondPlayer.key, thirdPlayer.key]
},
turn: context.params.playerId
}
database.ref("games/" + gameId).set(game).then(snapshot => {
console.log("Game created successfully!")
return null;
}).catch(error => {
console.log(error);
});
return null;
}).catch(error => {
console.log(error);
});
return null;
}).catch(error => {
console.log(error);
});
});
function generateGameId() {
var possibleChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var gameId = "";
for (var j = 0; j < 20; j++) gameId += possibleChars.charAt(Math.floor(Math.random() * possibleChars.length));
return gameId;
}我收到了一些错误,比如matchmaking.forEach is not a function、Cannot read property 'params' of undefined或Cannot read property 'val' of undefined
Console.log(婚介)显示如下:
{ '32idNK8OndcujN8CFNe3VBTxsXL2': { gameId: 'placeholder' },
LnMnOtdLJYbsRuTeUpeHfaAhpX32: { gameId: 'placeholder' },
plpISHWWtuNJvhSlFwfik6DOHR53: { gameId: 'placeholder' } } 我真的很感谢你的帮助。
更新:
解决方案:
database.ref("matchmaking").transaction(function (matchmakingSnapshot) {
if (matchmakingSnapshot) {
matchmakingSnapshot[context.params.playerId].gameId = gameId; // assign game id to player
matchmakingSnapshot[secondPlayer.key].gameId = gameId;
matchmakingSnapshot[thirdPlayer.key].gameId = gameId;
return matchmakingSnapshot;
} else if ( // If any of the players gets into another game during the transaction, abort the operation
matchmakingSnapshot === null ||
context.params.playerId.gameId !== "placeholder" ||
matchmakingSnapshot[secondPlayer.key].gameId !== "placeholder" ||
matchmakingSnapshot[thirdPlayer.key].gameId !== "placeholder") {
return matchmakingSnapshot;
}
}).then(result => {问题是,当我试图更新gameId时,事务返回一个空数据。在访问上下文参数matchmaingSnapshot之前,我必须确保playerId不是null。我不知道为什么调用matchmakingSnapshot.val()返回未定义的函数,但就是这样!
发布于 2020-10-23 23:18:57
您目前不应该得到错误matchmaking.forEach is not a function。
".forEach“函数可以在数组或DataSnapshot上工作(在子程序上迭代,依次提供每个子程序的DataSnapshot )。
但是,如果您有一个对象,".forEach“将提供您描述的错误消息。目前的代码似乎有“匹配”作为一个DataSnapshot,因此,它应该是".forEach“的时候。
错误说明:无法读取未定义的属性“params”
我认为您不小心插入了变量名,而不是告诉javascript使用变量名的值
if (matchmaking === null ||
matchmaking.context.params.playerId.gameId !== "placeholder" ||
matchmaking.secondPlayer.key.gameId !== "placeholder" ||
matchmaking.thirdPlayer.key.gameId !== "placeholder"
) return matchmaking; 我想你不是指matchmaking.secondPlayer.key.gameId。我认为你指的是matchmaking[secondPlayer].key.gameId,所以如果secondPlayer是"ABC123",你指的是matchmaking.ABC123.key.gameId
thirdPlayer也一样。
错误说明:无法读取未定义的属性“params”
你是说只有context.params.playerId.gameId而不是matchmaking.context.params.playerId.gameId?你可能是错误地添加了“婚介”?
探索错误: TypeError:无法读取未定义的属性“gameId”
如果您从以下内容中得到上述错误:
matchmaking[context.params.playerId].key.gameId` 首先,检查是否需要步骤".key“。看一下您的对象,在我看来,".gameId“直接出现在matchmakingplayerId之后,不需要".key”。如果您确信您需要".key",那么我将按照以下方式进行调试。在该语句之前插入以下控制台日志。
console.log("playerId:",context.params.playerId)
console.log("matchmaking[context.params.playerId]:",
matchmaking[context.params.playerId])然后检查一下playerId是否是明智的。如果不是,则将整个上下文console.log为
console.log("context:",JSON.stringify(context)) // This avoids getting something useless logged like `[Object object]`.如果playerId是正确的,那么您将看到matchmaking是否有该播放器的条目。这种调试方法最终会暴露问题的所在。
我认为最后一个问题是“匹配”( DataSnapshot )和简单的、可写的对象之间的混淆。
这对我来说很难理解,因为婚介目前是一种DataSnapshot,这是一种有点令人困惑的东西。它似乎得到了console.logged,好像它是一个对象,但它是不可写的。
我建议我们提取一个实际的对象如下:
database.ref("matchmaking").transaction(function (matchmaking) {
let matchmakingObject = matchmaking.val();
// ... remainder of code as before, and then:
matchmakingObject[context.params.playerId.gameId] = gameId; // assign game id to player
matchmakingObject[secondPlayer.key].gameId = gameId;
matchmakingObject[thirdPlayer.key].gameId = gameId;
return matchmakingObject;我希望这能解决问题!
我避免这种问题的方法是总是调用快照xxxxSnapshot。这样,我永远不会忘记,虽然它可能console.log,好像它是一个物体,但在现实中,它是某种神秘的东西。
例如,如果我正在编写这段代码,我将按如下方式调用:
database.ref("matchmaking")
.transaction(function (matchmakingSnapshot) {
let matchmakingObject = matchmakingSnapshot.val();
// ... remainder of code as before, and then:
matchmakingObject[context.params.playerId.gameId] = gameId; // assign game id to player
matchmakingObject[secondPlayer.key].gameId = gameId;
matchmakingObject[thirdPlayer.key].gameId = gameId;
return matchmakingObject;它有点丑陋,但比尝试调试一个具有两个非常不同的含义,很容易混为一谈的名称更痛苦。
https://stackoverflow.com/questions/64508339
复制相似问题