我使用Cordova为iOS和Android编写了一个混合游戏。在某些Android设备上,几分钟后游戏崩溃,屏幕上出现一条消息“(App Name)已停止”。我一直试图找到过去一周崩溃的东西,但我一直无法找到它。我已经开始讨论这个问题,但是今天我发现了一些保证其自身线索的东西。请允许我先告诉你有关崩溃的事情,以及我为解决这个问题所做的工作。
游戏使用两个画布。一个不可见的,不属于DOM(MAINCanvas)的一部分,无论真正的屏幕大小如何,它总是具有固定的大小。所有绘图都在该画布上完成。另一个画布与屏幕尺寸相同并且可见(DISPLAYCanvas)。我在游戏开始时存储了这些画布的上下文:
var MAINCanvas = document.createElement( "canvas" );
var DISPLAYCanvas = document.createElement( "canvas" );
document.body.appendChild(DISPLAYCanvas);
MAINCanvas.context = MAINCanvas.getContext("2d", { alpha: false } );
DISPLAYCanvas.context = DISPLAYCanvas.getContext("2d", { alpha: false } );
我的游戏的主循环看起来像这样:
function MainLoop() {
doStuff();
doSomeMoreStuff();
Render(); // This renders all game elements on the invisible MAINCanvas
DISPLAYCanvas.context.drawImage( MAINCanvas, 0, 0 );
window.requestAnimationFrame( MainLoop );
}
几分钟的比赛结束后,比赛每次都会崩溃。为了弄清楚崩溃的位置,我添加了一些console.logs:
function MainLoop() {
console.log( "Stuff" );
doStuff();
console.log( "SomeMoreStuff" );
doSomeMoreStuff();
console.log( "Render" );
Render(); // This renders all game elements on the invisible MAINCanvas
console.log( "Draw" );
DISPLAYCanvas.context.drawImage( MAINCanvas, 0, 0 );
window.requestAnimationFrame( MainLoop );
}
事实证明,它在不同的地方坠毁。
然后我怀疑这可能是罪魁祸首:
MAINCanvas.context = MAINCanvas.getContext("2d", { alpha: false } );
DISPLAYCanvas.context = DISPLAYCanvas.getContext("2d", { alpha: false } );
我正在向DOM对象添加属性,我记得在某个地方读取这是禁止的,它会阻止(副本)对象被垃圾收集。所以我改变了这个:
var MAINContext = MAINCanvas.getContext("2d", { alpha: false } );
var DISPLAYContext = DISPLAYCanvas.getContext("2d", { alpha: false };
我的主要话题是:
function MainLoop() {
console.log( "Stuff" );
doStuff();
console.log( "SomeMoreStuff" );
doSomeMoreStuff();
console.log( "Render" );
Render(); // This renders all game elements on the invisible MAINCanvas
console.log( "Draw" );
DISPLAYContext.drawImage( MAINCanvas, 0, 0 );
window.requestAnimationFrame( MainLoop );
}
它不再崩溃了!经过7天的纯粹令人沮丧的调试后,我很高兴终于找到了崩溃的东西。我现在可以毫无问题地玩游戏。
所以为了准备游戏进行发布,我删除了console.log()行。可以肯定的是,我再次对游戏进行了测试......几分钟后它就崩溃了。所以我在我的mainloop中添加了一个console.log:
function MainLoop() {
console.log( "Stuff" );
doStuff();
doSomeMoreStuff();
Render(); // This renders all game elements on the invisible MAINCanvas
DISPLAYContext.drawImage( MAINCanvas, 0, 0 );
window.requestAnimationFrame( MainLoop );
}
再次测试它并没有崩溃。删除了console.log()并崩溃了。我已经尝试了几次,每次删除console.log()时,游戏都会崩溃。如果我添加它,它不会。始终如一。
我现在唯一能想到的是console.log以某种方式触发垃圾收集?
在我看来,这是console.log()在生命周期中创建的延迟。
过去有过类似的问题。
尝试在超时中包装代码,延迟0秒,以便循环运行该循环。
例
function MainLoop() {
//console.log("MainLoop start");
doStuff();
doSomeMoreStuff();
Render(); // This renders all game elements on the invisible MAINCanvas
DISPLAYContext.drawImage( MAINCanvas, 0, 0 );
window.setTimeout(function(){
window.requestAnimationFrame( MainLoop );
},0);
}
也许可以玩它,并以相同的方式添加其他密集的行动。
编辑:您也可以尝试降低帧速率 - 也许这些特殊的Android设备没有足够的功率来处理帧速率...
例
var framesPerSecond = 10;
function MainLoop() {
//console.log("MainLoop start");
doStuff();
doSomeMoreStuff();
Render(); // This renders all game elements on the invisible MAINCanvas
DISPLAYContext.drawImage( MAINCanvas, 0, 0 );
window.setTimeout(function(){
window.requestAnimationFrame( MainLoop );
}, (1000 / framesPerSecond));
}
希望这会有所帮助。
请享用!