Suggestions for creating a Standard Loading Screen

Monkey Archive Forums/Monkey Discussion/Suggestions for creating a Standard Loading Screen

Paul - Taiphoz(Posted 2013) [#1]
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.



Paul - Taiphoz(Posted 2013) [#2]
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 ..


Paul - Taiphoz(Posted 2013) [#3]
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



Paul - Taiphoz(Posted 2013) [#4]
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.


ElectricBoogaloo(Posted 2013) [#5]
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..


Paul - Taiphoz(Posted 2013) [#6]
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





therevills(Posted 2013) [#7]
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



Paul - Taiphoz(Posted 2013) [#8]
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.


therevills(Posted 2013) [#9]
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...


Paul - Taiphoz(Posted 2013) [#10]
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.


Nobuyuki(Posted 2014) [#11]
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.