一、cocos2dx视图层级介绍
不管在Android、IOS、还是h5平台,videoview与webview永远都是压在游戏视图之上的,所以当我们在项目内添加组件webView或者videoPlayer的时候,你会发现,这两个view会无视当前canvas节点的层级永远显示在最上面,以Android举例,为什么会是这样子
首先查看文件Cocos2dxActivity.java,发现如下代码
其中init添加了游戏视图
Cocos2dxWebViewHelper.java在如下函数中添加了webview图层
而Cocos2dxVideoViewHelper.java在如下函数中添加了视频图层,并且设置为最上层
按照视图绘制顺序,越先绘制的图层再越下面,而且,视频图层VideoView将之层级设置为Top,所以,正常情况下,游戏图层是被压在视频图层与网页图层之下的。
二、在视频上添加按钮或其他内容
这是个很普遍的需求,即使你现在正常做的项目没有这样的需求,但是只要你一直从事这一行,就一定会遇到。
首先思考一下,我们想在视频上添加其他UI,并且能够与这些UI进行交互,那么必然需要能够接收到用户的触控事件,假如游戏图层上方有其他图层A,那么必然是A接收并阻拦掉触控事件,所以,我们先将游戏视图的层级放到视频视图之上。
然后游戏视图默认是黑色的,如果盖在视频之上,那么视频也就看不到了,所以我们还需要将游戏视图默认背景设置透明。
1、h5的实现
video0.style.zIndex = -1 说明视频层级放在最下层
c.Camera.main.backgroundColor 设置游戏视图背景透明,
setClearColor说明刷新的背景板颜色也为透明
2、Android的实现
Cocos2dxVideoHelper._createVideoView 内,将设置视频层级最高的代码删除
Cocos2dxActivity.onCreateView 内,设置游戏视图层级最高
AppActivity.onCreateView 内,将游戏视图背景设置为透明
3、IOS实现
CCApplication-ios.onCreateView中,将视图背景设置为透明
AppController中,修改代码,先绘制视频图层、再绘制游戏图层
4、IOS兼容处理
在creator 2.1.2之前的版本,ios用户展示视图的控件为MediaPlayer,该控件在IOS往上的设备已经弃用了,需要手动升级到AVPlayerViewController, 更高版本的creator已经替换了,不需要处理。
5、引擎底层c++处理
如果做过渲染这块的同学应该知道,我们的游戏场景之所以会在屏幕上展示出连续的画面,是因为有类似这样的代码
while (true){
draw()
}
draw里面一般是刷新我们的视图内容,因为是一个循环的过程所以我们会不停刷新形成动态画面。
而一般在刷新之前,我们需要删除上一帧的残留画面,cocos在代码上表现在这里
clearColor函数在每次绘制一开始,将上一帧的画面擦干净,引擎之前是1,1,1,1,也就是纯黑色,我们把刷新的alpha值改为 0,这样就能通过glsurfaceView 透视到下面的视频图层了
至此 项目中的视频会作为背景存在于游戏视图之下,你可以在上面添加UI了。
三、在WebView上面加按钮
如果你没有经验,那么你首先想到的可能是调整WebView层级,当然,最终可以顺利的实现这个效果,但是这种方案最终会带来一个致命的问题:
一般webview承载的内容为有许多交互内容,例如按钮。webview放置于glView之下,那么glView将完全拦截点击事件,我们只能观看它。
1、在webView上面添加webView
看到这,你应该知道我想说什么。没错,webview与webview是同一层级的图层,后面添加的webview当然会覆盖在之前的上面。
2、将后添加的webview当作按钮来用
以上图为例,webviewBtn1加载的是一个网页 http://xxx.html,而这个网页的内容,就是一张全屏幕的按钮图片。
上图是两个webview。
3、相应webview的点击事件
首先,在webview的node节点上,添加button是不行的,因为button属于游戏层级,在webview层级之下,我们是无法通过button接收到的,我们只能通过接收webviewBtn内网页的内容来达到我们的目的。
h5平台,这个webviewBtn该这么响应,当然这种方式不用遇到跨域的问题,请放心:
// webviewBtn.html 点击后,触发动作
document.location = 'close://hahaha=1';
// 在h5客户端,得到响应
window.addEventListener("message", (e) =>{
if (e.data == "close") {
// do something
}
}
再来看看原生平台该如何响应
// webviewBtn.html 点击后,触发动作
parent.postMessage("close", '*');
// 在原生客户端,得到响应
var jsCallback = function (sender, str) {
// do something
}
// this.btn,为webViewBtn的cc.WebView组件
this.btn.setJavascriptInterfaceScheme("close")
this.btn.setOnJSCallback(jsCallback)
至此,你可以在webview上自由添加按钮了
4、与videoView的兼容处理
如果你不需要在自己的项目处理videoView的话,那么在第3步的时候,你已经完成了webview部分的功能。但是如果你在自己的项目内同时使用两套方案,那么请继续往下看。
首先为了能够在视频上添加ui等内容,我们在Android平台上,将游戏图层设置为最上了,所以,它一定是覆盖在webview之上的,我是这么解决Android平台的问题的:
// 进入webview时
glSurfaceView.setZOrderOnTop(false);
// 离开webview时
glSurfaceView.setZOrderOnTop(true);
四、webview加载部分网页的兼容处理
cocoscreator2.1.2以下的webview,在原生设备上加载某些网页会崩溃,需要升级使用webkit,具体的升级方式请参考creator最新版本的源码,或者在开发的时候使用最新版本的引擎。
PS:笔者截稿时,creator最新版本为2.3.1,由于刚发布,稳定性未知。而据笔者了解2.3.0的版本又有许多bug待解决。所以最稳定版本为哪个也不好说,但是不管用哪个版本,通过合并fix保证自己的creator最稳定总是没错的。
笔者的方案不是demo,有正在线上运营的项目为保证,请放心食用。文章可能比较粗糙,有问题或者建议可以留言或私信。