這周還是在改自己的這個框架,被多線程折騰了兩天,最終無奈放棄在游戲啟動時調用引擎進行圖片相關資源的初始化,當然進展還是不錯的。
嗯,下面還是以流水的方式繼續記錄一下本周完成的工作:
1、調通了客戶端與lua的相互調用,用的是verysimple這個第三方庫(跨平台的庫)。這邊遇到一個坑,特此記錄。
我用的版本lua5.3,似乎官方已經取消了module函數,反正我在lua文件裡面直接寫“module(模塊名,package.seeall)”,require這個lua文件的時候會報錯。網上查了不少資料,據說module方法效率慢,而且極易污染全局空間,官方並不提倡使用。看來真有可能新版本把這個方法給丟棄了。反正我是沒辦法再去花時間找原因了(已經浪費了大半天時間,而且有個前輩勸我說不要用這個方法)。後來實現的代碼如下,在此特別感謝 "廣州-隨雲" 的無私幫助。
local module_notice = {} function module_notice:open() client.monitor:register(1100,module_notice.OnClose); createScene("notice"); end function module_notice:OnClose() closeScene("notice"); client.monitor:unRegister(1100,module_notice.OnClose); end return module_notice
testLua('lua system running'); notice = require "script/module_notice"; notice:open();
2、關於資源的加載:本來的思路是游戲啟動時載入一個base.data的資源包,顯示一個載入界面(包含背景圖、logo、進度條、默認字體等等),然後同時開個網絡線程進行自動更新,自動更新完再開一個線程進行各種配置文件、聲音文件、腳本文件、字體文件、圖片資源文件的加載/初始化。但是前面幾個操作在線程裡面都沒有問題,就是有兩個地方無法做到:
1)lua文件,不能統一加載到一個列表中,否則lua文件中用require函數無法正常載入。
2)用pxl(asphyre)引擎進行圖片資源的加載及初始化,在線程裡面各種錯誤。首先,報“ECannotCreateWICImagingFactory”錯誤,加了"{$IFDEF MSWINDOWS}CoInitialize(nil);{$ENDIF}"代碼後,不再報錯了。然後在初始化圖片時,偶爾會報浮點錯誤,這個搞了一天多愣是沒解決,問了pxl的作者,他回復我在主線程初始化不會有錯(ps:這個我知道的,作者自己的游戲就是啟動的時候開了個窗口在初始化)。沒辦法了,後來整理了一下思路,最終決定在解析配置的時候進行初始化。具體實現看下面幾段代碼。
function TFOLScene.createButton(const pvParent: TFOLSprite; const pvName, pvRectSet, pvImageName: string; const pvMsgcode: Integer; const pvText: string): TFOLButton; var lvRect: TIntRect; lvImageAry: TButtonImageAry; begin lvRect:= parseRect(pvRectSet); gvArchiveManager.require(pvImageName, lvImageAry); result:= TFOLButton.Create(pvParent); result.ObjType:= tstUI_Button; result.Name:= pvName; result.X:= lvRect.Left; result.Y:= lvRect.Top; result.Width:= lvRect.Width; result.Height:= lvRect.Height; result.EventID:= pvMsgcode; result.Text:= pvText; result.setButtonImage(lvImageAry); FObjects.Add(pvName,result); end;
procedure TFOLArchiveManager.require(const pvName: string; out pvOuter: TButtonImageAry); var lvEnum: TFOLButtonState; lvSuffix, lvFullName: string; begin for lvEnum:= Low(TFOLButtonState) to High(TFOLButtonState) do begin pvOuter[lvEnum]:= nil; lvSuffix:= gcButtonStateImageNameSuffix[lvEnum]; lvFullName:= pvName+lvSuffix; pvOuter[lvEnum]:= loadImage(lvFullName, pvOuter[tbsNormal]); end; end; function TFOLArchiveManager.loadImage(const pvName: string; pvDefaultImage: TAtlasImage): TAtlasImage; var lvIndex: Integer; lvStream: TStream; begin result:= FEngineImages.Image[pvName]; if not Assigned(result) then begin FGameImages.TryGetValue(pvName, lvStream); if Assigned(lvStream) then begin lvIndex:= FEngineImages.AddFromStream('.png',lvStream,pvName); result:= FEngineImages.Items[lvIndex]; end else if Assigned(pvDefaultImage) then result:= pvDefaultImage else result:= FEngineImages.Image['globa_error']; end; end;
3、實現了UI消息的轉發,下面代碼以按鈕點擊為例(代碼比較粗糙,看看知道怎麼回事就行)
{ TFOLButton } procedure TFOLButton.render(); var lvButtonState: TFOLButtonState; lvHint: string; begin lvButtonState:= tbsNormal; if PointInRect(Point2px(Trunc(gvEngineMouseData.X), Trunc(gvEngineMouseData.Y)), IntRect(FWorldX, FWorldY,FWidth,FHeight)) then begin case gvEngineMouseData.State of 1: begin lvButtonState:= tbsActive; lvHint:= 'down:' + FName; //按鈕圖片切換到按下態,這裡可以處理長按事件 end; 2: begin lvButtonState:= tbsNormal; gvEngineMouseData.State:= 0; gvGameMonitor.execMsgfunc(FEventID); lvHint:= 'up:' + FName; //按鈕圖片切換回常態,這裡可以觸發點擊事件並做相應處理 end; 3: begin lvButtonState:= tbsHover; lvHint:= 'move:' + FName; //圖片切換到高亮態 end; 4: begin lvButtonState:= tbsNormal; lvHint:= 'wheel:' + FName; //一般根據WheelDelta處理一些縮放、列表滾動等事件 end; end; end; gvEngineCanvas.UseImagePx(FButtonImageAry[lvButtonState], FloatRect4(0, 0, FWidth, FHeight)); gvEngineCanvas.TexQuad(FloatRect4(FWorldX, FWorldY, FWidth, FHeight), IntColorWhite4, TBlendingEffect.Normal); inherited; end; procedure TFOLButton.setButtonImage(pvImageAry: TButtonImageAry); var lvEnum: TFOLButtonState; begin for lvEnum:= Low(TFOLButtonState) to High(TFOLButtonState) do FButtonImageAry[lvEnum]:= pvImageAry[lvEnum]; end;
monitor單元的相關代碼:
procedure TFOLGameMonitor.execMsgfunc(const pvMsgCode: Integer); var lvInvokeEvent: TNotifyEvent; lvData: TFOLInvokeScriptFuncObject; begin FEventListener.TryGetValue(1, lvInvokeEvent); if Assigned(lvInvokeEvent) then begin lvData:= TFOLInvokeScriptFuncObject.Create(gcExecLuaMsgFuncName); lvData.pushInteger(pvMsgCode); lvInvokeEvent(lvData); end; end;
小結:目前基本上就是實現如下:
1、游戲啟動後,顯示一個啟動頁面(背景、logo、進度條、進度文字)
2、連接到版本服務器自動下載最新的資源文件更新(線程中,通過信號量反饋下載進度)
3、加載配置文件、聲音文件(線程中,通過信號量反饋載入進度)
4、資源載入完畢,運行app.lua,app.lua會調用客戶端函數根據傳入的ui名稱,創建一個頁面(現在是公告頁面)。
5、點擊公告頁面上的關閉按鈕,觸發notice.lua中的關閉頁面事件,調用客戶端的關閉頁面方法把此scene.visible設置為false,這樣在渲染循環裡面就不會去渲染這個頁面,達到不顯示的目的。
接下去應該是會考慮把主界面配置起來,同步完善一些ui控件。好吧,就這樣吧。