Preloading images

Hello,

I’m loving Corona – making a game right now that pretty much kicks ass.

One thing I haven’t figured out yet: To avoid stuttering upon starting a “stage”, if you will, I’m trying to cache the image assets, and wait until they are finished loading. I’d love to find a good solution for loading a group of images based on a table of filenames.

Also, I’d like to know the progress of the amount of images loaded, so I could control the size of a loading bar.

I tried the code in the “utilities” code section that explains a bit of this. But I don’t think it actually worked.

So, I ask this, based on the loading example in “utilities”, when you load an image, does the application wait for it to load before executing the next line of code? If not, how do I detect when that image has finished loading? It’d be nice to have a “complete” event, or something.

Sorry if this sounds elementary, but I’ve scoured the forums and documentation on the subject. Haven’t found much at all. Thought I’d just go ahead and ask…

Thanks!
Mike [import]uid: 4454 topic_id: 2327 reply_id: 302327[/import]

Here’s some of my code to illustrate what I’m doing… This function adds an image to an object, and repeats 64 times. Immediately after, it tweens the images’ scale to 100%. There are 6 small pngs that are randomly loaded and placed in these objects.

The very first time this happens, there is some stuttering, as in, the framerate drops and it doesn’t look smooth. Once gameplay commences, and this function repeats again, and various images have been removed and nil’d, it looks really smooth.

I’ve read the docs from Ansca staff that it’s good to “lazily” load assets when you need them.

function addMCsToItems()  
 local hasNewItems = false  
 local currentSlot = {}  
 local newMCTable = {}  
 local i = 0  
 for i = 1, #mBoardSlots do  
 if mBoardSlots[i] ~= nil then  
 currentSlot = mBoardSlots[i]  
 local itemReference = mBoardSlots[i].boardItem  
 if itemReference ~= nil then  
 if itemReference.MC == nil then  
 local itemPicName = itemReference.itemPicName  
 local itemPic = display.newImageRect( itemPicName, 40, 40 )  
 itemPic.xScale = 0.1  
 itemPic.yScale = 0.1  
 local itemMC = display.newGroup()  
 itemMC:insert( itemPic )   
 mBoard:insert( itemMC )  
 newMCTable[#newMCTable+1] = itemMC  
 hasNewItems = true  
 end  
 end  
 end  
 end  
 -- display items ( tween scale to 100 )  
 for i = 1, #newMCTable do  
 local itemPic = newMCTable[i].itemPic  
 transition.to( itemPic, { time = 200, xScale = 1, yScale = 1, transition = easing.outQuad } )  
 end  
 return hasNewItems  
end  

I’ve tried to cache the images beforehand ( several seconds before addMCsToItems ):

-- Load Images  
local loadAssets = function()  
 local i = 0  
 for i = 1, #mCompareArray do  
 mImageArray[i] = display.newImageRect( mCompareArray[i], 40, 40 )  
 mImageArray[i].isVisible = false  
 end   
end  
loadAssets()  

This runs as soon as the code is instantiated. It doesn’t seem to help stop the stuttering issue.

All of this occurs in a package that is being required at the start of the app’s main.lua. Is the fact that it’s in a package being required have anything to do with it?

Moreover, what I’d love to know is a good preloading strategy, and to be able to show a preloader bar, much like how Alien Horde displays when it is first launched.

Any help would be appreciated. Thanks!

Mike [import]uid: 4454 topic_id: 2327 reply_id: 7153[/import]

I’d also like to know this since I want to preload some images on game start to avoid “hickups”.

However, once I load an image using display.newImageRect, the image is displayed immediately. How can images be loaded into a variable without being forced to display them immediately?

And I am also curious about the other question asked above -does Corona stop execution until an image is loaded, then proceed with the next line, or will it load images in the background while the code execution continues? If so, is there a “complete” event we could use to generate a progress bar and keep track of the loading progress?
[import]uid: 9644 topic_id: 2327 reply_id: 7421[/import]

One way to load images and not have them show directly is to load them at a out of the coordinate system.

local img = display.newImage("myImage.png",-1000,-1000);  

another way is turn off its visibility immediately.

local img = display.newImage("myImage.png",-1000,-1000);  
img.isVisible = false;  

Corona loads the image, then proceeds to the next line. There is no complete handler.

How to create a preloader?

Create an event loop and load the images on the event loop and put up a display bar.

something like (no real code but pesudo code)

[code]

local img = {} – table;

local function preLoad ()

if (ImageNumber > numImages )
Runtime::RemoveEventListenter(“enterFrame”,preLoad);
return
end

local imgage = display.newImage(“img”…ImageNumber…".png",0,0);
imgage.isVisible = false;

table.insert(img,image);

ImageNumber = ImageNumber + 1;

– calculate progress ( ImageNumber / numImages )

end

Runtime:AddEventListenter(“enterFrame”,preLoad);

[/code] [import]uid: 24 topic_id: 2327 reply_id: 7428[/import]

Ah, I now realize that by using the enterframe handler, the bar will redraw once this block finishes. I was trying to execute a preloader all within a “while” or “for” loop. “Enterframe” will advance through time and its next iteration will occur after the screen has redrawn.

Thanks, Carlos!

Mike [import]uid: 4454 topic_id: 2327 reply_id: 7429[/import]

That’s exactly what I was looking for, thanks :wink: [import]uid: 9644 topic_id: 2327 reply_id: 7784[/import]

Ive never been fond of adding the enterFrame listener as my way of getting out of the initial load of the program.

I prefer to do something like this:
function preload_stuff_before_start()
load_x()
end

function main()
start_loading_stuff_and_show_load_bar() --has enterFrame code in here
end
prelaod_stuff_before_start() --loads stuff before iphone gives control to corona, if you want to even do this
timer.performWithDelay( 0, main ) --when iphone gives control to corona, then call main
So basically, the timer.performWithDelay call will allow corona to read all of your code, and then once all of the code has been read, corona takes control and fires off the one timer function immediately. At this point, you have control of what you want to do on the screen.
Its different than just:
prelaod_stuff_before_start()
main()

Without the timer call, all the stuff in main() is loaded before the iphone gives control to the corona event system, and thus, you cant do any drawing until that happens.

[import]uid: 8541 topic_id: 2327 reply_id: 7949[/import]

Also, you can use this event instead to get in to your application from Corona’s event system:

Runtime:addEventListener(“applicationStart”,main)

[import]uid: 8541 topic_id: 2327 reply_id: 7956[/import]

Yes, that makes sense. I’ve been using the “applicationStart” event. [import]uid: 2138 topic_id: 2327 reply_id: 7972[/import]

bumping an old thread, because I searched before posting and found this, which is the same exact question I had.

First of all, since this thread is over a year old, it looks like the new code for checking application start is now:

[lua]local loadAssets
loadAssets = function(event)
if event.type == ‘applicationStart’ then
print(“this is where assets should be preloaded”)
end
end

Runtime:addEventListener(“system”,loadAssets)[/lua]

However, I’m wondering if there’s a way to tell when all assets have actually been loaded, or even the actual progress of the loading (e.g. check some constant value like TEXTURE_MEM_BUFFER against garbage collector count / texture memory?)

My images are showing up fine, but I’m using the physics engine, and there is a noticeable stagger when the game starts. And since there’s no frameskipping enabled for the box2d physics, I can’t think of any other way around that stagger. [import]uid: 49447 topic_id: 2327 reply_id: 61293[/import]