從零開始自製遊戲引擎 IV
這幾天要麼刷題,要麼寫引擎,要麼寫文章,都沒怎麼說好玩的事,這期我來講講我開發引擎過程中遇到的二三事吧。
比較雜亂,想到哪寫到哪,主要娛樂向。
第一件事
第二件事
鑒於第三篇文章被建議修改的原因,我已經刪除。
第三件事
下文涉及比較複雜的Kotlin語言特性。
那就是我終於體會到了什麼叫「對一種技術上癮到走火入魔」的感受。曾經看到知乎上一個問題叫「玩C++模板元編程到走火入魔是怎樣的體驗?」,看到了許多我這個不會寫工程C++的弱渣看不懂的代碼。我只知道,那滿屏的template就是這些吸毒者的罪惡之源。
真愛生命,遠離模板。而且OI有句古話,「有了STL,媽媽再也不用擔心我TLE了!」,畢竟STL裡面有些本身可以O(1)的演算法經常為了內存上的優化而做成了O(n)的,Java的范型集合庫也有這個問題,這多半就是那天我在一張圖片裡面廣搜搜半天出不來結果的原因(長跪不起)。
那麼我是又是玩什麼走火入魔了呢?使用Kotlin+anko開發過Android的人,應該對這個東西不陌生吧:
async() { // Access network or database, or some bad stuff #(滑稽) uiThread { // Display data }}
著名的async代碼塊,再也不需要那糟糕的AsyncTask了。而我也實現了這麼一個代碼塊:
inline fun <T> T.async(crossinline block: T.() -> Unit): T { Thread({ block.invoke(this) }).start() return this}
然後你在你的代碼裡面可以直接調用(這也是寒冰引擎截圖功能的正確使用方式):
async() { ImageIO.write(getScreenCut().image, "png", File("截屏" + cnt++ + ".png"));}
然後我發現這太好玩了,於是專門在utils包下弄了個叫kotlin的包,裡面專門放這種東西。因為extension只有在Kotlin中使用才會體現出它的方便,所以這些東西只支持Kotlin。
inline fun <T> T.loop(block: T.() -> Unit): T { while (true) block.invoke(this)}inline fun <T> T.loop(count: Int, block: T.(Int) -> Unit): T { for (index in 0..count - 1) block.invoke(this, index) return this}inline fun <T> T.loopIf(condition: () -> Boolean, block: T.() -> Unit): T { while (true) if (condition.invoke()) block.invoke(this)}inline fun <T> T.forceRun(block: T.() -> Unit): T { try { block.invoke(this) } catch (e: Throwable) { } return this}inline fun <T> T.forceGet(default: Any, block: T.() -> Any) = try { block.invoke(this) } catch (e: Throwable) { default }/** * if theres exception, it will exit */inline fun <T> T.forceLoop(block: T.() -> Unit) = forceRun { loop(block) }fun <T> T.pause(length: Int) = pause(length.toLong())fun <T> T.pause(length: Double) = pause(length.toLong())fun <T> T.pause(length: Long): T { Thread.sleep(length) return this}
沒錯,壓行的習慣是OI撿來的。
然後你們曾經在第二章看到過的那一段刷新主線程的代碼,已經發生了翻天覆地的變化:
// Original 原來的樣子while (true) if (!paused && !stopped) { try { onRefresh() } catch (ignored: Exception) { } timeListeners.forEach { it.check() } panel.repaint() Thread.sleep((1000.0 / refreshPerSecond).toLong())}// Current 魔改版loopIf({ !paused && !stopped && refresh.ended()}) { forceRun { onRefresh() } timeListeners.forEach { it.check() } panel.repaint()}
資料庫讀寫、音頻播放什麼的全部都被我下了毒。。。
第四件事
那就是我發現了發文章的時間對文章的贊同數是有影響的。
第一篇文章我是在晚上發的,當天晚上就來了60多個贊同。第二天早上我就把第二章發了,結果到現在也只有13個。第三篇是當天中文發的(間隔時間也太短了吧。。),效果接近。
估計是因為晚上大家都在線,我一發文章,你們在時間線裡面就看得到。所以我決定在晚上發這篇文章。嘿嘿。
說實話贊同數對於寫文章的人來說是一種莫大的鼓勵啊!
第五件事
我一直對Java的性能很不自信,以為Java卡,Java慢,反正就是垃圾語言。所以我一開始給引擎固定的刷新率是40fps(我提供了API修改這個值),然後整個畫面看起來有點卡,不過還行,起碼看得過去。然後後來在和凱凱(3A)聊天時,提到了fps這個東西。
凱凱是元火引擎的作者,元火是個C++引擎。我發現fps原來都是幾百上千的,於是也想試試,看看Java(Kotlin)引擎性能怎麼樣。
然後我把這個調到了1000fps,發現毫無卡頓,如絲般順滑。。我當時就被這個流暢的畫面驚艷到了,Java的渲染也沒那麼糟糕嘛。看來無論什麼事都得試試才行啊。
說實話我對Java的負面印象全是C++吧吧務團隊給我留下的,我曾經以Java廚的身份被他們集體吊打,並且被打為「可見Java廚並不知道Java是什麼,就廚了」,當時給我留下了很深的陰影(特大霧),讓我再一次意識到自身的弱小。。
重拾自信!
第六件事
上期已經說過了,在commit message裡面寫fuck JRuby,被JRuby的開發者之一上門查水表,看到郵件嚇得我一身冷汗。這件事告訴我們不能在commit message裡面亂寫東西。不過人家還幫我解決了疑惑,讓我受寵若驚。
另外,總感覺JRuby的人在盯著我。。
第七件事
讀者們,這玩意掛在GitHub上,求各位客官給個star,或者把release弄下來寫點小遊戲唄。
隨時歡迎各種pull request,各種issue,一定看得到!五天寫了6k+行代碼,刪了2k+行代碼,還是在我是壓行狂魔的基礎上,我寫這個一直樂在其中。但是沒人用就很尷尬了,我的wiki寫的挺詳(la)細(ji),最多遺漏一兩個剛更新的API。我的README也寫的很誘(wei)人(suo),但是就是沒人用啊,唉。。。。
順帶一提
寒冰引擎的截圖略扯淡,雖然畫面很流暢,但是截圖出來的效果是這樣的:
謎之錯位。更神奇的是,那個我吹了很多次的65行Flappy bird,我加了幾行代碼,讓它在你死的時候截圖,效果出來是這樣的:
這個bird的力氣真大,柱子都被你撞動了。當時看到圖的時候真是戳笑點,哈哈。
轉載自我的博客,原文鏈接:https://ice1000.github.io/2016/08/17/MakeEngine4.html
推薦閱讀:
※為什麼 Qt Creator 的編譯如此之慢?
※如何學習程序語言比如C#之類?
※如何學習開源代碼?有什麼好的書籍可以引導初學者學習?
※編程是否該作為基礎教育的一部分?