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,再绕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){
    mPreviewSV = new SurfaceView(JniDoIt.this);
    addContentView(mPreviewSV,new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,FrameLayout.LayoutParams.MATCH_PARENT)); // keep old views
    Log.i("SHOW_AR", "mPreviewSV is null and now it is added");
}
else{
    Log.i("SHOW_AR", "mPreviewSV already exist......");
}
if(mySurfaceHolder==null){
    mySurfaceHolder = mPreviewSV.getHolder();
    mySurfaceHolder.setFormat(PixelFormat.TRANSPARENT);
    Log.i("SHOW_AR", "mySurfaceHolder is null and now it is defined to mPreviewSV.getHolder()......."+mySurfaceHolder);
}
else{
    Log.i("SHOW_AR", "mySurfaceHolder already exist......"+mySurfaceHolder);
}
```


回调定义:
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,new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,FrameLayout.LayoutParams.MATCH_PARENT)); // keep old views
```


类定义:
private class ArSV extends SurfaceView implements SurfaceHolder.Callback{
    private SurfaceHolder mySurfaceHolder = null;
    private Camera myCamera = null;
    
    @SuppressWarnings("deprecation")
    public ArSV(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        mySurfaceHolder = getHolder();// 获得surfaceHolder引用
        mySurfaceHolder.addCallback(this);
        // TODO Auto-generated constructor stub
    }
    
    
    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; iindex=" + 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会永远在最上层吧。

好了,写完笔记,上张图,演示一些笔记里面说的这些东西是用在什么地方的,呵呵。坐标系转换是那个火控雷达用的,要让它显示出围绕着用户前后上下左右的敌机,并且用一颗绿色小准心死死咬住面前的敌机,就得靠几层的3D坐标向屏幕坐标的转换和映射了。背景的实景,就是依靠surfaceview开启的手机摄像头AR。

  

 


帅不帅,嘿嘿,是不是史上最另类的打飞机:882:


 
http://www.cocoachina.com/bbs/read.php?tid-271501.html

http://www.cocoachina.com/bbs/read.php?tid-271514.html

http://www.cocoachina.com/bbs/read.php?tid-272524.html

http://www.cocoachina.com/bbs/read.php?tid-273080.html

http://http://www.cocoachina.com/bbs/read.php?tid-273549.html

http://www.cocoachina.com/bbs/read.php?tid-277033.html

支持下楼主…干的漂亮

波总么么哒

:842: :842:

一看就是大神 小弟想做个 3D空间控制飞机 自由飞的Demo 摄像机的控制一直不对 大神能给点意见吗? 就是各个方向的旋转问题 学生党 菜鸟一枚 给大神跪了

这个问题其实在本篇里面,我已经把重点说到了,限于项目限制,具体解决方案暂时不能说得更多,呵呵,但是我给出的那段有bug的代码已经非常接近了。

嘿嘿,据说cocos下一版要出skybox和terrain了,在想下一篇是不是写一下这两个东西呢,捂了好久了,而且貌似项目已经不准备用这skybox和terrain了:882:

先上实现图显摆下吧,天空盒实现得比较完美,地形暂时还很粗糙:882:

其实,cocos做3D,只要自己愿意花点心思,可以做的很不错的!当然我不是说我发这个哦,哈哈,这个就是还没开始做美工的破烂:)

哦 好吧 谢谢大神 :6: :6: :6:

支持一下:2::2::2::2::2::2:

围观大神,万一混脸熟了呢

楼主别捂了,赶紧滴。预先给你那篇文章预留了加亮,申精,提前了…cocos教程实在是太少了。:12:

能不能说。。。。。脑海中浮现三个字母。。。。。。。。:12:

我擦, 都要支持 天空盒了 看来是时候学习一下cocos2d了.
不知道还来不来得及:3::3::3::3::3: