‘s有自己的循环,它每秒调用draw()函数FPS总量次数。但是,有一个函数noLoop()可以放在setup()函数中,它禁用P5.js自己的循环。
因此,我创建了自己的循环(这对于我的项目是必要的),如下所示:
customLoop = function(){
while(somethingIsTrue){
//custom code here
draw();
}
}因此,我希望看到画布更新相当快,因为没有FPS集。但是,画布只有在完成customLoop之后才会重新绘制。
简而言之:画布在自定义循环仍在运行时不会更新,它只会在完成自定义循环之后显示更新。
如何在我自己的循环中连续地更新画布?
人们已经要求更多的背景,所以我会尽力解释。我制作了我的自己的JS图书馆,这使得为神经网络创建遗传算法变得很容易。
我的图书馆中的遗传算法设置如下:
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中的评论。然后,我运行一个遗传算法循环如下:
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的。所以在适应度函数中,我实际上在运行神经网络,直到蛇死为止。然而,对于每一条被测试的蛇,我希望用户通过查看神经网络是如何工作的。所以我的健身功能看起来如下:
fitnessFunction = function(network){
while(snakeIsNotDead){
computeNeuralNetworkOutput();
giveSnakeNewMovementDirectionBasedOnOutput();
// most importantly
redrawTheSnakeWithNewPosition(); // which is redraw() with P5.js
}因此,对于每一代的测试,我想看到所有50条蛇表演。然而,在网络完成后,我看到的只是蛇在最后一次蛇评估中的最后位置。
发布于 2017-03-01 16:05:55
请尝试将您的代码发布为我们可以实际运行的MCVE。下面是一个显示您的问题的小例子:
function setup(){
createCanvas(500, 500);
for(var i = 0; i < 600; i ++){
redraw();
}
}
function draw(){
ellipse(random(width), random(height), 20, 20);
}这将显示一个画布与一堆随机的圆圈已经画在上面。我认为你想要的是看到圆圈的累积,就像你在“快速转发”草图。
用你自己的循环有点可疑。处理已经有了自己的循环机制,它包含用于双缓冲画布的逻辑。这就是为什么在绘图完成之前你什么也看不见。您可以只依赖于处理的内置定时机制。下面是一个例子:
function setup(){
createCanvas(500, 500);
frameRate(120);
}
function draw(){
if(frameCount == 600){
frameRate(60);
}
ellipse(random(width), random(height), 20, 20);
}请注意,如果您正在运行的设备限制了框架,则这可能无法工作。但关键是,您不需要创建自己的循环。只需使用处理的内置循环逻辑。
编辑:,就像我说的,您看不到任何帧的原因是处理是双缓冲的。这意味着处理将等待,直到它遍历所有事件并将所有内容绘制到屏幕上。这是一个过度简化的过程,但是您可以将上面的循环看作是将600个重绘事件添加到事件队列中。处理通过它们,但实际上不显示结果,直到它完成。
您可以在此事件队列清空后调用每个重绘来解决此问题。一种略带恶意的方法是使用setTimeout()函数:
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()函数是可行的,但我猜它会给您带来麻烦。
发布于 2017-03-01 12:18:23
根据文档,您希望避免直接调用“Based ()”。试一试如下:
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/
你可以尝试这样的方法:
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()
}https://stackoverflow.com/questions/42531371
复制相似问题