Estoy tratando de crear una función que verifique si la bala en movimiento está golpeando a los jugadores.
El código simplificado: shoot() está moviendo la bala, y check_if_bullet_hit_player(bulletRef) obtiene una referencia de bala y verifica si la bala está golpeando a algún jugador.
Este es mi código:
function shoot(){ // ... moving bullet code const bulletRef = firebase.database().ref(`bullets/${bulletKey}`); if(check_if_bullet_hit_player(bulletRef)){ alert("player got hit"); bulletRef.remove(); } } function check_if_bullet_hit_player(bulletRef){ bulletRef.once("value").then(function(snapshot) { //for simplicity I just return true - player got hit return true; } } El código no activa la alert() . Después de leer esta pregunta , creo que el problema es la asincronía, pero ¿cómo paso parámetros a la función y obtengo el valor de retorno de la función?
Esta es la función check_if_bullet_hit_player() completa, que paso por encima de los jugadores y verifica si la viñeta es <0.5 para un jugador (si es así, cuenta como un acierto):
function check_if_bullet_hit_player(bulletRef){ //bulletRef.once("value").then(function(snapshot) { return bulletRef.get().then(snapshot => { let bulletX = snapshot.val().x; let bulletY = snapshot.val().y; let shooterId = snapshot.val().shooterId; //loop over players const allPlayersRef = firebase.database().ref(`players`); allPlayersRef.once("value", (snapshot) => { players = snapshot.val() || {}; Object.keys(players).forEach((key) => { if(getDistance(players[key].x, players[key].y, bulletX, bulletY) < 0.5){ if(players[key].id != shooterId){ //not the shooter return true; } // ...De hecho, el problema proviene del hecho de que el método once() es asíncrono. Pero también te olvidas de devolver la cadena de promesas en la función check_if_bullet_hit_player() .
Lo siguiente, usando then() como lo hace en su pregunta, debería funcionar:
function shoot() { // ... moving bullet code const bulletRef = firebase.database().ref(`bullets/${bulletKey}`); check_if_bullet_hit_player(bulletRef) .then(result => { if (result) bulletRef.remove(); }) } function check_if_bullet_hit_player(bulletRef) { return bulletRef.get().then(snapshot => { // See return at the beginning, and also that we use get() return snapshot.exists(); // I think you should check if the snapshot exists }); } Tenga en cuenta que la función shoot() también es asíncrona. Entonces, si lo encadena con otra llamada de función, debe usar then() (y devolver la cadena de promesas) o async/await .
Edite siguiendo su comentario y la actualización de su pregunta:
Nuevamente, no está devolviendo la cadena de promesa. Puede modificarlo de la siguiente manera, pero le recomendaría que use el método every() que "ejecuta la función de devolución de llamada proporcionada una vez para cada elemento presente en la matriz hasta que encuentra el que devuelve un valor falso "
function check_if_bullet_hit_player(bulletRef) { let bulletX; let bulletY; let shooterId; return bulletRef.get().then(snapshot => { bulletX = snapshot.val().x; bulletY = snapshot.val().y; shooterId = snapshot.val().shooterId; //loop over players const allPlayersRef = firebase.database().ref(`players`); return allPlayersRef.get(); // HERE we chain the promise }) .then(allPlayersSnap => { players = allPlayersSnap.val() || {}; let result = false; Object.keys(players).forEach((key) => { if (getDistance(players[key].x, players[key].y, bulletX, bulletY) < 0.5 && players[key].id != shooterId) { result = true; } }); return result; }); } Parece que estas funciones se ejecutan en el front-end (usted usa firebase.database()... ) Probablemente debería hacer los cálculos en el back-end, por ejemplo, a través de una función en la nube, para evitar la posibilidad de que un usuario malintencionado falsifique el resultados.