Home > Software design >  Pass firebase reference to function, and get return value
Pass firebase reference to function, and get return value

Time:03-14

I'm trying to create a function that check if mooving bullet is hitting players.

The code simplified - shoot() is moving the bullet, and check_if_bullet_hit_player(bulletRef) gets a bullet ref, and checks if the bullet is hitting any player.

This is my code:

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;
  }
}

The code is not triggering the alert(). After reading this question I think the problem with the asynchrony, but how do I pass parameters to the function, and get the function's return value.

EDIT:

This is the full check_if_bullet_hit_player() function, which I loop over the players, and checks if the bullet is <0.5 to a player (if so - its count as a hit):

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;
            }
  // ...

CodePudding user response:

Indeed the problem comes from the fact the once() method is asynchronous. But you also forget to return the promises chain in the check_if_bullet_hit_player() function.

The following, using then() as you do in your question, should do the trick:

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
    });
}

Note that the shoot() function is also asynchronous. So if you chain it with other function call, you need to use then() (and return the promises chain) or async/await.


Edit following your comment and your question update:

Again you are not returning the promise chain. You can modify it as follows, but I would recommend you use the every() method which "executes the provided callback function once for each element present in the array until it finds the one where callback returns a falsy value"

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;
        });

}

Extra note

It seems these functions are executed in the front end (you use firebase.database()...) You should probably do the calculations in the back-end, e.g. via a Cloud Function, to avoid possibilities for a malicious user to fake the results.

  • Related