Thursday, June 5, 2014

Getting Started with Cocos2d-JS 3.0 Part 1 - First Sprite

Prerequisites

  • Knowledge of how to download, unzip and install software packages and software on your computer and how to change environment variables for your operating system of choice (Linux / Windows)
  • Basic knowledge of JavaScript (should know what closures are, what a callback function is, etc.) in other words not a complete beginner. If you need a refresher on JavaScript I suggest this tutorial.
  • Some experience using Eclipse-like IDEs would be helpful (although not necessary). If you can step through a debugger you will be fine.

Introduction

Cocos2d-JS 3.0 is an html5 framework derived from cocos2d-x. It was recommended to me by a coworker as a JavaScript framework. This will be a tutorial on how to get started with Cocos2d-JS with the most basic type of rendering -- a 9-slice sprite from the very beginning (downloading, installing, configuration and code sample). Proper scaling is crucial to resolution independent and mobile development. Later tutorials will cover event handling, physics and more advanced topics.

Because installation, configuration and setup is often the first major hurdle, much of Part 1 will be spent on creating your environment (stick with it, trust me it pays off) or at least pointing you in the right direction.

As of June 1st, 2014 Cocos2d-JS is still in beta stage so not ready for production. But it is looking very promising and is just a few weeks/months away from production (already been through alpha). Since cocos2d-JS 2.0 was rock solid for years and the team appears dedicated I have no reason to doubt 3.0 will eventually be released production ready.

This tutorial will assume you have an Ubuntu-like system. If you are familiar with unzipping and changing environment variables on Windows, you should also be able to follow along since the code will be compatible.

Advantages of Cocos2d-JS 3.0 (as of June 1st, 2014) or Why Use Cocos2d-JS?

  • HTML5 compatible so mobile friendly with wrappers like Intel Crosswalk (Android) or Ejecta (iOS). Also has JSB (JavaScript bindings) to compile with cocos2d-x to native, though the JSBs lag behind the main trunk for now.
  • JavaScript for fast development (debatable)
  • MIT License

Disadvantages (few, but worth mentioning) or Why Not to Use Cocos2d-JS

  • A little more difficult to use compared to other JavaScript frameworks. This is being resolved by the cocos2d-JS team (they acknowledge this).
  • Cutting edge (as of June 1st, 2014) so not ready for production. Not a big deal since it will be ready eventually.
  • Not too many tutorials or examples (one of the reasons I'm writing this, plus will get solved eventually when the framework is out of beta).
  • JavaScript (for people who hate / can't stand JavaScript)
The goals of this tutorial will be to setup your environment and create reusable sample code for a 9-slice sprite. A 9-slice sprite is a sprite which scales properly on all devices without distorting the image, crucial for mobile friendly games and apps.

Step 1 - Downloading Cocos2d-JS


Download the Cocos2d-JS v3.0 beta. By the time you read this, cocos2d-js may be out of beta.



The setup will ask you a few questions, mainly about Android NDK and SDK locations and ant locations. You should have ANT properly installed and setup; if not, run sudo apt-get install ant and rerun the cocos setup. We will be building for web only, so we will not bother with Android for now.

If you are having trouble setting the environment variables or downloading the prerequisites (Python 2.7.6 32-bit, not Python 3, Ant) see the section SETUP here. Unfortunately installing Python, Ant and so on is outside the scope of this tutorial; however your distro should have these preinstalled. If this is a problem for some people I can write another article about how to install packages in Ubuntu.

Step 2 - Downloading Aptana Studio


Download the Aptana Studio standalone version. Unfortunately Aptana Studio does not support OpenJDK (the default Java installation that comes with Ubuntu) so you will need to switch to Oracle JDK to use it. Switching from Open JDK to Oracle JDK is outside the scope of this tutorial; see this link for a comprehensive tutorial. If you are using Windows, Aptana Studio comes with a prepackaged JDK.

If you don't want to bother with the switch, or you hate Eclipse-style IDEs in general you can use Jetbrains Webstorm. However Jetbrains Webstorm is non-free. However Webstorm has much smarter autocompletion and if you are doing a serious project I would consider buying a license.

Note about Aptana Studio Bug #1: I encountered a bug when using Aptana Studio with Linux Mint (an Ubuntu variant) and found the solution here. It involves the default web browser and Firefox.

Note about Aptana Studio Bug #2: I encountered another bug when using Aptana Studio debugger with Firefox. If you see a window like below when running debug mode, uninstall the Firebug addon in Firefox, uninstall the Aptana Studio addon in Firefox, close all your browser windows and restart debug mode in Aptana Studio. The problem is with Firebug > 1.8.3 not being compatible with Aptana Studio (another reason to shell out the bucks for an IDE like Webstorm if you are doing a serious project, this bug has been around for quite some time).



Step 3 - Creating the Cocos2d-JS Project


Run the following from wherever you create new projects:

You should see the default Cocos2d-JS hello world screen now.



Step 4 - Importing into Aptana Studio

Start Aptana Studio from the folder you installed Aptana Studio in. It will prompt you for a workspace. Create a new folder and select a workspace for Aptana.





Click the "Import Project" button and go to "Existing Folder as New Project". Then pick the folder with the web application.



Step 5 -  Get a 9-slice Sprite

This is the easiest part of the tutorial. Get the 9-slice (9patch in Android) image for free courtesy of dibbus.com




Next, place the image in the res directory of the 01-sprite cocos2d-JS project (assuming btn_red_matte.9.png).




Now, add btn_red_matte.9.png to resource.js as one of the available resources.


Step 6 - Get the required information from the sprite

We require the following information from btn_red_matte.9.png in order to render the 9-slice sprite. Note that in Cocos2d-JS capInsets is a rectangular area, not margins of pixels to avoid scaling as in Cocos2d-x. Don't worry if you don't understand all of it; it makes more sense in Step 7 with the code.
  • Bottom left x coordinate - Cocos2d-JS treats the bottom left corner as the origin point. We will pick a portion of the image to render. The image is larger than we need, since it comes from Android and Android uses the Draw 9-patch tool to create 9-slice sprites. We do not need the black marks or the margin because Cocos2d-JS will use capInsets to define the scalable area instead (explained below). Therefore, the portion should be the red area of the image and only the red area. You will create a rectangle with the bottom left x, bottom left y, width and height then pass it in as the second parameter to the cc.Scale9Sprite constructor. 
  • Bottom left y coordinate - Same as above
  • Width - Width of rectangular area of image to render
  • Height - Height of rectangular area of image to render
  • capInsets - The capInsets are a little different than in Cocos2d-x. In iOS and Cocos2d-x you would define the capInsets as the number of pixels of top, left, bottom and right of the selected area in that order to ignore scaling. In Cocos2d-JS the "capInsets" parameter is actually an instance of cc.rect which is the stretchable area within the sprite. The green area below is the "capInsets" parameter for Cocos2d-JS. You will create this rectangle and pass it in as the third parameter to the cc.Scale9Sprite constructor.




Using GIMP, we discover that the bottom left x-coordinate of the sprite we want is 2,2 and it is 44 pixels wide and 47 pixels high. Note that GIMP doesn't treat the bottom left as (0,0) like Cocos2d-JS does so you'll have to do some simple math.

As well, using GIMP we discover that the inner green rectangle (the area we want to allow to scale) has its origin at (8,7) and is 32 pixels wide and 36 pixels high.

Step 7 - Code


At long last, the code.

First, modify the project.json file to add the "extensions" module to the cocos2d-JS boot loader. cc.Scale9Sprite is an extension.


Open up app.js and delete all the text in the file. We will code from scratch.

Fill up app.js with the following (explanation below the code):
Lines 1 to 7 should be self-explanatory. HelloWorldScene is called by main.js by the boot loader. This is unmodified from the default HelloWorld application when you first create a Cocos2d-JS project. The scene is created, which is basically a container for layers. Then the layer is created, defined below.

Lines 11 to 34 are the object properties.

Line 39 to 42 is the constructor. It calls the init() function to initialize the layer.

Lines 48 and 49 set a couple instance variables of the layer (the width and height, which we will use to scale.)

Line 50 schedules a update every frame. The update function (ticker) will be called each frame. Usually the update function will have a delta time parameter (dt) to model physics. However in this tutorial we will simply use the update function once, to draw three sprites scaled without distortion.

Line 58 creates conditions to draw the buttons. We only want to draw the buttons once (since they don't move) and check whether the buttons have been created previously. If they haven't we enter the block.

Lines 60 to 62 create the buttons. Down at lines 90 to 94 you see the create button function. For simplicity sake we have hardcoded the dimensions of the delimitation zone (area of the .png file to render) and the capInsets (area of the sprite to allow to scale). Note that the Cocos2d-JS definition of capInset is different than the Cocos2d-x definition or indeed the iOS definition.

Lines 65, 68 and 71 draw the buttons on the screen. This is done using three functions, drawButton, getWidthPercent and getHeightPercent on lines 79, 97 and 101.

For the getWidthPercent and getHeightPercent functions, it is a simple calculation of number of pixels for a given percentage. If 20 is passed to the function, it calculates 20 percent of the pixels available on the width/height of the screen and returns it. If 50 is passed to the function, it calculates 50 percent of the pixels available on the width/height of the screen and returns it.

At line 80 the drawButton function first sets the anchor point to (0,0). An anchor point is the
 "origin" point in the sprite's internal coordinate system where all the transformations are applied. It is also where the sprite's position (its x and y coordinate) is centered.  The anchor point is by default (0.5,0.5). We want it at the bottom left of the sprite, (0,0), so that when the sprite is scaled up it is scaled to the right and upwards, not below and to the left.

At line 81 we use the setContentSize function to scale the image up and down without distortion. Note that using the setScaleX and setScaleY functions will distort the sprite, ruining the whole point of a 9-slice sprite. By using setContentSize we make sure the edges are not scaled upwards and only the center of the button is scaled.

At line 82 and line 83 we set the x and y position. Since we set the anchor point at line 80 to the bottom left of the sprite, the x and y position is fixed regardless of whatever scale we set at line 81 using setContentSize.

Finally at line 84 the button is added as a child to the current layer.

You should get a screen similar to the following





Note that the corners and edges are not distorted in any way. You can now create buttons and sprites without distortion of any size with a relative percentage of the screen. Congratulations.

The entire project is available here. Note you should do it yourself by reading the above blog post instead of downloading this, since the version of Cocos2d in that zip will be drastically outdated by the time you've read this.

The next tutorial will deal with basic physics and collision detection.

Monday, April 21, 2014

Libgdx Internal Files Directory Listing

Hi,

Found a little tidbit of information others might find useful specific to the Libgdx framework. When iterating through files and trying to list all files in a directory, the result will always be an empty list when using Internal file type.

See http://bitiotic.com/blog/2012/05/15/libgdx-internal-files-hacks/ for more details.


Thursday, March 20, 2014

Java InstanceOf Alternative with Enum

Hello,

Everyone deals with the instanceof problem in their Java (or is in C#) career. Instanceof isn't just considered wrong by most authors and programmers, but is aesthetically unpleasant.

So many programmers move to design patterns and the Visitor or Composite pattern. While perfectly valid solutions, there is another obvious solution not to be overlooked, particularly when polymorphism fails.

For the Libgdx game framework, I wanted to create a traditional observer - observable class hierarchy independent of the Libgdx framework. For example, for each type of event (a key pressed, the screen touched) I wanted a workflow to create that event, assign observers to it and be done with it.




These events descend from an AbstractEvent object which itself is a subclass of observable. They will be populated by an InputProcessor and GestureListener with the appropriate properties (if you haven't used Libgdx and want to make cross platform Java games I definitely recommend it).

When the Libgdx framework detects an event, it calls an object with the InputProcessor or GestureListener interface to handle the events. However, since I'm creating a class hierarchy outside Libgdx, I needed a way to populate these InputXXXX and GestureXXXX objects dynamically at runtime. For example, if the user pressed the screen, I wanted an object of InputTouchDown populated by Libgdx.

This InputTouchDown will already have been created and have its observers assigned. The issue however is I don't add InputTouchDown instances to the queue. I add AbstractEvent objects to the queue with a method signature like this :

public InputProcessor add(AbstractInput input) {  

So, how exactly does the add method know what is being added? The add method needs to know what is being added because each input event has different properties. For example, some events have x and y coordinates, some have counts, some have buttons. The add method then adds the AbstractInput to the appropriate instance variable (for example, an InputKeyUp instance) so that when an event happens the correct methods are called at runtime by Libgdx to populate it.



As you can see the problem is how to set the inputTouchDown when an AbstractInput is passed to the add method without resorting to instanceof? And even worse (though I don't have to deal with it in the Libgdx framework) how would I know when to call touchDown?

I could either push all the properties of the children into the parent (and pollute the class hierarchy) or find a way to deal with it.  The obvious solution was Visitor or Composite pattern. However, Visitor pattern seemed inadequate. Not only was it a limited number of visits (once every user initiated action) but it is a large number of events. The composite pattern made even less sense, because events are not "composed" of other events.

 


The answer was an enum. Here is the process.

1. Create a final variable in the superclass of the enum's type

2. Create a constructor in the superclass which requires the enum type as a parameter.



Now in the inherited classes, you do not need to put the enum in your constructors. Simply call super with the appropriate enum type within the constructor (do not expose this implementation).



Now a concrete instance variable assigned to an AbstractXXXX instance variable can always determine its correct type without instanceof, perhaps for casting or other runtime operations.

If you find that there are a limited number of subclasses possible for your class hierarchy (usually because you do not control the class hierarchy such as when building adapters for a third party framework), and you dislike the bloat of Visitor or the Composite pattern doesn't make sense, consider using this enum method. It probably violates every principle of object oriented design, but it keeps the codebase simple to debug and intuitive. You will still have the switch statement using getInputType but with aesthetically pleasing enums instead of instanceof calls.

Comments welcome below.