使用cocos2dx结合bullet设计一款简陋的桌球游戏,就是为了回顾前期学过的bullet。@H_404_13@
首先要把桌球游戏需要的基本资源准备好,15个球,1个白球,1张台球桌,球杆可有可无。@H_404_13@
@H_404_13@
@H_404_13@
至于这张台球桌的模型,我是随便设计一下@H_404_13@
当然这个模型只是为了加载raw文件(静态网格数据),为了使模型的贴图显示出来,@H_404_13@
我使用Blender直接创建了一个Plane,然后将台球桌的贴图贴在Plane上,于是就能以假乱真的@H_404_13@
实现一个台球桌@H_404_13@
@H_404_13@
在游戏开始前,初始化物理环境,加载一张台球桌,设置相应的物理属性,按规则摆放好台球。@H_404_13@
1.设置重力为(0.f,-9.8f,0.f),以模拟真实的物理环境。@H_404_13@
_world = PhysicsWorld3D::createWithDebug(this,btVector3(0.f,0.f));
2.加载台球桌@H_404_13@
首先将台球桌的贴图模型加载进游戏,设置相应的位置,@H_404_13@
然后加载台球桌的物理网格,还记得PhysicisMesh3D吗,并调整好位置,@H_404_13@
当然比较不好设置的就是台球桌的物理属性,什么摩擦系数啊,弹性系数啊,滚动摩擦系数啊@H_404_13@
void HelloWorld::initTable() { auto tableSprite = Sprite3D::create("ball/table.c3b"); this->addChild(tableSprite); tableSprite->setPosition3D(Vec3(0.f,-0.57f,0.f)); tableSprite->setCameraMask(2); _tableMesh = PhysicsMesh3D::constuct("table.raw"); _world->addTriangleMesh(_tableMesh,btVector3(0,0),PhysicsMaterial3D(0.f,0.5f,0.2f,0.2f)); }
3.摆放台球@H_404_13@
对于15球来说摆放的顺序是这样的,在网上找的规则@H_404_13@
黑8放在第三行的中间位置,白色的为全色球,黑色的为花色球。@H_404_13@
@H_404_13@
可以这样设想,只要定义一个数组存放每个位置的球号就行了,@H_404_13@
BALLS_NUMBER[0]=1;@H_404_13@
@H_404_13@
BALLS_NUMBER[1]=2;@H_404_13@
BALLS_NUMBER[2]=9;@H_404_13@
@H_404_13@
BALLS_NUMBER[3]=10;@H_404_13@
BALLS_NUMBER[4]=8;@H_404_13@
BALLS_NUMBER[5]=3;@H_404_13@
@H_404_13@
BALLS_NUMBER[6]=4;@H_404_13@
BALLS_NUMBER[7]=11;@H_404_13@
BALLS_NUMBER[8]=5;@H_404_13@
BALLS_NUMBER[9]=12;@H_404_13@
@H_404_13@
BALLS_NUMBER[10]=13;@H_404_13@
BALLS_NUMBER[11]=6;@H_404_13@
BALLS_NUMBER[12]=14;@H_404_13@
BALLS_NUMBER[13]=15;@H_404_13@
BALLS_NUMBER[14]=7;@H_404_13@
@H_404_13@
球号是我自己按照规则随便放的。@H_404_13@
@H_404_13@
下面就是如果将这些球放好,@H_404_13@
假设每个球半径为0.57f,球都在Y坐标为0的位置,那么关键就是如何确定每个球的@H_404_13@
X,Z.台球摆放好无论多少行都是个等边三角形,以3行为例@H_404_13@
先放置第一个球,以后每一行的第一个球都是按照蓝色箭头的方向放置,假设上为Z,右为X@H_404_13@
那么第二行第一个球就是(ball[1].posX+ball.radius,ball[1].posZ+√3*ball.radius)@H_404_13@
设方向向量为dir(ball.radius,√3*ball.radius);@H_404_13@
即ball[2].pos=ball[1].pos+dir@H_404_13@
第三行就是ball[3].pos=ball[1].pos+dir*2;@H_404_13@
一次类推ball[n].pos=ball[1].pos+dir*(n-1);@H_404_13@
对于同一行的第k个球就是同一行的第一个球.pos.x-2*radius;@H_404_13@
Sprite3D* ballSprite; btRigidBody* ballBody; int curNumber = -1; float offsetZ = -7.f; Vec3 ballPos; const Vec3 dir = Vec3(-0.57f,0.f,-0.987269f); for (int i=0; i<5; ++i) { ballPos = dir * i; ballPos.x += -1.14f; ballPos.z += offsetZ; for (int j=0; j<=i; ++j) { curNumber++; // 第几个球 ballPos.x += 1.14f; // 每行第k个都是上一个球的X+ 2 * radius ballSprite = Sprite3D::create("ball/ball.c3b",StringUtils::format("ball/ball_%d.png",BALLS_NUMBER[curNumber])); this->addChild(ballSprite); ballSprite->setPosition3D(ballPos); ballSprite->setCameraMask(2); ballBody = _world->addSphere(0.57f,btVector3(ballPos.x,ballPos.y,ballPos.z),PhysicsMaterial3D(4.2f,0.9f,0.15f)); ballBody->setUserPointer(ballSprite); _balls.push_back(ballBody); } }
Sprite3D::create("ball/ball.c3b",BALLS_NUMBER[curNumber]));
根据提前的设计加载相应的球号。@H_404_13@
@H_404_13@
ballPos=dir*i;@H_404_13@
ballPos.x+=-1.14f;@H_404_13@
ballPos.z+=offsetZ;@H_404_13@
设置每行第一个球的位置@H_404_13@
@H_404_13@
最后就是加载白球,白球要特别独立出来@H_404_13@
// white ball ballSprite = Sprite3D::create("ball/ball.c3b","ball/ball_white.png"); this->addChild(ballSprite); ballSprite->setPosition3D(Vec3(0.f,5.f)); ballSprite->setCameraMask(2); _whiteBallBody = _world->addSphere(0.57f,5.f),0.15f)); _whiteBallBody->setUserPointer(ballSprite);
4.更新物理世界@H_404_13@
_world->update(delta); float m[16]; for (auto ballBody : _balls) { ballBody->getWorldTransform().getOpenGLMatrix(m); static_cast<Sprite3D*>(ballBody->getUserPointer())->setNodeToParentTransform(Mat4(m)); } _whiteBallBody->getWorldTransform().getOpenGLMatrix(m); static_cast<Sprite3D*>(_whiteBallBody->getUserPointer())->setNodeToParentTransform(Mat4(m));
每一帧都去更新实际上是很浪费资源的,当所有的球都不动时,其实没必要更新,但是只有不到20个球,@H_404_13@
性能不会影响,当游戏中出现大量的物体时,就要重载btMotionState,这个以后讨论。@H_404_13@
5.测试一下@H_404_13@
当点击屏幕是给白球施加一个冲量,记住一定要先唤醒物体,不然不会有效果的@H_404_13@
_whiteBallBody->setActivationState(ACTIVE_TAG);@H_404_13@
_whiteBallBody->applyCentralImpulse(btVector3(0.f,-60.5f));@H_404_13@
总结:@H_404_13@
不是美工,模型什么的设计很费劲,贴图都是网上找的。@H_404_13@
台球桌,台球的物理属性,调整麻烦,目前调整的还不好@H_404_13@
对于添加的Sprite3D一定要设置CameraMask不然是不会被看到的。@H_404_13@
// light auto light = SpotLight::create(Vec3(0,-1.f,0.f),Vec3(0.f,Color3B::WHITE,1000.f); light->setPosition3D(Vec3(0.f,100.f,0.f)); this->addChild(light); light->setCameraMask(2);
Bullet库的设置方法请参考http://www.jb51.cc/article/p-nbqlamce-bkn.html@H_404_13@ 原文链接:https://www.f2er.com/cocos2dx/344574.html