在原生环境下运行
1. 在安卓环境下运行
Android端引擎渲染视图使用GLRecorderView跟XERenderView
对于有录制需求的情景,使用GLRecorderView;对于没有录制需求的情况,推荐使用XERenderView
1.1. XERenderView的使用
XERenderView总体上分为以下3个步骤:
- view创建并配置
- 开始创建view的环境并监听
- 加载游戏资源
- 释放
具体使用如下:
1.1.1. view的创建(前两步也可以通过xml的方式代替)
- new一个View
mXERenderView = new XERenderView(this);
- 添加到容器中
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(xxx,xxx); containerFrameLayout.addView(mXERenderView);
- 创建一个controller并绑定
mXERenderViewController = new XERenderViewController(); mXERenderViewController.bindView(mXERenderView);
- 配置参数
XEViewConfig config = XEViewConfig.obtain(); config.mRootPath = "/sdcard/xxx"; config.mFrameRate = 30;//根据需要设置帧率 config.mRenderSize = new Point(480, 640);//设置渲染尺寸,若不设置默认view的宽高大小 mXERenderViewController.config(config);
开始准备,监听准备成功回调
注意,如果视图不可见的情况,系统创建surfaceTexture可能失败,所以,一定要保证视图大小不为0,且在屏幕内,可见
创建一个回调
XERenderViewController.OnPreparedCallback callback = new XERenderViewController.OnPreparedCallback() { @Override public void onPrepared() { //下面是加载资源的逻辑,跟view无关~~~ XE3DEngine engine = mController.getEngine(); engine.addSearchPath("zombiePartyDemo"); engine.getScriptEngine().startGameScriptFile("app"); } @Override public void onSurfaceChanged(int w, int h) { } @Override public void onDestroyed() { Log.e("LiveGame", "onDestroyed: "); } }
开始准备,并传入监听。 环境异步创建成功后,会在onPrepared中进行回调
mXERenderViewController.prepare(callback);
加载资源
在onPrepared回调中,调用engine.getScriptEngine().startGameScriptFile("app")加载资源。
注意路径是基于上面配置的rootPath的。
也可以通过engine.addSearchPath(scenePath)配置searchPath(也是基于rootPath),这样资源也会在searchPath中去查找
参考代码见上一步中onPrepared回调部分
释放
释放有两种方式,即自动释放与手动释放
- 自动释放
页面退出,或者父布局被移除等触发onDetachFromWindow的时候,会触发同步退出 - 手动释放
手动释放需要调用父布局容器的removeView(mXERenderView)来移除,移除过程是同步的,调用remove后会触发onDestroy()回调containerFrameLayout.removeView(mXERenderView); //containerFrameLayout.removeAllView();
2. 在iOS环境下运行
2.1. 普通渲染
场景选择:只有一个业务使用到引擎渲染,且不需要使用渲染录制、截屏功能
渲染视图选择
XSKDisplayView:
封装GLView作为渲染视图,引擎绑定的OpenGLES Context和GLView的Context是同一个,引擎渲染直接通过GLView展示出来。
接口介绍
@interface XSKDisplayView : XSKTouchView
- (instancetype)initWithFrame:(CGRect)frame;
@property (weak) id <XSKDisplayViewDelegatedelegate; // 每帧Render回调
- (void)setupEngine:(NSString *)path; // 启动引擎,建议以XSKEngine接口替换
- (void)destoryEngine; // 销毁引擎,建议以XSKEngine接口替换
@end
@protocol XSKDisplayViewDelegate <NSObject>
@optional
- (void)displayView:(XSKDisplayView *)displayView willRender:(CGRect)renderRect; // 每帧渲染回调
- (void)displayView:(XSKDisplayView *)displayView customRender:(CGRect)renderRect; // 默认调用render(),可以自定义调用render(sceneID)
@end
接入示例
// 启动引擎
NSString *path = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/demo.bundle"];
[[XSKEngine shareInstance] configResourcePath:path]; // 引擎根路径配置
[[XSKEngine shareInstance] runEngine]; // 启动引擎
[[XSKEngine shareInstance] setupLuaScriptEngine]; // 启动Lua脚本引擎
// 渲染设置
self.preview = [[XSKDisplayView alloc] initWithFrame:CGRectMake(0, 0, 375, 667)];
[self.view addSubview:self.preview];
// 通过lua脚本启动
[[XSKEngine shareInstance] addSearchPath:@"game"]; // 添加脚本在引擎根路径的相对路径
[[XSKEngine shareInstance] execteGameScriptFile:@"app"]; // 启动Lua脚本
// 脚本代码参考文末
2.1.1. 共享渲染
场景选择:有多个业务使用到引擎渲染,如:直播视频特效和交互礼物同事支持,或者需要使用录制、截屏功能
渲染视图选择
XSKGLDisplayView:
封装GLView作为预览视图,引擎绑定的OpenGLES Context和GLView的Context不是同一个,引擎有单独的OpenGLES Context,引擎先渲染到PixelBuffer,然后通过预览视图预览PixelBuffer的内容。
接口介绍
@interface XSKGLDisplayView : XSKTouchView
- (instancetype)initWithFrame:(CGRect)frame;
@property(nonatomic, assign) CGSize renderSize; //默认为 viewSize*nativeScale
@property(nonatomic, assign) NSUInteger frameRate; //默认是 30帧
@property(nonatomic, weak) id <XSKGLDisplayViewDataOutputDelegatedelegate; // 录屏回调
@property(nonatomic, readonly) CGFloat nativeScale; // 来自UIScene的nativeScale
- (void)shot:(void (^)(UIImage *))callback; // 截图
- (void)pause; // 渲染暂停,不调用引擎render()
- (void)resume; // 恢复渲染
- (void)updateRenderID:(NSString *)renderID; // 特殊情况需要用到指定渲染ID调用此接口
@end
// 回调录屏PixelBuffer,不设置代理则不处理录屏相关操作,性能会更高
@protocol XSKGLDisplayViewDataOutputDelegate <NSObject>
@optional
- (void)displayView:(XSKGLDisplayView *)displayView didOutputVideoPixelBuffer:(CVPixelBufferRef)pixelBuffer timinginfo:(CMSampleTimingInfo)timingInfo;
@end
接入示例
// 启动引擎
NSString *path = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/demo.bundle"];
[[XSKEngine shareInstance] configResourcePath:path]; // 引擎根路径配置
[[XSKEngine shareInstance] runEngine]; // 启动引擎
[[XSKEngine shareInstance] setupLuaScriptEngine]; // 启动Lua脚本引擎
// 渲染设置
self.preview = [[XSKGLDisplayView alloc] initWithFrame:CGRectMake(0, 0, 375, 667)];
[self.view addSubview:self.preview];
// 渲染尺寸设置
self.displayView.renderSize = CGSizeMake(720, 1280));
// 通过lua脚本启动
[[XSKEngine shareInstance] addSearchPath:@"game"]; // 添加脚本在引擎根路径的相对路径
[[XSKEngine shareInstance] execteGameScriptFile:@"app"]; // 启动Lua脚本
// 脚本代码参考文末
2.1.2. 示例使用Lua脚本参考
function ONLINE_LOG(log)
print(tostring(os.time()) .. " GAME_LOG: " .. tostring(log))
end
local App = {}
function App.onStart()
ONLINE_LOG("App onStart")
local scene = xe.Scene:new("com.wemomo.engine")
scene:GetWorld():LoadScene("xxxx.xscene")
xe.Director:GetInstance():PushScene(scene)
end
function App.onResume()
ONLINE_LOG("App onResume")
end
function App.onPause()
ONLINE_LOG("App onPause")
end
function App.onEnd()
ONLINE_LOG("App onEnd")
end
xe.AppDelegate = App
3. 与原生环境通信
引擎提供了Bridge模块进行Lua与原生平台的通信.
3.1. Lua调用原生平台
在原生平台注册Bridge Handler后才可以进行在Lua中调用原生平台.
3.1.1. 注册Handler
在iOS中:
//Handler实现类
@interface MyHandler : NSObject
- (NSString *)action:(NSString *)msg;
- (void)actionAsync:(NSString *)msg callback:(void (^)(NSString *))callback;
@end
//注册Handler
MyHandler *handler = [[MyHandler alloc] init];
[XSKBridge regist:handler forHandler:@"handler"];
在安卓中:
//Handler实现类
public class MMGameHandler {
public String action(String msg);
public void actionAsync(String msg, ScriptBridge.Callback callback);
}
//注册Handler
MyHandler handler = new MyHandler();
ScriptBridge.regist(new MMGameHandler(),"handler");
3.1.2. 在Lua中调用Handler
--调用同步方法
local result = xe.ScriptBridge:call("handler", "action", "lua message");
--调用异步方法
xe.ScriptBridge:callAsync("handler", "actionAsync", "message form lua", function(result)
print(result);
end);
注意事项:Bridge Handler 中的方法被Lua调用时是在引擎的渲染线程中,所以需要使用者注意线程问题,如有需要自行在bridge方法中调度线程。
3.2. 原生平台调用Lua
相对于Lua调用原生平台看来说,原生调用Lua的时候,我们提供了更多的方式以适应不同的业务场景
3.2.1. 通过事件派发器
在安卓中:
//Java
DataEvent event = new DataEvent();
event.setName("ActionName");
event.setContent("Action");
XE3DEngine.getInstance().sendEvent(event);
在iOS中
//Objc
xes::DataEvent event;
event.SetName("ActionName");
event.SetContent("Action);
xes::Director::GetInstance()->GetEventDispatcher()->DispatchEvent(&event);
在Lua中:
self.datalst = xe.DataEventListener:Create()
self.datalst:RegisterHandler(function(sender, data)
print('数据监听 ', data)
end, "ActionName")
xe.Director:GetInstance():GetEventDispatcher():AddEventListener(self.datalst, self)
3.2.2. 通过Bridge
在Lua中:
--lua
LuaObject = {} --全局对象
LuaObject.action = function(message)
print("原生调用Lua传递消息", message)
end
在安卓中:
//Java
ScriptBridge.callLua("LuaObject", "action", "message");
在iOS中:
//Objc
[XSKBridge callLua:@"LuaObject" action:@"action" message:@"message"];
通过脚本解释器
在安卓中:
//Java
XELuaEngine.getInstance().executeScriptFile("print('lua print')");
在iOS中:
//Objc
xes::LuaEngine::GetInstance()->ExecuteString("print('lua print')")