昨天談了Render,那今天要開始針對我們的需求實作了嗎?
我只能說,沒錯我們快要來談需求實作了,但是不是今天,今天我們要來談談Runner。
Runner是提供一個類似處理迴圈的模組,會持續更新 Engine中的內容,你如果有自己寫好的控管迴圈,那你也可以使用你自己的,筆者這邊還是會稍微介紹,預設模組還是有它的方便性。
我們一樣先看到啟動的指令,會透過這行來做為迴圈的觸發:
Runner.run(runner, engine);
大家可以看一下下面這行(第三個按鈕),會比較能理解實際上Runner做的事。
function TriggerEngineUpdate()
{
var delta = 1000/60;
Engine.update(engine, delta);
}
這邊是官方說如果你要自行管理迴圈運行的話可以用的方式,可以看到這段裡面呼叫了 Engine 的更新,指定更新的 engine對象,以及更新往前的時間,這邊單位是ms,以我的參數帶入 1000/60 就相當於 60FPS的一幀。
可以到畫面上按按看第一個跟第三個按鈕體會一下這兩者更新方式的差異,在於 Runner 他會直接做為一個持續的迴圈(固定特定頻率)持續呼叫 engine 對象的更新,另一個則是每次只讓 engine 對象流逝固定的時間。
第四個按鈕的 Trigger runner with tick 的原始碼是這樣:
function TriggerRunnerWithTick()
{
var delta = 1000/60;
Runner.tick(runner, engine, delta);
}
其實跟第三個的方式大同小異,但官方文件有註明這個方式會觸發對象 engine 的 beofreTick 、 tick 和 afterTick的相關事件,這邊大家可以依需求作使用。
既然提到了事件,我們稍微來看一下跟 Runner 相關的五個事件的觸發順序與時機
Events.on(runner, "beforeTick", function(){ alert("Before tick triggered");})
Events.on(runner, "tick", function(){ alert("Tick triggered now");})
Events.on(runner, "beforeUpdate", function(){ alert("Before canvas update");})
Events.on(runner, "afterUpdate", function(){ alert("After canvas update");})
Events.on(runner, "afterTick", function(){ alert("After tick triggered");})
上面五行程式其實就是了我們 Runner 相關的五個事件,上到下為執行順序。
可以發現如果 Tick 做為一個行為,After tick 的 signal 會是在最後才被發出,如果我們在畫面更新前後有一些要做的邏輯操作,可以透這個方式做監聽,也要清楚順序,才不會搞錯邏輯先後。
要實驗的話可以透過把 50 - 54 行的註解解掉,按下正常 Run 的鈕或是 Tick 鈕,就會看到這些 Alert一直跳出來了。
上面提到要使用這些事件的話要採用 Tick的方式這邊可以觀察到對應行為,因為這時候如果按第三個按鍵,你會發現畫面有更新,但上面的一個事件都沒有觸發。
最後是 Runner 的停止方式:
Runner.stop(runner, engine);
運行這行指令就會讓 Runner 的迴圈停止,因為是迴圈停止,實際上 Engine 只是沒有被觸發更新而已,所以當你再次跑 Runner.run 的時候,會發現畫面一樣是從停止的位置開始更新,而不是重置畫面,因為實際的畫面裡面的狀態是 Engine 在管的, Runner 負責的是時間的流動而已。
恭喜你,我們一起走到了第五天,我們已經認識了這個世界的顯示與運行,我們差不多可以進入我們的正題了 ─ 建構世界了。