Delaying custom preloader from disappearing

Hi,

I’m setting up a Preloader on my openFL game, it works fine, but i would like, when the loader has complete, to delay the moment when the loader will be hidden and the main will be added to the stage, in order to play a nice tween to remove to loader (rather then suddenly seeing it disappear)

On my project.xml, i added

<app main="Main" file="xxx" path="bin" preloader="CPreloader" />

I’m using the following CPreloader class :

package;

import com.vinc.layout.LayoutManager;
import openfl.Assets;
import openfl.display.Bitmap;
import openfl.display.BitmapData;
import openfl.display.PixelSnapping;
import openfl.display.Sprite;
import openfl.events.Event;
import openfl.events.ProgressEvent;
import openfl.geom.Point;

@:keep class CPreloader extends Sprite {
	
	public function new () {
		super ();
		// loading events
		addEventListener(Event.ADDED_TO_STAGE, onInit);
		addEventListener(Event.COMPLETE, loaderInfo_onComplete);
		addEventListener(ProgressEvent.PROGRESS, loaderInfo_onUpdate);
	}
	
	public function onInit (e:Dynamic = null):Void {
		
		trace ("Preloader.init");
		initAssets();
	}
	
	public function loaderInfo_onComplete(e:Event):Void {
		trace("LOADING COMPLETE!");
	};
	
	public function onLoaded (e:Dynamic = null):Void {
		
		trace ("Preloader.loaded");
		var delay = 60;
		
		addEventListener (Event.ENTER_FRAME, function (_) {
			
			delay--;
			if (delay == 0) {
				trace ("delayed start");
				//dispatchEvent (new Event (Event.COMPLETE));
			}
		});
	}
	
	
	
	public function loaderInfo_onUpdate(e:ProgressEvent):Void {
		
		var bytesTotal:Float  = e.bytesTotal;
		var bytesLoaded:Float = e.bytesLoaded;
		var _progress:Float = bytesLoaded / bytesTotal;
		
		if (bytesTotal == 0) {
			setAssetProgress(0);
		} else {
			setAssetProgress(_progress);
		}
	}
	
	
	//_____________________________________________________________________
	
	function initAssets() 
	{
		var bg:Bitmap = createBitmap(new BackgroundBMPD(750, 1334));
		this.stage.addChildAt(bg, 0);
		bg.name = "bgloader";
		
		LayoutManager.init(null, new Point(Constants.GAME_WIDTH, Constants.GAME_HEIGHT), new Point(stage.stageWidth, stage.stageHeight));
		LayoutManager.resizeContainer(bg, 1, null);
		bg.x = stage.stageWidth * 0.5 - 750 * bg.scaleX * 0.5;
		bg.y = stage.stageHeight * 0.5 - 1334 * bg.scaleY * 0.5;
		
		var container:Sprite = new Sprite();
		addChild(container);
		
		var loader:Bitmap = createBitmap(new LoaderBMPD(366, 300));
		container.addChild(loader);
		
		loadersub = createBitmap(new LoaderSubBMPD(73, 18));
		container.addChild(loadersub);
		loadersub.x = 202; loadersub.y = 136;
		
		_mask = new Sprite();
		_mask.graphics.clear();
		_mask.graphics.beginFill();
		_mask.graphics.drawRect(0, 0, 73, 18);
		container.addChild(_mask);
		_mask.x = loadersub.x; _mask.y = loadersub.y;
		loadersub.mask = _mask;
		
		container.x = this.stage.stageWidth * 0.5 - 366 * 0.5 - 10;
		container.y = this.stage.stageHeight * 0.5 - 300 * 0.5;
	}
	
	private function setAssetProgress(_progress:Float):Void
	{
		var step:Int = Math.floor((_progress * 100) / 8);
		var step2:Int = step % 4;
		_mask.scaleX = step2 / 3;
	}
	
	
	private function createBitmap(_bmpd:BitmapData):Bitmap
	{
		return new Bitmap(_bmpd, PixelSnapping.AUTO, true);
	}
	
}

@:bitmap("assets/preload/bg.png") class BackgroundBMPD extends BitmapData {}
@:bitmap("assets/preload/asset-loader.png") class LoaderBMPD extends BitmapData {}
@:bitmap("assets/preload/asset-loader-point.png") class LoaderSubBMPD extends BitmapData {}

Thanks in advance

We designed the custom preloader system to dispatch ProgressEvent.PROGRESS during loading, then Event.COMPLETE when it is finished, and then the default behavior is automatically dispatch an Event.UNLOAD for your preloader immediately. That’s what you change :slight_smile:

Add an event.preventDefault () in your loaderInfo_onComplete method, and then your preloader will stay on screen unt8il you dispatch your own Event.UNLOAD event, after your animation is finished :slight_smile:

Ahhh, prevenDefault(), it crossed my mind but i didn’t go through this idea :slight_smile:

Thanks, it works !

1 Like

The solution above isn’t working for me.

package io.newgrounds.test;

import openfl.display.Sprite;
import openfl.display.Preloader;
import openfl.events.Event;

class TestPreloader extends Preloader {
	
	public function new() {
		
		var sprite = new Sprite();
		sprite.graphics.beginFill(0xFF0000);
		sprite.graphics.drawRect(50, 350, 700, 50);
		sprite.graphics.endFill();
		
		super(sprite);
	}
	
	override function loaderInfo_onComplete (event:Event):Void {
		//super.loaderInfo_onComplete(event);
		
		event.preventDefault();
	}
}

I’m expecting the loading screen to never disappear, but I only see it for 1 frame, if at all.

Make sure you…

1.) Add <app preloader="MyPreloader" /> to project.xml
2.) Create the MyPreloader class (or the name you choose)
3.) Make your class extend Sprite, and listen to Event.COMPLETE
4.) event.preventDefault () the event, and dispatch Event.UNLOAD when you’re done

This won’t work on HaxeFlixel, because those are very old versions of OpenFL, which use a different method (extend NMEPreloader, override onLoaded (), dispatch Event.COMPLETE when ready) (in case you are using Flixel)

Check

<app main="io.newgrounds.test.Main" path="bin" file="Newgrounds" preloader="io.newgrounds.test.TestPreloader" />

Check

Check
openfl 7.1.1

Hmm, so in my case I’m extending openfl.display.Preloader, which extends Sprite, and I’m overriding Preloader. loaderInfo_onComplete which is dispatched from a Event.COMPLETE event from Lib.current.loaderInfo… I’ll try something more like what vulkanosaure was doing, but it seems like my current approach checks all these boxes.

package io.newgrounds.test;

import openfl.display.Sprite;
import openfl.events.Event;
import openfl.events.ProgressEvent;

class TestPreloader extends Sprite {
	
	var _sprite:Sprite;
	
	public function new() {
		super();
		
		x += 50;
		graphics.beginFill(0xFF0000);
		graphics.drawRect(0, 350, 700, 50);
		graphics.endFill();
		
		addEventListener(Event.COMPLETE, onComplete);
		addEventListener(ProgressEvent.PROGRESS, onProgress);
	}
	
	function onProgress(e:ProgressEvent):Void {
		
		if (e.bytesTotal == 0)
			scaleX = 0;
		else if (e.bytesLoaded < e.bytesTotal)
			scaleX = e.bytesLoaded / e.bytesTotal;
		else
			scaleX = 1;
	}
	
	function onComplete(event:Event):Void {
		
		event.preventDefault();
		//cast (event.currentTarget, Sprite).dispatchEvent(new Event(Event.UNLOAD));
	}
}

This is working. The first difference that sticks out is that the listener is added to the sprite, where openfl.display.Preloader added listeners to loaderInfo… shrug.gif

Thanks for the help!

No problem! Sorry for the confusion, we maybe should move openfl.display.Preloader to somewhere private, or do something to distinguish it

I don’t think anything would have stopped me from finding and using it, if openfl’s preloader was well hidden I would have gone straight to lime’s. Another option is to make Preloader more extend friendly

Yeah, I thought about that too :slight_smile: