首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将P5.js绘图函数放在自定义循环函数中

将P5.js绘图函数放在自定义循环函数中
EN

Stack Overflow用户
提问于 2017-03-01 12:10:20
回答 2查看 2.7K关注 0票数 3

‘s有自己的循环,它每秒调用draw()函数FPS总量次数。但是,有一个函数noLoop()可以放在setup()函数中,它禁用P5.js自己的循环。

因此,我创建了自己的循环(这对于我的项目是必要的),如下所示:

代码语言:javascript
复制
customLoop = function(){
  while(somethingIsTrue){
    //custom code here
    draw();
  }
}

因此,我希望看到画布更新相当快,因为没有FPS集。但是,画布只有在完成customLoop之后才会重新绘制。

简而言之:画布在自定义循环仍在运行时不会更新,它只会在完成自定义循环之后显示更新。

如何在我自己的循环中连续地更新画布?

人们已经要求更多的背景,所以我会尽力解释。我制作了我的自己的JS图书馆,这使得为神经网络创建遗传算法变得很容易。

我的图书馆中的遗传算法设置如下:

代码语言:javascript
复制
var evol = new Evolution({
  size: 50,
  mutationRate: 0.05,
  networkSize: [4,10,1],
  mutationMethod: [Mutate.MODIFY_RANDOM_BIAS, Mutate.MODIFY_RANDOM_WEIGHT],
  crossOverMethod: [Crossover.UNIFORM, Crossover.AVERAGE],
  selectionMethod: [Selection.FITNESS_PROPORTIONATE],
  elitism: 5,
  fitnessFunction: function(network){
    //something here that computes for every network, AT THE SAME TIME showing it LIVE for the user to watch
  }
});

注意fitnessFunction中的评论。然后,我运行一个遗传算法循环如下:

代码语言:javascript
复制
 var notFinished = true;
  while(notFinished){
    evol.evaluate();
    if(evol.getAverage() > 2000){
      notFinished = false;
      console.log('done');
    }
    evol.select();
    evol.crossOver();
    evol.mutate();
    evol.replace();
  };

所以正如你所看到的,我的代码连续运行遗传算法。但整个问题在于健身功能。该遗传算法是用来训练神经网络如何玩snake的。所以在适应度函数中,我实际上在运行神经网络,直到蛇死为止。然而,对于每一条被测试的蛇,我希望用户通过查看神经网络是如何工作的。所以我的健身功能看起来如下:

代码语言:javascript
复制
fitnessFunction = function(network){
  while(snakeIsNotDead){
    computeNeuralNetworkOutput();
    giveSnakeNewMovementDirectionBasedOnOutput();

    // most importantly
    redrawTheSnakeWithNewPosition(); // which is redraw() with P5.js
}

因此,对于每一代的测试,我想看到所有50条蛇表演。然而,在网络完成后,我看到的只是蛇在最后一次蛇评估中的最后位置。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-03-01 16:05:55

请尝试将您的代码发布为我们可以实际运行的MCVE。下面是一个显示您的问题的小例子:

代码语言:javascript
复制
function setup(){
  createCanvas(500, 500);
  for(var i = 0; i < 600; i ++){
    redraw();
  }
}

function draw(){
  ellipse(random(width), random(height), 20, 20);
}

这将显示一个画布与一堆随机的圆圈已经画在上面。我认为你想要的是看到圆圈的累积,就像你在“快速转发”草图。

用你自己的循环有点可疑。处理已经有了自己的循环机制,它包含用于双缓冲画布的逻辑。这就是为什么在绘图完成之前你什么也看不见。您可以只依赖于处理的内置定时机制。下面是一个例子:

代码语言:javascript
复制
function setup(){
  createCanvas(500, 500);
  frameRate(120);
}

function draw(){
  if(frameCount == 600){
    frameRate(60);
  }
  ellipse(random(width), random(height), 20, 20);

}

请注意,如果您正在运行的设备限制了框架,则这可能无法工作。但关键是,您不需要创建自己的循环。只需使用处理的内置循环逻辑。

编辑:,就像我说的,您看不到任何帧的原因是处理是双缓冲的。这意味着处理将等待,直到它遍历所有事件并将所有内容绘制到屏幕上。这是一个过度简化的过程,但是您可以将上面的循环看作是将600个重绘事件添加到事件队列中。处理通过它们,但实际上不显示结果,直到它完成。

您可以在此事件队列清空后调用每个重绘来解决此问题。一种略带恶意的方法是使用setTimeout()函数:

代码语言:javascript
复制
function setup(){
  createCanvas(500, 500);
  for(var i = 0; i < 600; i ++){
    setTimeout(redraw, 0);
  }
}

function draw(){
  ellipse(random(width), random(height), 20, 20);
}

现在,代码不再在一行中调用redraw()函数600次,而是将600个超时事件添加到事件队列中。它们中的每一个都将被单独处理,因此您可以看到间歇性的帧。

我要说的是,这似乎仍然是实现你的目标的一个讨厌的方式。如果我是您,我仍然会尝试将draw()函数从实际逻辑中分离出来。拥有您的模拟集变量,并让draw()函数使用这些变量。这是解决这个问题的“正确”方法。现在使用setTimeout()函数是可行的,但我猜它会给您带来麻烦。

票数 3
EN

Stack Overflow用户

发布于 2017-03-01 12:18:23

根据文档,您希望避免直接调用“Based ()”。试一试如下:

代码语言:javascript
复制
customLoop = function(){
    while(somethingIsTrue){
        //custom code here
        redraw();  // Causes the code inside "draw()" to execute once
    }
}

https://p5js.org/reference/#/p5/draw

具体来说,它是自动调用的,不应该被显式调用。应该始终使用noLoop()、重绘()和循环()来控制它。

此外,由于JavaScript是单线程的,只要while循环在滴答作响,其他任何东西都无法执行。下面是一篇相关文章:

时间循环中的异步函数。

还有一个很好的,彻底的解释:

http://blog.carbonfive.com/2013/10/27/the-javascript-event-loop-explained/

你可以尝试这样的方法:

代码语言:javascript
复制
var timerId = 0;

timerId = setTimeout(myCustomRedraw(), 10); // Every 10 milliseconds.
myCustomRedraw = function () {
    // custom code here
    if (<stop loop condition>) {
        clearTimeout(timer); // Will stop the timeout loop.
    }
    redraw()
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42531371

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档