用Cocos2d-x-3.0及Box2d预测物体弹道轨迹


英文论坛原帖:
http://discuss.cocos2d-x.org/t/cocos3-0-tutorial-predict-a-trajectory-with-cocos2d-x-and-box2d/13493

如何使用cocos2d-x和Box2d来预测物体弹道轨迹

 

 


本部分内容设定了隐藏,需要回复后才能看到

创建一个新项目

用这些代码创建一个新cocos2d-x项目:
cocos new MyGame -p com.MyCompany.MyGame -l cpp -d ~/MyCompany

关于创建新项目的细节请查阅下面的网页:
http://cocos2d-x.org/wiki/How_to_Start_A_New_Cocos2D-X_Game

注意:当你使用cocos-console新创建一个项目时,文件夹cocos2d会在你的项目文件夹里生成。但因为它太大了,所以我并没有将它上传。

素材资源
下载ball.png 和 dot.png 并复制进Resources文件夹。



  

Linux版本

打开你的项目文件夹并且在文件夹CMakeLists.txt第161行添加box2d(在on target link libraries那一部分)

box2d
结果看起来就像是:
target_link_libraries(${APP_NAME}
      ui
      network
      storage
      spine
      cocostudio
      cocosbuilder
      extensions
      audio
      cocos2d
      box2d
  )
Windows版本

打开你的proj.win32 .SLN 文件并添加Box2D文件依赖

右键点击解决方案Solution而不是项目名称然后点击添加add—>现有项目add exist project,搜索外部资源“BOX2D“并添加

现在右键点击解决方案,点击属性,选择项目依赖项Project Dependencies并勾取libBox2D使其加入编译

现在右键点击你的项目名称(解决方案的里面),并选择引用reference,在底部点击添加新引用ADD NEW REFERENCE然后勾选libBox2D并点击确定OK。

点击确定OK关闭窗口。

是时候敲键盘写代码了:

在HelloWorldScene.h里,在第四行也就是#include "cocos2d.h"的下面添加:


?
1
USING_NS_CC;


在public的下面添加:

?
1
2
3
bool onTouchBegan(Touch* touch, Event* event);
void onTouchMoved(Touch* touch, Event* event);
void onTouchEnded(Touch* touch, Event* event);


在INIT主要函数中添加鼠标监听事件(提示:是在HelloWorldScene.cpp)

?
1
2
3
4
5
6
7
8
9
10
//SET MOUSE LISTENER
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches( true );
 
listener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this );
listener->onTouchMoved = CC_CALLBACK_2(HelloWorld::onTouchMoved, this );
listener->onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this );
 
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this );
//END MOUSE LISTENER


在CPP主文件里(HelloWorldScene.cpp)添加下列函数:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
bool HelloWorld::onTouchBegan(Touch* touch, Event* event)
{
 
     return true ;
}
 
void HelloWorld::onTouchMoved(Touch* touch, Event* event)
{
 
 
}
 
void HelloWorld::onTouchEnded(Touch* touch, Event* event)
{
 
}


在INIT函数中添加:

?
1
2
3
4
5
6
7
8
9
10
11
//CREATE A BALL
dragOffsetStartX = 0;    
dragOffsetEndX = 0;    
dragOffsetStartY = 0;    
dragOffsetEndY = 0;    
existBall= false ;    
ballX = 500;
ballY = 200;    
ball =Sprite::create( "ball.png" );
ball->setPosition(CCPoint(ballX,ballY));
this ->addChild(ball);


在头文件(HelloWorldScene.h)中添加:

?
1
2
3
4
5
6
7
8
9
10
11
12
Sprite *ball;
bool existBall;
float ballX;
float ballY;    
int dragOffsetStartX;
int dragOffsetEndX;
int dragOffsetStartY;
int dragOffsetEndY;    
b2Body *ballBody;    
b2CircleShape ballShape;
b2BodyDef ballBodyDef;  
void defineBall();


添加物理引擎

在头文件中添加box2d程序库:

?
1
#include <Box2D/Box2D.h>


添加b2ContactListener
更改:

?
1
class HelloWorld : public cocos2d::Layer

成:
?
1
class HelloWorld : public cocos2d::Layer, public b2ContactListener

然后添加:
?
1
2
b2World *world;
float deltaTime;

在INIT函数里添加下列代码:
?
1
2
b2Vec2 gravity = b2Vec2(0.0f, -10.0f);
world = new b2World(gravity);    

参数-10.0f指出了在y轴上的重力加速度:
现在我们需要添加一个SCALE_RATIO。将其定义在文件顶端:
?
1
#define SCALE_RATIO 32.0


SCALE_RATIO指出了将单位:像素转换成单位:米的值,因为BOX2D使用的计量单位是米。

在主文件(HelloWorldScene.cpp)中添加:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void HelloWorld::defineBall() {
     ballShape.m_radius = 45 / SCALE_RATIO;
     b2FixtureDef ballFixture;
     ballFixture.density=10;
     ballFixture.friction=0.8;
     ballFixture.restitution=0.6;
     ballFixture.shape=&ballShape;
 
     ballBodyDef.type= b2_dynamicBody;
     ballBodyDef.userData=ball;
 
     ballBodyDef.position.Set(ball->getPosition().x/SCALE_RATIO,ball->getPosition().y/SCALE_RATIO);
 
     ballBody = world->CreateBody(&ballBodyDef);
     ballBody->CreateFixture(&ballFixture);
     ballBody->SetGravityScale(10);
}    


在添加球精灵this->addChild(ball)后面引用函数:

?
1
HelloWorld::defineBall();



添加一个时间来更新physics

在头文件里添加:
?
1
void update( float dt);


在主文件cpp中添加:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Simulate Physics
void HelloWorld::update( float dt){
    int positionIterations = 10;  
    int velocityIterations = 10;
 
    deltaTime = dt;
    world->Step(dt, velocityIterations, positionIterations);  
 
    for (b2Body *body = world->GetBodyList(); body != NULL; body = body->GetNext())  
      if (body->GetUserData())
      {  
        CCSprite *sprite = (CCSprite *) body->GetUserData();  
        sprite->setPosition(ccp(body->GetPosition().x * SCALE_RATIO,body->GetPosition().y * SCALE_RATIO));  
        sprite->setRotation(-1 * CC_RADIANS_TO_DEGREES(body->GetAngle()));
 
 
 
      }  
     world->ClearForces();
     world->DrawDebugData();        
}  


在init函数中引用scheduleUpdate:

?
1
scheduleUpdate();


如果这个时候你尝试着运行你的应用程序,你会看到掉了个球。

现在添加一堵墙,是我们的球能够反弹。

在头文件中添加:
?
1
void addWall( float w, float h, float px, float py);


在主文件夹cpp中添加:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void HelloWorld::addWall( float w, float h, float px, float py) {
 
     b2PolygonShape floorShape;
 
     floorShape.SetAsBox(w/ SCALE_RATIO,h/ SCALE_RATIO);
     b2FixtureDef floorFixture;
     floorFixture.density=0;
     floorFixture.friction=10;
     floorFixture.restitution=0.5;
     floorFixture.shape=&floorShape;
     b2BodyDef floorBodyDef;
 
     floorBodyDef.position.Set(px/ SCALE_RATIO,py/ SCALE_RATIO);
     b2Body *floorBody = world->CreateBody(&floorBodyDef);
 
     floorBody->CreateFixture(&floorFixture);
 
}      


并且在INIT文件主函数里添加:

?
1
2
3
addWall(visibleSize.width ,10,(visibleSize.width / 2) ,0); //CEIL
addWall(10 ,visibleSize.height ,0,(visibleSize.height / 2) ); //LEFT
addWall(10 ,visibleSize.height ,visibleSize.width,(visibleSize.height / 2) ); //RIGHT


为弹道轨迹添加指示点

在头文件里添加:
?
1
Sprite *points[32];

并且在INI主函数里添加:
?
1
2
3
4
for ( int i = 1 ; i <= 31; i++){
     points<i> =CCSprite::create( "dot.png" );
     this ->addChild(points<i>);
}</i></i>


添加控制

删除掉原先在INIT方法里的HelloWorld::defineBall();

现在在方法 onTouchBegan里面添加方法:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
dragOffsetStartX = touch->getLocation().x;
dragOffsetStartY = touch->getLocation().y;
 
CCPoint touchLocation = touch->getLocation();
 
ballX = touchLocation.x;
ballY = touchLocation.y;
 
if (existBall){        
world->DestroyBody(ballBody);
}
 
ball->setPosition(ccp(ballX ,ballY));


在onTouchMoved里面添加:

?
1
2
3
4
5
6
7
8
9
CCPoint touchLocation = touch->getLocation();
 
dragOffsetEndX = touchLocation.x;
dragOffsetEndY = touchLocation.y;
 
float dragDistanceX = dragOffsetStartX - dragOffsetEndX;
float dragDistanceY = dragOffsetStartY - dragOffsetEndY;
 
HelloWorld::simulateTrajectory(b2Vec2((dragDistanceX )/SCALE_RATIO,(dragDistanceY )/SCALE_RATIO));



现在我们需要创建函数simulateTrajectory。

在头文件中添加:
?
1
void simulateTrajectory(b2Vec2 coord);


在cpp文件中添加
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void HelloWorld::simulateTrajectory(b2Vec2 coord){
 
     //define ball physicis
     HelloWorld::defineBall();
 
     ballBody->SetLinearVelocity(b2Vec2(coord.x,coord.y));
     for ( int i = 1; i <= 31; i++){
     world->Step(deltaTime,10,10);
     points<i>->setPosition(CCPoint(ballBody->GetPosition().x*SCALE_RATIO,ballBody->GetPosition().y*SCALE_RATIO));
     world->ClearForces();
 
     }
 
     world->DestroyBody(ballBody);
}</i>


如果你试着运行代码,你会得到个球,在屏幕中心的球,如果你试着拖拽鼠标,你会看到从球里伸展出弹道轨迹。

投球
现在我们需要添加onTouchEnded
?
1
     existBall = true ;


?
1
2
3
4
5
6
7
8
9
10
11
HelloWorld::defineBall();
 
CCPoint touchLocation = touch->getLocation();
 
dragOffsetEndX = touchLocation.x;
dragOffsetEndY = touchLocation.y;
 
float dragDistanceX = dragOffsetStartX - dragOffsetEndX;
float dragDistanceY = dragOffsetStartY - dragOffsetEndY;
 
ballBody->SetLinearVelocity(b2Vec2((dragDistanceX)/SCALE_RATIO,(dragDistanceY)/SCALE_RATIO));  


添加简单的投掷力量
为了添加投掷力量仅仅只需添加一个乘法系数,将其添加进头文件里:
?
1
float powerMultiplier;

设置创建球时的力量大小:

?
1
powerMultiplier = 10;


然后把下列行:
?
1
HelloWorld::simulateTrajectory(b2Vec2((dragDistanceX )/SCALE_RATIO,(dragDistanceY )/SCALE_RATIO));

改为:
?
1
HelloWorld::simulateTrajectory(b2Vec2((dragDistanceX * powerMultiplier)/SCALE_RATIO,(dragDistanceY * powerMultiplier)/SCALE_RATIO));

还有行:
?
1
ballBody->SetLinearVelocity(b2Vec2((dragDistanceX)/SCALE_RATIO,(dragDistanceY)/SCALE_RATIO));

改为:
?
1
ballBody->SetLinearVelocity(b2Vec2((dragDistanceX * powerMultiplier)/SCALE_RATIO,(dragDistanceY * powerMultiplier)/SCALE_RATIO));

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值