Archive

Posts Tagged ‘Corona SDK’

Using Corona SDK with REST API Services

April 15th, 2012 16 comments

People frequently ask on the Corona SDK forums about how to make their mobile apps connect with some Internet web service or if it’s even possible.  Corona SDK has various ways of interacting with Internet based services and depending on the service, you might want to use one over the other.

The three main ways that Corona SDK can communicate is broken down into three main categories:

  1. Socket communications.
  2. Synchronous Web Services.
  3. Asynchronous Web Services. 

Sockets are great for passing instantaneous data, like a multi-player game where what one player does on their device shows up almost immediately on their opponents computer.  Things like FTP and such would also tend to use sockets.  This is pretty low level programming and most people don’t want to get to that level.

This leaves us with Web based services.  In both cases, some webserver somewhere has a published API (Application Programming Interface) that defines how applications can interact with their services.    These API’s involve making a request to the server and then waiting for some response.

That waiting for a response can take time, so Corona SDK has two methods of waiting on the data:  Synchronous which means “Stop the app and wait until the data is done downloading” or Asynchronous which is “Hey, I need this data.. Let me know when it’s done and I’ll deal with it”.

In mobile apps, stopping and waiting on data, in particular if you’re downloading a large file like a photo, means your user can’t do anything else.  You generally don’t want to have your app “block” while waiting on data.  So we are going to focus on option 3 because it’s the simplest and easiest to work with.

Services will generally fall into three categories:  SOAP, REST and what I like to think:  Roll your own.  SOAP  or Simple Object Access Protocol is generally XML based and has overhead to start communications, maintain sessions and is generally not a simple approach despite the word “Simple” in it’s name.

REST or “Representational state transfer” on the other hand is generally easier to work with and can return data in the user’s choice of XML, JSON or other defined formats.

This tutorial is going to focus on a “Roll our own – based on REST” because, like SOAP, there is a lot to the server side of REST and frankly we don’t need that.  We just want to make a request and process the data and you don’t want to deal with the complexity of setting up a full REST service on your host. 

Before we get to the code here is what we are going to do.

On the server side, we are going to write a simple PHP based script to access a MySQL database to login a user to your server.  This script does nothing to create the user account nor are we going to go into setting up the database.

We are going to use HTTP GET requests to communicate with the server.  Sure in theory GET should be for getting things and POST for putting things, but in reality, GET is simpler and if your total data is less than 8Kbytes.

We are going to also use JSON to encode and decode our data so that it’s safe to transmit using HTTP requests.  This is  term called serialization.   We don’t need to know JSON.  We are going to let our PHP and Corona SDK libraries do the work for us.

So without further ado lets jump into some code.

SERVER SIDE

On the server side, we need some program that will process the HTTP GET request, contact a database, and then return some result to the application.  My language of choice is PHP for this and we are going to use a MySQL database.  This is probably the most common setup that almost every Web Hosting service offers to its customers.  You’re responsible for setting up your database, getting your database DSN (Data Set Name) or database name, the server name of the database (typically just the string “localhost”), and a Username/Password pair that lets your PHP script talk to your database.

You will need to setup a database with the following fields:

  • id — a integer (number) field, typically the Primary Index with an AUTOINCREMENT attribute.  Basically it’s a unique number for each user.
  • playername — you might want to call this username or userid.  Variable length character string probably 64 bytes long is good (VARCAR(64)).
  • password — another varchar string, 64 bytes long is sufficient.  We are going to use an MD5 hash process to one-way encrypt the passwords in the database, we won’t be using MySQL’s “Password” encryption.
  • Optional First and Last Names, again 64 byte varcar’s will be fine.
  • Last Login.  I’m old school unix guy, so I’m just going to make it an unsigned int and shove the unix time() number in the field.  MySQL offers a bunch of built in dates.  Don’t need them.

With that database setup and some accounts added, we are ready to go.  You probably should have some web page/form setup that lets users register for accounts and a PHP script that takes that form data and adds the users to the database, but that’s beyond the scope of this post.

Lets start by connecting to the database:

 PHP |  copy code |? 
01
02
<?php
03
define("DB_DSN",'yourdbname');
04
define("DB_HOST",'localhost');
05
define("DB_USER",'yourdblogin');
06
define("DB_PASS",'yourdbpass');
07
 
08
// Connecting, selecting database
09
$link = mysql_connect(DB_HOST, DB_USER, DB_PASS) or die('Could not connect: ' . mysql_error());
10
mysql_select_db(DB_DSN) or die('Could not select database');
11
 
12
if(isset($_GET)) {
13
    $playername = base64_decode($_GET["playername"]);
14
    $password = base64_decode($_GET["password"]);
15
    $query = 'SELECT * FROM players WHERE playername="' . mysql_real_escape_string($playername) . '" or email="' . mysql_real_escape_string($loginid) . '"';
16
    $dbresult = mysql_query($query, $link);
17
    if (!$dbresult) {
18
        //echo "query failed";
19
        $result = array();
20
        $result["result"] = 403;
21
        $result["message"] = mysql_error();
22
        echo json_encode($result);
23
        mysql_free_result($dbresult);
24
        exit;
25
    }
26
    $player = mysql_fetch_array($dbresult, MYSQL_ASSOC);
27
    if (strcmp($player["password"],md5($password)) == 0) {
28
        $result = array();
29
        $result["result"] = 200;
30
        $result["message"] = "Success";
31
        $result["playername"] = $player["playername"];
32
        $result["firstname"] = $player["firstname"];
33
        $result["lastname"] = $player["lastname"]; 
34
        $query = sprintf("UPDATE players SET lastlogin=NOW() WHERE id=%s;", $player["id"]);
35
        $uresult = mysql_query($query, $link);
36
        if ($uresult) {
37
            //code if your update failed.  Doesn't really impact what we are doing. so do nothing.
38
        }
39
        echo json_encode($result);
40
    } else {
41
        //echo "password mismatch";
42
        $result = array();
43
        $result["result"] = 403;
44
        $result["message"] = "Forbidden";
45
        echo json_encode($result);
46
    }
47
} else {
48
    $result = array();
49
    $result["result"] = 400;
50
    $result["message"] = "Bad Request";
51
    echo json_encode($result);
52
}
53
exit;
54

This script defines our database parameters for accessing the database. Then it checks to see if the special PHP Array (or Table in Lua terms) called $_GET exists. If this script was executed as an HTTP GET request will will exist and each table entry contains each parameter passed to it.

Let’s look at what an HTTP GET request looks like. It’s basically a URL with some parameters tacked on to the end, such as:

So we have our server name and URL to run login.php. Then there is a question mark, which start’s a list of key-value pair parameters that will be passed. In this case we are passing a parameter named “playername” and it has a value of “my name”. Then an ampersand (&) separates the next key-value pair, in this case a parameter named password with a value of letmein.

You might be asking what is that %20 in the playername value. Well its the encoding for a space character. Your parameters must be “URL Encoded” before you pass them to the server if they have spaces or ther special characters in them. In our example, instead of using the standard urlecode/urldecode method, we are going to use a technique called “base64 encoding” because it produces a web-safe string that also hides the data (so our passwords are not sent in the clear).

Depending on what variables you need to send to the server, these URL strings can get quite long and complex. We are just going to be sending two to the server. These variables will be magically decoded into a PHP Associative Array called $_GET for us.

 PHP |  copy code |? 
1
2
if(isset($_GET)) {
3
    $playername = base64_decode($_GET["playername"]);
4
    $password = base64_decode($_GET["password"]);
5

We first check to make sure the table exists, then we create two PHP variables: playername and password from the $_GET table entries. Note that we are passing that data through PHP’s built in base64_decode() functions to decrypt the data we will be sending.

 PHP |  copy code |? 
01
02
    $query = 'SELECT * FROM players WHERE playername="' . mysql_real_escape_string($playername) . '" or email="' . mysql_real_escape_string($loginid) . '"';
03
    $dbresult = mysql_query($query, $link);
04
    if (!$dbresult) {
05
        //echo "query failed";
06
        $result = array();
07
        $result["result"] = 403;
08
        $result["message"] = mysql_error();
09
        echo json_encode($result);
10
        mysql_free_result($dbresult);
11
        exit;
12
    }
13

This block of code will query the database for the player’s record that matches that playername/password combination. Notice that we are calling a function “mysql_real_escape_string” on any string we send to the database. This is to protect against SQL Injection attacks where people send in SQL strings in an attempt to hack your database. Always escape any string sent to your database. User data cannot be trusted… Period…

If the query fails, we create a table called result, and add in some values to send back to your mobile app. The “echo json_encode()” will cause the table to be encoded into JSON magically for us and then the string is written out to the app.

This basic technique is how we are going to communicate with our app.

In the rest of the code, if the database query was successful, put the data from the query into a PHP table for us to use. Check to see if the password in the database matches ours (we are using md5() so we have to compare the database password with the results of md5(our password).

If that’s all good, build up a table called $result. Put whatever variables you want in the table. Then echo json_encode($result) the table and now your app should have data to use. If the passwords don’t match, send some result back to the app so it will know about the failure.

APP SIDE

We are going to use the Corona SDK network.request API call.

Using GET is pretty simple:

 Lua |  copy code |? 
01
02
local mime = require("mime")
03
local json = require("json")
04
 
05
local playerName = "fflintstone"
06
local password = "I<3Wilma!"
07
local URL = "http://yourserver.com/login.php?playername=" ..
08
      mime.b64(playerName) .. "&password=" .. mime.b64(password)
09
network.request( URL, "GET", loginCallback ) 
10

At this point, we’ve required in two modules we need, mime and json. For our example I’ve hard coded the player name and password into Lua variables.

Construct the URL which is a simple URL GET string and then pass that to network.request.

Since we are doing this asynchronous, your app will continue on doing whatever it was doing. Mean while it will wait until the server responds. When it does a function that you write called “loginCallback” that will then handle the result.

 Lua |  copy code |? 
01
02
    local function loginCallback(event)
03
        if ( event.isError ) then
04
            print( "Network error!")
05
        else
06
            print ( "RESPONSE: " .. event.response )
07
            local data = json.decode(event.response)
08
            -- do with data what you want...
09
        end
10
        return true
11
    end
12

At this point the Lua table “data” should contain entries for “result”, “message”, “playername”, “firstname” and “lastname” that we had set in the PHP script.

You could simply check:

 Lua |  copy code |? 
1
2
if data.result == "200" then
3
   -- player logged in okay
4
   print("Welcome back", data.firstname)
5
else
6
   -- prompt them to login again
7
end
8

At this point you know you’re logged in. It’s up to you to decide what data you need to pass and how to use it within your app.

Most REST services work this way. You make requests… you get back JSON or XML data. You will need to make sense out of the API documents of the service that you are using. Some will be easier to digest than others. For instance, PARSE seems to be pretty straight forward. Amazon’s SimpleDB made me ill trying to decode their API documents. But this is the basics. Have at it!

If you would like a complete Lua example, please check out the Corona Geek’s implementation at: https://github.com/CoronaGeek/Corona-SDK-JSON-Example

Kindle Fire — A hands on review

March 31st, 2012 1 comment

I have been building mobile apps for over a year now and I’ve recently started building for Android as well as for Apple iOS. Android provides some interesting challenges since there are three major markets to sell your app: Google Play, Amazon.com and Barnes & Noble’s Nook Color/Tablet app store.

In addition to three markets with different rules, you have a host of devices you have to target. It makes programming for these devices an interesting exercise for sure.

Before any app developer releases apps or games to the wild they should test their apps on a device. No one could possibly own all the billion’s of different Android devices to test on. Given that the Android market’s are not known for generating a lot of sales income, most of have to be picky on which devices to get and test on.

For me, I was considering a refurbished Nook Color for $135. But this device has some hoops to jump through to get test apps on it. I considered some of the cheap 7″ Android tablets which can be found for under $80, but you never know if the processor is fast enough to provide a good test platform. Since I use Corona SDK, an armv7 processor is required. Used smartphones can either be too expensive or hard to find at a price cheap enough for a test device. Then there is the Kindle Fire, a $199 7″ tablet.

As one of the more expensive test platforms, I had really had a hard time pulling the trigger on this. I want to get an iPad and I felt that any 7″ tablet was going to reduce my need for the iPad. But when Amazon put refurbished Kindle Fire’s on sale this week for $139, it was time to hop on it. Priced at the same price point as the Nook refurbs and cheaper than I could get a used on on Craigslist, this seemed to be a no-brainer decision. I opted for 2 day delivery and was surprised when it arrived the next day. Excited to mess with it, I popped it open right away and dove in.

The box came with the Fire in a plastic sleeve and a power charger. No USB cable. No manuals. No fluff. I searched around to find the power button, which is located on the bottom of the device beside the USB charger point and the headphone jack. It powered up about the same speed it takes my iPhone 4 to power up and it was about 85% charged.

There are a billion reviews about this device on the Internet, so I’m going to try and say focused on using at a development platform for Corona SDK except for one thing.

I now understand why Apple says there will be no 7″ tablet. This is an awkward size. It’s just a little too big to hold like a phone in one hand, but its too small to be used 2 handed. Also when using it one handed, I tend to hit the power button too often. It’s a lot heaver that I thought it would be too.

On to using it as an app development platform for Android apps, in particular with Corona SDK.

You need to be able to install apps from your webserver unless you want to tether. The Fire by default is set to only allow you to install from Amazon. In the settings, there is an on-off switch you can toggle that will allow you to download from any source.

I already had an Android .apk file loaded to my webserver, so I bopped the Fire’s browser to the URL where the .apk file lived, it downloaded the file and then let me install it with ease. I was quite happy with the process. Right until I launched the App. It started up but immediately gave me an message that I needed to build specifically for Amazon/Kindle Fire. This appears to be a Corona SDK generated message.

The Fire has restricted hardware and by default Android apps are built with access to the telephone, which for Fire apps isn’t available, so Ansca is probably trying to protect us, but this shows the limits for using the Fire with its restricted hardware from being a good generic Android test platform.

Since I only have one app out, that requires hardware the Fire doesn’t offer, this really isn’t that big of an issue, I just have to build versions specifically for the Fire. I produced .apk’s for several of my apps and have installed them.

Here’s the lowdown…

Omniblaster, my first app: This runs like a dog on the Fire. The player’s ship moves based on the accelerometer. The ship moves smoothly on iOS devices, but on the fire, there were very noticeable pauses as you tilt the device to move.

Turkeys Revenge which is live in the Amazon store played pretty well. Not real complaints but one, which I’ll get to in a minute.

An un-released photo gallery app: Had all kinds of problems. This is a storyboard based app, so I’m fighting the “fixed” delays. There were noticeable pauses during scene transitions. When I used my zoom function to load a larger version of the photo into a scroll view, I couldn’t close the screen with a double tap. This same code worked flawlessly on my iPhone 4 and in the Corona simulator.

Regardless of which app, custom fonts just flat out don’t work. I can’t with 100% certainty say I know how to do custom fonts with Android, but from my testers, the fonts appear to work on Android phones. I wrote a simple test App that just prints out the name of the available fonts, which should show any TrueType fonts in the resource bundle along with installed fonts and my custom fonts just simply are not in the list. This is a huge turn off for the Kindle Fire as a test environment, though it’s important to know about the problem since how I know about this Fire behavior.

In conclusion, as a consumer of the device, if I was just interested in watching video or some casual web surfing or reading books and I’m an “Amazon” person, the Fire would be worth the $199. It is not a great replacement for a general tablet and it’s not that great as a Corona SDK test environment since there are clearly differences between what a general Android device will see and what the Fire will see. If you were one of the lucky ones to snag a refub then it’s probably a fair price to pay to see what your apps are going to be like to the Amazon customers.

Collision detection without physics.

December 14th, 2011 10 comments

A frequent question that comes up in the Corona SDK forums is how to detect when two images on a screen hit each other. This is known as a “Collision”. The ability to determine when two things have bumped into each other is called “Collision Detection”.

Within Corona SDK, being that its an event driven system, we like the idea that we can have the system tell us when things hit each other and we just have to write the code to handle the interaction of the two. This is a cool concept and it works, but . . .

It requires using the Physics engine to do so.

Corona SDK uses a wonderful 2D Box model for physics and that model supports this event driven model and it works well. But if you’re game does not need physics and many apps don’t, like a card game where you move a card to a stack, its kind of silly and wasteful to include the overhead of the physics engine. You don’t need all of those angular momentum floating point mathematics going on in your game.

So how do I detect collisions? I don’t see any API calls to do that?

We really can’t use an event driven model like the physics engine, but there is a very simple method (well there are two) that use other features of Corona SDK, in particular using an “enterFrame” event on the Runtime listener.

Basically we have to write the code that the physics engine is doing for us and it’s not all that complex.

In my personal model, I typically have a table/array of all of my on screen objects and then I have my player’s avatar object.

 Lua |  copy code |? 
1
2
local objects = {}
3
for i=1, 20, do
4
    objects[i] = spawnEnemy() -- spawnEnemy creates on display objects and returns it.
5
end
6
 
7
local player = display.newImageRect("avatar.png", 64, 64) -- create me.
8

At this point we have a table of enemies in the “objects” table and my player object.

For the Runtime enterFrame event, you need a function to process the collision detection.

 Lua |  copy code |? 
01
02
local function testCollisions()
03
    for i=1, #objects do
04
         if hasCollided(objects[i], player) then
05
             -- do what you need to do if they hit each other
06
         end
07
    end
08
end
09
 
10
Runtime:addEventListener("enterFrame", testCollisions)
11

So we simply iterate over the list of objects and see if any have hit the player object using a function called hasCollided.

This is a function that you also have to write.

There are two main methods for doing this, one is based on rectangles overlapping each other. The other involves circle testing.

 Lua |  copy code |? 
01
02
-- rectangle based
03
local function hasCollided(obj1, obj2)
04
    if obj1 == nil then
05
        return false
06
    end
07
    if obj2 == nil then
08
        return false
09
    end
10
    local left = obj1.contentBounds.xMin <= obj2.contentBounds.xMin and obj1.contentBounds.xMax >= obj2.contentBounds.xMin
11
    local right = obj1.contentBounds.xMin >= obj2.contentBounds.xMin and obj1.contentBounds.xMin <= obj2.contentBounds.xMax
12
    local up = obj1.contentBounds.yMin <= obj2.contentBounds.yMin and obj1.contentBounds.yMax >= obj2.contentBounds.yMin
13
    local down = obj1.contentBounds.yMin >= obj2.contentBounds.yMin and obj1.contentBounds.yMin <= obj2.contentBounds.yMax
14
    return (left or right) and (up or down)
15
end
16
 
17
-- circle based
18
local function hasCollidedCircle(obj1, obj2)
19
    if obj1 == nil then
20
        return false
21
    end
22
    if obj2 == nil then
23
        return false
24
    end
25
    local sqrt = math.sqrt
26
 
27
    local dx =  obj1.x - obj2.x;
28
    local dy =  obj1.y - obj2.y;
29
 
30
    local distance = sqrt(dx*dx + dy*dy);
31
    local objectSize = (obj2.contentWidth/2) + (obj1.contentWidth/2)
32
    if distance < objectSize then
33
        return true
34
    end
35
    return false
36
end
37

Depending on the shape of your player and objects, you may find that circles work better or rectangles work better. In my game Omniblaster I used both methods depending on the objects. My space ship has rounded shields and my rocks were basically round, and my enemies were basically round, so using the hasCollidedCircle made more sense to use.

When I say rounded, the images have transparency that when using rectangles would cause the objects to hit before they looked like it.

Yet, when I fired my phasers or torpedoes, those graphics fit nicely into rectangles, so using the rectangle hasCollided method was a better choice.

One gotcha that you need to be aware of is that if your processing takes too long, (longer than 1/30th of a second or 1/60th depending on frame rate) then your collision detection will fire again before you finish, so I usually change my collision handler to something like this:

 Lua |  copy code |? 
01
02
local isCheckingCollisions = false
03
local function testCollisions
04
    if isCheckingCollisions then 
05
        return true 
06
    end
07
    isCheckingCollisions = true
08
    for i=1, #objects do
09
         if hasCollided(objects[i], player) then
10
             -- do what you need to do if they hit each other
11
         end
12
    end
13
    isCheckingCollisions = false
14
    return true
15
end
16

This should be a lighter weight collision detection system than the overhead of the physics engine. Though you don’t get filters, being able to define polygon shapes unless you roll you’re own!

Happy coding!

Implementing a Game Center button in your Corona SDK Game.

June 13th, 2011 8 comments

I’ve been trying to figure out how to do a Game Center button for my game and be able to link to the Game Center leaderboards and achievements directly from my Corona SDK based game.

I had not found much information on the Internet on how to do this. Most examples were involving Objective C using Xcode and adding the Game Center framework to the game, then calling relevant methods from the framework.

I basically gave up on the idea about connecting directly to the leaderboards and decided to just try and launch the Game Center app from my game.

Here is the code I used (mostly lifted from Jayant C Varma’s “rating.lua” file found on the Corona SDK site):

And much to my surprise, it works like a charm. Now to track down those pesky specific URL’s…. I should note, this is a new addition to my game and it has not been submitted to Apple yet. No warranties expressed or implied.

Implementing a Health Status Bar in Corona SDK

May 30th, 2011 4 comments

Implementing a Health Status Bar in Corona SDK

Many games need a way to show the players how well they are doing. It could be a simple counter to show the number of lives left or a bar that decreases and increases as a players energy goes up and down.

There are as many different ways to do this as there are games but lets look at a couple of different ways.

The simplest may be simply using text to display the health status:

Then later in your code when a player looses a life (or gains one back) simply change the text value of “livesValue” and Corona will magically update the value for you:

Of course you might want to drop a graphic behind the text, set the colors accordingly, and possibly drop a duplicate text string underneath offset by a pixel to give a little stroke/shadow to the text.

But our players expect more from games and a simple text display won’t be accepted as high quality. Traditional arcade games have shown your lives as small versions of your player’s graphic. If your game involves a ship, perhaps you see a display of 5 little ships to show your life count.

With a display of say 5 small rockets, you will need one image and you will replicate it several times.

This will create a display of 5 little icons that shows your full life status. Later in your code when you need to change the display:

Later when you need to give a life back:

But what if you want more of a bar-graph display. As long as you’re using discrete values, you can continue to use a similar method using different graphics for each value, in this example, there are 5 lives, so you can create 5 different graphics for each of the 5 life states.


Instead of using a loop to load in the same graphic, you would need to load in each of the separate five graphics in and position them all at the same location:

Then to change the graphic:

This same concept can be done with MovieClips.

Then to show the current health level:
[/crayon]
lives = lives – 1
if lives < 0 then
lives = 0
end
if lives == 0 then
healthSprites:play{startGrame=6, endFrame=6, loop=1, remove=false}
else
healthSprites:play{startFrame=1, endFrame=lives, loop=1, remove=false}
end
[/crayon]
This gives you the benefit of a little animation as well. Unlike the example above, we load in the “No life left” graphic in frame 6, because movieclip starts at frame 1. We could have put frame 0 first, and just done a “lives + 1″ to get the right offset.

Hope this is helpful!