91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android游戲開發十日通(8)- Box2D的例子和學習小結

發布時間:2020-07-07 11:26:02 來源:網絡 閱讀:846 作者:拳四郎 欄目:開發技術

提要

       今天要學習的是cocos2dx中的Box2d物理引擎。

       Box2D是一款開元的C++編寫的物理引擎,起初是用于Flash的游戲開發中,隨后推出了C++版本,其開發和升級工作一直非常活躍,幾乎成了2D游戲產品的必備物理引擎。Box2D引擎為開發者提供了一個二維剛體的物理模擬庫,借助Box2D的強大功能,游戲中的動畫可以更加真實,讓游戲世界更具交互性。

      Box2D物理引擎所創建的物理引擎具有下面的三個特點:

1.物理世界存在一個重力場;

2.物理世界可以是一個存在邊界的范圍(有碰撞效果);

3.在世界中加入靜態和動態的物體,符合現實的運動規律;

       今天要學習的內容還是以實例為主。有不會的細節留言或者自行google。


最簡單的Box2D的例子

      先看最終效果

      Android游戲開發十日通(8)- Box2D的例子和學習小結


這個例子的實現思路如下:

1.定義物理世界,定義地面;

2.響應觸控操作,在點擊的位置創建一個物理世界中的正方塊,并用debugdraw顯示;

3.將帶紋理的精靈和物理世界中的正方塊相連接;


關于DebugDraw

當開發者使用物理引擎開發時,需要將物理世界繪制出來,但是我們都知道物理引擎中只存在碰撞檢測和物理模擬,沒有任何繪制功能,為了方便調試,就加入了調試繪圖功能,這個繪圖都是一些先狂,并不能作為游戲的畫面,只是為了方便開發者,看到物體世界的樣子。

利用DebugDraw,開發者可以輕易地看到物體的形狀,關節,用于連續碰撞的核心形狀,AABB包圍盒,接觸,質心。


         還是按前面兩篇教程那樣創建工程,然后將cocos2d-x-2.2/samples/Cpp/TestCpp/Classes/Box2DTestBed/GLES-Render.h和cocos2d-x-2.2/samples/Cpp/TestCpp/Classes/Box2DTestBed/GLES-Render.cpp復制到工程的Classes文件夾中,修改pro.linux 的MakeFile和pro.android 的Android.mk,將文件包含進去,接下來是具體的代碼實現。

HelloWorld.h

#ifndef __HELLOWORLD_SCENE_H__ #define __HELLOWORLD_SCENE_H__  #include "cocos2d.h" #include "Box2D/Box2D.h" #include "GLES-Render.h"  using namespace cocos2d;  class HelloWorld : public cocos2d::CCLayer {  private:     b2World *world;     GLESDebugDraw * m_debugDraw;     CCTexture2D* m_pSpriteTexture;  public:     HelloWorld();     ~HelloWorld();      // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone     virtual bool init();        void initPhysics();     virtual void draw();      void addNewSpriteAtPosition(CCPoint p);     void update(float dt);     virtual void ccTouchesEnded(CCSet* touches, CCEvent* event);      // there's no 'id' in cpp, so we recommend returning the class instance pointer     static cocos2d::CCScene* scene();          // a selector callback     void menuCloseCallback(CCObject* pSender);          // implement the "static node()" method manually     CREATE_FUNC(HelloWorld); };  #endif // __HELLOWORLD_SCENE_H__ 

        private成員里面,world是一個b2World,Box2D程序都是從創建一個b2World對象開始的。b2World就像一個管理內存,物體以及模擬的物理樞紐。你可以在堆,棧或者數據段上創建物理世界。m_debugDraw用于調試繪制,m_pSpriteTexture是一個2d紋理,在繪制Spirit的時候會用到。

       public的函數里面,有三個函數要注意,update是更新物體的位置,ccTouchesEnded是在觸控結束,也就是手指離開屏幕時觸發。addNewSpiriteAtPosition是在某個點添加一個Spirite。函數實現如下:

HelloWorld.cpp

#include "HelloWorldScene.h"  USING_NS_CC;  #define PTM_RATIO 32 enum {     kTagParentNode = 1, };  HelloWorld::HelloWorld() {     setTouchEnabled( true );     setAccelerometerEnabled( true );     this->initPhysics();     m_pSpriteTexture = CCTextureCache::sharedTextureCache()->addImage("blocks.png");     scheduleUpdate();  }  HelloWorld::~HelloWorld() {     CC_SAFE_DELETE(world);     world = NULL;     delete m_debugDraw; }  CCScene* HelloWorld::scene() {     // 'scene' is an autorelease object     CCScene *scene = CCScene::create();          // 'layer' is an autorelease object     HelloWorld *layer = HelloWorld::create();      // add layer as a child to scene     scene->addChild(layer);      // return the scene     return scene; }    // on "init" you need to initialize your instance bool HelloWorld::init() {     //////////////////////////////     // 1. super init first     if ( !CCLayer::init() )     {         return false;     }          CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();     CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();      /////////////////////////////     // 2. add a menu item with "X" image, which is clicked to quit the program     //    you may modify it.      // add a "close" icon to exit the progress. it's an autorelease object     CCMenuItemImage *pCloseItem = CCMenuItemImage::create(                 "CloseNormal.png",                 "CloseSelected.png",                 this,                 menu_selector(HelloWorld::menuCloseCallback));          pCloseItem->setPosition(ccp(origin.x + visibleSize.width - pCloseItem->getContentSize().width/2 ,                                 origin.y + pCloseItem->getContentSize().height/2));      // create menu, it's an autorelease object     CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);     pMenu->setPosition(CCPointZero);     this->addChild(pMenu, 1);      /////////////////////////////     // 3. add your codes below...      // add a label shows "Hello World"     // create and initialize a label          CCLabelTTF* pLabel = CCLabelTTF::create("Box2d Test", "Arial", 24);          // position the label on the center of the screen     pLabel->setPosition(ccp(origin.x + visibleSize.width/2,                             origin.y + visibleSize.height - pLabel->getContentSize().height));      // add the label as a child to this layer     this->addChild(pLabel, 1);       setTouchEnabled( true );     setAccelerometerEnabled( true );      // init physics     this->initPhysics();      return true; }  void HelloWorld::initPhysics() {     CCLOG("Init physics!");     b2Vec2 gravity;     gravity.Set(0.0f, -10.0f);     world = new b2World(gravity);      // Do we want to let bodies sleep?     world->SetAllowSleeping(true);     world->SetContinuousPhysics(true);      m_debugDraw = new GLESDebugDraw( PTM_RATIO );     world->SetDebugDraw(m_debugDraw);      uint32 flags = 0;     flags += b2Draw::e_shapeBit;     m_debugDraw->SetFlags(flags);      // Define the ground body.     b2BodyDef groundBodyDef;     groundBodyDef.position.Set(0, 0); // bottom-left corner     CCSize screenSize = CCDirector::sharedDirector()->getVisibleSize();     // Call the body factory which allocates memory for the ground body     // from a pool and creates the ground box shape (also from a pool).     // The body is also added to the world.     b2Body* groundBody = world->CreateBody(&groundBodyDef);      // Define the ground box shape.     b2PolygonShape groundBox;     groundBox.SetAsBox(screenSize.width, 1.0f);     groundBody->CreateFixture(&groundBox, 0.0f); }  void HelloWorld::menuCloseCallback(CCObject* pSender) { #if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)     CCMessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert"); #else     CCDirector::sharedDirector()->end(); #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)     exit(0); #endif #endif }  void HelloWorld::update(float dt) {     int velocityIterations = 8;     int positionIterations = 1;     world->Step(dt, velocityIterations, positionIterations);      for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())     {         if (b->GetUserData() != NULL) {             CCSprite* myActor = (CCSprite*)b->GetUserData();   //獲取精靈             myActor->setPosition( CCPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO) );             myActor->setRotation( -1 * CC_RADIANS_TO_DEGREES(b->GetAngle()) );         }     } }  void HelloWorld::draw() {     // This is only for debug purposes     // It is recommend to disable it     CCLayer::draw();     ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position );     kmGLPushMatrix();     world->DrawDebugData();     kmGLPopMatrix(); }  void HelloWorld::ccTouchesEnded(CCSet* touches, CCEvent* event) {     //Add a new body/atlas sprite at the touched location     CCSetIterator it;     CCTouch* touch;      for( it = touches->begin(); it != touches->end(); it++)     {         touch = (CCTouch*)(*it);         if(!touch)             break;         CCPoint location = touch->getLocation();         addNewSpriteAtPosition( location );     } }  void HelloWorld::addNewSpriteAtPosition(CCPoint p) {     CCLOG("Add sprite %0.2f x %02.f",p.x,p.y);     // Define the dynamic body.     //Set up a 1m squared box in the physics world     b2BodyDef bodyDef;     bodyDef.type = b2_dynamicBody;     bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);     b2Body *body = world->CreateBody(&bodyDef);      // Define another box shape for our dynamic body.     b2PolygonShape dynamicBox;     dynamicBox.SetAsBox(.5f, .5f);//These are mid points for our 1m box      // Define the dynamic body fixture.     b2FixtureDef fixtureDef;     fixtureDef.shape = &dynamicBox;     fixtureDef.density = 1.0f;     fixtureDef.friction = 0.3f;     body->CreateFixture(&fixtureDef);  //    //We have a 64x64 sprite sheet with 4 different 32x32 images.  The following code is //    //just randomly picking one of the images     int idx = (CCRANDOM_0_1() > .5 ? 0:1);     int idy = (CCRANDOM_0_1() > .5 ? 0:1);     CCSprite *sprite = CCSprite::createWithTexture(m_pSpriteTexture,CCRectMake(32 * idx,32 * idy,32,32));     this->addChild(sprite,1);     body->SetUserData(sprite); } 


具體解析下addNewSpiriteAtPosition。

 CCLOG("Add sprite %0.2f x %02.f",p.x,p.y);

在eclipse終端打印log顯示添加spirit的位置。

    b2BodyDef bodyDef;     bodyDef.type = b2_dynamicBody;     bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);     b2Body *body = world->CreateBody(&bodyDef);

        創建一個剛體。首先需要b2BodyDef 剛體的定義(包含著剛體的坐標,剛體的類型:動態),而創造一個剛體需要世界來創造。
        這里說一下world里的坐標,world是個相對來說比較真實的世界,這個世界里剛體用的參數是MKS ,也就是說米/千克/秒 ,而我們精靈用到的是像素,要相互轉換,這里的PTM_RATIO也就是代表32個像素是一米,

    // Define another box shape for our dynamic body.     b2PolygonShape dynamicBox;     dynamicBox.SetAsBox(.5f, .5f);//These are mid points for our 1m box      // Define the dynamic body fixture.     b2FixtureDef fixtureDef;     fixtureDef.shape = &dynamicBox;     fixtureDef.density = 1.0f;     fixtureDef.friction = 0.3f;     body->CreateFixture(&fixtureDef);

          定義一個四邊形,設置它的物理參數。


    int idx = (CCRANDOM_0_1() > .5 ? 0:1);     int idy = (CCRANDOM_0_1() > .5 ? 0:1);     CCSprite *sprite = CCSprite::createWithTexture(m_pSpriteTexture,CCRectMake(32 * idx,32 * idy,32,32));     this->addChild(sprite,1);

        通過紋理創造一個物體(注意不說剛體),idx和idy隨機選擇0.5和1,因為紋理是64*64的,而正方形是32*32的,需要再屏幕上體現出來,得創造一個精靈,因為剛體并不能具象的在屏幕上表示。

body->SetUserData(sprite);

將剛體和sprite連接起來。


還要注意一下Update里面的一句:

    int velocityIterations = 8;     int positionIterations = 1;     world->Step(dt, velocityIterations, positionIterations);

         執行一個時間步。這個操作中會執行碰撞檢測(collision detection)、集成(integration)、求解約束(constraint solution)。
timeStep 模擬的時間量,這不應該是一個變化的量。
velocityIterations 速度的約束求解量。
positionIterations 位置的約束求解量。


Box2D的物理世界通常包括這樣幾個對象
world:一個物理世界,所有的剛體都將存在在這個世界里面,這個世界以米為距離單位。盡量貼近真實世界的度量。
body:剛體,存在在物理世界的理想物體,比任何物體都硬,不會發生形變。body對應著一個bodyDef(剛體定義),剛體定義指定了剛體的類型(動態、靜態、軌跡運動的)和剛體的位置,world通過剛體定義創建剛體。
fixture:剛體修飾物,描述剛體的一些特征。fixture對應著fixtureDef(修飾物定義),它將形狀綁定到剛體上,使剛體具有一些表現特征,如密度、摩擦系數、彈性等等。body通過fixtureDef創建fixture。
shape:一個幾何形狀,比如圓和多邊形。形狀是修飾物fixture的一個屬性,描述了剛體的碰撞邊界。

解釋一下b2World, b2Body, b2BodyDef, b2Fixture, b2FixtureDef, shpae之間的關系
1.b2World通過b2BodyDef創建b2Body,沒有b2BodyDef,b2Body不知道是什么類型,放在世界什么位置。
2.b2Body通過b2FixtureDef創建b2Fixture,沒有b2Fixture,b2Body不知道是什么形狀,摩擦、彈性、密度都不知道。shpae提供了碰撞檢測的外邊框。


學習小節

        好不容易,Android游戲開發十日通系列也可以告一段落了. 從當初學習libgdx到現在的cocos2d-x,我也從A成到了B城。
       libgdx是一款很不錯的引擎,也有一些成熟的作品,但和cocos2d-x這個全世界都在用的游戲引擎相比還是相去太多,特別是文檔的稀缺,無疑增大了學習成本。后面這幾篇的cocos2d-x的學習感覺作為入門的教程還是不錯的,基本美篇都有一個實例。
       本想在這篇blog里面實現一個簡單的憤怒的小鳥的demo,本來想把這個系列寫滿10篇,本來想用一個狂拽炫酷的實例來作為結尾....可是我已經不是那個可以幸福地決定自己想學什么就學什么的少年了。
        肯定會繼續學習游戲編程,可能是Unity,可能是ogre,又或許還是cocos2d-x,或者是將來的cocos3d。到時候肯定還會和電腦面前的你一起快樂地學習、分享。
      
        最后,今天是2014年的第一天,大家都新年快樂咯!


參考

Box2D教程1-創建碰撞世界 - http://www.comingx.com/blog-html/1579.html

學習 Box2D 個人筆記(二)b2body  - http://blog.csdn.net/adrianous/article/details/8435156

Cocos2d-x游戲開發技術精解

Cocos2d-x by Example Beginner's Guide



        

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

鄯善县| 万源市| 岚皋县| 余姚市| 泸西县| 黄陵县| 攀枝花市| 信宜市| 佳木斯市| 岢岚县| 永登县| 永寿县| 咸阳市| 夏邑县| 恭城| 宣武区| 平邑县| 宁武县| 红河县| 正镶白旗| 庆云县| 铜梁县| 永德县| 革吉县| 疏附县| 镇安县| 同仁县| 绥江县| 宾阳县| 万安县| 江源县| 建水县| 政和县| 拜泉县| 城固县| 商丘市| 抚宁县| 江安县| 秀山| 柳河县| 元朗区|