这周还是在改自己的这个框架,被多线程折腾了两天,最终无奈放弃在游戏启动时调用引擎进行图片相关资源的初始化,当然进展还是不错的。
嗯,下面还是以流水的方式继续记录一下本周完成的工作:
1、调通了客户端与lua的相互调用,用的是verysimple这个第三方库(跨平台的库)。这边遇到一个坑,特此记录。
我用的版本lua5.3,似乎官方已经取消了module函数,反正我在lua文件里面直接写“module(模块名,package.seeall)”,require这个lua文件的时候会报错。网上查了不少资料,据说module方法效率慢,而且极易污染全局空间,官方并不提倡使用。看来真有可能新版本把这个方法给丢弃了。反正我是没办法再去花时间找原因了(已经浪费了大半天时间,而且有个前辈劝我说不要用这个方法)。后来实现的代码如下,在此特别感谢 "广州-随云" 的无私帮助。
local module_notice = {} function module_notice:open() client.monitor:register(,module_notice.OnClose); createScene("notice"); end function module_notice:OnClose() closeScene("notice"); client.monitor:unRegister(,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 : begin lvButtonState:= tbsActive; lvHint:= 'down:' + FName; //按钮图片切换到按下态,这里可以处理长按事件 end; : begin lvButtonState:= tbsNormal; gvEngineMouseData.State:= ; gvGameMonitor.execMsgfunc(FEventID); lvHint:= 'up:' + FName; //按钮图片切换回常态,这里可以触发点击事件并做相应处理 end; : begin lvButtonState:= tbsHover; lvHint:= 'move:' + FName; //图片切换到高亮态 end; : begin lvButtonState:= tbsNormal; lvHint:= 'wheel:' + FName; //一般根据WheelDelta处理一些缩放、列表滚动等事件 end; end; end; gvEngineCanvas.UseImagePx(FButtonImageAry[lvButtonState], FloatRect4(, , 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(, 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控件。好吧,就这样吧。