Nightwatch.js: Check if a checkbox is checked

This test involves waiting for a checkbox to be visible, clicking on the checkbox, and then verifying that the checkbox has been checked.

The checkbox has the following HTML DOM:

<input type="checkbox" name="vote">

Here is the Nightwatch.js test:

.verify.visible('input[name="vote"]', 'The checkbox named vote is visible')
 .click('input[name="vote"]')
 .waitForElementVisible('body', 1000)
 .element('name', 'vote', function(response) {
 client.elementIdSelected(response.value.ELEMENT, function(result) {
 client.verify.ok(result.value, 'Checkbox is selected');
 });
 })

Scuba Chibi Postmortem #2: Data and Analytics

About two weeks ago on Thursday, June 18th, I released my game Scuba Chibi to the iOS App Store.  You may be wondering, how has it been doing since then?  I’m going to grab data from iTunes Connect App Analytics, Google Analytics, my blog, my Facebook page, and my Twitter.  Let’s see how this game held up day by day, week by week!


iTunes Connect App Analytics

This shows the number of app downloads

IOS Daily Downloads 6/19 - 6/28
IOS Daily Downloads 6/18 – 6/28
IOS Country Downloads 6/19 - 6/28
IOS Country Downloads 6/18 – 6/28

TOTAL APP DOWNLOADS (6/18 – 6/28): ~99-102 (?)


Google Analytics

New Users:

  • THU 6/18: 17
  • FRI 6/19: 37
  • SAT 6/20: 13
  • SUN 6/21: 3
  • MON 6/22: 2
  • TUES 6/23: 1
  • WED 6/24: 4
  • THURS 6/25: 0
  • FRI 6/26: 0
  • SAT 6/27: 3
  • SUN 6/28: 1
  • MON 6/29: 2
  • TUES 6/30: 15
  • WED 7/1: 4
  • THURS 7/2: ?

Active Users:

  • THU 6/18: 19
  • FRI 6/19: 39
  • SAT 6/20: 20
  • SUN 6/21: 11
  • MON 6/22: 7
  • TUES 6/23: 5
  • WED 6/24: 7
  • THURS 6/25: 2
  • FRI 6/26: 5
  • SAT 6/27: 5
  • SUN 6/28: 6
  • MON 6/29: 4
  • TUES 6/30: 19
  • WED 7/1: 6
  • THURS 7/2: ?
New Users / Active Users 6/18 - 7/2
New Users and Active Users 6/18 – 7/2

Countries:

  1. United States: 156 sessions (69.03%)
  2. China: 36 sessions (15.93%)
  3. Germany: 6 sessions (2.65%)
  4. Vietnam: 4 sessions (1.44%)
  5. Switzerland: 3 sessions (1.33%)
  6. United Arab Emirates: 2 sessions (0.88%)
  7. France: 2 sessions (0.88%)
  8. United Kingdom: 2 sessions (0.88%)
  9. Netherlands: 2 sessions (0.88%)
  10. Russia: 2 sessions (0.88%)
  11. Argentina: 1 session (0.44%)
  12. Canada: 1 session (0.44%)
  13. Spain: 1 session (0.44%)
  14. Indonesia: 1 session (0.44%)
  15. India: 1 session (0.44%)
  16. Philippines: 1 session (0.44%)
  17. Poland: 1 session (0.44%)
  18. Venezuela: 1 session (0.44%)
Countries 6/18 - 7/2
Countries 6/18 – 7/2

Top Device Models:

  • iPhone: 142 sessions (77.6%)
  • iPad: 41 sessions (22.4%)

User Engagement:

  • Screen Views: 285
  • Average Time On Screen: 00:02:33
  • Crashes: 0  😀
  • Events:
    • Ad Views: 500
    • Button Clicks:
      • Game Over Menu – Play Again: 367
      • Main Menu – Play Game: 240 
      • Main Menu – View Instructions: 98
      • Instructions Menu – Back to Main Menu: 94
      • Game Over Menu – Back to Main Menu: 52
      • Game Over Menu – Share Facebook: 4
      • Game Over Menu – Share Twitter: 2
    • Score View: Game Over Menu – LocalStorage Score: 147 (this is the number of times the high score was saved in the device’s local storage)
User Engagement 6/18 - 7/2
User Engagement 6/18 – 7/2

WordPress Blog – http://www.melkybee.com/blog

Best Views Ever: 197 on Friday, June 26

Blog Stats - June/July
Blog Stats – June/July

I couldn’t pull data that includes info from 6/18, but here is data from 6/25 – 7/5:

Blog Stats 6/29 - 7/5
Blog Stats 6/29 – 7/5

These are my all-time most popular blog posts:

Top 10 Most Popular Blog Posts
Top 10 Most Popular Blog Posts

Facebook Page – https://facebook.com/scubachibi

Page Likes

  • THU 6/18: 14
  • FRI 6/19: +30
  • SUN 6/21: +11
  • MON 6/22: +3
  • TUES 6/30: +2
    • TOTAL: 60 likes
Facebook Likes 6/18 - 7/2
Facebook Likes 6/18 – 7/2

Twitter – http://twitter.com/scubachibi

THU 6/18 – THU 7/2:

  • Tweets: 4
  • Tweet Impressions: 727
  • Profile Visits: 67
  • Mentions: 1
  • Followers: 43
  • Engagement Rate: 4.3%
  • Link Clicks: 12
  • Retweets: 8
  • Favorites: 12
Tweet Impressions 6/18 - 7/2
Tweet Impressions 6/18 – 7/2

 

Conclusion

What can we draw from this data?  Hrmmm…

  1. Well, I admit that I am no expert in marketing, and I spent $0 on marketing, so the numbers are not high and are also decreasing.  :'(  Lol.
  2. Also, although we saw some low numbers in New Users in Google Analytics, we still saw that there were Active Users each day, even on the days when New Users were at 0.
  3. Interestingly, if the data holds correct, there were more app downloads in China (according to iTunes Connect App Analytics), but more sessions in the U.S. (according to Google Analytics).
  4. Furthermore, the day after the release (Friday, 6/19) had the highest number of downloads, New Users, Active Users, and the highest increase in Facebook likes.  I think it had to do with people seeing the news about the app up to a day late, because the other Fridays don’t necessarily have any high numbers.
  5. There was a bit of an increase in New Users and Active Users on Tuesday, 6/30.  I am not sure how or why that happened.  I didn’t do any blog posts, Facebook posts, or tweets on that day.  Hrmmm!
  6. However, on Friday, 6/26, the Scuba Chibi blog was mentioned on the Phaser website, so that day I received 197 views, my best views ever for my blog!

In my next postmortem, I am going to write about the backstory of Scuba Chibi and how the game evolved into what it became.  It should be interesting from a game design perspective.  Stay tuned!

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 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.