cocos2dx 3D战斗类游戏制作:【四】——一些零散笔记,3D小地图,android surfaceview等

概述在cocos的坐标系、cocos与Android之间遇到一些事情,做个笔记。 首先是坐标系,Cocos的一个node,其rotation,是基于其父节点坐标的。例如layer里面添加一个camera,那么旋转camera的xyz,例如setRotation3d(Vec3(0,180,90)),并不是让camera绕自身y转180后,再绕自身z轴转90。而是camera绕layer的x转180,再绕 在cocos的坐标系、cocos与AndroID之间遇到一些事情,做个笔记。


首先是坐标系,Cocos的一个node,其rotation,是基于其父节点坐标的。例如layer里面添加一个camera,那么旋转camera的xyz,例如setRotation3d(Vec3(0,180,90)),并不是让camera绕自身y转180后,再绕自身z轴转90。而是camera绕layer的x转180,再绕layer的z转90。脑补一下就知道,实际上两个方式的z旋转,因为y上已经转了180,所以方向是相反的了。清楚了一点,有助于处理比较麻烦的坐标系相对旋转问题。camera是与精灵们在同一个layer,还是不同layer,取决于要不要观察相机后方而维持正常的Z旋转。


然后就是独立于layer之外的camera,如何在小地图屏幕还原sprite的二维坐标?如果相机与sprite在同一layer,只需要相机矩阵简单一句mat.getInversed().transformVector(&pos)即可。但是当camera与layer分离时,又会有诸多情况,嘿嘿。这部分,贴一段看起来貌似OK但是实际会有问题的代码:

Vec3 bosspos = boss_i->getposition3D();Vec2 PosAfterRotate = Vec2(bosspos.x,bosspos.z).rotateByAngle(Vec2(0,0),CC_degrees_TO_radians(-_layer3D->getRotation3D().y));//X与Z绕Y还原至垂直相机的平面Vec4 pos;pos.x = PosAfterRotate.x; pos.y = bosspos.y; pos.z = PosAfterRotate.y;pos.w = 1;Mat4 mat = _CameraBird->getNodetoWorldtransform();mat.getInversed().transformVector(&pos);//使用相机矩阵,取得boss在屏幕的投射坐标Vec2 bossposAbs = Vec2(pos.x,pos.y) / (curPos.distance(bosspos));


这段代码看似无误,实际运用中却会发现还原出的bossposAbs与boss显示位置存在偏差,原因是什么,自己想吧,哈哈,就不说破了。正确的计算方式是什么?想明白了为什么这个会错,正确的自然也就呼之欲出了。



然后是cocos与androID的surfacevIEw的问题。androID的surfacevIEw是在游戏被推入后台时,会被自动destroy的。然后程序再被唤醒时,它又会被oncreate。这涉及了诸多线程的问题,也就会产生一堆的怪事。

首先,使用的是在主程序中创建一个新的surfacevIEw,通过其回调启动相机的方式。

if(mPrevIEwSV==null){<span >	</span>mPrevIEwSV = new SurfaceVIEw(JnIDoIt.this);<span >	</span>addContentVIEw(mPrevIEwSV,new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,FrameLayout.LayoutParams.MATCH_PARENT)); // keep old vIEws<span >	</span>Log.i("SHOW_AR","mPrevIEwSV is null and Now it is added");}else{<span >	</span>Log.i("SHOW_AR","mPrevIEwSV already exist......");<span >					</span>}if(mySurfaceHolder==null){<span >	</span>mySurfaceHolder = mPrevIEwSV.getHolder();<span >	</span>mySurfaceHolder.setFormat(PixelFormat.transparent);<span >	</span>Log.i("SHOW_AR","mySurfaceHolder is null and Now it is defined to mPrevIEwSV.getHolder()......."+mySurfaceHolder);<span >					</span>}else{<span >	</span>Log.i("SHOW_AR","mySurfaceHolder already exist......"+mySurfaceHolder);<span >					</span>}

回调定义:

private class ArSurfaceHolderCallBack implements SurfaceHolder.Callback{}


在游戏推入后台时,释放相机,并且删除surfacevIEw的回调,唤醒时重建一次surfacevIEw。如此做的结果是相机预览是恢复了,但是把cocos主界面也覆盖了,下面是其log




log那一行onenGL错误曾经误导了很久,那是一个在UI线程之外更新UI而产生的错误,结合cocos界面被覆盖的实际情况,感觉非常非常像是surfacevIEw进程与UI进程冲突,但是暂且忽略吧,因为后来发现完全注释掉surfacevIEw相关代码,这个错照样存在,而且在我最终的解决方案中,这个错虽然仍旧存在,但是可以做到正常唤醒。这个错应该是程序中某些其他位置导致的,暂且不理它。


那么不使用回调方式,直接使用surfacevIEw类内部取得自身handler,在游戏推入后台时,释放相机,并且删除surfacevIEw,唤醒时重建一次surfacevIEw,重新启动回调和相机如何呢?

呼叫方式:

mPrevIEwSV = new ArSV(JnIDoIt.getContext());mPrevIEwSV.setID(100);JnIDoIt.this.addContentVIEw(mPrevIEwSV,FrameLayout.LayoutParams.MATCH_PARENT)); // keep old vIEws

类定义:
private class ArSV extends SurfaceVIEw implements SurfaceHolder.Callback{
 <span >	</span>private SurfaceHolder mySurfaceHolder = null;  <span >	</span>private Camera myCamera = null;  <span >	</span>  <span >	</span>@SuppressWarnings("deprecation")<span >		</span>public ArSV(Context context) {<span >			</span>super(context);<span >			</span>// Todo auto-generated constructor stub<span >			</span>mySurfaceHolder = getHolder();// 获得surfaceHolder引用<span >			</span>mySurfaceHolder.addCallback(this);<span >			</span>// Todo auto-generated constructor stub<span >		</span>}  <span >	</span>public voID surfaceCreated(SurfaceHolder holder){}
..........
}

情况照旧,唤醒时,把cocos主界面也覆盖了。下面是其log。



log中可注意到一件小事,destroy发生在remove之前,而remove是主程序在PushBackground时使用如下代码进行的。

case PushBackground:	if(null != compass){		compass.stop();		Log.i("PushBackground","Compass stopped....");}else{	Log.i("PushBackground","Compass not exist....");}if(mPrevIEwSV!=null){	VIEwGroup vg = (VIEwGroup)mPrevIEwSV.getParent();      Log.i("PushBackground","child count=" + vg.getChildCount());      VIEw vIEwCamera = null;    for(int i=0; i<vg.getChildCount(); i++){         VIEw vIEw = vg.getChildAt(i);         Log.i("PushBackground","index=" + i +":vIEw = " + vIEw+"   ID="+vIEw.getID());        if(vIEw.getID()==100){        	vIEwCamera=vIEw;			vg.removeVIEw(vIEwCamera);			mPrevIEwSV=null;			Log.i("PushBackground","Remove vIEw = "+vIEwCamera+"  ID="+vIEw.getID());        }    }    for(int i=0; i<vg.getChildCount(); i++){         VIEw vIEw = vg.getChildAt(i);         Log.i("PushBackground","after clean------->index=" + i +":vIEw = " + vIEw+"   ID="+vIEw.getID());        vIEw.layout(120,120,250,250);    }}


也就是说for循环都还没List到mPrevIEwSV,它就已经destroy了。不过在后续循环中它仍旧被remove了。


分别在新线程中创建surfacevIEw,或者runonUIthread,没有什么区别,都存在surface在唤醒时,抢占顶层z序的问题。尝试使用bringToFront()将cocos的framelayout调到顶层,但是没什么作用。


ok,ok,看起来,应该是surfacevIEw太强大了,要不然就是新线程中运行的绘屏surface会永远在最上层吧。

总结

以上是内存溢出为你收集整理的cocos2dx 3D战斗类游戏制作:【四】——一些零散笔记,3D小地图,android surfaceview等全部内容,希望文章能够帮你解决cocos2dx 3D战斗类游戏制作:【四】——一些零散笔记,3D小地图,android surfaceview等所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1054166.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-25
下一篇2022-05-25

发表评论

登录后才能评论

评论列表(0条)

    保存