A Very Long Overdue Status

My last status post on SMS: The Next Mission was over 10 months ago. I figure it is about time I provided an update.

Reflecting

Looking back between September 2016 and about May 2017, I lost all desire to continue development in its current state, even though I had a lot completed. If you read through some of the older posts, you can see that something was just not right. I wasn’t sure about what features to add, and I was unsure about what to add to the shmup version (of even if I should include it). Development was also getting a little sticky as I was still learning some concepts in Unity. All of this caused me to stop development for a few months until I could figure out my next steps (and to build up a bit of excitement and momentum again).

Fast forward to June 2017. I decided I again wanted to continue (AND FINISH) this game. Looking at my project, I decided it was best to start over, but leverage any code that I had already written over the past 5 iterations. So here I am… the 6th time starting this project over and I am glad to say that progress so far has been great and I am confident that this will be the last time I need to restart.

I think the overall problem back in September 2016 was I was trying to take a game I previously wrote and love playing and create a PC/console version of the game that I think others want to play. That version of the game was not enjoyable to me and I lost motivation.

Currently, Space Mission Survival is available on mobile platforms and is a retro space shooter that I find quite enjoyable.  That is the basic game I want to recreate on PC/consoles, with some enhancements of course:

  • The Classic 70 Arcade, 80s Home Computer, and 90s Console versions that I previously mentioned will remain. They are basically the same game with some differences including graphics, sounds, and game play that was available during those past times.  All three modes will be complete, stand-alone games, and will feature enough unique game play and achievements to make them slightly different.
  • I do want to add a Shmup mode, but I a a bit unsure what this version will consist of, or how this mode will actually play at this time.
Current State
Classic 90s Mode

I decided to focus on the classic modes since I know for certain how these games will play. Using the mobile version as a model of game play, I will adjust game play to look and play like a game in those specific decades.

As of today, the 90s console version is pretty much complete. The game is playable and has a look and feel of a 90s game. Modifying the game to feel like a 70s and 80s game will be easy since most of the code will be identical… it just a matter of changing sounds and graphics for the most part.

I am going to begin a very small alpha testing of the 90s game with some friends and family soon. Any fixes will carry over to the 70s and 80s mode.

Future State

I am still undecided what the shmup mode of the game will be like, but I know I want the game to be intense (the classic modes are “wave-like”, so there is a bit of a breather between levels). I also think I want to utilize the 70s, 80s, and 90s modes somehow, perhaps through a time warp feature, but I am not sure.

Change of Attitude

During my hiatus from SMS: The Next Mission I decided that I am going to write a game that I want to play (and hope that other will as well), instead of trying to cater to the fickle demands of the masses. Making everyone happy is a game you cannot win. This will be a topic of another blog post, to be sure.

Conclusion

So there you have it! To summarize… SMS: The Next Mission will have 4 stand-alone games (70s Arcade, 80s Home Computer, 90s Console, Shoot-em-up). It may have a different name as well. Finally, my blog will be where I post updates (I hope you follow), and my decision to work the way I am working will be detailed in another article.

Thanks for reading!

Thoughts on My Ludum Dare 38 Results

Ludum Dare 38 is over and results have been released. Time to reflect on my score for this Compo, and perhaps compare some of the scores for this entry on my previous LD entries.

My Scores

Since the number of submitted entries is never the same, I converted my scores to percentages of total entries submitted, and will use these numbers for this article. Overall, I improved in all categories, and in fact, this is my best Ludum Dare out of the 4 I entered. I’ll point out a few of the categories in detail next.

Theme

My best category this time around, so I guess I understood the theme. For this LD, my idea came quite quickly. For my previous LDs, it took a long time before I felt comfortable with an idea to work on, and maybe that’s why those ratings were a bit lower, although I was a little surprised at the low rating for my LD37 entry, Bat Cave, since I think I got the “One Room” theme down, but I guess those that rated my game did not agree.

Humor

I’m within the top 25% for humor, and I am pleased with this. From time to time I do like to add a bit of humor to my LD games. For Contamination, I had to introduce bad germs that would attack the good ones, and what better way than through coughing and sneezing? I recorded an actual sneeze and some coughs and the rest is history. I am glad others liked it.

Fun

Within the top 30%. What else is there to say? Of course I strive to make my games fun… we all do. Not a bad score, but I would like it higher. I had to sacrifice some game play due to time and complexity… perhaps if I added those extra features, this rating would go a little higher.

Audio

Again, top 30%! Actually, looking at my previous 3 LD entries, the audio score was always getting worse. Nice to see this get better. One comment I always get for each entry is “the audio is too loud!”, which I find interesting since I just don’t get it. Maybe I play with the sound turned down or something, since the sounds appear fine for me, but this is something I need to attend to.

My Thoughts

Looking at my score, I am both happy and a little disappointed at the same time.

The Good
  • My entry for LD38 has the best scores all around, which of course is great. It demonstrates that I am (hopefully) improving. My results seem to be within the top 25 – 35%, so I am over the hump.
  • In the 4 times I did LD, I released something playable.
Why am I Disappointed?
  • I didn’t rate well in Graphics and Mood (although, I’m not really sure what Mood is). I did expect a little higher rating in Graphics, even though the models I used are very simple. I guess I have to brush up on my Blender skills.
  • I played a few games similar to mine and those rated higher. Perhaps my game was a bit too simple, not “cute” enough, or some other reason?

Should I Continue Development?

Based on how I like my game as well as comments of people who rate my game, I always consider continuing development of my entries (for Retro Rebound Challenge, I actually started work on a more polished game, but decided it wasn’t something that would generate downloads).  After brief consideration, I decided not to continue development of Contamination for the following reasons:

  • I feel my score just doesn’t justify it.
  • Similar games rated higher and authors of those games decided to continue development of their games.

Maybe I will change my mind in the future… who knows.  I am actually considering working on developing Bat Cave as well. Its how the mood strikes me, and comments from the community, I guess.

Conclusion

As always, I had a blast, released a game in 48 hours, and took part in a great community. It has already been announced that Ludum Dare 39 will take place July 28, and I look forward to taking part in that as well.

[divider]

Contamination Post Mortem

Another great Ludum Dare in the books (my 4th), and as always, it was a blast. While we wait for judging to begin, I figured it is a good time to work on this Post Mortem for the game I created, “Contamination”.

The theme was “A Small World”, and the idea for my game came much easier than I expected this time. After about 20 minutes putting together the idea, it was off to work.  All my previous LDs were 2D, so I decided to give 3D a shot, and I think it works quite nice with this game. Man, Blender is a monster… I can get simple shapes done, but anything else will take me a very long time… time I don’t have in the Compo. Luckily, the models for this game are simple, and something I thought I can do in Blender so I went for it.

After some sleep, it was back to it on Saturday, and the day was spent putting together the game: enemy germ AI, green cell movement and splitting, player movement and fire. All game movement was done with a tweening library, not physics.  I second-guessed that a few hours later when I could not really manage collisions since these were kinematic objects, but it did not become a problem since I decided I wanted all the game objects to be able to pass through each other (and used triggers instead), otherwise movement would become too cumbersome in such as small space.

Sunday was spent putting in the remaining game play: adding the Super Germ, tweaking the germ and cell spawning, etc.  The afternoon was spent creating sounds and music, adding the HUD, and adding a title screen and instructions.

So, What Went Well?

  • The idea came to me rather quickly, so I didn’t have to sweat it out.  I also felt like this was a game I really wanted to develop.  That kept me motivated throughout the Compo.
  • The tweening library worked like a charm.  What a time-saver.
  • Even though the game has “simple” objects and effects, they did come out better than I expected. I was successful in creating 3D objects and particle effects.

What Could’ve Gone Better?

  • I have to either get better at Blender, or find another tool.  I don’t do art well, but working in Blender seems like I am fighting the tool, and not my lack of modelling skills.  Yes, I get it, lots of keyboard shortcuts, but it is hard to work that way if you only get in there from time to time.

Please check out my game and let me know what you think.

Ludum Dare Entry

Direct link to Windows, Mac, Linux version

Direct link to WebGL version

[divider]

In for Ludum Dare 38

This will be my 4th LD.  Looking forward to it.

Most likely will be doing the Compo, and I will be using:

  • Unity
  • Photoshop, Paint.Net
  • Audacity
  • bfxr, Otomata

There is a slim chance that I may use Corona instead of Unity, but it depends on the theme and whether I decide to do a 2D game.  Not really sure… I have to be in the right mood.

[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]