My Unreleased CoronaSDK Plugin

I have 8 games created with CoronaSDK, some going back to 2012. I do revisit them from time to time to add features, fix bugs, and update libraries that I used. For the latter, I have used and purchased several libraries, and I have created a few as well. If I feel that there is a market for them, I release them as Plugins on the Corona Marketplace.

Over the years, I have developed and integrated GBC Data Cabinet, GBC Language Cabinet, and GBC Object Pool into my own projects.

  • GBC Data Cabinet manages your data. You can create storage “cabinets” to read, write, and save data for later use. This eliminates the need for global variables, and makes management of data between scenes much easier. And… it’s FREE.
  • GBC Language Cabinet manages translation within your game or app. You create the text for each language you want to support, and GBC Language Cabinet will handle grabbing the correct text, including the inclusion of any variable data. And… it’s also FREE.
  • GBC Object Pool manages your game objects so they can be reused. Instead of creating and destroying objects repeatedly (bullets or enemies, for example), GBC Object Pool creates game objects and manages them throughout the lifetime of your game. Performance using object pooling via this Plugin is noticeable. It’s not free, but it is a reasonable (I think) $5.00 USD.

I have one (well, actually two; more on that later) plugin that I have not released, GBC Text, which is a bitmapped-text manager.

GBC Text – The Highs

GBC Text started out as a replacement for a once-popular, but no longer sold/support text library that I purchased back in the 2012 time frame. I wanted similar features, since Corona’s text library is very basic, so I decided to write a library. The results are demonstrated in this Proof-Of-Concept video.

As of now, the library can do the following:

  • Allows you to load and use multiple bit-mapped fonts.
  • Displays the fonts in various sizes.
  • Left/right/center alignment.
  • Sets anchors.
  • Flows text.
  • Can change text dynamically, without the need to destroy/recreate.
  • Allows you to animate text as a whole or as individual letters.

I put a lot of time into engineering and developing this library, especially the last 2 features in the list above, and I feel the results are great. I have begun integrating this into all my current games, and will add additional features as needed.

GBC Text – The Lows

After reading thread after thread on the limitations of Corona’s text system, I felt that a plugin like this, at a reasonable price, would be greatly welcome. I posted a message on the Corona Forums showing the proof-of-concept and asked for feedback. I was surprised that there were close to 200 views, but only 2 replies. A bit discouraging, no doubt.

Reason for Not Releasing

This is eerily similar to my experience releasing GBC Object Pool… there was a lot of talk about performance in creating/destroying objects repeatably, and I wanted to develop a method to manage objects easily within Corona. I spent a great deal of time on the library to enhance performance, remove bugs, document, and prepare for Marketplace. The development and engineering, as well as ongoing support, requires time, effort, and money, so I decided to release it for five bucks. Sales in the two years since release are dismal (maybe this plugin is a solution to a problem that does not exist), and I do not want to go through this again with another plugin.

I had high hopes for GBC Text, but based on the lack of responses in the forums, and on Twitter, I am no longer sure if people would pay for an enhanced text library, so for now, this library will remain an internal library for my own use.

“Free” you say? “Open Source” you say? Maybe at some point, but not now.

Oh, My Second Unreleased Plugin?

I also developed another library I have been using for years. It is sort of a game center library to manage the iOS Game Center, Google Play, and Amazon GameCircle (when it was active) plugins. I also spent a lot of time on this library, since Apple and Google enhance their SDKs quite a bit, and each platform has their quirks on how they handle leaderboards and trophies. I also want to add PC and Mac support at some point. I am not sure about releasing this plugin either, since this library requires a lot of maintenance when Game Center and/or Google Play changes something on their end.

My CoronaSDK Text Manager Proof of Concept

I have been developing a text manager library for use with CoronaSDK. Below is a Proof of Concept video that shows what it can currently do. I am planning on using this library in all my existing (and new) projects.

I am considering releasing it as a plugin in the Corona Marketplace, but I am not sure at this time. I guess it depends on whether there is a demand for this.

[divider]

From Unity To Corona

In 2018 I released a mobile app named Tappy Easter. In 2019 I released an update. Well, not really an update, more of a complete rewrite. Version 1.0 of Tappy Easter was written in C# using Unity. Version 2.0 is written in Lua using CoronaSDK.

This article will document my experience writing the same app using two different languages in two different game engines, and will cover the great and not-so-great of each.

Background

I have been using CoronaSDK since 2012 and have written several apps currently on the iOS and Android play stores. Some time in 2016 I picked up Unity since I wanted to try my hand at a 3D game. I spent a lot of time learning Unity, developing games for game jams, but I wanted to release something to the app store. Even though it was a 2D game, I decided to create Tappy Easter using Unity as a good test case.

Design

The game’s layout is fairly simple: a title screen, a level select screen, and the game screen, and some additional pop-ups and menus to move between the game scenes.

The game scene consists of a series of Easter baskets that are tapped to move a colored egg. The controls are quite standard and very simple from a development perspective.

The level select screen is a bit more complex… it consists of 20 level buttons on two panels. The user can scroll between two panels and can only select levels that have been unlocked. In this scene, the 20 level buttons are built using either a locked or unlocked graphic and if the level is unlocked and previously played, the number of stars that were awarded are also displayed.

Unity Development

Development took approximately four months, and it went very well. The Unity interface makes it easy to lay out your game screens, and I like using C#. Unity UI development is awesome, and the text features of TextMesh Pro give the game extra polish.

In addition to some assets I previously purchased, I also decided to purchase a couple of assets to make development a bit easier for this game. The code I wrote for swiping and tapping screen items was not really working as well as I wanted, so I purchased an asset to handle the mobile gestures. I also purchased an asset to simplify other features found in mobile games such as game services, advertisements, and rating systems. Since these features are platform dependent, using an asset to mange this was a no-brainer.

Development was a breeze… no issues with coding or screen design. It was now time to test on my devices and upload to the app stores.

Time To Compile v1.0

It felt like I spent more time getting the app to compile than I did to develop it, and this was becoming more and more frustrating.

You would think that adding Google Play and Admob would be easy since they are both Google products, but this was an exercise I never want to go through again. These libraries seem to be incompatible with each other since each library includes older versions of files that the other library needs. This caused so many incompatibility issues. After several weeks of research into the issue, it seems trial and error is the only way to get this resolved. Finally, I could get the app to compile and run under Android, but I am not 100% sure how I did it or whether I can do it again.

Now on to the iOS version. I imported the Xcode project generated by Unity which resulted in several hundred “warning” messages and some errors. Reading through tons of support messages, it appears that 200+ warnings can be ignored, but I don’t feel ignoring that many warnings is a great solution. Admob errors were also fussy, and again, I am not sure how I overcame the errors, but I got to a point where it compiled and ads were being displayed.

After more days than I can remember, I now have a working Android and iOS build, so time to put them on the app store!

Working On The Update

A few weeks later, I wanted to tweak a few things and put out an update which seemed a bit more difficult than expected.

I updated all my plugins, including Admob and Google Play (I had to due to some required Google changes), and again there were errors caused by file incompatibilities. This time, no matter what I did, I could not get these 2 plugins to play nice together.

What I also found interesting with the iOS build is that the file size of the v1.0 build was 120mb! Looking at the Unity logs, a lot of unused files and asset demo folders were included during the build, and I could not understand why. Reading through some forum messagess (since my question on the forum went unanswered), it appears that iOS builds do not really exclude everything that is not needed.

At this point, I decided not to update the app, and let it ride in its current behemoth state. Early in 2019 I decided to revisit the update and had the same issues. The frustration level was off the charts, and I convinced myself it would be easier just to start again using Corona… which is exactly what I did.

Corona Time

My previous experience with Corona, and utilizing the sound and image assets created for the Unity version, allowed me to put an improved version of Tappy Easter on the iOS and Android app stores in under 1 month.

Corona is somewhat of an underrated 2D engine, but it is robust and established, and this made development quite easy. There is a lot of things that Corona does that require a bit of work in Unity:

  • I did not have to manage aspect ratios and screen sizes. Just place your images where you want them, and Corona will handle it appropriately, no matter what display.
  • Admob and Google Play actually work without hours of tweaking. Include the plug-ins and start coding.
  • XCode not required!!! Just choose File -> Build and Corona will compile an app to an IPA file without needing a Doctorate in Xcode, and will create an Android APK file without needing to install all the Android libraries.

In order to have really nice fonts in Corona, I had to create images of text. Since this app is English only (at this time), that’s not an issue, but I would have to create text image files for every language I want to support.

As a result, I am currently working on a Corona plugin that will manage fancy text and I am encouraged by my results so far. My free plugin (GBC Language Cabinet) simplifies the management of language support, so utilizing this library with a text library should provide a great solution to multi-language fancy text.

My Unity vs Corona Experience
 UnityCorona
Development Time4 months1 month
File SizeiOS - 120mb
Android - 33mb
iOS - 11mb
Android - 10mb
Additional AssetsFingers Touch Gestures
EasyMobile Pro
none
StrengthsVisual Editor
Text features
3D
"One Button" build
WeaknessesXCode frustrationNo visual editor... images must be coded to screen
Text features
Conclusion

I love working with both Unity and Corona, and it seems that each tool has its strengths and weaknesses. No one tool can do it all.

For 2D mobile development, Corona (to me) is the better choice… it’s a great way to release a game quickly and easily. Tappy Easter is one of those games where Corona was the perfect choice.

For desktop, 3D, or perhaps more complex mobile games, I would consider using Unity. There are some really complex games written with Corona, as well as some desktop games, so the Corona platform would still be a consideration when evaluating my game requirements.

I do wish Unity could build mobile apps more simply, like Corona does.
Building a desktop app with Unity is so simple, so it should be possible to improve building for mobile. Building the app seems more complicated than actually developing it, but maybe I’m just spoiled.

[divider]

Post Mortem – Pumpkin Patch Match (Updated)

Back in 2016, I wrote a Post-Mortem blog on my mobile app Pumpkin Patch Match (actually, I wrote it when I released PPM in 2015, but took several months to publish the article). Since the release of the Windows and Mac version, I decided to update the article a bit, and it follows below.

Background

Pumpkin Patch Match bannerI wanted to create a Halloween themed game along the lines of my past two holiday releases, Tappy Holidays, and Tappy Valentines Day. Tappy Halloween, as it was going to be called, was going to be a simple game with the same game mechanics as the first two games in the series, but I just couldn’t figure out a game that would be interesting.

After a couple of weeks of trashing ideas, it came to me… make a game where you have to match a pattern of jack-o-lanterns. Shortly after, I decided to change the name to Pumpkin Patch Match since it seemed better suited for the game.

Putting It Together

I have been learning Unity throughout the first part of 2015, and I thought that this would be a good “first game”. I got pretty far, and was pretty impressed with it, but what I thought were a couple of limitations prevented me from continuing, so I went back to CoronaSDK for this app.

I put together a CoronaSDK based application in no time and I am very happy with the results. I feel it is one of my better developed apps.

Stuff I Encountered
  • CoronaSDK is great for 2D games. I built Pumpkin Patch Match rather quickly, but I’ve been trying to find a reason to move completely to Unity. I guess both have their strengths and weaknesses. I am close though, since there are a few things that are a bit limiting with Corona.
    • 2016: Looking back, I think I should of continued to use Unity… it would of been a great learning experience.
    • 2018: Looking back again, it may have been more difficult to use Unity. CoronaSDK makes creating iOS apps so easy (it takes the complexity out of XCode). With Unity, integration of Admob on mobile is a bit difficult, and working with XCode for app updates is killing me. If this was a non-mobile game, it would be a no-brainer to use Unity, but I am gload I stuck with CoronaSDK. I found this out when I wrote Tappy Easter using Unity.
  • I decided to try Vungle for monetization… let’s see how this pans out. I hate ad based games, and I’ve been trying unsuccessfully to get out of that, but I don’t seem to have a choice. My games with In-App Purchases, or games I originally released as a pay-to-play (no ads) were unsuccessful.
    • 2016: Still not sure Vungle is the way to go.  It fits well with the game (allowing the player to continue at the same level if he/she watches a video), but I do not see the profits I expected.
    • 2018: I moved from Vungle to AdMob. Easier, less hassle.
  • I am also going to release on the Windows Phone platform. I have no experience there, and have no idea how this will turn out. CoronaSDK recently released a Windows Phone build.
    • 2016: I did release a Windows Phone version, but since Vungle on CoronaSDK on Windows Phone is not supported, I had to go with a $0.99 app, and as I expected, not a single purchase was made.
    • 2018: Windows Phone version is still there, and not being purchased (*sigh*), but a Windows desktop version released!!

For the Windows version, I released it on itch.io for a low price (right now, only $1.00 USD). All ads have been removed. This version makes a great game for toddlers and young children… it’s “Halloween-y” without being scary, is a good way to improve memory, an does not display advertisements. It’s also great for adults who remember and enjoy a certain popular hand held audio matching game as well.

I have some ideas to add features to the game, and may add them as time goes on. Of course, if Pumpkin Patch Match for desktops becomes popular, it would be a great incentive to add these features sooner.

[divider]

GBC Object Pool New Feature – Passing Parameters

The latest update to GBC Object Pool now supports the passing of parameters to your create and return functions! By passing in a table of key/value pairs, you can reduce the amount of create and return functions needed when creating object pools.

Previously, you had to code a separate create function for every pool you created. Seems like a lot of code for creating similar objects.

Check out this example below:

Old Way

local function CreateImagePool1()
    local obj = display.newImageRect("image.png", 50, 50)
    physics.addObject(obj, "dynamic", {
        friction = myParams.friction,
        bounce = myParams.bounce,
    })

    obj.id = myParams.id
    return obj
end

local function CreateImagePool2()
    local obj = display.newImageRect("image.png", 50, 50)
    physics.addObject(obj, "dynamic", {
        friction = myParams.friction,
        bounce = myParams.bounce,
    })

    obj.id = myParams.id
    return obj
end

imagePool_1 = GBCObjectPool.init(CreateImagePool1)

GBCObjectPool.create(imagePool_1 , 10, 0, false, {
    friction = 0.1,
    bounce = 0.1,
    id = "Image Pool 1"
})

imagePool_2 = GBCObjectPool.init(CreateImagePool2)

GBCObjectPool.create(imagePool_2 , 10, 0, false, {
    friction = 0.25,
    bounce = 0.5,
    id = "Image Pool 2"
})

New Way

local function CommonCreateFunction(myParams)
    local obj = display.newImageRect("image.png", 50, 50)

    if myParams ~= nil then
        physics.addObject(obj, "dynamic", {
            friction = myParams.friction,
            bounce = myParams.bounce,
        })

        obj.id = myParams.id
    end

    return obj
end

imagePool_1 = GBCObjectPool.init(CommonCreateFunction)

GBCObjectPool.create(imagePool_1 , 10, 0, false, {
    friction = 0.1,
    bounce = 0.1,
    id = "Image Pool 1"
})

imagePool_2 = GBCObjectPool.init(CommonCreateFunction)

GBCObjectPool.create(imagePool_2 , 10, 0, false, {
    friction = 0.5,
    bounce = 0.25,
    id = "Image Pool 2"
})

In the example above, using the old method, you had to code a new create function for every pool you wanted to use.  This was a lot of code, especially for pooled objects that had very similar, but different, settings. Notice that friction and bounce settings are slightly different.  Same with your return to pool function. It gets worse as you add more pools.

Using the new method, we use a single create function to create multiple image pools, and pass in parameters that are used to modify physics properties for the pool. We also add an id field to each image to show that you can create your own fields to store data in each object.

Another example demonstrates passing in the name of the actual image into the create function:

local function CommonCreateFunction(myParams)
    if myParams ~= nil then
        local obj = display.newImageRect(myParams.image, 50, 50)

        physics.addObject(obj, "dynamic", {
            friction = myParams.friction,
            bounce = myParams.bounce,
        })

        obj.id = myParams.id
    end

    return obj
end

imagePool_1 = GBCObjectPool.init(CommonCreateFunction)

GBCObjectPool.create(imagePool_1 , 10, 0, false, {
    image = "coolimage.png",
    friction = 0.1,
    bounce = 0.1,
    id = "Image Pool 1"
})

imagePool_2 = GBCObjectPool.init(CommonCreateFunction)

GBCObjectPool.create(imagePool_2 , 10, 0, false, {
    image = "anothercoolimage.png",
    friction = 0.5,
    bounce = 0.25,
    id = "Image Pool 2"
})

In the example above, we use a common create function to create an image with physics properties. Passing in the parameters for the actual image to use allows us to have a single, generic create function instead of creating multiple functions to create your pool.

Examples Available

Check out the GBC Object Pool Git for source code and compiled examples.  If you have any questions, I am available in the Corona Forums.

[divider]

GBC Object Pool – Pooling Complex Physics Objects

GBC Object Pool is a CoronaSDK plugin that simplifies the management of Object Pooling. In this article, I describe the method to pool complex physics objects.

A complex physics object consists of several display objects connected together by a physics joint. I recently added another example to the GBC Object Pool sample app that demonstrates how to pool complex physics objects. This article will go through some of the code in that example.

Using the traditional way of object creation, you would need to create multiple objects and joints in order to display a complex physics object. Depending on the complexity of this object, there may be visible performance issues (screen stutter or delay) when creating these types of objects. Utilizing object pooling will reduce or eliminate this delay.

The general solution is to create as many pools that are needed in order to create the object, and then join them via joints after you extract them from the pool. For example, connecting similar items may only require one pool. In the example, though, we connect three circles to a square, so I created two pools… every time we wish to display this type of complex object (when we tap on the screen), we grab one square from the square pool and three circles from the circle pool, and join them together.

squarePool = GBCObjectPool.init(createMainObject, returnMainObject)
GBCObjectPool.create(squarePool, 10, 0, true) 
        
circlePool = GBCObjectPool.init(createSatellite, returnSatellite)
GBCObjectPool.create(circlePool, 100, 0, true)

-- This creates a complex object using multiple pools when the screen is touched.
-- We grab 1 object from the square pool, and 3 objects from the 
-- circle pool.
-- Notice, we then create the proper joints, and event listeners.
-- We also have to save a reference to the joints and the circles so that
-- they can be returned to the pool later.
function onScreenTap(event)
    local Circles = {}
    local Joints = {}
    
    local square = GBCObjectPool.get(squarePool)
    
    for i = 1, 3 do
        Circles[i] = GBCObjectPool.get(circlePool)
    end
    
    square.x = event.x
    square.y = event.y
    Circles[1].x = square.x - 70
    Circles[1].y = square.y
    Circles[2].x = square.x + 70
    Circles[2].y = square.y
    Circles[3].x = square.x + 5
    Circles[3].y = square.y + 70
    
    Joints[1] = physics.newJoint("rope", square, Circles[1], 0, 0, 0, 0)
    Joints[2] = physics.newJoint("rope", square, Circles[2], 0, 0, 0, 0)
    Joints[3] = physics.newJoint("rope", square, Circles[3], 0, 0, 0, 0)
    
    -- Save a reference to all the joints and circles in the square object
    -- We will need this later when placeing back into the pool
    square.satellites = Circles
    square.joints = Joints    
    
    square:addEventListener("tap", onSquareTap)
    
    return true
end

We need a way to track all the objects used, so we can return them to the pool later. Notice above, we save a reference to the joints and circles in the square object itself. Since the square object will contain a listener that will start removing everything when tapped, it’s a great place to store it.

The code below is the listener that is called when you tap the square. This function will dismantle the complex object and return the parts to their appropriate pool.

-- When you tap on the square object, the entire complex object
-- is returned to the proper pools.
-- Note that since we are not destroying objects (we are pooling them)
-- we have to manually remove and nil all physics joints, since we created them
-- when we created this complex object.
function onSquareTap(event)
    local object = event.target
    
    -- remove the physics joints
    for i = #object.joints, 1, -1 do
        display.remove(object.joints[i])
        object.joints[i] = nil
    end
    
    -- put the circles back into the pool
    for i = #object.satellites, 1, -1 do
        GBCObjectPool.put(circlePool, object.satellites[i])
    end
    
    -- nil out the joint and circle variables
    object.satellites = nil
    object.joints = nil
    
    -- remove listener from square
    object:removeEventListener("tap", onSquareTap)
    
    -- place square into pool
    GBCObjectPool.put(squarePool, object) 
    
    return true
end

That’s really all there is to it. In summary, just remember:

  • When creating a complex object
    • Grab the objects from the pools
    • Create your physics joints
    • Store a reference to all the objects and joints used
  • To remove a complex object
    • Remove the joints using display:remove(joint) or joint:removeSelf()
    • Return all items to the appropriate pools

[divider]

GBC Object Pool Performance

The sample app included in my GBC Object Pool plugin has a performance scene that compares object pooling to traditional object creation. I took that scene, and modified it to execute 100 times automatically. After each run, it dumped the amount of time it took to execute.

Here are the results I experienced using the following settings in the app:

  • Display 100 images, 200 times
  • Use colors, physics, and scaling
  • Display the images using traditional methods, then pooling. Record both times
  • Repeat 100 times

Note that while the app is running, I did not attempt to access the devices, and no other apps were running in the background. Basically, I ran the app, clicked Start, and walked away.

Windows Desktop Performance

For this test, I used my development machine… a 2 year old Dell XPS 8700 with 16GB RAM.

Notice the tightness of the pooling times? GBC Object Pool (and object pooling in general) is pretty consistent, operating on average around 6700 milliseconds to perform the task.

The blue dots represents the traditional method of creating 200 images via display.newImageRect() 100 times, and then removing them. Notice the sporadic times and wide distribution. The dotted line represents a linear average where 50% percent of the dots are above the line and 50% are below the line. Notice that all of the object pooling tests are mapped below this line.

Android Performance

Moving on to smart devices, I used my Android phone… a 2+ year old mid-range Samsung.

Again, notice how pooling provides a more consistent result and maps faster than traditional average times?

What is interesting is the first few items between run 1 and run 10 (and again between run 61 and 75). Check out the data listed here:

Run
Traditional
Pooling
Difference
1 7706 6678 -13.34%
2 7962 6722 -15.57%
3 8844 6671 -24.57%
4 7787 6680 -14.22%
5 8030 6651 -17.17%
6 8243 6739 -18.25%
7 7679 6928 -9.78%
8 7221 6846 -5.19%
9 7278 6988 -3.98%
10 7318 6886 -5.90%

Something definitely was happening on the phone (memory allocation? background OS task?), but you will notice that it wasn’t a noticeable factor when using pooling. Since it is not possible to know when or if a background task will start executing while a user is playing your game, I would expect the game to stutter if you were creating a lot of objects during this time via the traditional method.

Announcing: GBC Object Pool

My latest plugin, GBC Object Pool, is now in the marketplace.

The GBC Object Pool plugin allows the CoronaSDK developer to easily and quickly implement object pooling within your application. Using two lines of code, you can create an object pool. GBC Object Pool optimizes the management of pooling, allowing for object reuse and eliminates garbage collection inherently found with traditional create/destroy functions.

The plugin provides several examples of pooling.  If there are any questions or requests, please let me know. I plan on writing more examples, blogs, and perhaps some videos on the  use of this plugin.

Some links:

GBC Object Pool in the Corona Marketplace

Link to documentation

Link to example code

[divider]

Using GBC Data Cabinet

I think it’s time to give GBC Data Cabinet some love… it’s been in the Corona Marketplace for over a year and it just works!

GBC Data Cabinet is my free Corona SDK plugin that can be used to keep temporary and persistent data for your Corona written apps.  It is very easy to use… simply create a data repository, and start adding and reading data.  That’s two lines of code!

GBC Data Cabinet does not use global variables to store data. Any data type, including tables, can be stored and used between scenes as well.

Do you need to store data between runs of your game? Just call save and pass in the data repository, and values are saved. Use the load command to bring everything back the next time you need it.

[divider]