用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。

在頭文件中添加:
HelloWorld::simulateTrajectory(b2Vec2((dragDistanceX )/SCALE_RATIO,(dragDistanceY )/SCALE_RATIO));
相關文章
相關標籤/搜索