Sunday, November 9, 2014

Creating Boundaries for our physics world

In the game i am making, i want my player to be inside a cage or locked room. To achieve this is pretty easy using physics:


auto edgeBody = PhysicsBody::createEdgeBox(visibleSize, PHYSICSBODY_MATERIAL_DEFAULT, METER_TO_PIXEL(1));
auto edgeNode = Node::create();
edgeNode->setPosition(Point(visibleSize.width/2,visibleSize.height/2));
edgeNode->setPhysicsBody(edgeBody);
this->addChild(edgeNode);

We need to create a node because bodies need to be attached to something. We could do the same with a sprite that was going to act as a border or could just leave it like that and put the art on top of it as it is not going to be movable.

I am using a couple macros:

#define PTM_RATIO 32

#define METER_TO_PIXEL(n) ((n) * PTM_RATIO) //macro to convert meters to pixels.

#define PIXEL_TO_METER(n) ((n) / PTM_RATIO) //macro to convert pixels to meters.

PTM_RATIO defines how many pixels i have per meter and the other two allow me to switch between them, so i can basically work in meters in my game.
My PTM_RATIO is 32 and my DesignResolution is 480x320, so i have an area of 15mx10m.

In this example i am creating the edge at the end of the visible size, but i am using a thickness of 1 meter (in every direction), so as a result i have a border around my screen of 1 meter (+1 more meter in the non visible area). I doubt he can escape now :P

Using Physics in cocos2dx

In my last entry i tried to explain how to setup a world and a body in cocos2dx. This time i will explain how to replace that with the built in physics in cocos2dx, which is based on chipmunk.

You can follow this tutorial in the documentation.

The concepts are bassically the same, we need a body, attach it to a world and to a sprite and then update the sprite to match our physics. The main advantage of using this engine instead of Box2D is that most of that work is taken care of by the cocos2dx.

In create method you will need:


Scene* GameScene::createScene()
{
    // 'scene' is an autorelease object
 auto scene = Scene::createWithPhysics();
 scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
    
    // 'layer' is an autorelease object
    auto layer = GameScreen::create();
    layer->setPhyWorld(scene->getPhysicsWorld());

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}
The main difference is that you are creating the scene with createWithPhysics().

Your .h should look like this:


using namespace cocos2d;
class GameScene : public cocos2d::Layer
{
public:
    // there's no 'id' in cpp, so we recommend returning the class instance pointer
    static Scene* createScene();

    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
    virtual bool init();
    
    // implement the "static create()" method manually
    CREATE_FUNC(GameScreen);

 void goToPauseScene(Ref *pSender);
 void goToGameOverScene(Ref *pSender);
 void update(float dt);

 void setPhyWorld(PhysicsWorld *world){m_world=world;}

private:
 PhysicsWorld *m_world;
};

Don't forget to add your using namespace, or it may start causing some conflict and won't run.
And to end replacing Box2D, our init method will be:


bool GameScene::init(){
    if ( !Layer::init() )
    {
        return false;
    }
    
    Size visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();

 auto player = Sprite::create("player.png");
 auto body = PhysicsBody::createCircle(player->getContentSize().width / 2);
 player->setPhysicsBody(body);
 player->setPosition(Point(visibleSize.width/2, visibleSize.height/2));

 this->addChild(player);

    return true;
}

And that's it. As you can see, if you compare it with my past entry, we reduced 16 lines of code to 3, making it easier to understand and mantain.
We didn't even need to update our physics in the main loop or have 2 different scales, one for screen and one for world. The API handles all that for us.

This physics engine, as mentioned before, is based on chipmunk, so it does not have support for CCD (Continuous Collision Detection). There are some extra techniques you will have to use when you need to use bullets or something else that needs this.

As a good resource, there is a comunity driven documentation in github that seems to be pretty good. You can check the programmers guide here.

Friday, November 7, 2014

Adding physics to my game - Box2D

I wrote about Box2D before in previous post, but now i am going to go into detail and starting from scratch, writing about the key concepts and little details that help understand how things work.

For this entry i will work on creating a world, a body, a sprite and adding all that together to make a simple scene, where we see our sprite falling.

I will use PTM_RATIO, WORLD_TO_SCREEN and SCREEN_TO_WORLD macros, so make sure you read about them in my old post.

We start with our init method:


bool GameScene::init()
{
    if ( !Layer::init() )
    {
        return false;
    }
    
    Size visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();

 b2Vec2 gravity(0, -9.8f); //normal earth gravity, 9.8 m/s/s straight down!
 gameWorld = new b2World(gravity);//Set a new world with the given gravity

 auto player = Sprite::create("player.png");
 player->setPosition(Point(visibleSize.width/2, visibleSize.height/2));

 b2BodyDef playerBodyDef;
 playerBodyDef.type = b2_dynamicBody; //this will be a dynamic body
 playerBodyDef.position.Set(SCREEN_TO_WORLD(player->getPosition().x), SCREEN_TO_WORLD(player->getPosition().y)); //set the starting position
 playerBodyDef.angle = 0; //set the starting angle
 playerBodyDef.userData = player;

 b2Body *playerBody = gameWorld->CreateBody(&playerBodyDef);

 // Create shape definition and add to body

 //set each vertex of polygon in an array
 b2Vec2 vertices[5];
 vertices[0].Set(-1,  2);
 vertices[1].Set(-1,  0);
 vertices[2].Set( 0, -3);
 vertices[3].Set( 1,  0);
 vertices[4].Set( 1,  1);
  
 b2PolygonShape playerShape;
 playerShape.Set(vertices, 5); //pass array to the shape

 b2FixtureDef playerFixtureDef;

 playerFixtureDef.shape = &playerShape; //change the shape of the fixture
 playerFixtureDef.density = 10.0f;
        playerFixtureDef.friction = 0.4f;
        playerFixtureDef.restitution = 0.1f;

 b2Fixture *playerFixture = playerBody->CreateFixture(&playerFixtureDef);

 this->addChild(player);

 this->scheduleUpdate();
    return true;
}

For this to work properly, add a private member "gameWorld" to your GameScene.h (and #include "Box2D\Box2D.h").

For this exercise, all i do is create a world initialized with some value for gravity. You can change gravity variable to play with it and modify the physics output for your world.

To add bodies, you need to create some kind of template and then create an actual physics body with it. In the example the template is playerBodyDef. I add type (read Box2D docs on body types), position, angle and user data.
I Added a sprite, and then convert the position of my sprite into coordinates that my physics body can handle and position it there.
Remember to add userData, it is important to recognize the sprite attached to your body.

Once we are done setting the BodyDef, we create an actual body (playerBody).

The fixtures represent physical properties and just like bodies, we create a template first (playerFixtureDef) and then create an actual fixture, attached to a body. The fixture is the one that interacts with the physics world.

The last line in our method is this->scheduleUpdate(), which will start our game's main loop.

The void update(float dt) method can be overriden to go into the game's main loop, and we will, so add that to your GameScene.cpp.


void GameScene::update(float dt){
 int velocityIterations = 10;
 int positionIterations = 10;

 // Instruct the world to perform a single step of simulation. It is
 // generally best to keep the time step and iterations fixed.
 gameWorld->Step(dt, velocityIterations, positionIterations);

 bool blockFound = false;

 // Iterate over the bodies in the physics world
 for (b2Body* b = this->gameWorld->GetBodyList(); b; b = b->GetNext()){
  if(b->GetUserData() != NULL){
   Sprite *sprite = (Sprite*)b->GetUserData();
   sprite->setPosition(Point(b->GetPosition().x*PTM_RATIO, b->GetPosition().y*PTM_RATIO));
   sprite->setRotation(-1*CC_RADIANS_TO_DEGREES(b->GetAngle()));
  }
 }

}

velocityIterations and positionIterations are values that are used in the physics calculation, and the higher they are the more accurate our physics will be, but the longer it will take to calculate them.

The gameWorld->Step() is telling the world to update physics.

We need to manually update our sprite according to physics world, so we search in every body in the physics world for sprites (remember i told you to add userData in body?) and if some body has a sprite, we update it's position. Remember we need to convert from meters to pixels, and that's what PTM_RATIO is for.

With this you should be able to set up a body in a scene and see how it falls into it's death (not really). You can simulate several things, but without anything else to interact it is kinda plain (feel free to add more bodies and watch them collide). I will go into adding more things to the scene in a future entry.

Thursday, November 6, 2014

Creating a basic main menu for our game

When you create a new project you get a couple files named HelloWorldScene.cpp and HelloWorldScene.h.

Rename them and refactor them to look like this:

MainMenuScene.h:


#ifndef __MAINMENU_SCENE_H__
#define __MAINMENU_SCENE_H__

#include "cocos2d.h"

class MainMenu : public cocos2d::Layer
{
public:
    // there's no 'id' in cpp, so we recommend returning the class instance pointer
    static cocos2d::Scene* createScene();

    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
    virtual bool init();
    
    // implement the "static create()" method manually
    CREATE_FUNC(MainMenu);

 void goToGameScene(Ref *pSender);
};

#endif // __MAINMENU_SCENE_H__


MainMenuScene.cpp:


#include "MainMenuScene.h"

USING_NS_CC;

Scene* MainMenu::createScene()
{
    // 'scene' is an autorelease object
    auto scene = Scene::create();
    
    // 'layer' is an autorelease object
    auto layer = MainMenu::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 MainMenu::init()
{
    if ( !Layer::init() )
    {
        return false;
    }
    
    Size visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();
 auto *title = Label::createWithBMFont("myfont.fnt", "My Awesome Title", TextHAlignment::CENTER);
 auto menuTitle = MenuItemLabel::create(title);
 auto playItem = MenuItemImage::create("play.png", "play.png");
 auto menu = Menu::create(menuTitle, playItem, NULL);
 menu->alignItemsVerticallyWithPadding(visibleSize.height / 4);
 this->addChild(menu);

 auto background = Sprite::create("mainmenu-background.png");
 background->setPosition(Point(visibleSize.width/2, visibleSize.height/2));
 
 CCLOG("Characters: %f", background->getBoundingBox().size.width);
 CCLOG("Characters: %f", this->getBoundingBox().size.width);
 this->addChild(background, -1);
    
    return true;
}

What i did is pretty simple, i just created two menu items and added them to a menu. After that i loaded a background and positioned it in my scene.

The first menu item is created with Label::createWithBMFont, which takes a .fnt file and uses it to draw some text.
I created my files with BitMap Font Generator. All you need to do is tell it which font to use (you can download a ttf font from internet and load it too). Select the chars you want to load (that bar with checkboxes at the right side).
To make it work with cocos2dx you need it to generate only one page and to output a .png as texture. You can set both of those in export options (you need to play around with output sizes to find one that fits your desired chars and font size).
Once you are done with that, go to "Save bitmap as..." and place into a valid path.

The other menu item was easier...just load a sprite.

Once i have my items i create a menu with a padding of 1/4 of the height. If you have more items you may need to make this value lower.

When we are in the scene, we can reference it with "this", which i do to add the menu as a child.

Now i wanted to add a background, so i loaded a sprite. As the sprites have an anchor point at the middle of them and by default they are put at 0,0 in the parent, you need to move it to the center of the screen with setPosition(Point(visibleSize.width/2, visibleSize.height/2)). If you use visibleSize you can position the childs based on % instead of px. If you want to use px, make sure you use your designSizeResolution, as everything is based on it.

In this case my background was 480x320, the same size as my design resolution, so i don't need to resize it to fit anything that fits my "low-res" setting.

With that you should have a basic scene with a menu that contains a title and a play button. You even have a background now.

If you want to link your scene to another one, you can add something like to play item:
auto playItem = MenuItemImage::create("play.png", "play.png", CC_CALLBACK_1(MainMenu::goToGameScene, this));
and later in MainMenu.cpp:

void MainMenu::goToGameScene(Ref *pSender)
{
 auto scene = GameActionScene::createScene();
 
 Director::getInstance()->replaceScene(scene);
}
Don't forget to create another scene with the class GameActionScene (you can use HelloWorldScene as a template again).

Monday, November 3, 2014

Multi Resolution Support in Cocos2dx - Windows

For this entry i will explain the best way i found to work with multiple resolutions in Cocos2dx.

The page on the documentation gives you a code snipet:


 typedef struct tagResource
    {
        cocos2d::CCSize size;
        char directory[100];
    }Resource;

    static Resource smallResource  =  { cocos2d::CCSizeMake(480, 320),   "iphone" };
    static Resource mediumResource =  { cocos2d::CCSizeMake(1024, 768),  "ipad"   };
    static Resource largeResource  =  { cocos2d::CCSizeMake(2048, 1536), "ipadhd" };
    static cocos2d::CCSize designResolutionSize = cocos2d::CCSizeMake(480, 320);

    bool AppDelegate::applicationDidFinishLaunching() {
        // initialize director
        CCDirector* pDirector = CCDirector::sharedDirector();
        CCEGLView* pEGLView = CCEGLView::sharedOpenGLView();

        pDirector->setOpenGLView(pEGLView);

        // Set the design resolution
        pEGLView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::SHOW_ALL);

        CCSize frameSize = pEGLView->getFrameSize();

        std::vector<std::string> searchPath;

        // In this demo, we select resource according to the frame's height.
        // If the resource size is different from design resolution size, you need to set contentScaleFactor.
        // We use the ratio of resource's height to the height of design resolution,
        // this can make sure that the resource's height could fit for the height of design resolution.

        // if the frame's height is larger than the height of medium resource size, select large resource.
        if (frameSize.height > mediumResource.size.height)
        { 
            searchPath.push_back(largeResource.directory);
            pDirector->setContentScaleFactor(largeResource.size.height/designResolutionSize.height);
        }
        // if the frame's height is larger than the height of small resource size, select medium resource.
        else if (frameSize.height > smallResource.size.height)
        { 
            searchPath.push_back(mediumResource.directory);
            pDirector->setContentScaleFactor(mediumResource.size.height/designResolutionSize.height);
        }
        // if the frame's height is smaller than the height of medium resource size, select small resource.
        else
        { 
            searchPath.push_back(smallResource.directory);
            pDirector->setContentScaleFactor(smallResource.size.height/designResolutionSize.height);
        }
        ...................
        ...................
        auto fileUtils = FileUtils::getInstance();
 fileUtils->setSearchPaths(searchPath);
    }
You probably can tell already what the code is trying to do:

  1. Define a serie of resolutions for which you will design resources (low res, hd, etc).
  2. Set a DesignResolution
  3. Select a set of resources based on the frame size of the current device
  4. Send your director a content scale factor so it can know how to resize everything.
  5. Set your directory search path according to your resource selection.
The design resolution is the resolution for which you are designing your game natively and it is very important because everything will be based on it.

But there is another issue other than resolutions: the aspect ratio. There are a ton of device screen sizes and aspect ratios(4:3, 3:2, 16:10, etc). To solve this you have several options (i will be brief on this because on the documentation explain it in detail):
  • Exact fit: App will fill the screen, forgetting about the aspect ratio and stretching or compressing as needed (There can be a noticeable distorsion on your shapes)
  • No border: Your app will fill the screen but it will keep it's aspect ratio. It can crop at 2 of the 4 borders if the aspect ratio of the device is different than the aspect ratio of the design resolution.
  • Show all: This is my favorite. The app will be completely visible in the screen and will keep the same aspect ratio as design resolution. This can cause that 2 of the 4 borders have black borders. There is an easy workaround for this that i will explain in short.
  • Fixed height/Fixed width: As the name implies, it will keep either the height or the width constant and scale the other.
I found a very good explanation in here on using show all policy and fix your black borders (it is for another engine and uses another terms but you should read it, it has very good information).
If you know you can get black borders when you resize, design your backgrounds to be bigger than your current screen.
The recommendation is to work with an aspect ratio of 3:2. If you scale to 4:3 you will have your borders at the top/bottom and if you scale to 16:9 they will be left/right . Those will be your worst case scenarios and you will design your background image to fit it.
Knowing that all you have to do is calculate how much bigger your background will have to be in each direction. The calculations are simple, just do the following:

  • For X axis you have that your worst case is 16:9, that being an aspect ratio can be reduced to a fraction: 16/9 = 1.777777. Having that 3:2 = 3/2 = 1.5 we can conclude that 16:9 is 1.185185 times bigger than 3:2 ( 1.777777/1.5 ). What this implies is that for your supported resolution (ie. 480x320) your X axis will have to be 1.185185 times larger. This is something as simple as 480*1.185185=568.88 (round it to 570px). You will need a background with an X axis of 570px in the worst case, so create your regular 480px background and add it some pretty borders or something to cover the missing 90px (45px in each side). 
  • For the Y axis the procedure is exactly the same but with an aspect ratio of 4:3. In this case 4:3 aspect ratio is 1.125 times bigger than 3:2 (apply the same reasoning as X axis) so you will need to make your Y axis at least 320*1.125=360px
Try to round your calculations to the next higher pair number, so you can add the same number of pixels at both sides and avoid errors on your centering.

Repeat this for every resolution you are going to support (For obvious reasons it is better to start at a high resolution and then scale down because the distortion is not noticeable, but i am doing it this way for the sake of clarity).

If we used 16:9 instead of 3:2 as our design aspect ratio, we would have a worst case of 1.333 times when converting to 4:3, which is worse than using an intermediate aspect ratio as 3:2, so we would have more wasted space to fill.

If you have doubts about this you can check the linked explanation (again, very good and with pictures!!) or leave a comment.

We covered multisupport resolution in cocos2dx and the way to overcome the drawback of a good resolution policy for scaling our app into different aspect ratios.

All that is left is to explain how to test this in windows.

In windows, cocos2dx uses main.cpp to set it's entry point. You can create a frame size there with the desired resolution and the app will behave as it is running in a device with that resolution. You can even scale it to show bigger on your screen to avoid missing details because it is too little!!!

In your main.cpp (project/win32):

#include "main.h"
#include "AppDelegate.h"
#include "cocos2d.h"

USING_NS_CC;

int APIENTRY _tWinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPTSTR    lpCmdLine,
                       int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // create the application instance
    AppDelegate app;
    auto director = Director::getInstance();
    director->setDisplayStats(true);
    auto glview = GLViewImpl::createWithRect("MyApp", Rect(0, 0, 480, 320), 2.0f);
    director->setOpenGLView(glview);

    return Application::getInstance()->run();
}



We create a GLView and set it our resolution and our zoom (the zoom won't change the resolution, just scale it in your window). Then just leave your appdelegate as we saw at the beggining and it should work. You can start making an app that will scale with no major drawbacks in any resolution and aspect ratio!!!

Sunday, April 27, 2014

Add sound to my Cocos2dx game

At some point you will want to add some awesome sounds to your game. The way to do it is very simple but before explaining it let's check a couple concepts:

Background Music: The background music (or BGM for short) are the sounds that are played in the background. Normally this music is played at low volume to keep it out of the focus of the player and avoid obscuring sounds that are more important. BGM is normally long and there is only one at a time (Except maybe at some points where you are going to a new level and there is a fade in and fade out).

Effects: This kind of sound is short and normally represents a game event (Walking, running, jumping, shooting, etc). There are tons of effects in a game and they are played constantly.

Depending on the platform you are going to run your game the format of the sounds should be different according to documentation.

The module of Cocos2dx that handles music is called CocosDenshion. To use it you must include a .h file in your game:

#include "SimpleAudioEngine.h"

You can use CocosDenshion namespace too:

using namespace CocosDenshion;

To use different formats depending on what platform you are in, you can use this comparison:

#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
    #define EFFECT_FILE        "effect2.ogg"
#elif( CC_TARGET_PLATFORM == CC_PLATFORM_MARMALADE)
    #define EFFECT_FILE        "effect1.raw"
#else
    #define EFFECT_FILE        "effect1.wav"
#endif // CC_PLATFOR_ANDROID

#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
    #define MUSIC_FILE        "music.mid"
#elif (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
    #define MUSIC_FILE        "background.wav"
#elif (CC_TARGET_PLATFORM == CC_PLATFORM_BLACKBERRY || CC_TARGET_PLATFORM == CC_PLATFORM_LINUX )
    #define MUSIC_FILE        "background.ogg"
#elif (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    #define MUSIC_FILE        "background.caf"
#else
    #define MUSIC_FILE        "background.mp3"
#endif // CC_PLATFOR_WIN32

I took this fragment of code from the test project on Cocos2dx download. As you can see depending on the platform the #define directive is different, pointing to a file with another format. The files in this case should be located at the Resources folder in your project. If you want to have a folder for sounds you can create it and then reference the files with the relative path from the Resources folder (Something like "sounds/myFile.mp3").

In your init() methods you should preload the sounds you are going to use later. You can do that like this:

SimpleAudioEngine::getInstance()->preloadBackgroundMusic( MUSIC_FILE );
SimpleAudioEngine::getInstance()->preloadEffect( EFFECT_FILE );

Now you can play the sounds wherever you want with:

SimpleAudioEngine::getInstance()->playBackgroundMusic(MUSIC_FILE, true);
SimpleAudioEngine::getInstance()->playEffect(EFFECT_FILE, false, pitch, pan, gain);

There are also functions to stop the playback, pause, resume, etc. To control volume use:

SimpleAudioEngine::getInstance()->setEffectsVolume(volume);
SimpleAudioEngine::getInstance()->setBackgroundMusicVolume(volume);

The volume value must be between 0 and 1.

As a last hint remember to use bitrates that are enough for what you want. Use values around 128kbps - 256kbps, not something like 2822kbps (Yeah, happened to me once and took me a while to notice). You can find more information on supported formats for specific platforms in their respective documentations. In the case of android you can check this.

This should be enough to get you started with the music and effects on Cocos2dx. Good luck and rock on!



Thursday, April 17, 2014

Shooting bullets using Box2D

I got to the point where i wanted to shoot a bullet from some position toward my main character (its centroid).

To do this you have to make a little set up in the body definition:

b2BodyDef bulletBodyDef;
bulletBodyDef.type=b2_dynamicBody;
bulletBodyDef.bullet = true;

Additionally to the regular settings you have to set "isBullet" to true. This will tell Box2D to calculate collision continuosly for that body to avoid tunneling (passing through other bodies when moving too fast).

To actually shoot the bullet just apply a linear impulse to it. To calculate the direction in my case just get the vector from bullet to target, normalize it and multiply it by the magnitude of the impulse you are applying.

auto force = 10.0f;
auto hyp = target - bullet->GetPosition();
hyp.Normalize();
bullet->ApplyLinearImpulse(b2Vec2(force*hyp.x, force*hyp.y), bullet->GetWorldCenter(), true);

Once you have this you can shoot as many bodies as you want and if you are lucky enough your main character will have tons of holes :)

Tuesday, April 8, 2014

Using Box2D on Cocos2dx

Box2D is an open source C++ engine for simulating rigid bodies in 2D.

This does not pretend to be an exhaustive tutorial about using Box2D, there is a lot of information about that already. I will try to show you the biggest mistake i made when using it and that took me a while to figure out: using the PTM_RATIO.

There will be 2 worlds: a graphic world and a physics simulation world.
When you are working on the graphic world you will have everything on terms of pixels, so you need to define a "pixel to meter ratio". This ratio will allow the worlds to communicate.

You can define a couple macros on C++ like this:

#define PTM_RATIO 50
#define WORLD_TO_SCREEN(n) ((n) * PTM_RATIO) //macro to convert meters to pixels.
#define SCREEN_TO_WORLD(n) ((n) / PTM_RATIO) //macro to convert pixels to meters.

You have to remember to use those macros when sending info from a world to another.

You can send info to the physics world:

myBodyDef.position = b2Vec2(SCREEN_TO_WORLD(mySprite->getPositionX()), SCREEN_TO_WORLD(mySprite->getPositionY()));

You will need a method to update your graphics world, and inside it you will move your graphics depending on the output of the physics world. Remember to scale them back:


mySprite->setPosition(WORLD_TO_SCREEN(myBody->GetPosition().x), WORLD_TO_SCREEN(myBody->GetPosition().y));

The third option you will have is to set some variables to the physics world. If you have them in pixels you can use a macro, but if you have them directly on MKS system (the system Box2D uses by default) you can send them directly:

world = new b2World(b2Vec2(0.0f, -9.8f)); //Sets a gravity of 9.8m/s^2

Box2D is designed to work efficiently with objects ranging from 0.1m to 10m. You can scale them back in your graphics world as much as you want, but remember to use the values in that range in the physics world.

Have fun using Box2D...it is amazing!!! :)

Sunday, April 6, 2014

Installing cocos2dx 3.0 on Windows



Cocos2d-x is a multi-platform framework for building 2d games, interactive books, demos and other graphical applications. It is based on cocos2d-iphone, but instead of using Objective-C, it uses C++. It works on iOS, Android, Windows Phone, OS X, Windows and Linux.
This guide is based on Cocos2dx-3.0. I am using Windows 7 and plan to release it for android devices first, however i had several issues trying to make it work so i will post the whole process to make it easy for you.

To get started you will need to download a lot of things:
Cocos2d-x: Get the 3.0 version in this case.
Android SDK: There is a full packed release that includes eclipse and the ADT already, making your life easier. You can find it on android developer’s page.
Android NDK: Cocos2d-x uses native C++ code to get into the mobile application, so you need the android native development kit as well. There are some enhanced versions by Crystax. You can use the latest.
Python: You will need this to run a path setting script that comes along with Cocos2d-x. You can find all the stable releases for Windows on the download page.
Apache Ant: Apache Ant is a Java library and command-line tool whose mission is to drive processes described in build files as targets and extension points dependent upon each other. You should get the binary release.
Visual Studio Express 2012: The IDE and the tools for compiling for Windows. Developing it on a desktop OS makes the process faster than compiling and running on the device every time. Express version is free and can be downloaded directly from microsoft’s page.
And thats it!!!

Ok, now that you are done with the downloads lets get to the installing. You can install Python as you would install any other program however the rest of the downloads are compressed packages. Uncompress every package on a folder you can find easily.

Look on the root folder of Cocos2d-x for a python script named setup.py. This script will open a console and will ask you for the paths to the other pieces. It will look like:
-> Adding COCOS2D_CONSOLE_ROOT environment variable… ALREADY ADDED
-> Looking for NDK_ROOT envrironment variable… FOUND
-> Looking for ANDROID_SDK_ROOT envrironment variable… FOUND
-> Looking for ANT_ROOT envrironment variable… FOUND
For NDK_ROOT and ANDROID_SDK_ROOT just add the path where you uncompressed them. For ANT_ROOT add the path to the bin folder inside the root directory of ant.

Once this is done you can already compile the tests of the cocos2d-x framework to your android smartphone. Let’s create a blank project and compile it.
Inside the cocos2d-x directory look for tools/cocos2d-console/bin and then run install.py. This console makes creating projects and compiling for android quite easy. 
To create a game type on the comman prompt: > cocos new “My Game” -l cpp -p org.cocos2d.mygame and press enter. Once this is done go inside the project that was just created and type:

 >cocos compile -p android -m debug

If your command prompt says it cant figure what cocos is, add it to your path (cocos-console/bin) and restart it.
This process will take a while but once it is done you should have a .apk file inside the android folder of the project. Move it to your phone and install it so you can see how the hello world for cocos2d-x looks like!!!
 
Now we get to the part that took me a while: setting up the windows development enviroment.
First install microsoft visual studio express 2012. This may take a while.
Inside the game we created are several folders. Go to the one named proj.win32 and run Game1.sln. This will open visual studio:




You can run the solution and it will start compiling (may take long the first time). To do that click on the arrow “Local Windows Debugger”.
There are some issues with the current setting of the visual studio project so we will fix em now. Go to the project’s properties:



Find the Linker’s section and add the following at Ignore Specific Default Libraries: libcmt.lib; libcmtd.lib; msvcrt.lib.
Next step is important. Cocos2dx has several libs that you can add depending on what you are planning to do. In this example we are going to add Box2D but it is the same for anything else inside the cocos package.

Add libBox2D.lib to additional dependencies



To compile Box2D go to your game's directory and find cocos2d/external/Box2D/proj.win32 and run Box2D.vcxproj. This will open the visual studio project containing Box2D code. Compile it (make sure you are using debug settings).
Back at our game’s properties go to the Linker’s general configuration page and add to Additional Library Directories:
cocos2d-x/build/Debug.win32

With this you should have everything you need to make your project work including physics. 

You can run your apps directly on a device using the cocos-console. Make sure your device is in developer mode. You can find more info about setting it up here.

To run something directly on the device type on the command prompt:
> cocos run -p android

With the basic example it wont have any errors, but if you added extra libs you may need to set it up a little to make it work. Go to your game/proj.android/jni and open Android.mk. That file helps find the dependencies and libraries required. Whenever you add new source files or libraries you need to update this file too.

To add more source files just follow the pattern:

LOCAL_SRC_FILES := hellocpp/main.cpp \
                   ../../Classes/AppDelegate.cpp \
                   ../../Classes/HelloWorldScene.cpp \
                   ../../Classes/MyNewSource.cpp

To add new include directories:

LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../cocos2d

Notice the second one has a "+="

To add new libraries and load them use:

LOCAL_WHOLE_STATIC_LIBRARIES := cocos2dx_static
LOCAL_WHOLE_STATIC_LIBRARIES += cocosdenshion_static
LOCAL_WHOLE_STATIC_LIBRARIES += box2d_static
LOCAL_WHOLE_STATIC_LIBRARIES += cocostudio_static

$(call import-module,Box2D)
$(call import-module,editor-support/cocostudio)

This one is a little tricky but you can solve all the compiling/linking issues using it.

If you find any mistakes, parts you don't understand or something you would like to be explained better feel free to leave a comment :).