Showing posts with label lua. Show all posts
Showing posts with label lua. Show all posts

Sunday, February 17, 2013

Beware the widget



The Jabberwock, as illustrated by John Tenniel
 
"Beware the Jabberwock, my son!
The jaws that bite, the claws that catch!
Beware the Jubjub bird, and shun
The frumious Bandersnatch!"
 
So, I wanted a simple drop down list so a tester/player could pick a scene and then go there.  I didn't find what I wanted, but there was this nice feature of the Corona Widget object library called the newTableView:
Corona tableView widget
 
Looks good, maybe more complicated than what I need but the code looks straight forward (okay, not as easy and straight forward as old school classic VB 6 - but not as weird and hard as Visual C++ MFC of the same era - and once again I'm dating myself...)
 
The demo's I found here and here provided the basics - but!  I need to incorporate this inside the Corona Storyboard construct.  And that is where the fun and games began...
 
Now a mea maxima culpa is in order - what follows is probably due to my being overzealous in getting rid of memory issues.
 
I created two arrays - one is a straight forward array with the names of the scenes in order that I want to provide.
 
The second is an array of arrays used by the tableView object.  One of the weaknesses in using Corona is the documentation is sparse and terse - just enough to get you into trouble - but the stuff you really need to know is found in the forums. From what I've figured out is the row construct in the list allows you to have a picture object, a title and then descriptive text. There may be more, but this is far more at this point than what I really need.  Hence an array of arrays - or to use the Lua way of thinking - a table with individual rows that could contain a number of fields (columns) greater than one.  Let's move on.
 
He took his vorpal sword in hand:
Long time the manxome foe he sought—
So rested he by the Tumtum tree,
And stood awhile in thought. 
 
Got my lists, got my tableView, and wow - it actually displays what I want!
 
 
It's just that the damn thing crashes when I do a selection.  This one got me. 
 
And as in uffish thought he stood,
The Jabberwock, with eyes of flame,
Came whiffling through the tulgey wood,
And burbled as it came!

 
So I unsheathed my vorpal sword - er, I started to really use the Lua Glider debugger.  Need to go back a bit here.  In my desire not to create any more memory leaks I had made sure in the storyboard function scene:exitScene I set any variable I declared to nil.  And that was the source of my errors. 
 
One, two! One, two! and through and through
The vorpal blade went snicker-snack!
He left it dead, and with its head
He went galumphing back.
 
The errors were just - weird.  Didn't make sense.  And here is where using Lua Glider saved the day (used as my vorpal blade).  I set a break point for the listener function in my code - the code that gets fired when a user clicks on a selection in the list.
 
And as I expected the code worked perfectly - selecting the correct item in the selection array based off the event index.  But then we went down the rabbit hole...
 
It turns out after all of that the storyboard code kicked in.  The exitScene code got called - setting all of my variable to nil.  Oh - and then the listener function got called again - and since everything had just been set to nil it set off errors - oh my...
 
Okay, I'm sure my code isn't the most efficient at this point.  Why the listener function is getting called twice I can't answer.  However I did learn a valuable lesson here.
 
"And hast thou slain the Jabberwock?
Come to my arms, my beamish boy!
O frabjous day! Callooh! Callay!"
He chortled in his joy.

'Twas brillig, and the slithy toves
Did gyre and gimble in the wabe;
All mimsy were the borogoves,
And the mome raths outgrabe.
 
Clearly, at this point in my Lua/Corona development the ONLY stuff I should be setting to nil (null) in the storyboard scene:exitScene function are those objects that get inserted into the display view/self view group.  Anything else - well as the maps used to say here be dragons...
 
Cross posted at my other blog Greffin's Feather



Bugs and Options


This week has been a combination of extending the UI and continuing the debugging.

As a team we started using Lua Glider as our main development platform for working on our game.  I had installed a demo version of Corona Project Manager – which is now known as Outlaw – and worked with it for a short while.  I just liked Lua Glider better.

Lua Glider has a lot of hooks into our project tools:

·         Works with Corona SDK

·         Provides debug capability with the ability to set breakpoints with Corona SDK

·         Works with both Subversion and Git

·         Works with Bugzilla and JIRA (no plug in that I can find for Mantis BT)

So it’s been a week of tracking down and taking care of bugs using Glider.

The more interesting part of the week has been adding an options menu to the game.
If you tap twice on the of part of Flights of Fancy (note the elipse around the word) – and then click the Play button:
You get this menu screen.

Set Auto Fire – this button either turns it on or off.  It does a read/write to a save state JSON file.  Code has been added to the scenes to utilize this - and I've found a couple of 'features'...
First one - I've not commented out the tap listeners in the scenes.  So you can double the fire rate by allowing the autofire to go, and them supliment the rate of fire by tapping like mad.
Second 'feature' - in scene 3 where there are multiple enemy planes - the shots coming from the player can show two bullets side by side.  Nice!  Just need to be able to replicate it as a feature later on!

Change Side – this button changes the side that you picked – so if you started working for the  Allies you now work with the Axis powers and shoot down your former buddies.  Again, does a read/write to the same JSON file.

After selecting either of these buttons you go back to the main menu screen.

Do Intro – this button allows you to redo the intro/training missions.  Once pressed you go immediately to the first scene of the intro.

Scene List – this one took a bit of time to get in.  Clicking this button displays another screen:

 
This screen uses a Corona Widget table view object.  It’s a bit cranky, but when it works it opens up the scene that gets picked from the displayed list. 
I'm going to write another post on an issue I ran into using this object.

Sunday, February 10, 2013

Offering the red pill...

So this week is about choices. 

The player was given the ability to make a choice during the demo/training scenes - but we weren't doing anything game wise with the players pick, at least up until now.

I've got a version in my SVN repo for the team to demo - now if the player decides to assist the Axis powers he/she gets to shoot down what would usually be the good guys airplanes.

Let's start with Snoopy's favorite ride - a Sopwith Camel.  This is currently the default Allied ship the player is going against.

Keeping with the RAF motif - the second enemy fighter the player goes against is a S.E.5a.

And the boss is a RAF RE.7 two seat light bomber/recon/fighter.

So, how does this work.  We  have two modules - a background and a ship module.  Using the JSON file created when a player makes a choice in level 0 -

local playerScore = require "playerScore"
local mySide = playerScore.whichSide() --pulls the value from the mycurrentstate.json file
some function()
     if (mySide == "A") then
         --do some Allied stuff --I love warm beer and haggis
     or
         --do some Axis stuff --I love bratwurst und sauerkraut!!
     end
end
 
This way the 'knowledge' of what choice the player makes is only available to those modules that need it. 
 
However this isn't going to be as pure as an OO narzi would like it to be.  I'm thinking to keep things compact and easy we may well have to have various scenes in on the players choice - some things may happen different depending the story line specific to the side the player chose. 
 
And I added a new background to our game:

I found this site:  http://www.spiralgraphics.biz/packs/terrain_civilization/index.htm

If you download and install their Genetica viewer you  get access to a lot of images, then can change the image size, then save it as a jpeg or png file type.

Once I saved an image I used Paint.NET to carve out the final image and size it to fit our game.
 
The red pill reference - that's a rabbit hole for another time...

Sunday, February 3, 2013

Moving On

New Stuff

Spread Shot

Added a new ‘spread shot’ feature to the game.  First I tried to do it programmatically, which didn’t work as I thought it would.  Simply put – I was trying to use the same graphic image twice –both images had the same vertical axis but the horizontal axis would be slightly different for the individual shot.  Just couldn’t get it to work.

So, I created a new graphic which has three shots in it.  Looks nice, and is easier to control.  Here is a screen shot: 

New Enemy Plane


Added a new enemy plane which for now debuts in level 3:


This isn’t working as well as I wanted, and I’m going to have to put some more effort into it.  What I wanted to see was first the default red enemy planes, then my new planes, then the boss.  For right now that isn’t happening, the new planes don’t display – so for demonstration purposes I changed the ‘default’ enemy plane to the new one for this level.
Intro Level

I made some refactoring changes here as well.  First of all, I pulled in Jim’s code that provides more player ship movement - it now moves up and down on the screen as well as rotates in the direction of travel.  Looks a lot better this way. 

Travis had originally gotten rid of the health bar and the multiple lives for the intro; unfortunately they both got reintroduced due to the additional code.  Changes were made to again not display the health bar and the additional player lives.
Lua IDE’s

Downloaded and installed then started working with two Lua/Corona SDK IDE’s:

·         Corona Project Manager – now known as Outlaw

·         Cider – now known as Lua Glider

I’m more impressed with Glider but I’ll be playing with both off and on.  My original editor was TextPad which I still like – but it clearly does NOT have all the features a full blown IDE has.

One thing I liked about Lua Glider, and should see if Outlaw also has – Glider ‘understands’ Subversion.  I was able to look at the back history of modules (as long as comments were posted to the SVN commit).  Very nice feature.

Tuesday, January 29, 2013

Plugging Memory Leaks in Corona


I’m finding out that Lua is not as forgiving a language as I had first thought.  These were the changes I made in level0 to get rid of the various memory leaks I had created.
Destroying Objects
This was the most obvious thing to do, and so became the first order of business.  We have been inserting objects into a self.view group – and that order of removal is a very important thing in Lua.
Using this article on removing objects properly as a guide I found a number of things.  First just removing an object from a group isn’t enough for the garbage collector – the reference the variable is pointing to must also get removed.  So there are two steps to destroying an object – first is to remove it from a group by calling the group:remove( object name or index ) or object:removeSelf() methods.  Then you have to set the object = nil to remove the reference.
But wait – there’s more!  The order of removal from a group is also important.  In fact a common pitfall is to iterate thru a group in a normal forware fashion – which may in fact skip every other item in the group.  I’m going to copy and paste the relevant section from the above link here:
Common Pitfalls
A common mistake is to improperly remove all objects from a group. This typically happens when you write code that iterates through a group attempting to remove each child from the display hierarchy. It’s natural to iterate through the group in the forward direction. However, this can cause no end of confusion.
Continuing with our solar system example, consider the following where we attempt (incorrectly) to remove all the objects from the solar system.
for i=1,solarSystem.numChildren do
        local child = solarSystem[i]
        child.parent:remove( child )
end
The problem here is that we are modifying a collection (i.e. the group’s children array) as we iterate through that same collection. The result is we remove every other child. The easiest way to illustrate this is with a parallel example involving an array of integers:
local array = {1,2,3,4,5,6,7,8,9,10}
print( table.concat( array, " " ) ) --> 1 2 3 4 5 6 7 8 9 10
 
for i=1,#array do
        table.remove( array, i )
end
 
print( table.concat( array, " " ) ) --> 2 4 6 8 10
The fix is to iterate backwards.
for i=solarSystem.numChildren,1,-1 do
        local child = solarSystem[i]
        child.parent:remove( child )
end
Of course, this only ensures that all children have been removed from the display hierarchy; you till have to set all references to these display objects to nil. So in this example, we were merely trying to illustrate the highlight the pitfalls of iterating forward through the children of a group and modifying the group at the same time. A good implementation would also set the corresponding properties in solarSystem to nil for proper cleanup. 
So as part of my exitScene function I’ve added the following:
for i=screenGroup.numChildren,1,-1 do
        local child = screenGroup[i]
        child.parent:remove( child )
end 
Then I do this:
screenGroup:removeSelf()
And then set the various objects equal to nil.
We aren’t done yet tho…

Forward Referencing

This part comes from reading this handy article on The Significance of Local Variables in Lua.  We’ve all seen this:
local myFunction = function()
        callback()  -- ERROR: function 'callback' does not exist yet
end 
local callback()
        print( "Hello World" )
end 
myFunction()    -- will produce error 
Refactored this way, the code works: 
local callback    -- forward reference (for later use)
local myFunction = function()
        callback()    -- output: "Hello World"
end
-- function below is still local, because of forward reference
callback = function()
        print( "Hello World" )
end
 
myFunction()    -- no error; happy code :-) 
So I took every function that was not part of the scene template and moved it above function scene:createScene( event ).  This took care of a few ambiguous runtime errors.  This includes the addListeners() and removeListeners functions.
At this point things were supposed to be better, but I started to get screen freezes – holy cow things are getting worse!

Runtime Listeners

I next turned to this handy guide, Corona SDK Memory Leak Prevention 101.  And found this handy scrap if information:
When you remove a display object, listeners that are attached to it are also freed from memory. However, when you add listeners to Runtime (e.g. enterFrame listeners), those never get freed until you manually remove them.
 
A common leak that occurs with Runtime/enterFrame listeners is when a developer adds a Runtime listener to the particular screen they’re in, but they forget to remove the event listener whenever the user leaves the screen. So what happens is, the user leaves the screen, and then when they come back to it, there are two identical Runtime listeners running on top of one another.
Now, we do add a Runtime enterFrame listener with the gameloop code.  I make extra sure that the removeListeners function has the Runtime:removeEventListener('enterFrame', gameloop ) and that it gets called.

Timers and Transitions

Again back to this handy guide, Corona SDK Memory Leak Prevention 101.  I’m just going to copy and paste from the guide:
Timers and Transitions are probably one of the most common causes of crashes, mostly due to the fact that countless (unaccounted for) things could happen between the time the timer/transition starts, and the time it ends. What’s worse, if you forget to cancel these and nil out their variables when no longer needed, things could get stuck in memory and cause more leaks.
One way you could manage these is to store ALL of your timers and transitions in a table, so that when you know for sure no timers or transitions should be running, you can cancel all of them at once.
If you add the following code to your main.lua file (or another module and require it in), you can easily keep track of your timers/transitions and also cancel them all at once if and when needed:
timerStash = {}
transitionStash = {} 
function cancelAllTimers()
    local k, v
    for k,v in pairs(timerStash) do
        timer.cancel( v )
        v = nil; k = nil
    end
 
    timerStash = nil
    timerStash = {}
end
--
function cancelAllTransitions()
    local k, v
    for k,v in pairs(transitionStash) do
        transition.cancel( v )
        v = nil; k = nil
    end 
    transitionStash = nil
    transitionStash = {}
end
Then, whenever you start a new timer or transition, you assign it to the respective table first, like so:
timerStash.newTimer = timer.performWithDelay( ...
transitionStash.newTransition = transition.to( myObject { ... 
Then you can use the cancelAllTimers() and cancelAllTransitions() functions to stop all timers and transitions all at once. If you have timers you don’t want to be cancelled, then don’t add them to the “stash” tables in the first place (but be sure not to forget to keep track of them). 
So I added the above cancel functions to level0, and then call them after the removeListeners call.  I found I could do this in the gameloop function and it would work:
transitionStash.newTransition1 = bg1:translate(0,2)
transitionStash.newTransition2 = bg2:translate(0,2)
 
Things are better but I still was getting some runtime errors – not as many, and no crashes but still annoying.

Proper Placement of Cleanup Code

I was experimenting with the right place to put all this garbage collection code – and in desperation decided to go back to the documentation.  One last link – storyboard.gotoScene():
Description:
Used to transition to a specific scene (determined by scene's module name). Internally, this will handle all loading/unloading of the scenes. Scenes may also be explicitly unloaded/removed by the user.
When this function is called, the "exitScene" event will be dispatched for the currently loaded scene (if one exists), followed by the "createScene" event (for the specified scene—sceneName—if no "view" property is present), and then the "enterScene" event (also for the specified scene—sceneName).
It dawned on me – keep the code in the exitScene and it would always get called in correct order. 
At this point I was about 99.5% there.

Zombie Scenes

Yes, the dead still inhabited the program.  I was seeing calls to level0 when in level2 – no crashes but still getting some runtime errors.  So I found this reference to storyboard.purgeAll().  In cutscene1, the scene:createScene( event )function I replaced the call to storyboard.purgeScene( priorScene ) with storyboard.purgeAll().  Inside the Lua command box I was seeing calls to scene:destroyScene( event ) in both level0 AND train3.  More importantly it got rid of the last runtime errors.

Sunday, December 2, 2012

Code Refactoring

I started noticing I was writing paths to image files a lot as I was creating scenes.  And I realized as we kept adding more and more, we were going to run into problems if we decided to change images.

As an example - a line of code may have something like this: 

local bullet = display.newImage('resources/Bullet_Black.png')
 
As you can imagine, that image gets used a lot.  If we want to change to a different bullet image, and decided to keep Bullet_Black.png we may have to edit a lot of files.
 
So I built three resource Lua files:
 
  • bgFile.lua - to hold background image paths
  • controlFile.lua - to hold button and other control image paths
  • shipFile.lua - to hold the various ship image paths
 
Those files have local variables that hold the path statements to the images, and then get functions so other modules can gain access to the resource path.
 
It dawned on me, this is a classic refactoring scheme -  what is the least amount of 'knowledge' a code module has to have to do it's work.
 
So now - the resource files 'know' where to get an image; a scene file 'knows' how to manipulate an image, and so it goes.
 
One benefit we will be able to capitalize on later - as we add higher definition images for other devices we won't have to have the scene modules 'know' how to determine what image to use.  That bit if knowledge can be transferred to yet another module - and then 'asked' by the resource modules.  If the device is a higher res one - then the resource module can serve up a HD version; or else just the regular res image if the device can't handle it.
 
One thing that caused a bit of a struggle - Lua and the way it handles arrays.
 
Lua it turns out is a fairly primitive language - in that I mean primitive in the way C is.  Arrays are very simple structures in Lua - no matter how you have defined an array it is actually a KV collection set into memory.  And of course the variable name is just a pointer to the actual location where the values are stored.
 
Using them is not a big deal - it's copying them that things get fun.  There isn't anything built into Lua that provides a way to copy an array:
 
MyArray = {a, b, c}
foo = {}
foo = MyArray
 
becomes an assignment for the pointer foo to the pointer MyArray - not the values MyArray is pointing to.
 
So - I found a deep copy function at http://www.dreamincode.net/code/snippet5401.htm, made a couple of changes to it and added it to our fileIO.lua file.  That is what gets used when we need to make a copy from one array to another.
 
So when we have this defined in the ship file:
 
local uavShip = {'resources/drone1a.png', 'resources/drone1b.png','resources/drone1c.png','resources/drone1d.png'}

Using the deep copy function the KV collection uavShip is pointing to can be copied to the memory location myDrone is pointing to:

local shipFile = require "shipFile"
local myDrone = { }
myDrone = shipFile.getDroneTbl( myDrone )

Saturday, November 24, 2012

Winter Intersession - the Game goes on...

I'm taking advantage of the period between the two sessions for now.  I've started working on the beginning/training missions/point of our intrepid player having to make his/her first in game choice.

So I've started by adding a few new ships to the mix.  Found a bunch of nice top down view graphics, and adapted them to our use.

For the here and now these are the 'canon' images I've added - these should be considered source files in that the in game images have been altered:

First is a background for our training mission:
 
This image is a cut out from the full size below:

 
I wanted something modern and very different from the rest of the game.  But I noticed the transitions were choppy - then I really looked at the image.  It's lighter at the bottom than the top, and of course the small craters or whatever they are don't match up.  So I found another desert type background that is a lot more even:
 
 
I also added a whiteboard:
 
This helps keep the intro-training text in an uncluttered environment.
 
As for ships, I've added  three - first is a training drone:
 
This gives our pilot something to test his/her new prototype GAU-6 20mm Vulcan Rail cannon against.
 
Next is the Zeppelin that may or may not make an appearance later:
 
 
And a steam punk boss of all bosses zeppelin which may make its debut later in the game:
 
From the looks of this bad boy our hero may have just met his/her match.  Kind of excited to see what happens...
 
 
Okay - now in keeping with a tech discussion with our Tom Resource writer - my original question was how do we keep a slightly future tech airframe full of gas and bullets in the time frame of 1917?
 
So I took some liberties.  Our pilot has two X type technologies on board - a Warshawski generator (okay - kudos to the Honorverse BUT Warshawskys has been a huge auto parts seller in Chicago for a very long time...) and the GAU-6 20mm Vulcan Rail cannon.  The current gen Vulcan is a GAU-4 - I added the electric Rail gun so means no cartridge case, propellant etc. to worry about. In other words we are just carrying the things that go out the barrel - nothing else.  The rail gun supplies the motive power.   In a pinch add ball bearings - heck even just washers and out they go at an astonishing speed.  Tom Swift can eat his electric rifle!
 
What's a Warshawski generator you ask?  Slyly I answer - it's the typical Sci-Fi X device that allows this discussion to move forward.  Gives us the ability to take slightly future tech and have it run in 1917 without trying to figure out how we are going to get JP8 or any other type of AvGas for our jet driver.  It's when our plane driver is asked to test full military power that things get - well, interesting shall we say?

Sunday, November 11, 2012

Player State

My task this week was to display the players high score.  A simple task yet it lead to several paths...

Okay, so first up was just to display a simple high score.  I built a way to keep this tidbit of information, using the json library available in the corona sdk.

It's nice, what gets created is a essentially a name/value pair list.  Nice and light, especially for this use.  So our game has two of these data constructs - one keeps the current level and score values (it gets zeroed out at the start of the game), then there is another key value pair that holds onto the highest level and score achieved by the player, as well as a simple counter that holds onto the total score number for the player.  Not sure if there is any value to that yet, but we'll see.

So next up was a task to display the high score value.  Fairly easy to do, John created a topScore library file to which I added the functionality to read from the json table, then display the high score.

Well - that was so easy I figured I might as well add the highest level the user attained.  Few more minutes of coding and done.

Okay - but my current gaming obsession is Fallout New Vegas.  Second time around in fact.  And that reminded me - there are achievements in the game based on hitting certain criteria.

So I built a quick if...elseif...else structure and then got some simple achievements displayed.

Nice, but not all that satisfying.  Besides, it just looked like it was going to get clumsy trying to keep that up and running in case the rest of the team liked the idea.

This really needs to be a table based data construct - so I found that lua/corona sdk supports SQLite tables.  Built a nice quick and dirty one using SQLite Admin - and changed the code from the ugly if...elseif...else structure to a sql call to the database.  Took a bit more time to get the correct code but it's in place.

The payoff will be later on - this is a solution a number of other developers use to not just keep player state in but also stats of the various objects in a game. 

Here is a screenshot of our topscore page from the game:

Monday, November 5, 2012

Hurricane Sandy

I'm becoming a veteran of this I guess - last year was Irene, this year Sandy.  I live in a semi-rural area - which means my water comes from a well.  No electricity no water.  However, I do live on a lake, so getting water for other use (think flushing...) is only a bucket away.

We stocked up on water - bottled and filled up a number of water jugs - got propane, positioned tools, camping gear, all the other things that need to be done before the storm hits and power goes out for several days.

We lucked out - lost power for a bit over 24 hours - Monday afternoon to Tuesday evening.

So - after the clean up, got back into coding.  I extended and refactored our scoring scheme - instead of just using a text file, I found that Lua has a fairly robust support for JSON.  It becomes almost trivially easy to have a SQL-less data table get created, read from and written to using the built in JSON library.  So I've got the following libraries:

File IO - general functions to read, write and append files; functions to write to and read from Lua tables.

User State - functions that use the File IO library that write or read user state; right now current level and current score, functionality for highest level and score started on.

Player Score - a centralized set of functions that use the User State library to write out or read from the user state tables.

Code has been added to the main.lua as well as the three user level lua files that writes out the user score.

Plan is to further extend this code so as to have the highest level achieved and total accumulated score to also be saved.

Sunday, October 28, 2012

A gotcha and a gripe

Gripe first.

Once again, need to learn a 'new' way to concatenate strings.

One would think such a common programming task would be easily done regardless of language. 

One of course would be wrong.

Lua furrowed new ground for me here - no pipes, no use of the ampersand or the plus sign.  No sir!  Instead Lua uses two dots to indicate the concatenation of two stringvalues.  Go figure.

Lua concatenation: string3 = string1..string2

Gotcha next - spent some time trying to figure this one out. Kept getting an obscure error.  I was calling a function in another file - had the proper initializing statement in the file trying to use the function:

requires ( "filename" )
 
Instead of using the name space idea common to Java or .NET, Lua has you put this line into your functions:
 
module(..., package.seeall);
 
Added that as a line to my two new files and no more errors.