Using sprite atlases in a multi resolution setup in Cocos2D-x - cocos2d-x

I've just been able to setup a Cocos2d-x for a multiresolution environment. Ie supporting all/most of the available iPhone screen sizes.
My next step is to scrap the individual files (bunch of pngs) and use sprite atlases (aka sprite sheets) instead.
How does this work in Cocos2D-x? Does anyone have a working sample setup?
Once again, Google and existing documentation (well, I don't think that exists) fail me.

For cocos2d-x v3.5...
The cocos2d-x test classes are always a great place to look to see how things can be done with cocos2d-x.
Check out the AppDelegate.cpp in:
Cocos2d-x/cocos2d-x-3.5/tests/cpp-tests/Classes/AppDelegate.cpp.
In that class the window size is tested to see which set of assets should be loaded. That is part of the issue, deciding which assets to load.
For iOS retina, you can check the size of the screen and then set the content scale factor to either 1.0 for standard resolution or 2.0 for retina resolution.
Unfortunately, cocos2d-x doesn't seem to ever detect certain screen sizes and call Director::getInstanct()->setContentScaleFactor(2.0) for you, so I think we have to do this our self.
I have not tested the impact of setting contentScaleFactor on non-apple devices yet...
Check out the code below. Try running it in your AppDelegate::applicationDidFinishLaunching() method to get an idea of how cocos2d-x sees screen pixels and points; the result is not exactly what I expected. The output below is for an iPhone 5 device.
director->setContentScaleFactor(2);
Size winSizePoints = director->getWinSize();
Size winSizePixels = director->getWinSizeInPixels();
Size visibleSize = director->getVisibleSize();
CCLOG("Content scale factor set to 2.0.");
CCLOG("winSizePoints:%.2f,%.2f", winSizePoints.width, winSizePoints.height);
CCLOG("winSizePixels:%.2f,%.2f", winSizePixels.width, winSizePixels.height);
CCLOG("visibleSize:%.2f,%.2f", visibleSize.width, visibleSize.height);
director->setContentScaleFactor(1);
winSizePoints = director->getWinSize();
winSizePixels = director->getWinSizeInPixels();
visibleSize = director->getVisibleSize();
CCLOG("Content scale factor set to 1.0.");
CCLOG("winSizePoints:%.2f,%.2f", winSizePoints.width, winSizePoints.height);
CCLOG("winSizePixels:%.2f,%.2f", winSizePixels.width, winSizePixels.height);
CCLOG("visibleSize:%.2f,%.2f", visibleSize.width, visibleSize.height);
Output of above code:
Content scale factor set to 2.0.
winSizePoints:1136.00,640.00
winSizePixels:2272.00,1280.00
visibleSize:1136.00,640.00
Content scale factor set to 1.0.
winSizePoints:1136.00,640.00
winSizePixels:1136.00,640.00
visibleSize:1136.00,640.00
So it seems we have to check the the screen size and then choose assets.
One option is to then use code like this to decide which assets to load based on if the screen is retina or not. You could use a similar approach to also loading different size background images to deal with different aspect ratios (more aspect ratios below).
float scaleFactor = CCDirector::getInstance()->getContentScaleFactor();
if (scaleFactor > 1.99)
{
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("spriteSheet-hd.plist", "spriteSheet-hd.png");
}
else
{
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("spriteSheet.png", "spriteSheet.plist");
}
For sprite sheets, I highly recommend Texture Packer. Awesome tool that can create SD and HD sheets and .plist files for you with the press of one button.
If you publish to multiple platforms, you will also want to use the macros to detect the device type and use that information in deciding which assets to load.
e.g.
if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
elif CC_TARGET_PLATFORM == CC_PLATFORM_WP8
elif CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
elif CC_TARGET_PLATFORM == CC_PLATFORM_IOS
elif CC_TARGET_PLATFORM == CC_PLATFORM_MAC)
endif
Another thing to consider is that on low power CPU and RAM devices, loading large assets might make your frames per second (FPS) go to crap. Or worse, the device might not be able to load the asset or could crash the game. So be sure to test/profile on least common denominator devices that you plan to support.
Aspect Ration is another important issue (landscape width:height).
iPad aspect ratio is 4:3
iPhone 4 is 3:2
iPhone 5 & 6 are 16:9
Android throws in a bunch more width:height ratios.
WP8.1 is 15:9... not sure if others.
The point is that you probably don't want to stretch your backgrounds to get them to fill the screen, or have black bars on the edges where assets are not tall or wide enough.
To deal with this I create background assets that are wider than they need to be going off the right side of the screen. That content looks good but is not vital to convey the meaning of the background. That extra content can be clipped on devices that have narrower aspect ratios, i.e. ipad, and is visible on wider aspect ratio devices, i.e. iPhone 6.
The background images are then scaled up/down to match the screenSize height and retain their aspect ratio.

Related

Proper positioning (Screen width & height)

A little lost here. I've got two movieclips. I want one on the far left (out of reach until the user hovers over their left side of the screen) and one on the far right. I've tried playing with Screen, Capabilities, and stage.
I don't know why, but apparently my resolution 1536 by 864?
trace("Screen x = " + Capabilities.screenResolutionX); //Screen x = 1536
trace("Screen y = " + Capabilities.screenResolutionY); //Screen y = 864
I don't want to set the position of the native window to what the difference of the stage's with and height is to screenResoltionX and Y just because that number seems so off to me. I'm on a monitor with it's current resolution at 1920 x 1080. The only thing I can think of is that I have my laptop set to display only on the monitor at this time with it's main screen inactive, yet the window appears on my monitor, so i'm assuming its picking up the values from my monitor .. and my laptop's screen has no where near that weird of a resolution. Anyone know where this is coming from? I've never seen this before. The same numbers return from stage.fullScreenWidth and stage.fullScreenHeight..
I'm using Adobe AIR 17.0 to build this. Building it with an opaque window. The current size of the stage is set to 1024 x 786.
Edit: I want these objects on the edges of the user's screen. I'm trying to get a grid that represents the entire bounds of the user's screen.
When using Capabilities.screenResolutionX & Capabilities.screenResolutionY, it is reporting for the primary display (so if you have more than one monitor, regardless of which monitor your app is on, it will report back the primary monitor's resolution), and only at the time your application starts (so if you change resolution after the app starts Capabilities.screenResolutionX will not reflect the new screen resolution).
Here is a quote from the documentation: (emphasis mine)
This property does not update with a user's screen resolution and instead only indicates the resolution at the time Flash Player or an Adobe AIR application started. Also, the value only specifies the primary screen.
For your purposes, it seems like it shouldn't matter what the screen resolution is. Just use the stage.stageWidth & stage.stageHeight values since they reflect the boundaries of your actual app, regardless of which monitor it's on or if it's full screen, windowed, or scaled etc.
if(stage.mouseX < stage.stageWidth * 0.5){
//mouse is on the left hand side of the application.
}
EDIT
Based off your comment, sounds like you need to do this:
When your app first runs, do this to make it responsive/liquid:
stage.align = StageAlign.TOP_LEFT
stage.scaleMode = StageScaleMode.NO_SCALE
Then the stage.stageWidth and stage.stageHeight properties will reflect the actual window size.
You can maximize it through code with:
stage.nativeWindow.maximize();
You can listen for window sizing changes with:
stage.addEventListener(Event.RESIZE, myResizeHandler);
function myResizeHandler(e:Event):void {
//stage.stageWidth & stage.stageHeight have changed
}

Scaling a Game Maker app for mobile-device screens

I'm having a difficult time getting an HTML5 app I designed in Game Maker to scale for display on mobile-device screens. I've tried using this little bit of code, to set the width and height of a the main game room, in a setup object, before switching to that room:
room_set_width(rm_playspace,browser_width);
But that seems be doing absolutely nothing.
Have you successfully designed software for mobile devices with Game Maker? How did you get your software to scale for proper viewing on mobile devices with differently sized screens?
room_set_width( ind, w );
Description
With this function you can change (or set) the width of any room in your game except the current one.
so you need to go to another room, and then resize the first room and go back into it.
another option that you can try - just restart the room immediately after resizing, like
room_set_width(room, 640)
room_set_height(room, 480)
window_set_size(640, 480) // also you can use window_set_rectangle
room_restart()
(room should not be a persistent)
Don't forget to set view_port_xxx and view_size_xxx for proper sizes. You can use window_get_width() and display_get_width() etc. for that - refer to manual for more info.
You could also just resize the surface and before, the view.

AS3/Adobe AIR Starting in Portrait & changing to Landscape becomes wrong

I'm gonna try to explain this as good as I can with limited english!
Ok, I'm bulding an app that will on phones be in portrait mode and in landscape on tablets.
I do this by, first with calculating the display size than basically saying "if display size is more than 5 inches, consider this device to be a tablet".
This works great. I'm using Adobe Flash CS6 with FlashDevelop, so I have portrait mode as default once the application start. If the device is a tablet, it changes aspect ratio with stage.setAspectRatio(StageAspectRatio.LANDSCAPE);
This also works great.
Now, the problem is that stage.stageWidth will not change its value to the new aspectRatio. This is a easy fix with just using stage.stageHeight for the width. BUT the system bar on honeycomb/ics tablets/devices will not be changed.
Sorry for the bad explanation but let me show you with some numbers...
This is what happends when I start my application on my tablet.
Application start with Portrait. The height = 1232 width = 800. As you can see the display resolution should be 1280x720 but there is no way to get the height of the systembar througout any commands. I've test everything that returns resolution and none of them return the full resolution (1280x720).
Now the application turns into landscape (since it's a tablet) and gets this resolution height: 800, width 1232.
As you may can imagine this is wrong. Because the systembar is on the bottom. The resolution should be height: 752, width 1280.
Is there any solutions?
I've been thinking of a workaround that will basically calculate what the systembar *should be. But before I start on that, I would like to know if there is any way to solve this.*
-1. I don't know if there's an official way to do these,
but your first criteria sounds similar to this:
link: AS3/AIR: If phone use portrait, if tablet use landscape?
This also solves the problem that some devices' default orientation are "portrait" but some devices' are "landscape"
-2. As for the area of the screen
The following should give the pixel dimensions of the device:
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.fullScreenWidth;
stage.fullScreenHeight;
//import flash.system.Capabilities;
Capabilities.screenResolutionX;
Capabilities.screenResolutionY;
And then using this (which I assume you've been using) should return the usable area minus the Status Bar (a post I read mentioned it is correct for iPad but some Android tablets did not take into account the Navigation Bar):
stage.stageWidth;
stage.stageHeight;
Then this one should give the correct value of screen resolution minus Status Bar and Navigation Bar area:
//import flash.display.Screen
var screenBounds:Rectangle = Screen.mainScreen.visibleBounds;

Set ApplicationDPI in AS3 Mobile application

I developing an application in Flash Builder with AS3 only (no flex stuff). In flex it is possible to set the application's dpi by the following code:
<s:ViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" applicationDPI="320">
But I using only AS3. I have read that it is not possible to change the application's DPI in run-time (with AS3), but how can I set this in project settings, compiler settings or is there another way to do it?
Also, what is the default application's DPI setting?
Ask it here because can't find it on the net (only flex based solutions).
The DPI on mobile is set by the hardware, it is entirely dependent on the phone and screen. When you set the applicationDPI in a Flex mobile you're telling Flex to automatically scale your assets.
Automatic scaling. Developers can choose to specify a target DPI for their application by setting the applicationDPI property on the application. When this is explicitly set, developers should set up their skins and layout as if they were running on a device of the given DPI. At runtime, if the device has a different DPI from the specified target DPI, Flex will automatically scale the entire application to preserve the approximate physical size of the application and its controls. For example, if an application is targeted at 160 DPI, it will automatically scale by 1.5x on a 240 DPI device. If you choose not to use this feature, you'll need to make sure your custom skins and view layouts adapt properly to different pixel densities at runtime.
Source
In an AS3 mobile project you're going to need to handle this yourself.
You can get the current DPI using Capabilities.screenDPI but I think what you may be after is a ratio to scale your assets by. One way to do this would be to start with the original game width.
private static const WIDTH:Number = 1024;
You can then get a ratio using
var ratio:Number = stage.fullScreenWidth / WIDTH;
And apply this to your assets
myBitmap.scaleX = myBitmap.scaleY = ratio;
Now this isn't going to take the rotation of the device into account, so fullScreenWidth/Height may be flipped. To check for that you're going to need to do something like this
if (stage.fullScreenWidth > stage.fullScreenHeight){
//portrait
} else {
//landscape
}
Hopefully this helps

ActionScript Screen Measurements

i'm attempting to use the Capabilities class to draw an accurately sized sprite on screen at exactly (2.5" x 5") regardless of the screen's resolution, but while i believe the code is correct, the size of the sprite is not accurate - when actually measuring it with a ruler.
function inchesToPixels(inches:Number):uint
{
return Math.round(Capabilities.screenDPI * inches);
}
var mySprite:Sprite = new Sprite();
mySprite.graphics.beginFill(0x000000, 0.5);
mySprite.graphics.drawRect(0, 0, inchesToPixels(2.5), inchesToPixels(5));
mySprite.graphics.endFill();
addChild(mySprite);
I'm not entirely sure about this, but my feeling is that the screenDPI value being returned by the Capabilities class would be the same value for two monitors running the same resolution, even if the monitors had different physical dimensions.
To illustrate, if you have two monitors, one which is 14" and the other which is 28", both displaying the same resolution of 800 x 600 pixels, that screenDPI property will return the same thing because they're both using the same resolution.
However, the number of dots in a literal, real-world inch on each screen will be different because of the physical dimensions of the monitor. So when you're running your code and measuring the on-screen Sprite you create with a ruler, it's not going to match up to real-world inches. I'm not sure how you could get around this problem (if I'm right about what's causing it), it seems like it'd be difficult.
Debu
I suggest at the start of your app telling the user "I detected your monitor is XX inches" (where XX is calculated from screenDPI), and allow the user to type in a correct monitor size.