Customize preloader html5 : different background image?

Hi,

I’m a bit confused as to how I’m supposed to customize the preloader (html5 target).
The only thing I want to do, is use a background image from the game, and maybe move the loading bar a bit up or down.
Is there an easy way to do this ?

1 Like

@loudo : Thank you for your help, but I don’t understand what you are saying … :thinking:
I’m quite happy with the default preloader ; I just want to add my own background image.
I think that’s not what you are talking about ?

Also, if I were to create my own Preloader class … Do I need to instantiate it somewhere, or is this taken care off by the entry in the project.xml ?

Try the “CustomPreloader” sample:

openfl create CustomPreloader
cd CustomPreloader
openfl test html5 -Dsimulate-preloader

Take a look at the included Preloader class as an example for making your own preloader, based on progress or complete events. You can skip the event.preventDefault in COMPLETE and your preloader will be unloaded automatically, or you can preventDefault and manually unload when you are ready

The problem I’m having with that, is that my preloader background image is loading inside the preloader (if that makes sense). I see a black rectangle in my browser, and a message ‘this asset is available, but only asynchronously’.

So, how do I get it to load before everything else ?
I’m going for something like this :

You should create custom class and extend preloader class

class CustomPreloader extends Preloader 

then

override public function onInit (e:Event):Void 
	{
		super.onInit(e);
		
		Assets.loadLibrary ("preloader").onComplete (function (_) {
		
		var bitmapData:BitmapData=null;
		
		#if html5
			bitmapData = Assets.getBitmapData("preloader:assets/preloader/logo.png");
		#end
		
		if (bitmapData == null)
			return;
			
		var logo = new Bitmap(bitmapData, PixelSnapping.AUTO, true);
		addChild(logo);
		logo.x = (Lib.current.stage.stageWidth / 2) - logo.width / 2;
		logo.y = (Lib.current.stage.stageHeight / 2) - logo.height / 2;
		
		progress = new Sprite ();
		progress.graphics.beginFill (0xFF0000);
		progress.graphics.drawRect (0, 0, logo.width, 20);
		addChild (progress);
		
		
		progress.x = logo.x;
		progress.y = logo.y+logo.height+10;
		progress.scaleX = 0;
});
		

	}

override public function onUpdate (e:ProgressEvent):Void 
	{
		super.onUpdate(e);
		
		if (progress == null)
			return;
		
		if(progresNum==0)
		{
			progress.scaleX = 0;
		}
		else
		{
			progress.scaleX = progresNum;
			//trace(progresNum,progress.scaleX);
		}
	}


and add some customisation in project.xml

<assets path="assets/preloader" library="preloader" />
<library name="preloader" id="preloader" embed="true" />

<app main="your main file" file="final name" preloader="com.something.CustomPreloader" path="bin" />

Sorry I’ve just copied/pasted an answer from a similar topic. In fact, I think my answer is partly wrong.
You should extend your own preloader from DefaultPreloader and not from Preloader.
Then you do like @gonzos suggests (but extending with DefaultPreloader).

1 Like

:confused:
Sorry, but then, how does this work ?

bitmapData = Assets.getBitmapData("preloader:assets/preloader/logo.png");

I created a folder ‘preloader’ under ‘assets’ and have an img called ‘logo.png’ in there.
I have this in my project.xml :

<assets path="assets/preloader" rename="preloader"/>
<library name="preloader" />
<app preloader="Preloader_FF"  />

In my custom preloader class, I have an onInit() that contains this :

bitmapData = Assets.getBitmapData("preloader:preloader/logo.png");

I’m still getting the console msg ‘this asset is available, but only asynchronously’ and a black rectangle on screen.

I really thought this would be easier to do …:sob:

You CAN do something like this:

Assets.loadBitmapData ("preloader/logo.png").onComplete (function (bitmapData) {
    var bitmap = new Bitmap (bitmapData);
    addChildAt (bitmap, 0);
});

…however, the above asset library solution is nice, because you can go from a preloader that uses only one asset to 100 assets, and still load all of your required preload assets at once. It also makes sure that you don’t load preloader assets twice (preloading the preload assets with the regular assets). It lets you do something like the above call, but for any preload-related assets

Assets.loadLibrary ("preloader").onComplete (function (_) {
    var bitmap = new Bitmap (Assets.getBitmapData ("preloader:logo.png"));
    addChildAt (bitmap, 0);
});

The “preloader:” prefix in the getBitmapData call from above specifies which asset library to request the asset from. By default (with no prefix) openfl.utils.Assets requests from the “default:” library

I probably would not set a “preloader” library to embed="true", though, because I am not sure that would be compatible with the Flash target (since embedded Flash assets are available, to my knowledge, only after preloading)

You can also do things like:

<assets path="preloader" embed="false" />
Assets.loadBitmapData ("preloader/logo.png").onComplete (...);

embed="false" tells asset system to copy the file, but not to preload it

Ok. It’s starting to become a bit clearer now …

Just one more thing : how do I create the preloader library ? Is it just right-clicking a folder under ‘assets’ >>> ‘add to library’ (I use HaxeDevelop), or do I do that from the command line ?

There is an optional “library” attribute in the <assets /> tag.

A tag without a “library” attribute will default to the “default” library. Thus, the following are the same :slight_smile:

<assets path="Assets" rename="assets" library="default" />
<assets path="Assets" rename="assets" />

Similarly, openfl.utils.Assets presumes “default:” as the asset prefix if you do not specify one, so these are also the same:

var bitmapData = Assets.getBitmapData ("default:logo.png");
var bitmapData = Assets.getBitmapData ("logo.png");

…just be careful that you do not include the same assets twice in multiple asset libraries. This can lead to loading the same assets twice, and generally is confusing :wink:

For example, this wouldn’t be ideal

<assets path="Assets" rename="assets" />
<assets path="Assets/preloader" rename="assets/preloader" library="preloader" />

…the “Assets/preloader” folder will be included in both libraries. For this sort of structure, you might use subdirectories, and include each one individually (or you could try to use filters). You do not have to use the “rename” attribute, but it does help in shortening/customizing the paths that exist in your final application

<assets path="Assets/images" rename="images" />
<assets path="Assets/sounds" rename="sounds" />
<assets path="Assets/preloader" rename="preloader" library="preloader" />

Success !!! :upside_down_face:

Thank you all for helping me out !

I will summarize what I did a bit further down, but first I would like to mention this to @singmajesty :
With the preloader, Firefox gives me an error message about 'texImage2D (fills up the entire console) ; Chrome does not.

Alright. The code.

  1. my asset folder looks like this :

assets_folder

  1. project.xml :
<!--preloader-->
<app preloader="Preloader_FF" />
		
<!-- assets -->
<icon path="assets/icon.png" />
<assets path="assets/preloader" rename="preloader" library="preloader" />
<assets path="assets/img" rename="img" />
<assets path="assets/sfx" rename="sfx" />
  1. Custom preloader class :

Since I had to override almost every function in the Preloader class that comes with the ‘CustomPreloader’ sample, I opted to not extend my own class from it, but just create it from scratch :

class Preloader_FF extends Sprite
{
	private var progress_fg:Sprite;
	private var w:Float = 0;
	private var h:Float = 0;
	private var TL_x:Float = 0;
	private var TL_y:Float = 0;

	public function new ()
	{
		super ();

		Assets.loadLibrary ("preloader").onComplete (function (_)
		{
			/*background img*/
			var bmd:BitmapData = null; 
                        #if html5   //without this check you get an error in Flash !
                        bmd = Assets.getBitmapData("preloader:preloader/bg.png");   //PATH !!!!!
                        #end
			if (bmd == null) return;

			var bm = new Bitmap(bmd, PixelSnapping.AUTO, true);
			addChild (bm);
			bm.x = (stage.stageWidth - bm.width) / 2;
			bm.y = (stage.stageHeight - bm.height) / 2;

			/*progress loader : background rect : brown*/
			var progress_bg:Sprite = new Sprite();     //CREATE NEW SPRITE (on top of bg img) !!!
			addChild(progress_bg);
			w = (256 / 800) * stage.stageWidth;
			h = (11 / 600) * stage.stageHeight;
			TL_x = (stage.stageWidth - w) / 2;
			TL_y = (279 / 600) * stage.stageHeight;

			progress_bg.graphics.lineStyle(1, 0xd6d1c3, 1);
			progress_bg.graphics.beginFill (0x2a1d1b);
			progress_bg.graphics.drawRoundRect (TL_x, TL_y, w, h, 8, 4);
			progress_bg.graphics.endFill();

			/*progress loader : foreground rect : white*/
			progress_fg = new Sprite();     //CREATE NEW SPRITE (op top of bg rect) !!!
			addChild(progress_fg);

			addEventListener (ProgressEvent.PROGRESS, this_onProgress);
			addEventListener (Event.COMPLETE, this_onComplete);
		});
	}
	
	private function update (percent:Float):Void
	{
		progress_fg.graphics.clear ();
		progress_fg.graphics.beginFill (0xd6d1c3);
		progress_fg.graphics.drawRoundRect (TL_x, TL_y, w*percent, h, 8, 4);
	}
	
	
/* *** EHs ************************************************************************************************************************* */
	

	private function this_onProgress (event:ProgressEvent):Void
	{
		if (event.bytesTotal <= 0) update (0);
		else update (event.bytesLoaded / event.bytesTotal);
	}

	private function this_onComplete (event:Event):Void
	{
		update (1);

		/*optional : unload at your own time ; if you comment this out : unload immediately*/
		event.preventDefault ();
		Timer.delay (function ()
		{
			dispatchEvent (new Event (Event.UNLOAD));
		}, 1000 /*2000*/);
	}
}

Two things that tripped me up :

  • The correct path for my preloader asset : Assets.getBitmapData(“preloader:preloader/bg.png”);
  • The fact that I needed to add sprites on top of the background image, so that the progress bar would be visible.
1 Like

I’ve tried a lot of different WebGL call combinations, but Firefox basically always gives a warning of some kind. I don’t think we need to worry about it :slight_smile:

Yep, I would recommend using “CustomPreloader” as a guide, but not using that Preloader class directly :slight_smile:

Thanks for sharing your final code!

1 Like

Just trying to get preloader image to work in my game and wonder if this works for HTML5?
Cause I see black screen, while it works fine elsewhere.

@:bitmap("assets/preload.jpg") class Back extends BitmapData {}

...

var bmpd:BitmapData = new Back(0, 0);
var back:Bitmap = new Bitmap(bmpd, PixelSnapping.AUTO, true);
addChild(back);

“embedded” images don’t preload on HTML5, there’s a delay before the bitmapData becomes available. I think there’s an onload callback parameter added on HTML5 right now:

#if html5
new Back (0, 0, function (bitmapData) {
    trace ("loaded");
});
#end

If this is available, you could use that to know just when the file is ready. Otherwise, I suggest using embed="false" on an asset, and BitmapData.loadFromFile ("assets/preload.jpg").onComplete (...) or using a separate preloader asset library, and loading that

1 Like

Actually, I was able to make embedded image work as expected in preloader by using “-Ddom” build option.
Is it ok, or this is some “undocumented” feature, that will go away eventually? :slight_smile:

1 Like

No, that should work. It sets the URL, and the browser loads it in when it is ready.

There is potentially an opportunity here to improve other targets, which used to wait until the BitmapData was valid, then started rendering it, but improvements to skipping rendering when nothing has changed may have affected this

Custom image is not working in latest version of OpenFL/Lime, I see black screen.
I have checked js code and couldn’t find any difference and image seems to load fine.
Any ideas? :slight_smile:

Do you have sample code you could share?

I’ve made a sample project, you can download it here: https://drive.google.com/open?id=1KCjQ8gY-a2ttuWX-SUlbaJFYCWpTXYBY

It has both sound test and preloader.
Thank you!