Suggestions for creating a Standard Loading Screen
Monkey Archive Forums/Monkey Discussion/Suggestions for creating a Standard Loading Screen
| ||
I need a loading screen/bar for my project, have lots of assets to load and do not want to leave the user with a black screen which I think we can all agree is a horrid thing. I have mentioned in other threads that I felt the community as a whole could really come together and put together a standard bit of code and art work to create a standard monkey loading screen, not only would it give Mark some much needed FREE advertising but it would help grow the community, which is good for everyone. Here are some of my current suggestions, I will probably edit this file as its in my dropbox folder so it may change over time.(god i fkn love drop box) Anyway.. What I offer here art wise, and I hope eventually code wise should be considered free for all to use, I hope some of the other artists our there can find a few moments to contribute something, coders more than welcome to throw in some code as well. worth a try... EDIT : forgot the link lol, noob. EDIT : this would be the format that I plan to use for the bar that I eventually go with. unless you guys have a better idea. |
| ||
Had some time to play with this today.. this is of course using the Diddy Framework, but its not intergrated into the Diddy Image class. I will update this as I mess with it more, the goal of course being to have it display one of the nice loading bars above as you load all your game assets, and not these crappy rects that I am using at the moment. Also I have noticed while testing with flash that the update rate seems really slow, and the bar pops along in big chunks rather than as expected as each image loads. can this be sped up ? EDIT :: Pulled the source out, posting a new post bellow with code. and images, and a working example, but the upload is taking time so .. |
| ||
OK.. here is a kinda working version.. Small note, I am syncing a few gig worth of data at the moment, so these files may not be immediately available while drop box chugs through all my files. should not be any longer than an hour or 2 the transfer seems to be going at around a meg a second. Info ~: I have made a loading bar class to try and keep things as modular as possible, but your still going to need to alter the way you load images, to take advantage of the new Async loading, and I am in no way a pro coder so there should be tons of room for improvement. The code bellow loads in a 4meg image a few hundred times just as a test, should probably test it with lots of different image types at some point. Issues : the update rate seems to be really slow while the files are being loaded which seems to be making the bar jump along rather than moving along at predicated intervals as an image or asset gets loaded, it also seems to prevent a nice frame rate for rendering animation which sucks. Is there a way we can speed up the update rate ? something like 30 renders a second or hell even 10 would be more than enough to make it look way better than it does at the moment, I may be misunderstanding the situation tho so if some better eyes could look at it, that would be cool. Whats working : Init your loader:cLoadingBar instance, set its initial values, then make sure your calling loader.update and render, it does the rest. Tips ? Feedback ? anyone ?? lol. Example https://dl.dropboxusercontent.com/u/56777267/code/Alpha/loading/MonkeyGame.html Image Code |
| ||
Actually seeing that loading from the webserver on dropbox it loads a lot better than it does via local/ted so I guess what I thought was an issue does not seem to be one after all. that being said the update rate still seems low. |
| ||
Note : I'm guessing here.. I haven't tested or checked your code, so am probably incorrect.. (Laziness on my part. Requires Diddy, and I can't be bothered installing extras. I have my own framework, I'm happy with that!) But.. For Local ls:Int = 0 To 199 LoadImageAsync("graphics/loading.png", 1, 0, Self) Next Could it be something to do with your initial request of 200 images, all at once? In my framework, I've spread out my requests over different frames, with each request happening over the coarse of the loading.. (And a lazyman's swirling circle of dots doing the duties of proper bar, because I can't be bothered counting assets each week!!) I mean, everything else looks like it works via ASync stuff, so technically it oughta be loading in the background, and not causing any issues, but if you're getting a bottleneck at all, then I'd expect it's probably the system trying desperately to make 200 requests all at the same time. Try chopping that up a bit. Spread it out to maybe 5 requests per update, and keep tabs on what's loaded/not. It might work a little better.. |
| ||
Now loads Sounds and Images, still faking the loading of the same sound and the same image just to test, but if you check out. https://dl.dropboxusercontent.com/u/56777267/code/Alpha/loading/MonkeyGame.html you will see it in action, using a diff theme for the bar from the one above tho. Question to anyone else whos done this before, I assume that the images will finish at different times depending on their size, so may come back to be used out of sync from when they were called to load, so how are you guys managing that. Strict Import diddy 'Import mainscr 'Import brl.asyncevent Global MainScr :Screen = New MainScreen() 'Main Screen. Global ImageList:Image[99] Global SoundList:Sound[99] Global Loader:cLoadingBar 'summary:MyGame main game class. Class MyGame Extends DiddyApp Implements IOnLoadImageComplete, IOnLoadSoundComplete Method OnCreate:Int() 'Seed = RealMillisecs() Super.OnCreate() SetGraphics(640, 480) SetScreenSize(640, 480, True) Loader = New cLoadingBar(61, 400, 200) LoadImages() LoadSounds() Loader.progress = int( (float(Loader.totalLoaded) / float(Loader.totalToLoad)) * 100) diddyGame.Start(MainScr) Return 0 End Method 'summary:Load Game Images Method LoadImages:Void() For Local ls:Int = 1 To 100 LoadImageAsync("graphics/loading.png", 1, 0, Self) Next End Method 'summary:Load Game Images Method LoadSounds:Void() For Local ls:Int = 1 To 100 LoadSoundAsync("sounds/test.mp3", Self) Next End Method Method OnLoadImageComplete:Void(_image:Image, path:String, source:IAsyncEventSource) ImageList[Loader.totalImageLoaded] = _image Loader.totalLoaded += 1 Loader.totalImageLoaded += 1 Loader.text = "Images" 'Loader.progress = int( (float(Loader.totalLoaded) / float(Loader.totalToLoad)) * 100) End Method OnLoadSoundComplete:Void(_sound:Sound, path:String, source:IAsyncEventSource) SoundList[Loader.totalSoundLoaded] = _sound Loader.totalLoaded += 1 Loader.totalSoundLoaded += 1 Loader.text = "Sounds" 'Loader.progress = int( (float(Loader.totalLoaded) / float(Loader.totalToLoad)) * 100) End End Class MainScreen Extends Screen Field Face:Image Method New() name = "Main Screen" End Method Start:Void() diddyGame.screenFade.Start(50, False) Print "Starting" Self.Face = Loader.sprite End Method Render:Void() Cls If Not Loader.done = True DrawImageRect(Self.Face, Rnd(640), Rnd(480), 0, 39, 64, 64) Loader.Render() Else DrawImage(ImageList[1], 1, 1) End End Method Update:Void() If Not Loader.done Loader.Update() Else If KeyHit(KEY_SPACE) Then PlaySound(SoundList[1]) EndIf End End 'TODO ' Make the bar segment widths variable, to allow for things like the banana loading bar. ' animate the bar ? update rate an issue. Class cLoadingBar Field x:Int Field y:Int Field width:float Field height:float Field progress:float ' percent done. Field progressStep:float 'the width of 1% Field sprite:Image Field totalToLoad:int Field totalLoaded:int Field totalSoundLoaded:Int Field totalImageLoaded:Int Field done:Bool Field text:string Field blink:Int Method New(_x:Int, _y:int, _toload:int) Self.width = 500 Self.height = 20 Self.x = _x Self.y = _y Self.progress = 0 Self.sprite = LoadImage("graphics/loading_theme_02.png") Self.totalToLoad = _toload Self.totalLoaded = 0 Self.totalImageLoaded = 0 Self.totalSoundLoaded = 0 Self.done = False Self.progressStep = (float(Self.width) / float(Self.totalToLoad)) Self.blink = Millisecs() Self.text = "Loading" End Method Method Update:Void() UpdateAsyncEvents() If Self.totalLoaded >= Self.totalToLoad And Self.done = False Then Print "Done" Self.done = True End If End Method Method Render:Void() DrawText("Loaded : " + Loader.totalLoaded, 5, 0) DrawText("Total Assests : " + Loader.totalToLoad, 5, 20) 'draw the left side DrawImageRect(Self.sprite, Self.x - 11, Self.y, 0, 103, 11, 25) 'draw the mid bar For Local range:Int = 0 To Self.width - 1 DrawImageRect(Self.sprite, Self.x + range, Self.y, 11, 103, 1, 25) Next 'draw the right side DrawImageRect(Self.sprite, Self.x + Self.width, Self.y, 12, 103, 11, 25) 'draw the active left side DrawImageRect(Self.sprite, Self.x - 11, Self.y, 23, 103, 11, 25) 'Draw the loading progress. If ( (Self.totalLoaded * Self.progressStep) - 1) > Self.width For Local range:int = 0 To Self.width - 1 DrawImageRect(Self.sprite, Self.x + range, Self.y, 34, 103, 1, 25) Next Else For Local range:int = 0 To(Self.totalLoaded * Self.progressStep) - 1 DrawImageRect(Self.sprite, Self.x + range, Self.y, 34, 103, 1, 25) Next EndIf 'draw the active right side If Self.done Then DrawImageRect(Self.sprite, Self.x + Self.width, Self.y, 35, 103, 11, 25) 'draw the chat bubble DrawImageRect(Self.sprite, Self.x + Self.width - 100, Self.y - 40, 0, 0, 128, 39) 'use a better font :) DrawText(Self.text, Self.x + Self.width - 80, Self.y - 30) 'Draw logo / head with a possible blink (not sure the update rate is fast enough for this.) If Millisecs() -Self.blink > 1000 DrawImageRect(Self.sprite, Self.x + Self.width + 2, Self.y - 22, 0, 39, 64, 64) Else DrawImageRect(Self.sprite, Self.x + Self.width + 2, Self.y - 22, 64, 39, 64, 64) If Millisecs() -Self.blink > 1100 Self.blink = Millisecs() EndIf EndIf End Method End Class 'summary:Launch Point Function Main:Int() diddyGame = New MyGame() diddyGame.FPS = 60 Return 1 End |
| ||
I've just committed a very simple Loading Screen to Diddy, it doesnt use the new flash async loading but it should be good enough. Please let me know in the main Diddy thread. Usage: Class MyGame Extends DiddyApp Method Create:Void() gameScreen = New GameScreen LoadData() End Method LoadData:Void() ' inits the loadingscreen graphics and steps ' params: ' 1: image which will be displayed in the center of the screen ' 2: full loading bar image ' 3: empty loading bar image: ' 4: number of resources (steps) ' 5: X position of the loading bar (optional, if empty or -1 it will be centered) ' 6: Y position of the loading bar (optional, if empty or -1 it will be centered) diddyGame.loadingScreen.Init("graphics/loadingScreen.png", "graphics/loadingbar.png", "graphics/loadingbarempty.png", 4, -1, 400) diddyGame.loadingScreen.destination = gameScreen Start(diddyGame.loadingScreen) LoadImages() End Method LoadImages:Void() images.Load("Ship1.png") diddyGame.loadingScreen.loadingBar.Progress() images.Load("sprites.png") diddyGame.loadingScreen.loadingBar.Progress() images.Load("zombie_0.png") diddyGame.loadingScreen.loadingBar.Progress() images.Load("libgdx_sprites.png") diddyGame.loadingScreen.loadingBar.Progress() End End |
| ||
That's very cool therevills , hope you expand on it , integrating my code into diddy was my goal but if you have a better way then it's all cool by me. I was wondering , you mention async and flash but I think async loading works on almost all the targets not just flash. |
| ||
Sorry I didn't mean the target Flash, I meant it as a flashy feature :-) But I do have a concern about having a loading screen and a preloader for Flash, as this would mean two loading bars... |
| ||
I'v tested my above code on Flash and GLFW and it works a treat but on Html5 I guess it pre-loads before it advances, I didnt notice Flash doing that tho, unless its something Diddy does and iv just not noticed. |
| ||
I've started to implement an async loading screen of my own, and have come up with a few challenges. How I handle the asset loading out-of-order is by creating a StringMap<Int> containing the paths of the images I want to load, and the position I want them to load in an array (for example). When OnLoadImageComplete() is called, I simply look up the position by specifying path as the key. The bigger challenge I have is determining which files to load based on the format we've decided to store assets in inside the data folder. We've got sequentially-numbered atlases and associated metadata organized by folder. In a synchronous operation, determining how many of these we have to load per folder is easy -- just do a Repeat loop and attempt to load the asset until one comes back null. The problem is that doing this asynchronously and still having an idea of your total progress is a huge pain. Two choices are to either use LoadString() for the metadata part (and suffer hiccups as it's parsed synchronously, choking the loading bar thread), or load metadata async into a DataBuffer, waiting for each one to finish sequentially (though in their own thread), counting how many times you did that until one returns Null, and then using that number to give an accurate reading on how far you are from loading the rest (ie: images/sounds). The latter solution is also suboptimal because a nontrivial amount of time is spent loading metadata resources without being able to give any estimate on how long it's going to take. It's grossly convoluted, and as a result I've made a request thread for a cross-platform way to check which files exist before we attempt to load them. |