Cocos2dx – Spinning Globe by Masking technique

In this post, lets see how we can implement a spinning world in cocos2d-x using masking technique. See the video below for sample output:


Low FPS is because of my Mac Mini; In device, it runs at 60 FPS

Downloads

1. Full Project

1. Create a Cocos2d-x Project

I am not going to discuss about how to setup a cocos2d-x project for iOS here. For info on how to setup cocos2d-x project, refer the official wiki.

All our code will go into `HelloWorld` class that comes with the template.

2. Masking Functionality

The hardest part in achieving our goal would be ‘Masking’ and we resort to Pavel Hancak’s tutorial on cocos2d-x masking. Please check the tutorial on how to mask a sprite. Based on that code, I rewrote the function as below:

CCSprite* HelloWorld::maskedSpriteWithSprite(CCSprite* pTextureSprite, CCSprite* pMaskSprite, float xoffset, float yoffset)
{
    // store the original positions of both sprites
    CCPoint textureSpriteOrigPosition(pTextureSprite->getPosition().x, pTextureSprite->getPosition().y);
    CCPoint maskSpriteOrigPosition(pMaskSprite->getPosition().x, pMaskSprite->getPosition().y);

    // convert the texture sprite position into mask sprite coordinate system
    pTextureSprite->setPosition(ccp(pTextureSprite->getContentSize().width/2 - pMaskSprite->getPosition().x + pMaskSprite->getContentSize().width/2 - xoffset, pTextureSprite->getContentSize().height/2 - pMaskSprite->getPosition().y + pMaskSprite->getContentSize().height/2 + yoffset));

    // position the mask sprite so that the bottom left corner lies on the (o,o) coordinates
    pMaskSprite->setPosition(ccp(pMaskSprite->getContentSize().width/2, pMaskSprite->getContentSize().height/2));

    CCRenderTexture* rt = CCRenderTexture::renderTextureWithWidthAndHeight((int)pMaskSprite->getContentSize().width, (int)pMaskSprite->getContentSize().height);

    ccBlendFunc bfMask = ccBlendFunc();
    bfMask.src = GL_ONE;
    bfMask.dst = GL_ZERO;
    pMaskSprite->setBlendFunc(bfMask);

    // turn off anti-aliasing around the mask sprite
    pMaskSprite->getTexture()->setAliasTexParameters();

    ccBlendFunc bfTexture = ccBlendFunc();
    bfTexture.src = GL_DST_ALPHA;
    bfTexture.dst = GL_ZERO;
    pTextureSprite->setBlendFunc(bfTexture);

    rt->begin();
    pMaskSprite->visit();
    pTextureSprite->visit();
    rt->end();

    // generate the resulting sprite
    CCSprite* pOutcome = CCSprite::spriteWithTexture(rt->getSprite()->getTexture());
    pOutcome->setFlipY(true);

    // restore the original sprite positions
    pTextureSprite->setPosition(textureSpriteOrigPosition);
    pMaskSprite->setPosition(maskSpriteOrigPosition);
    pOutcome->setPosition(maskSpriteOrigPosition);

    return pOutcome;
}

I added two parameters `xoffset` and `yoffset` to the original code. These parameters are to offset the position of underlying map. By varying this offset parameter in gameloop, we move the map linearly over a period of time.

3. Setup Sprites

Add two sprites `map` and `mask`, where

2d world map

`map` contains the full map. Only a part of will be seen at any time

When one edge of the scrolls into the keyhole (mask), we dont want the background to be visible, but the other edge to wrap and fit the gap. For this purpose, we duplicated the map horizontally, and when one edge is within keyhole, the duplicated part will fit in and when the edge crosses the keyhole completely, we reset the map to initial position. (Will see implementation details in subsequent sections).

mask for world map

`mask` picture is like a circular keyhole through which we sees part of a map.

Code to add these two sprites is as follows. Dont add the sprite as child of layer yet.

    
    // in init() function
    map = CCSprite::create("worldmap2d.jpg");
    map->setPosition( ccp(512, 768/2) );
    map->retain();

    mask = CCSprite::create("worldmapmask.png");
    mask->setPosition( ccp(512, 768/2) );
    mask->retain();

Apart from the `map` and `mask`, a star background is added behind.

4. Masking

With Pavel Hancak’s tutorial, masking is now very simple as following:

    // in init() function
    masked = maskedSpriteWithSprite(map, mask, 0, 100);
    addChild(masked);

Only the masked sprite should be added to the `layer`. I found the offsets on trial and error basis 😛 At this point, you should see circular part of the map and not the whole. We masked the map, but still it looks like a flattened map without any depth. To add some depth, add a `shade` picture, above all the sprites as follows

    // in init() function
    shade = CCSprite::create("worldmapshade.png");
    shade->setPosition( ccp(512, 768/2) );
    addChild(shade);
shade over world map

shade to be applied over the world map to create an illusion of depth

5. Spinning Animation

We dont have any real `3D` object here and so we achieve spinning animation by moving the map horizontally behind the keyhole (mask) infinitely. Add this final piece of code and we are done:

    // in init() function
    this->scheduleUpdate();

    void HelloWorld::update(float dt) {
        CCSprite *m;
        xoff += dt * 100;
        if (xoff > 1024) {
            xoff = 0;
        }
        m = maskedSpriteWithSprite(map, mask, xoff, 120);
        masked->setTexture(m->getTexture());
    }

In above code, `xoff` determines the amount of distance that the map should be moved. `Update` is the gamploop, where we increment `xoff` by small amounts in each frame, thus moving the map. When the `xoff` reaches its limit, we reset it. Changing `xoff` doen’t do anything magically. We create a new sprite based on offset position and apply the texture to our `masked` sprite.

Run the project and see the world spinning. Thats the end of the tutorial. Hope it helped :-)

Source can be browsed @ https://github.com/saiy2k/cocos2dx-masking 

Cocos2dx – Platformer Physics Tutorial

I tried implementing the platforming physics logic in cocos2d-x and it came out pretty well as per my expectations. This tutorial is about how I made it. It might not be the best solution out there, but it is something that works. Before diving in, here is the demo video showcasing the final output:

Downloads

1. Mid Project (with just the platforms render)
2. Full Project (all functionalities)

1. Create a Cocos2d-x Project

I am not going to discuss about how to setup a cocos2d-x project for iOS here. I will directly dwelve into the platforming mechanism here. For info on how to setup cocos2d-x project, refer the official wiki.

All our code will go into `HelloWorld` class that comes with the template.

2. Define the Platforms

Add the following struct in HelloWorld.h to model a Line

typedef struct {
    CCPoint p1, p2;
} Line;

Declare a pointer to Line struct in HelloWorld, which will be an array of all platforms and randomly add a few lines in it:

// in HelloWorld.h
Line *lines;

// in init function of HelloWorld.cpp
lines = (Line *)malloc(sizeof(Line) * COUNT);

lines[0].p1 = ccp(100, 100);
lines[0].p2 = ccp(400, 100);

lines[1].p1 = ccp(500, 600);
lines[1].p2 = ccp(700, 600);

lines[2].p1 = ccp(400, 400);
lines[2].p2 = ccp(600, 500);

lines[3].p1 = ccp(500, 200);
lines[3].p2 = ccp(1000, 200);

The platforms are defined well with their points. Now is the time to render them on screen. Add the `draw` function to the `HelloWorld` scene.

// in header file
virtual void draw();

// in cpp file
void HelloWorld::draw() {
    glLineWidth(4.0);
    for (int i = 0; i < COUNT; i++) {
        ccDrawLine( lines[i].p1, lines[i].p2 );
    }
    CCLayer::draw();
}

The above code sets the line width to 4 pixels, loops through our platform array and draws the lines. Our screen should look like this:

3. Character Sprite and Controls

The platforms are setup right. Now lets add the hero sprite which will run through the platforms and two button controls to make the character move. To add the hero and controls, do this:

// in header file
CCSprite* pSprite;
void menuCloseCallback(CCObject* pSender);

// in init function of HelloWorld.cpp
CCMenuItemImage *pCloseItem = CCMenuItemImage::create("CloseNormal.png",
                                                      "CloseSelected.png",
                                                      this,
                                                      menu_selector(HelloWorld::menuCloseCallback) );
pCloseItem->setPosition( ccp(CCDirector::sharedDirector()->getWinSize().width - 60, 60) );
pCloseItem->setTag(1);
pCloseItem->setScale(2.5f);

CCMenuItemImage *pCloseItem1 = CCMenuItemImage::create("CloseNormal.png",
                                                       "CloseSelected.png",
                                                       this,
                                                       menu_selector(HelloWorld::menuCloseCallback) );
pCloseItem1->setPosition( ccp(60, 60) );
pCloseItem1->setTag(2);
pCloseItem1->setScale(2.5f);

// controls for left and right movement
CCMenu* pMenu = CCMenu::create(pCloseItem, pCloseItem1, NULL);
pMenu->setPosition( CCPointZero );
this->addChild(pMenu, 1);   

// hero sprite
pSprite = CCSprite::create("CloseNormal.png");
pSprite->setPosition( ccp(600, 700) );
pSprite->setTag(-1);
this->addChild(pSprite, 0);

By now our screen should look like this:

4. Basic Movement

The stage is set with all the objects put in place. Now is the time to start moving the objects. Add two variables `speedX` and `speedY` that controls the movement of our hero and schedule the update function of CCLayer to get into the game loop.

// in header file
virtual void update(float dt);
float speedX, speedY;

// in init function of HelloWorld.cpp
speedX = 0;
speedY = 0;
this->scheduleUpdate();

// in HelloWorld.cpp
// moves the hero around the screen as per the speedX and speedY values
void HelloWorld::update(float dt) {
    CCPoint p = pSprite->getPosition();    
    pSprite->setPosition( ccp( p.x + speedX * dt, p.y + speedY * dt ) );
}

// makes the hero to move to left / right based on the touched control
void HelloWorld::menuCloseCallback(CCObject* pSender) {
    if (((CCNode *)pSender)->getTag() == 1) {
        speedX += 100;
    } else {
        speedX -= 100;
    }
}

Now touching the left control button, increases the movement of the hero in left direction and the same with the right control button. As of now, Movement happens only in x-axis and there is no gravity (falling down), friction and collision. The project at this point can be downloaded here for reference.

5. Physics Magic

First replace the `update` function with following code.

void HelloWorld::update(float dt) {
    CCPoint p = pSprite->getPosition();

    speedX *= 0.95; // friction reduces the speed over time

    if (pSprite->getTag() == -1) { // free falling
        CCLog("searching for platform... hero is falling");
        // iterate through all platforms
        for (int i = 0; i < COUNT; i++) {
            // if hero position lies between the x bounds of any platform
            if ( lines[i].p1.x < p.x && lines[i].p2.x > p.x ) {
                // also it is closer than 100 pixels to the platform
                if ( p.y - lines[i].p1.y < 100 && p.y - lines[i].p1.y > 0) {
                    // assign the platform to the hero
                    pSprite->setTag(i);
                    break;
                }
            }
        }
        // gravity pull decreases the y-speed
        speedY -= 10.0;

        // not allowing hero to go down indefinitely, by making him swap to the top
        if ( p.y < 0 ) {
             p.y = 768;
        }
    } else { // resting in or closer to some platform
        int tag = pSprite->getTag();
        CCLog("in platform %d", tag);

        // make sure if hero is still in the x bounds of the platform or moved away
        if ( lines[tag].p1.x < p.x && lines[tag].p2.x > p.x ) {
            float x2, y2;
            x2 = p.x;
            // platform may be a sloppy one, so interpolate the y value based on end points of platform and current hero position 
            y2 = (x2 - lines[tag].p1.x) * (lines[tag].p2.y - lines[tag].p1.y) / (lines[tag].p2.x - lines[tag].p1.x) + lines[tag].p1.y;
            if (p.y - y2 > 0) { // if hero is above platform, make him fall down
                speedY -= 10.0;
            } else {            // nullify the y speed and rest on platform
                speedY = 0;
                p.y = y2;
            }
        } else { // switch to free fall mode, if hero is moved away
            pSprite->setTag(-1);
        }
    }

    pSprite->setPosition( ccp( p.x + speedX * dt, p.y + speedY * dt ) );
}

I believe the above code is self-explanatory with all the comments put in. So I will just add few notes that deserve some explanation here.

Tag

`tag` property of Hero is used to refer to the platform he is in. If he is free falling (i.e., not attached to any platform) then `tag` will be -1.

Friction

 speedX *= 0.95;

Above code decrements the x speed of the hero by 5% on each update, thus simulating the friction effect.

Interpolation

If all the lines are perfectly horizontal, then y values of the end points or any other point in that line would be equal. If the lines are sloppy, things would be different and we need to calculate the y-value of any arbitrary point in the given line for the given x. If its confusing, see the picture below and read on.


For any platform, we have the end points A (x1, y1) and B (x2, y2) and we have the position of the hero represented here as H(hx, hy). But to check if the hero is above or below the line, we need the point that lies in the line which is P(x, y). Of course, x would be same as hx, but how to find y? Not to worry, we can interpolate the y value with the following formula:

y = y1 + (hx - x1) * (y2 - y1) / (x2 - x1)

The above formula is translated to CPP in our code with our variables as follows:

y2 = (x2 - lines[tag].p1.x) * (lines[tag].p2.y - lines[tag].p1.y) / (lines[tag].p2.x - lines[tag].p1.x) + lines[tag].p1.y;

Thats the end of the tutorial and here is the full project. This project can be easily extended to 2d side scrolling platformer games. I will try to write a post on that in future. There might be several places where a beginner can easily get lost. Post the queries in comments and I will try to resolve.

Integrating GoogleTest with Xcode 4

I been thinking and reading about Unit Testing for a long while, but never dared to actually implement it in any of my projects (both in work and hobby projects) for various reasons the most obvious one being ‘laziness’.

But all of a sudden I got enlightened yesterday and been sincerely reading about UnitTest++, googletest and some other testing frameworks and decided to go with googletest for obvious reasons.

I downloaded the framework but found that the official xcode integration guide is out of date now and I couldnt easily find any other guides to integrate it with xcode 4 (mine is 4.2). So here I am writing one….

Building the gtest framework

  • Download the framework.
  • Extract the zip.
  • Open the xcode project @ gtest-1.6.0/xcode/gtest.xcodeproj
  • Select gtest-framework Scheme and build the project.
  • If you get the errorThe run destination My Mac 64-bit is not valid for Running the scheme ‘gtest-framework’. The scheme ‘gtest-framework’ contains no buildables that can be built for the SDKs supported by the run destination My Mac 64-bit. Make sure your targets all specify SDKs that are supported by this version of Xcode“, try setting the following for both `Project` and `gtest-framework` Target:
    • `Base SDK` to any proper available SDK.
    • `Compiler for C/C++/Objective-C` to any proper compiler. LLVM GCC worked for me.
gtest-framework-scheme

scheme selection for gtest-framework

  • On successfull compilation, right click on gtest.framework in Products folder in Navigator and select ‘Show in Finder’
gtest-framework-products

build products for gtest-framework

 

  • Copy the gtest.framework folder to a common location (mine is /Users/saiy2k/projects/gtest-1.6.0/products)

Integrating with Real Project

  • Open the project in which testing capabilities need to be added.
  • Click on the project name in Navigator.
  • Create new target by clicking ‘Add Target’. (pic)
  • select Mac OS X –> Application –> Command Line Tool
  • Enter Product Name and other fields and click finish.
  • Selecting the newly created Target and goto Build Phases tab.
  • Add gtest.framework in our common location to ‘Link Binary with Libraries’
gtest-framework-target-build-phases

adding new target and adding gtest framework to it

Writing Test Case and Testing

In the Project Navigator, you should be having a new folder in the name given to the Target project. Under that project create a header file ‘TestCase1.h’ with the following contents:

TEST(SampleTest, Zero) {
    EXPECT_EQ(0, 0);
}

TEST(SampleTest, Positive) {
    EXPECT_EQ(1, 1);
    EXPECT_EQ(6, 3*2);
    EXPECT_EQ(20, 10*2);
}

TEST(SampleTest, Negative) {
    EXPECT_EQ(-1, -1);
    EXPECT_EQ(-2, -2);
    EXPECT_EQ(-3, -3);
}

Now select the scheme for New Test Target and run it and check the log for output of the test run. For writing actual test cases, refer the googletest wiki.

Interesting HTML5 Games around

I have been playing a few HTML5 games and reviewing a lot of them lately and found some amazing games, which unleashes the true potential of HTML5, showcasing the ultimate possibilities that could be done with HTML5. I just want to share some of them here and will update the post whenever I find something which belongs to this list.

 

1. Entanglement

Entanglement is a strategic puzzle game, where you gain points by forming and connecting   lines across hexagonal tiles maze. The goal is to make longest line without hitting the edges  and the center tile. Play Link

Entanglement ScreenShot

Screenshot of the Entanglement HTML5 Game

 

2. HTML5 Command and Conquer

Pakka clone of the classic Command and Conquer in HTML5 including several single player missions and multiplayer feature, developed single handedly by Aditya Ravi Shankar. Though its meant to be a proof of concept, its very good enough to be a playable game. Play Link

Command and Conquer Screenshot

Screenshot of HTML5 Command and Conquer by Aditya Ravi Shankar

 

3. Score Rush

Score Rush is a high action paced shoot em up game with bosses spraying bullets throughout the screen. Its highly addictive with 62M being my top score. Play Link

Score Rush Screenshot

Screenshot of the highly addictive HTML5 shoot em up game Score Rush

 

4. Subbania

I only played the demo version of this game. But I am highly excited about it considering the gameplay hours, levels it has. And again it is developed by a single developer fiblye. The developer’s blog post on the enormous amount of effort / frustrations with `work in progress` browser implementations and things he went through in developing the game is inspirational. Play Link

Subbania Screenshot

Screenshot of HTML5 game Subbania

HTML5 Rocks !!!

Integrated Facebook Open Graph in Tic Tac Toe Extended

My recent thoughts is to deeply integrate social networking with gethugames.in. As part of the mission, I already added FB Like, +1, tweet button to almost all pages / apps including blog posts. Last week I added custom Open graph obejct (badge) and actions (earn) to the game Tic Tac Toe Extended. Since the game already had a collectible like item namely badges, the task turned out to be very simple.

Open Graph Earn / Badge Architecture:

The goal is to let the player `earn` a `badge` object at the end of each game, where the badges are ranked based on IQ level. Or in other words, to make feed story that says `User has earned Student badge on Tic Tac Toe Extended`. The procedure will look complex for first timer, but its very simple as long as we rightly follow the docs correctly. I will explain things that I done step by step:

  1. Create pages that represent badge objects.
  2. Create an app @ Facebook Developers Apps.
  3. Configure earn action and badge object.
  4. Call OpenGraph API from in-game.

1. Page for Badge objects

I wrote a simple PHP scriptto map to 10 different in-game badges. The badge pages have the following meta tags for the facebook to identify them as Open Graph objects.

<meta property="fb:app_id" content="<app-id>" />
<meta property="og:type" content="ggtestapplication:badge"/>
<meta property="og:url" content="http:/localhost/ttt/badge.php?rank=10"/>
<meta property="og:title" content="Amoeba"/>
<meta property="og:image" content="http://localhost/ttt/images/Amoeba.png"/>
<meta property="og:description" content="Amoeba huh? Wish you atleast had multi celled brains."/>
<meta property="ggtestapplication:rank" content="10"/>

2. Create an app @ Facebook Developers Apps

Goto Facebook Developers and create a new app filling out the all the fields.

Facebook Create application

Sample Application creation dialog in Facebook Developers App

3. Configure earn action and badge object

Goto Open Graph Dashboard and create a new object, name it Badge. Add one custom Integer property and name it rank. This rank is to give different weight-age to different badges.

Open Graph Badge Object

Badge Open Graph object with custom Rank Parameter for Tic Tac Toe Extended

Similarly create `earn` action connected with `badge` object, so as to make the badge earnable. Optionally add a `report` String parameter which can be used to present with the game win / lose and game timings. Your earn action page should look like this after the above setup:

Open Graph Earn Action

earn action configured in open graph

Open Graph Earn Action Story Configuration

Open Graph Earn Action Story Configuration

Tip: While configuring story attachment and in aggregations, the object and action variables can be accessed by placing them in between paranthesis `{}`. Apart from our custom objects / actions, several templates are provided, which are documented very well in developer docs.

4. Call OpenGraph API from in-game

With everything setup properly, now we can get into coding. When the game is over and scores are calculated, the action can be posted with the following code:

FB.api('/me/' + 'tictactoeextended:earn',
    'post',
    {'report' : TicTacToe.GameState.gameDescription,
    badge : 'http://www.gethugames.in/tictactoe/badge.php?rank=' + (10 - TicTacToe.GameState.rank) },
    function(response) {
        console.log(response);
});

Before calling this code to post an action, the user should be logged in with corresponding `posting` permissions. I will write those procedures for those in my next upcoming posts. With all this done right, when I finish a game, an activity gets posted in my profile as shown below:

Tic Tac Toe Extended Activity Feed

Earn Badge action of Tic Tac Toe Extended showing up in Facebook Activity stream

Open Graph Aggregations

If you accomplished all the above steps, setting up an aggregation is just a piece of cake and I setup an aggregation box and it looks as below:

Tic Tac Toe Extended - Facebook Aggregations

Aggregations box in Facebook profile page for Tic Tac Toe Extended

PS: After finishing all this, I couldn’t submit the app to Facebook App Center as it require a secure URL (https) to access the game and I dont have SSL setup in my server :-( But I will be buying it soon and submit it to app center.

HTML5 Space Maze

Gethugames’ another product that has been dragged for 6 months of development period is finally released as BETA.

Play the game @ http://www.gethugames.in/html5spacemaze/ Source code @ https://github.com/saiy2k/HTML5-Space-Maze

Dynamic Size

Unlike Tic Tac Toe, which had 2 different sizes for mobile and desktop versions, the goal of this project is to make the gameplay area resize itself to any resolution. A wonderful post @ html5rocks.com made this task much easier.

Leader Board

Another goal is to integrate some sort of leader boards to save user score and make the game little competitive. I integrated Playtomic API for the leader boards and it was very simple and good. But there were some serious server stability issues with Playtomic few months back as more and more people started using it and so I temporarily turned off all Playtomic related code in my game. But now Playtomic seems to be working fine and soon will update the code with leader board functionality.
HTML5 Space Maze Screenshot

No Frameworks

The biggest mistake I been doing since my first project is not using any gaming frameworks / game engines. Hand coding menu systems / buttons / screen flow logics is hectic and meaningless when so much of the work is already being done in many open source game frameworks. This project made me realize my mistake and wont be doing any other project from scratch as this. Been looking into coco2dx for a while and probably will be using it for the next game.

Mobile

The main reason for implementing dynamic game layout is to make the game playable in mobile. But targeting this game for mobile is a bad idea. This gameplay mechanism wont suit for touch devices. The core mechanism is to evade existing lines and asteroids and draw the line through the gaps with high precision. But when you place the thumb in screen in mobile, your view of the drawing tip gets blocked and you lose the precision, thus making the gameplay frustrating.
I tried accelerometer integration and thought drawing as per the device orientation would be cool. It was cool actually, but the problem is browser’s auto-rotation. When you play, the browser auto rotates between portrait and landscape orientations in the mid of the game and there is no API in HTML5 to block browser auto-rotation. Hence mobile gameplay would not all be playable, though it works technically.

Not yet tested in IE. Will do when I get time.

Finally, The Team
Big thanks to Sankar Ganesh, Kevin Skyba for their overall support, ideas and more importantly contributions in programming. Thanks guys :-)

Then big thanks goes to open source / open art community for all the game assets including graphics / sound effects, etc., Here I list out the links to people whose work are used in this game