Abstract
Today I want to learn about the Box2d physical engine in cocos2dx.
Box2D is an open-source C ++ physical engine. It was initially used for Flash game development and then launched the C ++ version. Its development and upgrade work has been very active, almost became a required physical engine for 2D game products. The Box2D engine provides developers with a two-dimensional physical simulation library of rigid bodies. With the powerful functions of Box2D, the animations in the game can be more real and make the game world more interactive.
The physical engine created by the Box2D physical engine has the following three features:
1. There is a gravity field in the physical world;
2. the physical world can be a boundary range (with a collision effect );
3. Adding static and dynamic objects in the world is in line with Realistic motion rules;
The content to be learned today is still based on instances. You can leave a message without any details or google it on your own.
Simplest Box2D example
First look at the final result
The implementation of this example is as follows:
1. Define the physical world and the ground;
2. In response to the touch operation, create a square block in the physical world at the click position and display it with debugdraw;
3. Connect the texture Sprite with the square block in the physical world;
About DebugDraw
When developers use the physical engine for development, they need to draw the physical world, but we all know that there is only collision detection and Physical Simulation in the physical engine, and there is no drawing function. To facilitate debugging, I added the graphic debugging function. This drawing is a bit crazy and cannot be used as a game image, just to make it easier for developers to see the world of objects.
With DebugDraw, developers can easily see the shape and joint of an object, the core shape used for continuous collision, AABB surround box, contact, and center of mass.
Create a project as in the previous two tutorials, then copy cocos2d-x-2.2/samples/Cpp/TestCpp/Classes/Box2DTestBed/GLES-Render.h and cocos2d-x-2.2/samples/Cpp/TestCpp/Classes/Box2DTestBed/GLES-Render.cpp to the Classes folder of the project and modify pro. makeFile and pro. android. mk to include the file. The following is the specific code implementation.
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__
In a private member, world is a b2World, and Box2D programs start from creating a b2World object. B2World is like a physical hub for managing memory, objects, and simulation. You can create a physical world on a stack, stack, or data segment. M_debugDraw is used for debugging and painting. m_pSpriteTexture is a 2d texture, which is used when drawing Spirit.
There are three functions in the public function. update is used to update the object location, and ccTouchesEnded is triggered when the touch ends, that is, when the finger leaves the screen. AddNewSpiriteAtPosition is to add a Spirite at a certain point. Function implementation:
HelloWorld. cpp
# Include "HelloWorldScene. h "USING_NS_CC; # define PTM_RATIO 32 enum {kTagParentNode = 1,}; HelloWorld: HelloWorld () {setTouchEnabled (true); reset (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 (); // 'player' is an autorelease object HelloWorld * layer = HelloWorld :: create (); // add layer as a child to scene-> addChild (layer); // return the scene return scene ;} // on "init" you need to initialize your instancebool Hello World: init () {// 1. super init first if (! CCLayer: init () {return false;} CCSize visibleSize = CCDirector: sharedDirector ()-> getVisibleSize (); CCPoint origin = CCDirector: shareddire () -> 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 = C CMenuItemImage: 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-> DdChild (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 l Abel 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-> cancel (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: menuC LoseCallback (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: shareddire()-> end (); # if (CC_TARGET_PLATFORM = CC_PLATFORM_IOS) exit (0 ); # endif} void HelloWorld: update (float dt) {int velocityIterations = 8; int PositionIterations = 1; world-> Step (dt, velocityIterations, positionIterations); for (b2Body * B = world-> GetBodyList (); B = B-> GetNext ()) {if (B-> GetUserData ()! = NULL) {CCSprite * myActor = (CCSprite *) B-> GetUserData (); // get the genie 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 (); ccglablevertexattribs (kCCVertexAttribFlag_Positio N); 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 1 m 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 (& bo DyDef); // Define another box shape for our dynamic body. b2PolygonShape dynamicBox; dynamicBox. setAsBox (. 5f ,. 5f); // These are mid points for our 1 m 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. T He 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 );}
For more information, see addNewSpiriteAtPosition.
CCLOG("Add sprite %0.2f x %02.f",p.x,p.y);
Print the log on the eclipse terminal to display the position where spirit is added.
b2BodyDef bodyDef; bodyDef.type = b2_dynamicBody; bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO); b2Body *body = world->CreateBody(&bodyDef);
Create a rigid body. First, the b2BodyDef Rigid Body definition is required (including the coordinates of the rigid body, the type of the Rigid Body: Dynamic), while creating a rigid body requires the world to create.
Let's talk about the coordinates in the world. The world is a relatively real world. In this world, the parameter used by the rigid body is MKS, that is, meter/kg/second, our genie uses pixels to convert each other. The PTM_RATIO here means that 32 pixels are one meter,
// 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);
Define a quadrilateral and set its physical parameters.
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);
Create an object through texture (not to mention the rigid body). idx and idy randomly select 0.5 and 1, because the texture is 64*64, and the square is 32*32, you need to create an genie on the screen, because the rigid body cannot be represented on the screen.
body->SetUserData(sprite);
Connect a rigid body with sprite.
Note the following in Update:
int velocityIterations = 8; int positionIterations = 1; world->Step(dt, velocityIterations, positionIterations);
Execute a time step. This operation performs collision detection, integration, and constraint solution ).
The time used by timeStep simulation is not a variable.
VelocityIterations speed constraints.
PositionIterations.
The physical world of Box2D usually includes such objects.
World: in a physical world, all rigid bodies will exist in this world. The world is measured in meters. Try to be close to real-world measurements.
Body: a rigid body, an ideal object in the physical world. It is harder than any other object and will not be deformed. The body corresponds to a bodyDef (rigid body definition). The Rigid body Definition specifies the type of the Rigid body (dynamic, static, trajectory movement) and the position of the rigid body. world creates a rigid body through the rigid body definition.
Fixture: Describes features of a rigid body. Fixture corresponds to fixtureDef, which binds the shape to the rigid body, so that the rigid body has some characteristics, such as density, friction coefficient, elasticity, and so on. Body creates fixture through fixtureDef.
Shape: a geometric shape, such as a circle or a polygon. Shape is an attribute of fixture, which describes the collision boundary of a rigid body.
Explain the relationships among b2World, b2Body, b2BodyDef, b2Fixture, b2FixtureDef, and shpae.
1. b2World creates b2Body through b2BodyDef without b2BodyDef. b2Body does not know what type it is and where it is stored in the world.
2. b2Body creates b2Fixture through b2FixtureDef without b2Fixture. b2Body does not know the shape, friction, elasticity, and density. Shpae provides the outer border for collision detection.
The Learning Section is not easy, Android game development ten-day series can also come to an end. From the original learning libgdx to the present cocos2d-x, I also from A to B city. Libgdx is a very good engine, there are some mature works, but compared with the cocos2d-x, the world is using the game engine is still too much, especially the scarcity of documents, it will undoubtedly increase the learning cost. The next few articles of the cocos2d-x learning feeling as a beginner tutorial is good, the basic beauty of an instance. I wanted to implement a simple Angry Bird demo in this blog. I wanted to write this series full of 10 articles. I wanted to end it with a cool and arrogant instance .... but I am no longer the teenager who can happily decide what I want to learn. Will certainly continue to learn game programming, may be Unity, may be ogre, or perhaps cocos2d-x, or the future of cocos3d. At that time, I will certainly learn and share happily with you in front of the computer. Finally, today is the first day of 2014. Everyone is happy new year!
See Box2D tutorial 1-create a collision world-http://www.comingx.com/blog-html/1579.html
Learn Box2D personal notes (2) b2body-http://blog.csdn.net/adrianous/article/details/8435156
Cocos2d-x Game Development Technology
Cocos2d-x by Example Beginner's Guide