Porting game from Cocos2d-iPhone to Android?

Hi,

I already have a game http://itunes.apple.com/us/app/chickeneggs/id446767688?mt=8 on App Store wrote by cocos2d-iPhone.

Do you smart guys have any advices to me if I want to port this game to android?

Any guide or suggestion is appreciated!

Thank you all in advanced.

  1. Adjust the resolution to WVGA as default
  2. Using IAP or integrating ad sdk such as admob to get profits

Instead of adjusting the resolution, I recommend writing a self resize/repositioning algorithm.

What I do is have my artists design all the sprites for a 640x960 wireframe, then when the game loads on any device, I get the raw size of the screen in pixels, calculate the best fit ratio, and resize/position all objects based on that ratio. Not a plug go look at “Qach” in the app store and android market (its free), and load it up on an iPhone 3gs, iPhone 4, iPad, and/or android device and you will see it properly size and align on any screen it is placed on. That is ALL the same code path, and generated on the fly at load time. You may get a minor amount of “drift” based on changing aspect ratios, but I use an “align for” declaration that tells my algorithm if it should use the height, width, or “best fit” ratio when it places and scales the object. This is also a good method going forward since we have no confirmation what resolution the iPhone 5 / ipad 3 will have…

http://itunes.apple.com/us/app/qach/id457951411?mt=8
https://market.android.com/details?id=com.latman.Qach

@Alan Would you mind to share this resize/repositioning function with us?

Regards.


Please,

Site

Notes:

  1. “wireframeDimensions” is the original layout size of your assets. We generally design everything around a 960x640 wireframe. Thus all assets are scaled to 1 when on a 960x640.

  2. Scale your sprites with the return value of getScaleRelativeToDesignWireframe, and position them with the return value of getPointRelativeToDesignWireframe. The point value you pass to getPointRelativeToDesignWireframe will be the original position based on the 960x640 wireframe (or whatever wireframe you chose).

  3. I enable retina, but I do NOT use the hd extension for my sprites. All of my sprites are based on 960x640, thus when you get the scale using getScaleRelativeToDesignWireframe on a 480x320 device, it will actually return 0.5, if you usehd extensions, it will probably return the wrong size values because cocos2d does an internal conversion on load. Recap - enable retina, using sprites that would have a 1x1 ratio on 960x640 (or whatever you design wireframe is), DONT use -hd extension.

  4. Using “RELATIVE_TO_BEST” will make sure that all of the assets will fully make it on to the screen, although asset drift will be more prevalent.

    float DS_Utility::getScaleRelativeToDesignWireframe(CCSize wireframeDimensions, RelativeToType relativeTo)
    {
    //Calculate ratios
    CCSize screenSize = CCDirector::sharedDirector()->getWinSizeInPixels();
    float widthRatio = screenSize.width / wireframeDimensions.width;
    float heightRatio = screenSize.height / wireframeDimensions.height;

     switch(relativeTo)
     {
         case RELATIVE_TO_WIDTH:
             return widthRatio;
             break;
    
         case RELATIVE_TO_HEIGHT:
             return heightRatio;
             break;
    
         case RELATIVE_TO_BEST:
             return widthRatio > heightRatio ? heightRatio : widthRatio;
             break;
     }
    
     return 1;
    

    }

    CCPoint DS_Utility::getPointRelativeToDesignWireframe(CCSize wireframeDimensions, RelativeToType relativeTo, CCPoint point)
    {
    //Calculate ratios
    CCSize screenSize = CCDirector::sharedDirector()->getWinSizeInPixels();
    float widthRatio = screenSize.width / wireframeDimensions.width;
    float heightRatio = screenSize.height / wireframeDimensions.height;

     CCSize screenPoints = CCDirector::sharedDirector()->getWinSize();
     float screenWidthRatio = screenPoints.width / screenSize.width;
     float screenHeightRatio = screenPoints.height / screenSize.height;
     float screenScaleRatio, scaleRatio;
    
     switch(relativeTo)
     {
         case RELATIVE_TO_WIDTH:
             screenScaleRatio = screenWidthRatio;
             scaleRatio = widthRatio * screenScaleRatio;
             break;
    
         case RELATIVE_TO_HEIGHT:
             screenScaleRatio = screenHeightRatio;
             scaleRatio = heightRatio * screenScaleRatio;
             break;
    
         case RELATIVE_TO_BEST:
             screenScaleRatio = screenWidthRatio > screenHeightRatio ? screenHeightRatio : screenWidthRatio;
             scaleRatio = (widthRatio > heightRatio ? heightRatio : widthRatio) * screenScaleRatio;
             break;
     }
    
     //Calculate step factor, so we position evenly inside of the ratio
     float xStep = 0;
     float yStep = 0;
    
     if(scaleRatio == heightRatio)
     {
         xStep = widthRatio >= 1 ? (screenSize.width - wireframeDimensions.width)/2 * screenScaleRatio
                                 : (int(wireframeDimensions.width) % int(screenSize.width))/2 * screenScaleRatio;
     }
    
     else 
     {
         yStep = heightRatio >= 1 ? (screenSize.height - wireframeDimensions.height)/2 * screenScaleRatio 
                                  : (int(wireframeDimensions.height) % int(screenSize.height))/2 * screenScaleRatio;
     }
    
     //Position the centered on calculated ratio and step
     return CCPoint(point.x * scaleRatio + xStep, point.y * scaleRatio + yStep);
    

    }

Hope that helps! :smiley:

It will definitely be very useful.

Thanks a lot for sharing.

Regards.


Please,

Site

Alan Ide wrote:

Hope that helps! :smiley:

Thank you for your kindly sharing this beautiful algorithm.

It really helps!

I like your game, the duck is very cute.

My game also have some chickens, maybe we can build a bird’s happy land, haha.

Thank you again… sincerely…

Ok, so apparently I have not had enough caffeine this morning… For anyone who read what was here a moment ago about a bug, please ignore it. :stuck_out_tongue:

Ok, so there is a “bug”, but its not one that needs to be fixed per say… :stuck_out_tongue: Let me explain.

Currently the line:

if(scaleRatio == heightRatio)

is used to test if we need to default to stepping our calculated point in the x or y directions. This will work fine for any device that returns either equal values of PTs and Pixels, or equal ratios of Pts and Pixels. Example, “Pts = 320x480 Pxs = 320x480 is OK” & “Pts = 320x480 Pxs = 640x960 is OK”. However “Pts = 320x480 Pxs = 360x920 would NOT be ok”. This is because the ratio of pts/px width is not equal to the ratio of pts/px height. So:

if(scaleRatio == heightRatio)

would always return false. Now the only time this could possible happen would be if a device was released that had some seriously confused points/pixel ratios, and since iPhone is the only one that I am aware of that even uses the Pts part of this equation, then I dont feel that is something most people need to worry about. However I will take the time to fix it soon, and post a more bullet proof version.

I have one question about the device’s center point…

When I want to put the background image into a layer. I set the position to center of the device.

But when I use the functions above to get center point, it will be a little strange.

Right now, I use the temporary solution to always use half the actual resolution as a center coordinator except for iPhone retina.

Anybody has another smart way to this problem?

Thank you.

Could you explain what little strange is, or paste a image here?

Simon,

The algorithm is designed to find the location of the incoming point based on either the Width or Height ratios, not both. That is by design, since we “want” the point drift to make sure what we are displaying always ends up on screen no matter what the resolution. Thus finding a “center point” which relies on both width and height ratios working together wont work. Unless you simply call the function twice, once with a point holding your X value with a relativeTo value of Width, and once with a point holding your Y value with a relativeTO value of Height. By using the X value of the first, and the Y value of the second you will have generated a point that is scaled and stepped by both ratios. I do this as well when I need to have such things as screen center points, or things aligned to edges without drift, or when aligning to the edges of other sprites. For example, this should return the center of any screen if you are using a design wireframe of 640x960

ccp(DS_Utility::getPointRelativeToDesignWireframe(CCSize(640,960), DS_Utility::RELATIVETOWIDTH, CCPoint(320, 0)).x,
    DS_Utility::getPointRelativeToDesignWireframe(CCSize(640,960), DS_Utility::RELATIVETOHEIGHT, CCPoint(0, 480)).y));

Does that help?

Thank you, Alan, it really helps.

Your explanation is very good in detail, and when I applied the example code, "It just works

BTW, can you show me the path about my another question about CCMenuToggle and SimpleAudioEngine mute function?

Here is the link:

http://www.cocos2d-x.org/boards/6/topics/4305

Thank you in advanced.

Hi Alan ,

U r Using only one set of images(i.e., 960*640) for all Android devices.

By using above algorithms u r scaling right.

Santosh: Yes, the artists based all of the images off of 960x640 and only one set were used. The algorithm was designed to scale and position a sprite based on drift.

Alen: Thanks

it Won,t be pixelating if u r using 960*640 images to iPad Hd.

If you want to port an existing cocos2d-iphone game to Android you definitely want to consider Apportable which lets you cross-compile your Objectve-C code to Android platform.

Check out this tutorial for more details on using Apportable with cocos2d: http://2sa-studio.blogspot.com/2013/06/from-ios-to-android-with-apportable.html