辛巴學院-Unity-劍英的c#提高篇(一)主迴圈

瘋光無線發表於2015-11-02

這是測試版

辛巴學院:正大光明的不務正業。

最近剛剛離開了我服務了三年多的公司,因為一個無數次碰到的老問題,沒錢了。

之前不知道做什麼好的時候,機緣巧合之下和噠嗒網路的吳總聊了一下,發現了vr game這扇窗戶,這裡權當幫噠嗒網路打個廣告吧。^_^

回頭看看倉惶的這一段時間,荒廢了很多,抽空回來再和大家聊聊c#。

之前做了個入門系列,胡亂說了些東西。感覺入門這樣子也就差不多了,該稍微提高一點了。

 

從寫一段程式,到寫一個app,寫一個遊戲,到底其中有什麼不同呢?一段程式的執行時間很短,一個應用的執行時間很長,僅此而已。

 

遊戲中存在一個幀的概念。

這個概念大家都知道,類比的話,它就是電影膠捲的格。一格出現一段時間,然後換下一格。

電影一秒24格,遊戲用的是一秒30幀,60幀。

電影膠片是在鏡頭前一格一格的放映,遊戲邏輯是在update中一幀一幀的執行。

那麼Update函式的驅動是如何完成的呢?

 

這個東西就是主迴圈

先來看看一個基本的控制檯程式

唔,helloworld,這個程式我們已經很熟悉了。一閃而過的那個版本。因為他執行然後馬上就結束了。

 

那麼這個版本呢?

你會說,我去,你寫了一個死迴圈。

 

是的,主迴圈就是一個死迴圈。有了這個死迴圈,一段程式就能逐漸成為一個應用,一個遊戲。

讓我們把update拆出來,是不是看起來有點熟悉了。

 

再來個OnStart,是不是更加熟悉了

原來Unity的MonoBehaviour就是這樣啊。

 

任何的程式中都存在著主迴圈,在常用的介面框架中,通常隱藏主迴圈,留下事件型的介面。

主迴圈很簡單吧,僅僅是看起來這樣。

遊戲程式通常事件型的框架不多,大部分邏輯需要從主迴圈層次開始組建,也就是你需要對主迴圈的理解非常深,能夠從主迴圈上建立很多種模式的邏輯。

我們開始來介紹幾個常見的

主迴圈和定時器

試想如下需求,需要每三秒鐘列印一條log,怎麼做這個三秒鐘的計時?

電影是24格,每秒鐘24幀,穩定的,雷打不動。通過數幀就知道個大概。

可是大家都知道遊戲的幀率是跳躍的,每一幀的時間不固定。

Unity提供了一個引數,告訴你上一幀開始,到這一幀開始經過的時間,單位為秒 Time.Deltatime;

因為每一幀開始到上一幀開始的間隔給你了。只要把他們累加起來,就是一個計時器。你可以用秒錶確認一下這個程式,他的表現和你的秒錶一樣精準,分毫不差。

這就是一個計時器了,一個用不穩定的幀速率的主迴圈驅動的計時器。只是他光計時了,啥也沒幹,我們來讓他做點什麼。

 

這個計時器是最基本的一個邏輯,固定幀率在遊戲中只是一個理想化狀態,大部分情況下無法實現固定幀率。

幾乎所有的遊戲邏輯都涉及到計時問題,都會涉及到如何在浮動幀率時進行邏輯控制。

時間是連續累加的,請時刻記住這一點。

主迴圈與緩動

用定時器去驅動數值的變化,在一些情況下,被稱為緩動,dotween,itween,名字裡有個tween的這類庫或者外掛,都是做緩動的。

他們包裝了各式各樣的緩動的模式程式碼,幫你節約一點時間。

我們來讓一個box 3秒鐘從A點移動到B點,所有緩動的系統中都採用這樣一個考慮方式,零為開始,一為結束。那麼我們讓我們的timer 幾秒完成一個從零到一的過程,這就是一個緩動的週期。

就用我們之前的程式碼去考慮,我們的timer 加到3秒,然後變小,再到三,再變小,ok。直接給timer+=的時候乘一個係數可以改變timer變化的速度,可以調節為三秒鐘完成從零到一,但是我們入門篇講過,好程式碼從命名開始,既然他叫做timer,他就不應該從零到一,從零到一的標識的是緩動的進度。

取名為lerp

如上程式碼就完成了一個緩動邏輯,把這個指令碼給一個cube,然後begin end 填入不一樣的值,跑起來看看。

無論你用了什麼高大上的緩動庫,知其然總是有好處的,而這,就是緩動框架背後的事情。

 

主迴圈和狀態機

入門篇我們就講了一個時空觀的問題,這個用程式的概念就是狀態,圖靈機、馮諾依曼機,是計算機的基礎,這個基礎說的就是狀態機。

即使從更大的尺度來看,高階語言來看。在順序執行的程式體系中,狀態機依然是程式設計的基礎。

我們前面告訴過大家單步除錯,每一個斷點,就是一個狀態。

程式是由一個一個的狀態構成的。

再從更大的尺度看,功能模組和程式結構的角度,狀態機依然是功能的基礎,我現在處於主選單還是戰鬥選單?我現在是在充值還是還消費?

同級別的功能某一時刻必然處於某一功能中,是我們的設計基礎。

遊戲框架從哪裡開始,必然從狀態的分割開始。有些框架提供了一個比狀態機更高階一點的模式,導航器,其實也屬於狀態機,但是導航器記錄著之前的狀態,可以NavBack。

導航器模式是什麼?隨便點開一個手機app,點一個功能,再點一個功能,然後按back,back,這就是導航器。

現在由於手遊流行起來,遊戲介面效法了很多app的設計,所以現在導航器設計是一個非常主流的設計。

由於我們只是一個拋磚引玉的提高過程,我們這裡不會去寫一個導航器框架出來,我們只是去解釋狀態機背後的行為。

這個狀態程式碼這麼寫,有點長,我們分兩段來看,一段是update函式

一段是ongui函式

仔細看過這段程式碼,你也許會說,你騙人,這是個錘子的狀態機哦,這就是個if else

這就是個if else,狀態機的本質就是switch case,就是 if else,除非,給他一個結構化的設計。

當你的邏輯狀態只有兩三個的時候,if else,未嘗不可。然後我們來把他結構化一下吧。

看看結構化之後的程式碼

我們抽象出一個表達狀態的介面,於是主要的程式碼變得非常簡潔,這就是一個狀態機咯。

不過實現程式碼就不那麼簡潔了

有這樣的設計作為基礎,新增再多的狀態也不怕啦,不過這也只是一個解釋用的程式碼。

實際操作時肯定比這個面對的問題要更復雜一些。

 

 

再會,哈庫拉瑪塔塔

相關文章