這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
看這個源碼分析前,建議先看更簡單地例子 basic 的源碼分析(http://www.cnblogs.com/ghj1976/p/5183199.html), 一些基礎知識本篇將不再提及。
audio 的源碼比起 basic 最大的變化是使用了 golang.org/x/mobile/exp/sprite 這個對遊戲精靈的封裝包。
有關 audio 的簡單說明請看:https://godoc.org/golang.org/x/mobile/example/audio
它是一個跑來跑去的 Gopher ,當撞牆時會發出聲音,並彈回來。
這個遊戲是使用的sprite 包做的, Sprite包 是一個 2D 情境下的渲染和動畫封裝包。
Sprite包下面還有個glimage包 (目錄在 golang.org/x/mobile/exp/sprite/portable)通過渲染引擎把 image包的圖片以節點樹的方式繪製出來。這個樹的根節點就是要畫的螢幕背景。上面的元素是根節點的子節點。
有關 glimage 包的程式碼分析請看: http://www.cnblogs.com/ghj1976/p/5199789.html
由於是樹的資料結構,每個繪圖元素都是一個自己的座標系,這就涉及到座標系的轉換,相對父元素(父座標系)的仿射變換關係矩陣 用下面 Engine 介面的 SetTransform函數來設定。
SetTransform(n *Node, m f32.Affine) // sets transform relative to parent.
有關仿射變換矩陣的知識請看: http://www.cnblogs.com/ghj1976/p/5199086.html
有關座標系轉換的知識請看: http://www.cnblogs.com/ghj1976/p/5215707.html
下面是一些具體這個遊戲實現的分析:
背景的繪製
關鍵代碼
// ClearColor specifies the RGBA values used to clear color buffers.
ClearColor(red, green, blue, alpha float32)
該方法設定OpenGl ES"清屏"所用的顏色,四個參數分別設定紅、綠、藍、透明值:0為最小值,1為最大值。例如ClearColor(0, 0, 0, 0);就是用黑色“清屏”。
// Clear clears the window.
// The behavior of Clear is influenced by the pixel ownership test,
// the scissor test, dithering, and the buffer writemasks.
Clear(mask Enum)
mask
Bitwise OR of masks that indicate the buffers to be cleared. The three masks are GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, and GL_STENCIL_BUFFER_BIT.
可以使用 | 運算子組合不同的緩衝標誌位,表明需要清除的緩衝
- GL_COLOR_BUFFER_BIT: 當前可寫的顏色緩衝
- GL_DEPTH_BUFFER_BIT: 深度緩衝
- GL_STENCIL_BUFFER_BIT: 模板緩衝
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
第一條語句表示清除顏色設為黑色,第二條語句表示實際完成了把整個視窗清除為黑色的任務,glClear()的唯一參數表示需要被清除的緩衝區。
參考: http://www.xuebuyuan.com/1268040.html
遞迴繪圖
接上面的onPaint方法, 這裡面完成背景繪製後,就是做的繪圖引擎的情境繪製,如代碼入口, 這裡是一個樹節點的遞迴繪製。
eng.Render(scene, now, sz) 裡面我們可以看到是遞迴繪製每個有貼圖的節點
func (e *engine) render(n *sprite.Node, t clock.Time, sz size.Event) {
這個樹節點的層次關係如:
有一個根節點,一個子節點:
注意, 子節點的 相對轉換 relTransform 不是仿射變換矩陣, 而是三個點的座標(或者叫一個點+2個向量)合成的矩陣,
看起來像 仿射變換矩陣,但是實際不是。
原因是,仿射變換矩陣需要跟具體點座標相乘後,才是轉換後的矩陣, 而我們在具體繪圖時看到, 這個 relTransform 計算後的結果直接就當點來用了。
引擎的繪製在 eng.Render(scene, now, sz) 函數裡面,具體這個函數的實現在 glsprite 中,這裡的繪製邏輯如:
abs 是 absolute 絕對的縮寫 ; rel 是 relatively 相對的縮寫。
具體的繪製函數用的是(對這個函數的分析請看:http://www.cnblogs.com/ghj1976/p/5199789.html)
func (img *Image) Draw(sz size.Event, topLeft, topRight, bottomLeft geom.Point, srcBounds image.Rectangle)
這裡傳入的是三個點, 即平行四邊形的 左上、右上、左下 這三個點。
absTransforms 在所有 相對 relTransform 相乘完畢後, 算出的是 左上, 右上比左上的X、Y軸位移, 左下比左上的X、Y軸的位移值。
所以在傳入 Draw 的時候, 會有下面的寫法:
從矩陣運算的角度來說,最後一個矩陣的列,只會影響,不會影響最終值的其他列,只會影響本列,如:
所以最後這個relTransform 用三個節點來作為這個矩陣的三列是可行的。
這個相對轉換,最後是三個座標點的可以用表示:
精靈的動畫行為定義
我們用下面方式實現對精靈的行為定義:
這個定義是遵循下面介面定義的:
為了在引擎處理時,調用這個行為邏輯:
我們這裡有個小技巧實現了這個調用:
把行為函數定義成一個類型,然後這個類型實現了 Arrange 介面, 如下代碼。