Firebase Javascript + P5.js:异步函数阻碍了重绘画布

Ada*_*Lee 6 html javascript processing firebase p5.js

我正在尝试创建一个应用程序,通过从存储圆圈的x和y坐标的Firebase数据库中读取信息,将圆圈绘制到画布上.然而,执行下面的代码,根本不产生任何东西,没有圆圈的任何迹象,因为函数drawCricles异步运行,因此命令background(40)在绘制圆之前清除所有内容.

这是我的代码:

function setup() {
    createCanvas(windowWidth, windowHeight); 
    background(40); 
    stroke(80); 
    smooth();
    frameRate(60);
}

function drawCircles() {
    firebase.database().ref("circles").once("value", function(snapshot) {
        var snapshotVal = snapshot.val();
        var circleCount = snapshotVal.numCircles;

        for (var j = 0; j < circleCount; j++) {
            firebase.database().ref("circles" + j).once("value", function(snapshot) {
                var snapshotValue = snapshot.val();
                fill(143, 2, 2);
                ellipse(snapshotValue.xPos, 50, 50);
            });
        }
    });
}

function draw() {
    stroke(80);
    background(40);

    stroke(0);
    drawCircles(); 
}
Run Code Online (Sandbox Code Playgroud)

joh*_*bay 2

看来您的问题只是每秒 60 帧,这导致了竞走情况。Firebase.once在完成获取时将执行异步,P5 不会等待它获取,因为它将坚持其帧速率计时。

在这个具体案例中,我有多个建议,希望能让您非常接近您想要的结果。

1 - 重构你的代码

您的代码的当前结构存在两个问题。

  • 情况 1:您当前的代码会让我认为您的圈子在数据库中实时更新,并且您需要保持最新状态,因此您不断获取他们的最新位置。如果是这种情况,您应该使用.on("value")而不是.once("value")让 firebase 在圈子发生变化时向您发送更新,而不是每秒询问 60 次以节省往返请求时间。如果是这种情况:请参阅下面我的解决方案 1

  • 情况 2:如果您的圈子没有在数据库中实时更新,而您只想要整个圈子列表,那么您每秒会无缘无故地获取该列表 60 次。您应该在设置时获取列表.once,并在稍后迭代该列表draw()。请参阅下面的解决方案 2

2 - 重组你的数据库

无论哪种情况,您当前的数据库模型都要求您不断循环获取。这意味着您发出的请求数量与您的circleCount. 这对您的使用不利,因为每个请求都需要额外的行程时间,而我们正在努力减少所需的时间,以便更接近实时。(或匹配帧速率)

目前,您的圈子似乎circles1 circles2全部保存为root,因为您正在使用.ref("circles" + j)它们来检索它们。这样您就可以像这样保存您的圈子:.ref("circles/" + j)这意味着每个圈子circle现在都保存 circles. 像circles/circle1 circles/circle2等等

这样做的好处是,现在您不需要额外的请求来 firebase 获取所有圆圈。Firebase 具有非常方便的功能,例如forEach,可以通过单个请求迭代所有子级。

3 - 清除 Firebase 回调中的背景

目前,您以特定于帧速率的方式清除背景。这意味着,如果您的每个 Firebase 调用花费的时间超过 1/60 秒(16 毫秒),您将清除背景并继续前进。即使我们构建了数据库,达到这种速度的机会也非常低。因此,我建议首先使用 30fps,这也会将您对 Firebase 的调用次数减少到每秒 30 次。

解决方案1

如果您的圈子在数据库中更新(例如由其他游戏玩家或其他人更新,并且您希望代码始终显示最新的 xPos)

var latestCirclePositionsSnapshot;

function setup() {
  createCanvas(windowWidth, windowHeight); 
  background(40); 
  stroke(80); 
  smooth();
  frameRate(60);

  firebase.database().ref("circles").on("value", function(snapshot) {
    // got a new value from database, so let's save this in a global variable. 
    latestCirclePositionsSnapshot = snapshot;
    // we will keep drawing this update until we get a new one from the database.
  });
}

function draw() {
  drawCircles(); 
}

function clearBackground () {
  stroke(80);
  background(40);
}

function drawCircles() {
  clearBackground();
  stroke(0);  
  latestCirclePositionsSnapshot.forEach(function(circleSnapshot) {  
    // circleData will be the actual contents of each circle
    var circleData = circleSnapshot.val();
    fill(143, 2, 2);
    ellipse(circleData.xPos, 50, 50);
  });
}
Run Code Online (Sandbox Code Playgroud)

基本上,这将继续绘制我们从 firebase 获得的最后一个圆圈位置,直到我们得到一个新的位置。(因此 P5 将以 60fps 保持刷新,但您的 Firebase 更新将像 Firebase 可以运行并从 Firebase 获取等一样实时。)

解决方案2

如果您的数据库中没有实时更新,并且您想要的只是通过从 firebase 获取一次数据来绘制圆圈(例如根据某些数据绘制一些点)

var circlePositions;
var gotPositions = false;

function setup() {
  createCanvas(windowWidth, windowHeight); 
  background(40); 
  stroke(80); 
  smooth();
  frameRate(60);

  firebase.database().ref("circles").once("value", function(snapshot) {
    // got the circle values from the database
    // let's store them and we'll keep drawing them forever. 
    circlePositions = snapshot;
    gotPositions = true;
  });
}

function draw() {
  drawCircles(); 
}

function clearBackground () {
  stroke(80);
  background(40);
}

function drawCircles() {
  clearBackground();
  stroke(0); 

  if (gotPositions) {
    circlePositions.forEach(function(circleSnapshot) {  
      // circleData will be the actual contents of each circle
      var circleData = circleSnapshot.val();
      fill(143, 2, 2);
      ellipse(circleData.xPos, 50, 50);
    });
  } else {
    // Display some text here like "LOADING DATA FROM SERVERS..." 
  }
}
Run Code Online (Sandbox Code Playgroud)

希望这些有所帮助:) 很高兴见到另一位 Processing & Firebase 的粉丝。