diff --git a/CHANGELOG.md b/CHANGELOG.md
index d829d138..90b4a460 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -26,6 +26,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Fixed
+- Fixed issue where the initial scene onPreLoad was not being run
- Fixed unecessary coupling with `ex.ColliderComponent`/`ex.BodyComponent` that prevented collider tracking on entities that have `ex.TransformComponent`/`ex.ColliderComponent`, this influenced users doing Entity level ECS with pointer events.
- Fixed issue where passing 0 to `ex.Sound.play(0)` would not set the volume to 0, instead the previous volume would play.
- Fixed issue where the Actor.color did not respect being set
diff --git a/sandbox/tests/onpreload/index.html b/sandbox/tests/onpreload/index.html
new file mode 100644
index 00000000..6ad9a3b0
--- /dev/null
+++ b/sandbox/tests/onpreload/index.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+ Scene onPreload
+
+
+ Console should read
+ Pre loading empty scene
+ Initializing empty scene
+ Pre loading empty scene
+ Initializing empty scene
+
+
+
diff --git a/sandbox/tests/onpreload/index.ts b/sandbox/tests/onpreload/index.ts
new file mode 100644
index 00000000..b9541d99
--- /dev/null
+++ b/sandbox/tests/onpreload/index.ts
@@ -0,0 +1,40 @@
+export function delay(milliseconds: number, clock?: ex.Clock): Promise {
+ const future = new ex.Future();
+ const schedule = clock?.schedule.bind(clock) ?? setTimeout;
+ schedule(() => {
+ future.resolve();
+ }, milliseconds);
+ return future.promise;
+}
+
+class EmptyScene extends ex.Scene {
+ constructor(public name: string) {
+ super();
+ }
+ override onInitialize(engine: ex.Engine): void {
+ console.log(`Initializing ${this.name} scene`);
+
+ setTimeout(() => {
+ engine.goToScene('level2');
+ }, 5000);
+ }
+
+ override onPreLoad(loader: ex.DefaultLoader): void {
+ console.log(`Pre loading ${this.name} scene`);
+ const image = new ex.ImageSource('https://cdn.rawgit.com/excaliburjs/Excalibur/7dd48128/assets/sword.png');
+ loader.addResource(image);
+ }
+}
+
+const game = new ex.Engine({
+ width: 800,
+ height: 600,
+ scenes: {
+ start: EmptyScene,
+ level2: EmptyScene
+ //start: new EmptyScene('start'),
+ //level2: new EmptyScene('level2'),
+ }
+});
+
+game.start('start');
diff --git a/src/engine/Director/Director.ts b/src/engine/Director/Director.ts
index b52befd4..6f9b6e5b 100644
--- a/src/engine/Director/Director.ts
+++ b/src/engine/Director/Director.ts
@@ -188,6 +188,10 @@ export class Director {
if (deferredSceneInstance && deferredTransition) {
deferredTransition._addToTargetScene(this._engine, deferredSceneInstance);
}
+
+ const inTransition = this._getInTransition(deferredScene);
+ const hideLoader = inTransition?.hideLoader;
+ this.maybeLoadScene(deferredScene, hideLoader);
await this.swapScene(deferredScene);
if (deferredSceneInstance && deferredTransition) {
await this.playTransition(deferredTransition, deferredSceneInstance);
@@ -228,13 +232,16 @@ export class Director {
this.startScene = startScene;
+ const maybeHideLoader = options?.inTransition?.hideLoader ?? false;
+ this.maybeLoadScene(startScene, maybeHideLoader);
+
// Fire and forget promise for the initial scene
if (maybeStartTransition) {
- const startSceneInstance = this.getSceneInstance(this.startScene);
+ const startSceneInstance = this.getSceneInstance(startScene);
if (startSceneInstance) {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
maybeStartTransition._addToTargetScene(this._engine, startSceneInstance);
- this.swapScene(this.startScene).then(() => {
+ this.swapScene(startScene).then(() => {
startSceneInstance.onTransition('in');
// eslint-disable-next-line @typescript-eslint/no-floating-promises
return this.playTransition(maybeStartTransition, startSceneInstance);
@@ -242,7 +249,7 @@ export class Director {
}
} else {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
- this.swapScene(this.startScene);
+ this.swapScene(startScene);
}
this.currentSceneName = this.startScene;
@@ -558,6 +565,8 @@ export class Director {
/**
* Swaps the current and destination scene after performing required lifecycle events
+ *
+ * Note: swap scene will wait for any pending loader on the destination scene
* @param destinationScene
* @param data
*/
diff --git a/src/engine/Scene.ts b/src/engine/Scene.ts
index e1d87754..cfea6f00 100644
--- a/src/engine/Scene.ts
+++ b/src/engine/Scene.ts
@@ -88,6 +88,17 @@ export function isSceneConstructor(x: any): x is SceneConstructor {
* actors in a scene. Only actors in scenes will be updated and drawn.
*
* Typical usages of a scene include: levels, menus, loading screens, etc.
+ *
+ * Scenes go through the following lifecycle
+ * 1. onPreLoad - called once
+ * 2. onInitialize - called once
+ * 3. onActivate - called the first frame the scene is current
+ * 4. onPreUpdate - called every update
+ * 5. onPostUpdate - called every update
+ * 6. onPreDraw - called every draw
+ * 7. onPostDraw - called every draw
+ * 8. onDeactivate - called teh first frame thescene is no longer current
+ *
*/
export class Scene implements CanInitialize, CanActivate, CanDeactivate, CanUpdate, CanDraw {
private _logger: Logger = Logger.getInstance();