音游制作雜談(230409)
在xx時間,發(fā)生xx事件
大多數(shù)情況下,F(xiàn)lag法是很夠用的:
對于Lua而言,F(xiàn)lag法可以做一個簡單的升級:
{
{88888, "dosthA()"},
{77777, "dosthB()"}
}
事前按時間倒序排序,每幀從最后一組開始遍歷:當前時間>=發(fā)生時間,執(zhí)行之,然后給對應的元素賦nil;當前時間<發(fā)生時間,退出遍歷循環(huán)。
執(zhí)行上可以直接dofile(),執(zhí)行完直接給對應項賦nil。
時間敏感性:游戲引擎的生命周期函數(shù)很難均勻執(zhí)行,“基本只能保證每秒執(zhí)行的次數(shù)是對的”,因此如果涉及到時間敏感性很高的事件(比如有個Note要在下落紙帶上來回跳)就應該轉變思路、換用狀態(tài)機來實現(xiàn):
時間敏感事件? ->? 時間不敏感事件? +? 狀態(tài)機
異步輸入
音游是一個相對小眾的游戲品類,所以游戲引擎一般是不實現(xiàn)異步輸入的。游戲引擎一般考慮一幀一輪的設計思路,輸入檢測往往局限于“若該幀有輸入,就把輸入信息發(fā)給回調(diào)函數(shù)”。
近兩年的設備觸控報告率往往兩倍于甚至更多倍于屏幕刷新率,為了充分利用設備的觸控報告,就需要擺脫引擎本身的“一幀一輪”制約。那么,首先必須能直接對接操作系統(tǒng)API,甚至硬件API,以拿到原始輸入信息。其后考慮兩種思路:
A. Fixed Update。每秒執(zhí)行很多次“拿原始輸入”+“進行輸入有關的游戲邏輯”
B. 緩存近幾次輸入,然后走Update,還是每幀運行一次游戲邏輯。
關于腳本層面和怎么和系統(tǒng)層面通訊,不同引擎有不同的實現(xiàn)。就個人而言,個人計劃使用Defold引擎,而Defold所有腳本組件運行在同一個Lua State下,這意味著可以把“原始輸入”直接存在Lua State的一個全局變量中。通過C/C++修改Lua State里的某個Lua變量也是比較方便的。
最終,異步輸入這么實現(xiàn):
通過C/C++邏輯捕獲系統(tǒng)的輸入報告,經(jīng)過一些包裝之后把輸入報告(輸入情況+時間)緩存到Lua State里的一個全局表中。游戲邏輯可以直接訪問存儲輸入報告全局表。
簡單擬兩個注意事項:
A. 如果考慮緩存法的話,腳本一次Update會處理復數(shù)個輸入報告,就需要想個辦法判斷下緩存的輸入報告是否屬于當前幀的處理范疇。對于Defold的話,可以利用一下Update傳入的dt參數(shù),應該是沒問題的;
B. 很難預測全局Lua表更新、腳本的執(zhí)行等在時間上的先后,因此在腳本Update邏輯的開頭,應該把輸入報告表深拷貝一份,后續(xù)邏輯圍繞這份深拷貝進行。
曲線的實現(xiàn)
很難回避直線擬合+插值。
對于不太想涉獵底層API的人,能理解到這一層應該夠用了(指直接拿Sprite拼圖):
平行四邊形或梯形? =? 矩形? +? 一兩個直角三角形? =? 更多的直角三角形
愿意涉獵底層一些的API的話,就根據(jù)插值節(jié)點去生成頂點流,然后用頂點流去生成Mesh。拿到Mesh走材質(zhì)貼圖,甚至著色器,只要肯學都會有辦法的。
