Android Icon and Splash Screen Sizes in Phonegap Build Config

In the config.xml:

<!-- Define app icon -->
<icon src="assets/icons/android/icon-36-ldpi.png" gap:platform="android" gap:qualifier="ldpi" />
<icon src="assets/icons/android/icon-48-mdpi.png" gap:platform="android" gap:qualifier="mdpi" />
<icon src="assets/icons/android/icon-72-hdpi.png" gap:platform="android" gap:qualifier="hdpi" />
<icon src="assets/icons/android/icon-96-xhdpi.png" gap:platform="android" gap:qualifier="xhdpi" />
<!-- Define app splash screen -->
<gap:splash src="ldpi.png" gap:platform="android" gap:qualifier="ldpi" />
<gap:splash src="mdpi.png" gap:platform="android" gap:qualifier="mdpi" />
<gap:splash src="hdpi.png" gap:platform="android" gap:qualifier="hdpi" />
<gap:splash src="xhdpi.png" gap:platform="android" gap:qualifier="xhdpi" />
<gap:splash src="fr-xhdpi.png" gap:platform="android" gap:qualifier="fr-xhdpi" />
<gap:splash src="portrait-xxhdpi.png" gap:platform="android" gap:qualifier="port-xxhdpi" />
<gap:splash src="landscape-xxhdpi.png" gap:platform="android" gap:qualifier="land-xxhdpi" />

 

But how do these translate to pixels?

Icons:

  • LDPI:
    • 36x36px
  • MDPI:
    • 48x48px
  • HDPI:
    • 72x72px
  • XHDPI:
    • 96x96px
  • XXHDPI:
    • 144x144px
  • XXHDPI:
    • 192x192px
  • 512 x 512 pixel – only used in Android Market; resized to various sizes

Splash Screens:

  • LDPI:
    • Portrait: 200x320px
    • Landscape: 320x200px
  • MDPI:
    • Portrait: 320x480px
    • Landscape: 480x320px
  • HDPI:
    • Portrait: 480x800px
    • Landscape: 800x480px
  • XHDPI:
    • Portrait: 720px1280px
    • Landscape: 1280x720px

References:

Scuba Chibi: What’s Next?

In as much as I would like to move on to my next project, there are still a few things I need to finish with Scuba Chibi:

1. Android Support

Android friends, I haven’t forgotten about you.  I’ve tried out the game on Android, but it appears that Ad Mob and Phaser.js are not working well together.  If I remove Ad Mob, then the game loads fine.  I might have to look into using another Ad Mob plugin that works in Phonegap, or maybe I’ll do some Javascript magic without a library.  We’ll see.  There are also some resizing issues that I would need to take care of.  The game does not resize to the screen for my Android tablet.  This will be fun…

2. Suggestions?

I’ve had some suggestions as far as leaderboards, more enemies, and more backgrounds.  All are possibilites!  🙂  Any other suggestions?  🙂

Stay tuned for my upcoming blog post when I do my Postmortem #2 – Data and Analytics!

Scuba Chibi Released to the iOS App Store!

Scuba Chibi is now available on the iOS App Store!  Check it out!

https://itunes.apple.com/us/app/scuba-chibi/id970197009?ls=1&mt=8

appstore

Other links:

Scuba Chibi website:  http://melkybee.com/scubachibi/

Facebook page:  https://www.facebook.com/scubachibi

Twitter:  https://twitter.com/scubachibi

SlideDB:  http://www.slidedb.com/games/scuba-chibi

Scuba Chibi Postmortem #1: The Technical Learnings

I can finally say that Scuba Chibi is done and will soon be released to the iOS App Store!

As simple as this game is, it actually took me a whole lot longer to finish than I had expected.  Most of it was due to finding the free time to actually work on it.  But it was a lingering item on my To-Do list and I wanted it done and over with so that I can move on to my next project.  🙂

Nevertheless, from a technical and artistic standpoint, it was fun to work on.  It was a game that I had made with Phaser, Javascript, and Phonegap Build.  I do Javascript for work and I have played around with some small Phaser examples, but I am new to Phonegap Build.  So there would be times when I ran into some issues here and there and after googling for some solutions, I could not find any, so I resulted in doing a bit of trial and error.  That is where my blog comes into play.  I’ve always thought that my blog would be my way to remind my future self on how to do things.  Because let’s face it, I have a bad memory :-).

So here is a compilation of technical things that I have learned along the way while making Scuba Chibi:

Also, here are some blog entries for the art that I made for the game:

So, look out for my game Scuba Chibi, coming soon to the iOS App Store! 😀

iOS Icons and Splashes in Phonegap Config

Here’s what I put in my Phonegap build config.xml.  Note that I’ve got an icon.png and splash.png at the root level.

<!-- Icon -->
<icon src="icon.png" />
<!-- iPhone / iPod Touch -->
<icon src="assets/icons/ios/icon.png" gap:platform="ios" width="57" height="57" />
<icon src="assets/icons/ios/icon@2x.png" gap:platform="ios" width="114" height="114" />
<!-- iPhone 6 / 6+ -->
<icon src="assets/icons/ios/icon-60@3x.png" gap:platform="ios" width="180" height="180" />
<!-- iPhone / iPod Touch -->
<icon src="assets/icons/ios/icon-60.png" gap:platform="ios" width="60" height="60" />
<icon src="assets/icons/ios/icon-60@2x.png" gap:platform="ios" width="120" height="120" />
<!-- iPad -->
<icon src="assets/icons/ios/icon-76.png" gap:platform="ios" width="76" height="76" />
<icon src="assets/icons/ios/icon-76@2x.png" gap:platform="ios" width="152" height="152" />
<!-- Settings Icon -->
<icon src="assets/icons/ios/icon-small.png" gap:platform="ios" width="29" height="29" />
<icon src="assets/icons/ios/icon-small@2x.png" gap:platform="ios" width="58" height="58" />
<!-- Spotlight Icon -->
<icon src="assets/icons/ios/icon-40.png" gap:platform="ios" width="40" height="40" />
<icon src="assets/icons/ios/icon-40@2x.png" gap:platform="ios" width="80" height="80" />
<!-- iPad -->
<icon src="assets/icons/ios/icon-72.png" gap:platform="ios" width="72" height="72" />
<icon src="assets/icons/ios/icon-72@2x.png" gap:platform="ios" width="144" height="144" />
<!-- iPad Spotlight and Settings Icon -->
<icon src="assets/icons/ios/icon-50.png" gap:platform="ios" width="50" height="50" />
<icon src="assets/icons/ios/icon-50@2x.png" gap:platform="ios" width="100" height="100" />
<!-- Splash screen -->
<gap:splash src="splash.png" />
<!-- iPhone and iPod touch -->
<gap:splash src="assets/splash/ios/Default-iphone.png" gap:platform="ios" width="320" height="480" />
<gap:splash src="assets/splash/ios/Default@2x-iphone.png" gap:platform="ios" width="640" height="960" />
<!-- iPhone 5 / iPod Touch (5th Generation) -->
<gap:splash src="assets/splash/ios/Default-568h@2x-iphone.png" gap:platform="ios" width="640" height="1136" />
<!-- iPhone 6 -->
<gap:splash src="assets/splash/ios/Default-667h.png" gap:platform="ios" width="750" height="1334" />
<gap:splash src="assets/splash/ios/Default-736h.png" gap:platform="ios" width="1242" height="2208" />
<gap:splash src="assets/splash/ios/Default-Landscape-736h.png" gap:platform="ios" width="2208" height="1242" />
<!-- iPad -->
<gap:splash src="assets/splash/ios/Default-Portrait-ipad.png" gap:platform="ios" width="768" height="1024" />
<gap:splash src="assets/splash/ios/Default-Landscape-ipad.png" gap:platform="ios" width="1024" height="768" />
<!-- Retina iPad -->
<gap:splash src="assets/splash/ios/Default-Portrait@2x-ipad.png" gap:platform="ios" width="1536" height="2048" />
<gap:splash src="assets/splash/ios/Default-Landscape@2x-ipad.png" gap:platform="ios" width="2048" height="1536" />

 

Check if Device is Ready in Phonegap

Apparently, you have to check if your device is ready before you can use Phonegap plugins like Google Analytics and Admob.  Use the “deviceready” listener:

if(( /(ipad|iphone|ipod|android|windows phone)/i.test(navigator.userAgent) )) {
  document.addEventListener('deviceready', initApp, false);
} else {
  initApp();
}

Custom Share Buttons in Phaser and Phonegap

So let’s say you want a Twitter share button and a Facebook share button at the end of your game. With Twitter, you can share your high score. With Facebook, you can share your game’s website link. Here’s what you do.

Make a function for opening a window in a browser. For more on that, see http://www.melkybee.com/blog/2015/03/29/how-to-open-links-in-a-browser-in-a-phaser-js-and-phonegap-build-project/.

In index.html:

function openDeviceBrowser(externalLinkToOpen) {
  window.open(externalLinkToOpen, '_system', 'location=no');
}

In JS:

// Custom share buttons in Phaser
shareTwitterButton = game.add.button(10, 10, 'shareTwitterButton', this.shareTwitter, this, 0, 0, 0);
shareFacebookButton = game.add.button(10, 50, 'shareFacebookButton', this.shareFacebook, this, 0, 0, 0);

openDeviceBrowser() opens a URL that uses Twitter web intent. More on that here – https://dev.twitter.com/web/intents

shareTwitter : function() {
  openDeviceBrowser('https://twitter.com/intent/tweet?url=http://custom_url&text=Custom+Text&via=custom_via&hashtags=custom_hashtag');
}

The Facebook sharer.php is no longer documented, but it should still work. Just replace “http://custom_url” with your own custom url.

shareFacebook : function() {
  openDeviceBrowser('https://www.facebook.com/sharer/sharer.php?u=http://custom_url');
}

The HTML of the URL that you are sharing should have the proper <meta> tags. That way, data such as a title and image will populate when you share your link. For Twitter, see https://dev.twitter.com/cards/overview. For Facebook, see https://developers.facebook.com/docs/sharing/best-practices.

Example (put these in your <head> tag in the HTML of the web page (http://custom_url above) that you are sharing):

<!-- Twitter Card data -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@custom_twitter_handle">
<meta name="twitter:title" content="Custom Title">
<meta name="twitter:description" content="Custom Description">
<meta name="twitter:image" content="http://custom_image.png">
<!-- Facebook Open Graph data -->
<meta property="og:type" content="website">
<meta property="og:title" content="Custom Title">
<meta property="og:url" content="http://custom_url">
<meta property="og:description" content="Custom Description">
<meta property="og:image" content="http://custom_image.png">

Object Pooling Example in Phaser

Scuba Chibi is potentially endless, so if I’m up to 120 points or so, I could experience lots of lag if I don’t use object pooling. It’s because I’m doing a lot of creating and deleting of objects (i.e. the enemies), and that wastes memory. This is a situation when object pooling becomes useful, so that I just deactivate objects that aren’t used and then reactivate them when they need to be reused. http://en.wikipedia.org/wiki/Object_pool_pattern

So let’s make an object pool for enemies and have up to 10 enemies of one type on the screen at one time.

this.enemyPool1 = [];
this.MAX_ENEMIES_PER_TYPE = 10;

Create all the enemies in the object pools, but deactivate them. Setting “obstacle.outOfBoundsKill = true;” means that the enemy will be deactivated when they go offscreen.

create: function() {
  var obstacle;

  // define obstacle group
  this.obstacles = game.add.group();
  this.obstacles.enableBody = true;
  this.obstacles.physicsBodyType = Phaser.Physics.ARCADE;

  // create enemy object pools and deactivate enemies
  for (i = 0; i < this.MAX_ENEMIES_PER_TYPE; i++) {
    obstacle = this.obstacles.create(-1000, -1000, 'enemy1');
    obstacle.checkWorldBounds = true;
    obstacle.outOfBoundsKill = true;
    obstacle.kill();
    this.enemyPool1.push(obstacle);
  }
}

Activate an enemy.

addObstacle: function(x, y, type) {
  var obstacle,
    i = 0;
  if (type === 1) {
    for (i = 0; i < this.enemyPool1.length; i++) {
      if (!this.enemyPool1[i].alive) {
         obstacle = this.enemyPool1[i];
         obstacle.reset(x, y);
         return obstacle;
      }
    }
  }
  return obstacle;
}

So basically, a couple of important functions in Phaser for object pooling are:

sprite.kill(); // halts rendering, but the object still exists
sprite.reset(); // reactivates the object so that it renders again and you can interact with them

Resizing Sprites to Fit Screen Resolutions Using Phaser

When I started Scuba Chibi, I made the mistake of making sprites small, and then scaling them up to fit larger screen resolutions.

game.stage.smoothed = true; // render crisp art
game.stage.scale.fullScreenScaleMode = Phaser.ScaleManager.SHOW_ALL;

One problem is that they never scaled up at all. They remained small instead of resizing to larger resolutions. I had to do something more than those 2 lines of code.

But if they did scale up, I realized a potential second problem — the sprites would be artifacted and not crisp and clear. So, it’s best to create sprites that are really large and then scale them down for lower resolutions. Luckily, I use vector art, so resizing them (I used Flash to draw the images in the first place, and then used Flash to resize them 4x larger and then exported them as PNG’s) was not a problem at all.

So, I thought about the larger resolutions to support. I was at first thinking of my own device which was really small, 960×640, but it appeared to show things even smaller, at 480×320. So I resized everything to 4x larger. That means the base dimensions are now 1920×1280. And that is my baseline for all the sizes of my sprites.  1920×1280 is what is considered 100% width and 100% height.

Here are some examples of that in my code:

var GAME_WIDTH = screen.height,
 GAME_HEIGHT = screen.width,
// 1920x1280
 BASE_WIDTH = 1920,
 BASE_HEIGHT = 1280;
// add a chibi to the screen - 360x360
this.chibi = game.add.sprite(0, 0, 'chibi');
this.chibi.scale.setTo(((GAME_WIDTH/BASE_WIDTH)*360)/360, ((GAME_HEIGHT/BASE_HEIGHT)*360)/360);
this.chibi.anchor.setTo(0.5, 0.5);
this.chibi.x = GAME_WIDTH/2;
this.chibi.y = (GAME_HEIGHT/9)*4.5;
this.chibi.smoothed = true;

The actual chibi.png is 360×360. scale.setTo() considers “1” as being being “100%.”

The formula is this:

this.chibi.scale.setTo(((GAME_WIDTH/BASE_WIDTH)*BASE_CHIBI_WIDTH)/BASE_CHIBI_WIDTH, ((GAME_HEIGHT/BASE_HEIGHT)*BASE_CHIBI_HEIGHT)/BASE_CHIBI_HEIGHT);

GAME_WIDTH and GAME_HEIGHT is synonymous to the width and height of a device’s resolution (notice they are set to screen.width and screen.height above).

So if my device is 480×320, let’s try inputting the numbers:

this.chibi.scale.setTo(((480/1920)*360)/360, ((320/1280)*360)/360);

becomes

this.chibi.scale.setTo(0.25, 0.25);

which is what we want. 1/4 of 360 is 90, and that was my chibi’s size in the first place in a 480×320 screen.

The iPhone 6 is 1334×750.  Let’s input the numbers for that:

this.chibi.scale.setTo(((1334/1920)*360)/360, ((750/1280)*360)/360);

which is:

this.chibi.scale.setTo(0.6947916666666667, 0.5859375);

You’ll notice that the chibi will no longer be proportional in an iPhone 6, but that is one of the things to accept when developing for multiple devices.