diff --git a/toybox/Sandbox/1/scripts/scene.cs b/toybox/Sandbox/1/scripts/scene.cs
index eadcc3bac..1d46b4a46 100644
--- a/toybox/Sandbox/1/scripts/scene.cs
+++ b/toybox/Sandbox/1/scripts/scene.cs
@@ -154,11 +154,24 @@ function setCustomScene( %scene )
setSceneToWindow();
}
-function SceneWindow::onExtentChange(%this)
+//-----------------------------------------------------------------------------
+// Match the camera's horizontal extent to the current window aspect ratio,
+// keeping the camera height fixed. This fires on every live window resize, and
+// is also re-applied after a toy loads/resets (see loadToy / RestartToyOverlay) --
+// toys set a fixed camera size in their reset(), which bakes in a specific
+// aspect, so without re-applying this the scene stretches when the toy is
+// reloaded/restarted on a window that has since been resized to another shape.
+//-----------------------------------------------------------------------------
+function SceneWindow::updateCameraAspect(%this)
{
%extent = Canvas.extent;
%aspect = %extent.x / %extent.y;
- %cam = SandboxWindow.getCameraSize();
+ %cam = %this.getCameraSize();
%cam.x = %cam.y * %aspect;
%this.setCameraSize(%cam);
}
+
+function SceneWindow::onExtentChange(%this)
+{
+ %this.updateCameraAspect();
+}
diff --git a/toybox/Sandbox/1/scripts/toolbox.cs b/toybox/Sandbox/1/scripts/toolbox.cs
index 2527a8e87..83e68d122 100644
--- a/toybox/Sandbox/1/scripts/toolbox.cs
+++ b/toybox/Sandbox/1/scripts/toolbox.cs
@@ -290,6 +290,10 @@ function toggleToolbox(%make)
// Reset the toy.
if ( Sandbox.ActiveToy.ScopeSet.isMethod("reset") )
Sandbox.ActiveToy.ScopeSet.reset();
+
+ // reset() re-applies the toy's fixed-aspect camera size, so re-fit it to the
+ // current window (otherwise restarting on a resized window stretches the scene).
+ SandboxWindow.updateCameraAspect();
}
//-----------------------------------------------------------------------------
diff --git a/toybox/Sandbox/1/scripts/toys.cs b/toybox/Sandbox/1/scripts/toys.cs
index b27ac53a9..403ae32c6 100644
--- a/toybox/Sandbox/1/scripts/toys.cs
+++ b/toybox/Sandbox/1/scripts/toys.cs
@@ -88,7 +88,12 @@ function loadToy( %moduleDefinition )
%moduleDefinition.ScopeSet.add( SandboxScene );
// Add toy scope-set as a listener.
- SandboxWindow.addInputListener( %moduleDefinition.ScopeSet );
+ SandboxWindow.addInputListener( %moduleDefinition.ScopeSet );
+
+ // The toy just set its own (fixed-aspect) camera size during load. Re-fit it
+ // to the current window so the scene isn't stretched when the toy is loaded
+ // into a window that's been resized away from the toy's intended ratio.
+ SandboxWindow.updateCameraAspect();
}
//-----------------------------------------------------------------------------
diff --git a/toybox/TruckToy/1/assets/animations/Impact_ExplosionAnimation.asset.taml b/toybox/TruckToy/1/assets/animations/Impact_ExplosionAnimation.asset.taml
new file mode 100644
index 000000000..a081e69ab
--- /dev/null
+++ b/toybox/TruckToy/1/assets/animations/Impact_ExplosionAnimation.asset.taml
@@ -0,0 +1,6 @@
+
diff --git a/toybox/TruckToy/1/assets/animations/Projectile_FireballAnim.asset.taml b/toybox/TruckToy/1/assets/animations/Projectile_FireballAnim.asset.taml
new file mode 100644
index 000000000..b7ba5f661
--- /dev/null
+++ b/toybox/TruckToy/1/assets/animations/Projectile_FireballAnim.asset.taml
@@ -0,0 +1,6 @@
+
diff --git a/toybox/TruckToy/1/assets/animations/Projectile_Meteor_StrikeAnimation.asset.taml b/toybox/TruckToy/1/assets/animations/Projectile_Meteor_StrikeAnimation.asset.taml
new file mode 100644
index 000000000..93dacce5c
--- /dev/null
+++ b/toybox/TruckToy/1/assets/animations/Projectile_Meteor_StrikeAnimation.asset.taml
@@ -0,0 +1,5 @@
+
diff --git a/toybox/TruckToy/1/assets/images/Impact_Explosion.png b/toybox/TruckToy/1/assets/images/Impact_Explosion.png
new file mode 100644
index 000000000..613971fcf
Binary files /dev/null and b/toybox/TruckToy/1/assets/images/Impact_Explosion.png differ
diff --git a/toybox/TruckToy/1/assets/images/Impact_ExplosionSprite.asset.taml b/toybox/TruckToy/1/assets/images/Impact_ExplosionSprite.asset.taml
new file mode 100644
index 000000000..0949bdeeb
--- /dev/null
+++ b/toybox/TruckToy/1/assets/images/Impact_ExplosionSprite.asset.taml
@@ -0,0 +1,7 @@
+
diff --git a/toybox/TruckToy/1/assets/images/Projectile_Fireball.png b/toybox/TruckToy/1/assets/images/Projectile_Fireball.png
new file mode 100644
index 000000000..50f3d9591
Binary files /dev/null and b/toybox/TruckToy/1/assets/images/Projectile_Fireball.png differ
diff --git a/toybox/TruckToy/1/assets/images/Projectile_FireballImage.asset.taml b/toybox/TruckToy/1/assets/images/Projectile_FireballImage.asset.taml
new file mode 100644
index 000000000..b7f5c9209
--- /dev/null
+++ b/toybox/TruckToy/1/assets/images/Projectile_FireballImage.asset.taml
@@ -0,0 +1,7 @@
+
diff --git a/toybox/TruckToy/1/assets/images/Projectile_Meteor_Strike.png b/toybox/TruckToy/1/assets/images/Projectile_Meteor_Strike.png
new file mode 100644
index 000000000..7dda9109d
Binary files /dev/null and b/toybox/TruckToy/1/assets/images/Projectile_Meteor_Strike.png differ
diff --git a/toybox/TruckToy/1/assets/images/Projectile_Meteor_StrikeSprite.asset.taml b/toybox/TruckToy/1/assets/images/Projectile_Meteor_StrikeSprite.asset.taml
new file mode 100644
index 000000000..3adefc0cb
--- /dev/null
+++ b/toybox/TruckToy/1/assets/images/Projectile_Meteor_StrikeSprite.asset.taml
@@ -0,0 +1,7 @@
+
diff --git a/toybox/TruckToy/1/assets/images/background_0.asset.taml b/toybox/TruckToy/1/assets/images/background_0.asset.taml
new file mode 100644
index 000000000..bdb81279a
--- /dev/null
+++ b/toybox/TruckToy/1/assets/images/background_0.asset.taml
@@ -0,0 +1,3 @@
+
diff --git a/toybox/TruckToy/1/assets/images/background_0.png b/toybox/TruckToy/1/assets/images/background_0.png
new file mode 100644
index 000000000..305857a21
Binary files /dev/null and b/toybox/TruckToy/1/assets/images/background_0.png differ
diff --git a/toybox/TruckToy/1/assets/images/background_1.asset.taml b/toybox/TruckToy/1/assets/images/background_1.asset.taml
new file mode 100644
index 000000000..a8ed407ac
--- /dev/null
+++ b/toybox/TruckToy/1/assets/images/background_1.asset.taml
@@ -0,0 +1,3 @@
+
diff --git a/toybox/TruckToy/1/assets/images/background_1.png b/toybox/TruckToy/1/assets/images/background_1.png
new file mode 100644
index 000000000..0eec8e464
Binary files /dev/null and b/toybox/TruckToy/1/assets/images/background_1.png differ
diff --git a/toybox/TruckToy/1/assets/images/background_2.asset.taml b/toybox/TruckToy/1/assets/images/background_2.asset.taml
new file mode 100644
index 000000000..27b46746d
--- /dev/null
+++ b/toybox/TruckToy/1/assets/images/background_2.asset.taml
@@ -0,0 +1,3 @@
+
diff --git a/toybox/TruckToy/1/assets/images/background_2.png b/toybox/TruckToy/1/assets/images/background_2.png
new file mode 100644
index 000000000..e398fc6c8
Binary files /dev/null and b/toybox/TruckToy/1/assets/images/background_2.png differ
diff --git a/toybox/TruckToy/1/assets/images/background_day.asset.taml b/toybox/TruckToy/1/assets/images/background_day.asset.taml
deleted file mode 100644
index d596ffdbb..000000000
--- a/toybox/TruckToy/1/assets/images/background_day.asset.taml
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/toybox/TruckToy/1/assets/images/background_day.png b/toybox/TruckToy/1/assets/images/background_day.png
deleted file mode 100644
index 317a08077..000000000
Binary files a/toybox/TruckToy/1/assets/images/background_day.png and /dev/null differ
diff --git a/toybox/TruckToy/1/assets/images/background_night.asset.taml b/toybox/TruckToy/1/assets/images/background_night.asset.taml
deleted file mode 100644
index 1ee0d2b18..000000000
--- a/toybox/TruckToy/1/assets/images/background_night.asset.taml
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/toybox/TruckToy/1/assets/images/background_night.png b/toybox/TruckToy/1/assets/images/background_night.png
deleted file mode 100644
index 119bbba01..000000000
Binary files a/toybox/TruckToy/1/assets/images/background_night.png and /dev/null differ
diff --git a/toybox/TruckToy/1/assets/images/background_nightStars.asset.taml b/toybox/TruckToy/1/assets/images/background_nightStars.asset.taml
deleted file mode 100644
index 4d7530913..000000000
--- a/toybox/TruckToy/1/assets/images/background_nightStars.asset.taml
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/toybox/TruckToy/1/assets/images/background_nightStars.png b/toybox/TruckToy/1/assets/images/background_nightStars.png
deleted file mode 100644
index 5bf3d37ab..000000000
Binary files a/toybox/TruckToy/1/assets/images/background_nightStars.png and /dev/null differ
diff --git a/toybox/TruckToy/1/assets/images/brickPile.png b/toybox/TruckToy/1/assets/images/brickPile.png
index efd20831d..6c01e9b40 100644
Binary files a/toybox/TruckToy/1/assets/images/brickPile.png and b/toybox/TruckToy/1/assets/images/brickPile.png differ
diff --git a/toybox/TruckToy/1/assets/images/brickWall_01.png b/toybox/TruckToy/1/assets/images/brickWall_01.png
index 69bc5805d..0d8c257f5 100644
Binary files a/toybox/TruckToy/1/assets/images/brickWall_01.png and b/toybox/TruckToy/1/assets/images/brickWall_01.png differ
diff --git a/toybox/TruckToy/1/assets/images/brickWall_02.png b/toybox/TruckToy/1/assets/images/brickWall_02.png
index 64c40d14b..628a56e9f 100644
Binary files a/toybox/TruckToy/1/assets/images/brickWall_02.png and b/toybox/TruckToy/1/assets/images/brickWall_02.png differ
diff --git a/toybox/TruckToy/1/assets/images/brokenCementWall.png b/toybox/TruckToy/1/assets/images/brokenCementWall.png
index efec214ef..c99ad394e 100644
Binary files a/toybox/TruckToy/1/assets/images/brokenCementWall.png and b/toybox/TruckToy/1/assets/images/brokenCementWall.png differ
diff --git a/toybox/TruckToy/1/assets/images/foregroundWall_01.png b/toybox/TruckToy/1/assets/images/foregroundWall_01.png
index e58f252a0..d1b73ef3f 100644
Binary files a/toybox/TruckToy/1/assets/images/foregroundWall_01.png and b/toybox/TruckToy/1/assets/images/foregroundWall_01.png differ
diff --git a/toybox/TruckToy/1/assets/images/foregroundWall_02.png b/toybox/TruckToy/1/assets/images/foregroundWall_02.png
index 57b12442d..08b66ac45 100644
Binary files a/toybox/TruckToy/1/assets/images/foregroundWall_02.png and b/toybox/TruckToy/1/assets/images/foregroundWall_02.png differ
diff --git a/toybox/TruckToy/1/assets/images/industrialBuildings.asset.taml b/toybox/TruckToy/1/assets/images/industrialBuildings.asset.taml
deleted file mode 100644
index eb4554991..000000000
--- a/toybox/TruckToy/1/assets/images/industrialBuildings.asset.taml
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/toybox/TruckToy/1/assets/images/industrialBuildings.png b/toybox/TruckToy/1/assets/images/industrialBuildings.png
deleted file mode 100644
index cf6489930..000000000
Binary files a/toybox/TruckToy/1/assets/images/industrialBuildings.png and /dev/null differ
diff --git a/toybox/TruckToy/1/assets/images/industrial_01.png b/toybox/TruckToy/1/assets/images/industrial_01.png
deleted file mode 100644
index d5c5d15c5..000000000
Binary files a/toybox/TruckToy/1/assets/images/industrial_01.png and /dev/null differ
diff --git a/toybox/TruckToy/1/assets/images/industrial_02.asset.taml b/toybox/TruckToy/1/assets/images/industrial_02.asset.taml
deleted file mode 100644
index 4949b7a73..000000000
--- a/toybox/TruckToy/1/assets/images/industrial_02.asset.taml
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/toybox/TruckToy/1/assets/images/industrial_02.png b/toybox/TruckToy/1/assets/images/industrial_02.png
deleted file mode 100644
index 312ab77ef..000000000
Binary files a/toybox/TruckToy/1/assets/images/industrial_02.png and /dev/null differ
diff --git a/toybox/TruckToy/1/assets/images/industrial_lowOpacity.asset.taml b/toybox/TruckToy/1/assets/images/industrial_lowOpacity.asset.taml
deleted file mode 100644
index c34d48d2c..000000000
--- a/toybox/TruckToy/1/assets/images/industrial_lowOpacity.asset.taml
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/toybox/TruckToy/1/assets/images/industrial_lowOpacity.png b/toybox/TruckToy/1/assets/images/industrial_lowOpacity.png
deleted file mode 100644
index 0006891aa..000000000
Binary files a/toybox/TruckToy/1/assets/images/industrial_lowOpacity.png and /dev/null differ
diff --git a/toybox/TruckToy/1/assets/images/motorPile.asset.taml b/toybox/TruckToy/1/assets/images/motorPile.asset.taml
deleted file mode 100644
index b2102c9d6..000000000
--- a/toybox/TruckToy/1/assets/images/motorPile.asset.taml
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/toybox/TruckToy/1/assets/images/motorPile.png b/toybox/TruckToy/1/assets/images/motorPile.png
deleted file mode 100644
index 9830f8223..000000000
Binary files a/toybox/TruckToy/1/assets/images/motorPile.png and /dev/null differ
diff --git a/toybox/TruckToy/1/assets/images/pileORocks.asset.taml b/toybox/TruckToy/1/assets/images/pileORocks.asset.taml
deleted file mode 100644
index 0940811c7..000000000
--- a/toybox/TruckToy/1/assets/images/pileORocks.asset.taml
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/toybox/TruckToy/1/assets/images/pileORocks.png b/toybox/TruckToy/1/assets/images/pileORocks.png
deleted file mode 100644
index 60b4c6b21..000000000
Binary files a/toybox/TruckToy/1/assets/images/pileORocks.png and /dev/null differ
diff --git a/toybox/TruckToy/1/assets/images/planetFloor.asset.taml b/toybox/TruckToy/1/assets/images/planetFloor.asset.taml
new file mode 100644
index 000000000..3a9ab4aeb
--- /dev/null
+++ b/toybox/TruckToy/1/assets/images/planetFloor.asset.taml
@@ -0,0 +1,3 @@
+
diff --git a/toybox/TruckToy/1/assets/images/planetFloor.png b/toybox/TruckToy/1/assets/images/planetFloor.png
new file mode 100644
index 000000000..84a82c259
Binary files /dev/null and b/toybox/TruckToy/1/assets/images/planetFloor.png differ
diff --git a/toybox/TruckToy/1/assets/images/plank_01.png b/toybox/TruckToy/1/assets/images/plank_01.png
index ed4282245..743033d05 100644
Binary files a/toybox/TruckToy/1/assets/images/plank_01.png and b/toybox/TruckToy/1/assets/images/plank_01.png differ
diff --git a/toybox/TruckToy/1/assets/images/plank_02.png b/toybox/TruckToy/1/assets/images/plank_02.png
index cb84619a2..099fe101e 100644
Binary files a/toybox/TruckToy/1/assets/images/plank_02.png and b/toybox/TruckToy/1/assets/images/plank_02.png differ
diff --git a/toybox/TruckToy/1/assets/images/plank_03.png b/toybox/TruckToy/1/assets/images/plank_03.png
index 6eb3953e1..d40b955cd 100644
Binary files a/toybox/TruckToy/1/assets/images/plank_03.png and b/toybox/TruckToy/1/assets/images/plank_03.png differ
diff --git a/toybox/TruckToy/1/assets/images/tires.asset.taml b/toybox/TruckToy/1/assets/images/tires.asset.taml
deleted file mode 100644
index 23ac3f47d..000000000
--- a/toybox/TruckToy/1/assets/images/tires.asset.taml
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/toybox/TruckToy/1/assets/images/tires.png b/toybox/TruckToy/1/assets/images/tires.png
deleted file mode 100644
index 13fcce905..000000000
Binary files a/toybox/TruckToy/1/assets/images/tires.png and /dev/null differ
diff --git a/toybox/TruckToy/1/assets/images/torqueBrick.asset.taml b/toybox/TruckToy/1/assets/images/torqueBrick.asset.taml
new file mode 100644
index 000000000..ac5b8494c
--- /dev/null
+++ b/toybox/TruckToy/1/assets/images/torqueBrick.asset.taml
@@ -0,0 +1,7 @@
+
diff --git a/toybox/TruckToy/1/assets/images/torqueBrick.png b/toybox/TruckToy/1/assets/images/torqueBrick.png
new file mode 100644
index 000000000..d88d7118d
Binary files /dev/null and b/toybox/TruckToy/1/assets/images/torqueBrick.png differ
diff --git a/toybox/TruckToy/1/assets/images/torqueBridge.asset.taml b/toybox/TruckToy/1/assets/images/torqueBridge.asset.taml
new file mode 100644
index 000000000..e89a05bc5
--- /dev/null
+++ b/toybox/TruckToy/1/assets/images/torqueBridge.asset.taml
@@ -0,0 +1,3 @@
+
diff --git a/toybox/TruckToy/1/assets/images/torqueBridge.png b/toybox/TruckToy/1/assets/images/torqueBridge.png
new file mode 100644
index 000000000..dbb0e1a81
Binary files /dev/null and b/toybox/TruckToy/1/assets/images/torqueBridge.png differ
diff --git a/toybox/TruckToy/1/assets/images/truckBody.png b/toybox/TruckToy/1/assets/images/truckBody.png
index 2bd8f56a8..41134a0cf 100644
Binary files a/toybox/TruckToy/1/assets/images/truckBody.png and b/toybox/TruckToy/1/assets/images/truckBody.png differ
diff --git a/toybox/TruckToy/1/assets/images/truckTire.asset.taml b/toybox/TruckToy/1/assets/images/truckTire.asset.taml
new file mode 100644
index 000000000..a7569eda2
--- /dev/null
+++ b/toybox/TruckToy/1/assets/images/truckTire.asset.taml
@@ -0,0 +1,3 @@
+
diff --git a/toybox/TruckToy/1/assets/images/truckTire.png b/toybox/TruckToy/1/assets/images/truckTire.png
new file mode 100644
index 000000000..5ab04fb2e
Binary files /dev/null and b/toybox/TruckToy/1/assets/images/truckTire.png differ
diff --git a/toybox/TruckToy/1/assets/images/woodPile.png b/toybox/TruckToy/1/assets/images/woodPile.png
index f65e42ac8..6697cc0ce 100644
Binary files a/toybox/TruckToy/1/assets/images/woodPile.png and b/toybox/TruckToy/1/assets/images/woodPile.png differ
diff --git a/toybox/TruckToy/1/assets/images/wreckedBuilding.png b/toybox/TruckToy/1/assets/images/wreckedBuilding.png
index 766b2aaec..468ba4b97 100644
Binary files a/toybox/TruckToy/1/assets/images/wreckedBuilding.png and b/toybox/TruckToy/1/assets/images/wreckedBuilding.png differ
diff --git a/toybox/TruckToy/1/assets/images/wreckedCar_01.png b/toybox/TruckToy/1/assets/images/wreckedCar_01.png
index fe21ba978..c3f8fafe0 100644
Binary files a/toybox/TruckToy/1/assets/images/wreckedCar_01.png and b/toybox/TruckToy/1/assets/images/wreckedCar_01.png differ
diff --git a/toybox/TruckToy/1/assets/images/wreckedCar_02.png b/toybox/TruckToy/1/assets/images/wreckedCar_02.png
index b1aaf4001..8cf06754f 100644
Binary files a/toybox/TruckToy/1/assets/images/wreckedCar_02.png and b/toybox/TruckToy/1/assets/images/wreckedCar_02.png differ
diff --git a/toybox/TruckToy/1/assets/images/wreckedCar_03.png b/toybox/TruckToy/1/assets/images/wreckedCar_03.png
index 39b2023bf..10002cc65 100644
Binary files a/toybox/TruckToy/1/assets/images/wreckedCar_03.png and b/toybox/TruckToy/1/assets/images/wreckedCar_03.png differ
diff --git a/toybox/TruckToy/1/assets/images/wreckedCar_hood.asset.taml b/toybox/TruckToy/1/assets/images/wreckedCar_hood.asset.taml
deleted file mode 100644
index d7651c880..000000000
--- a/toybox/TruckToy/1/assets/images/wreckedCar_hood.asset.taml
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/toybox/TruckToy/1/assets/images/wreckedCar_hood.png b/toybox/TruckToy/1/assets/images/wreckedCar_hood.png
deleted file mode 100644
index 1398d651e..000000000
Binary files a/toybox/TruckToy/1/assets/images/wreckedCar_hood.png and /dev/null differ
diff --git a/toybox/TruckToy/1/assets/particles/bonfire.asset.taml b/toybox/TruckToy/1/assets/particles/bonfire.asset.taml
new file mode 100644
index 000000000..93bc10f0d
--- /dev/null
+++ b/toybox/TruckToy/1/assets/particles/bonfire.asset.taml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/toybox/TruckToy/1/assets/particles/explosion.asset.taml b/toybox/TruckToy/1/assets/particles/explosion.asset.taml
new file mode 100644
index 000000000..0e6536678
--- /dev/null
+++ b/toybox/TruckToy/1/assets/particles/explosion.asset.taml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/toybox/TruckToy/1/main.cs b/toybox/TruckToy/1/main.cs
index 72cbd7060..61f3abf9f 100644
--- a/toybox/TruckToy/1/main.cs
+++ b/toybox/TruckToy/1/main.cs
@@ -22,6 +22,9 @@
function TruckToy::create( %this )
{
+ // Load the parallax background system (createBackground, layers, per-tick update).
+ exec("./scripts/background.cs");
+
TruckToy.ObstacleFriction = 1.5;
TruckToy.CameraWidth = 20;
TruckToy.CameraHeight = 15;
@@ -37,7 +40,7 @@
TruckToy.ProjectileDomain = 16;
TruckToy.ForegroundDomain = 10;
- TruckToy.WheelSpeed = 400;
+ TruckToy.WheelSpeed = 500;
TruckToy.WheelFriction = 1;
TruckToy.FrontWheelDensity = 6;
TruckToy.RearWheelDensity = 3;
@@ -46,7 +49,7 @@
TruckToy.ProjectileRate = 3000;
TruckToy.ExplosionScale = 1;
- TruckToy.RotateCamera = true;
+ TruckToy.RotateCamera = false;
// Add the custom controls.
addNumericOption( "Wheel Speed", 100, 1000, 50, "setWheelSpeed", TruckToy.WheelSpeed, false, "Sets the rotational speed of the wheel when it is put into drive." );
@@ -70,6 +73,9 @@
function TruckToy::destroy( %this )
{
+ // Stop the per-frame parallax update.
+ SandboxScene.RenderCallback = false;
+
// Deactivate the package.
deactivatePackage( TruckToyPackage );
}
@@ -109,7 +115,7 @@
%this.createBonfire( -91.5, TruckToy.FloorLevel + 0.5, 1, TruckToy.BackgroundDomain-1 );
// Building with chains.
- %this.createForegroundWall( 2, -99, -5 );
+ %this.createForegroundWall( 2, -97, -5 );
%this.createForegroundWall( 1, -75.5, -6.5 );
%this.createBrokenCementWall( -78, -1.5 );
%this.createWreckedBuilding( -71.5, -1 );
@@ -137,7 +143,7 @@
%this.createPlank( 1, -20.5, TruckToy.FloorLevel + 1.5, -90, true );
%this.createPlank( 3, -19, TruckToy.FloorLevel + 4, 0, true );
%this.createPlank( 1, -16.5, TruckToy.FloorLevel + 1.5, -90, true );
- %this.createForegroundBrickWall( 2, -19, -6 );
+ %this.createForegroundBrickWall( 2, -15, -6 );
%this.createBonfire( -46.5, TruckToy.FloorLevel, 3, TruckToy.BackgroundDomain-1 );
%this.createBonfire( -18.7, TruckToy.FloorLevel + 1, 2, TruckToy.BackgroundDomain-1 );
@@ -154,7 +160,7 @@
%this.createPyramid( 2, TruckToy.FloorLevel + 0.25, 19, true );
%this.createForegroundWall( 1, 9, -6 );
%this.createPyramid( 2+21, TruckToy.FloorLevel + 0.25, 13, true );
- %this.createForegroundBrickWall( 1, 9, -7 );
+ %this.createForegroundBrickWall( 1, 23, -6.5 );
%this.createBonfire( 21, TruckToy.FloorLevel, 3, TruckToy.BackgroundDomain-1 );
@@ -178,61 +184,50 @@
%truckStartY = 3;
%this.createTruck( %truckStartX, %truckStartY );
+ // Pre-build the projectile and explosion pools so none are allocated mid-play.
+ %this.createProjectilePool();
+ %this.createExplosionPool();
+
// Start the timer.
TruckToy.startTimer( "createProjectile", TruckToy.ProjectileRate );
}
// -----------------------------------------------------------------------------
-
-function TruckToy::createBackground(%this)
-{
- // Atmosphere
- %obj = new Sprite();
- %obj.setBodyType( "static" );
- %obj.setImage( "ToyAssets:highlightBackground" );
- %obj.BlendColor = DarkGray;
- %obj.setSize( TruckToy.WorldWidth * (TruckToy.CameraWidth*2), 75 );
- %obj.setSceneLayer( TruckToy.BackdropDomain );
- %obj.setSceneGroup( TruckToy.BackdropDomain );
- %obj.setCollisionSuppress();
- %obj.setAwake( false );
- %obj.setActive( false );
- SandboxScene.add( %obj );
-
-
- // Industrial Background
- %obj = new Scroller();
- %obj.setBodyType( "static" );
- %obj.setImage( "TruckToy:industrial_02" );
- %obj.setPosition( 0, -1 );
- %obj.setSize( TruckToy.WorldWidth, 8 );
- %obj.setRepeatX( TruckToy.WorldWidth / 8 );
- %obj.setSceneLayer( TruckToy.BackgroundDomain);
- %obj.setSceneGroup( TruckToy.BackgroundDomain);
- %obj.setCollisionSuppress();
- %obj.setAwake( false );
- %obj.setActive( false );
- SandboxScene.add( %obj );
-}
-
+// createBackground and the parallax layer system live in scripts/background.cs.
// -----------------------------------------------------------------------------
function TruckToy::createFloor(%this)
{
- // Ground
+ // Ground.
+ // planetFloor.png is 1233x163, but only the bottom 148px is solid ground;
+ // the top 15px is empty. We size/position the image and the collision edge
+ // so the *solid* surface sits exactly on FloorLevel (the empty strip just
+ // hangs transparently above it).
+ %imageW = 1233;
+ %imageH = 163;
+ %solidH = 148;
+
+ // Make the solid band ~3 world-units thick (matching the old floor), then
+ // derive the full image height and where the solid surface falls locally.
+ %solidThickness = 3;
+ %floorHeight = %solidThickness * (%imageH / %solidH); // full image height (~3.30)
+ %emptyTop = %floorHeight * ((%imageH - %solidH) / %imageH); // empty strip height (~0.30)
+ %solidTop = (%floorHeight / 2) - %emptyTop; // local Y of solid surface (~1.35)
+ %tileWidth = %floorHeight * (%imageW / %imageH); // unstretched tile width (~25)
+
%obj = new Scroller();
%obj.setBodyType( "static" );
- %obj.setImage( "ToyAssets:woodGround" );
- %obj.setSize( TruckToy.WorldWidth, 3 );
- %obj.setPosition( 0, TruckToy.FloorLevel - (%obj.getSizeY()/2) );
- %obj.setRepeatX( TruckToy.WorldWidth / 12 );
+ %obj.setImage( "TruckToy:planetFloor" );
+ %obj.setSize( TruckToy.WorldWidth, %floorHeight );
+ %obj.setPosition( 0, TruckToy.FloorLevel - %solidTop );
+ %obj.setRepeatX( TruckToy.WorldWidth / %tileWidth );
%obj.setSceneLayer( TruckToy.ObstacleDomain );
%obj.setSceneGroup( TruckToy.GroundDomain );
%obj.setDefaultFriction( TruckToy.ObstacleFriction );
%obj.setCollisionGroups( none );
- %obj.createEdgeCollisionShape( TruckToy.WorldWidth/-2, 1.5, TruckToy.WorldWidth/2, 1.5 );
- %obj.createEdgeCollisionShape( TruckToy.WorldWidth/-2, 3, TruckToy.WorldWidth/-2, 50 );
- %obj.createEdgeCollisionShape( TruckToy.WorldWidth/2, 3, TruckToy.WorldWidth/2, 50 );
+ %obj.createEdgeCollisionShape( TruckToy.WorldWidth/-2, %solidTop, TruckToy.WorldWidth/2, %solidTop );
+ %obj.createEdgeCollisionShape( TruckToy.WorldWidth/-2, %solidTop, TruckToy.WorldWidth/-2, 50 );
+ %obj.createEdgeCollisionShape( TruckToy.WorldWidth/2, %solidTop, TruckToy.WorldWidth/2, 50 );
%obj.CollisionCallback = true;
%obj.setAwake( false );
SandboxScene.add( %obj );
@@ -282,7 +277,7 @@
{
for ( %n = 0; %n < %brickCount; %n++ )
{
- %this.createBrick( getRandom(1,5), %posX, %posY + (%n*0.5), %static );
+ %this.createBrick( getRandom(0,15), %posX, %posY + (%n*0.5), %static );
}
}
@@ -303,7 +298,7 @@
%stackY = %posY + ( %stack * 0.5 );
for ( %stackIndex = 0; %stackIndex < %stackIndexCount; %stackIndex++ )
{
- %this.createBrick( getRandom(1, 5), %stackX + %stackIndex, %stackY, %static );
+ %this.createBrick( getRandom(0, 15), %stackX + %stackIndex, %stackY, %static );
}
}
}
@@ -319,7 +314,7 @@
%rootObj = new Sprite();
%rootObj.setBodyType( "static" );
- %rootObj.setImage( "ToyAssets:cable" );
+ %rootObj.setImage( "TruckToy:torqueBridge" );
%rootObj.setPosition( %posX, %posY );
%rootObj.setSize( %linkWidth, %linkHeight );
%rootObj.setSceneLayer( TruckToy.BackgroundDomain-3 );
@@ -333,7 +328,7 @@
{
%obj = new Sprite();
- %obj.setImage( "ToyAssets:cable" );
+ %obj.setImage( "TruckToy:torqueBridge" );
%obj.setPosition( %posX + (%n*%linkWidth), %posY );
%obj.setSize( %linkWidth, %linkHeight );
%obj.setSceneLayer( TruckToy.BackgroundDomain-3 );
@@ -471,6 +466,8 @@
%obj.setActive( false );
SandboxScene.add( %obj );
+ TruckToy.registerParallaxObject( %obj, 1.35 );
+
return %obj;
}
@@ -500,6 +497,9 @@
%obj.setActive( false );
SandboxScene.add( %obj );
+ // Foreground depth: scroll a bit faster than the world so they read as close.
+ TruckToy.registerParallaxObject( %obj, 1.22 );
+
return %obj;
}
@@ -507,17 +507,18 @@
function TruckToy::createBrick( %this, %brickNumber, %posX, %posY, %static )
{
- if ( %brickNumber < 1 || %brickNumber > 5 )
+ if ( %brickNumber < 0 || %brickNumber > 15 )
{
echo( "Invalid brick no of" SPC %brickNumber );
return;
}
- %image = "ToyAssets:brick_0" @ %brickNumber;
+ %image = "TruckToy:torqueBrick";
%obj = new Sprite();
if ( %static ) %obj.setBodyType( "static" );
%obj.setImage( %image );
+ %obj.setImageFrame(%brickNumber);
%obj.setPosition( %posX, %posY );
%obj.setSize( 1, 0.5 );
%obj.setSceneLayer( TruckToy.ObstacleDomain );
@@ -539,7 +540,7 @@
%obj.setBodyType( "static" );
%obj.setImage( "TruckToy:brickPile" );
%obj.setPosition( %posX, %posY );
- %obj.setSize( 4, 1 );
+ %obj.setSize( 2, 1 );
%obj.setSceneLayer( TruckToy.BackgroundDomain-3 );
%obj.setSceneGroup( TruckToy.BackgroundDomain);
%obj.setCollisionSuppress();
@@ -637,7 +638,7 @@
%particlePlayer.SetPosition( %x, %y );
%particlePlayer.SceneLayer = %layer;
%particlePlayer.ParticleInterpolation = true;
- %particlePlayer.Particle = "ToyAssets:bonfire";
+ %particlePlayer.Particle = "TruckToy:bonfire";
%particlePlayer.SizeScale = %scale;
%particlePlayer.CameraIdleDistance = TruckToy.CameraWidth * 0.8;
SandboxScene.add( %particlePlayer );
@@ -647,45 +648,140 @@
// -----------------------------------------------------------------------------
+function TruckToy::createProjectilePool(%this)
+{
+ // Pre-build a fixed pool of projectiles so none are created mid-play
+ // (a 'new Sprite()' during play causes a visible hitch). Each one is fully
+ // configured once here, then parked invisible + inactive until needed.
+ //
+ // Worst case airborne = ceil(Lifetime 2.5s / fastest spawn 0.1s) = 25,
+ // plus headroom -> 32. The fastest spawn (100ms) is the Projectile Rate
+ // slider minimum registered in create().
+ TruckToy.ProjectileLifetime = 2.5;
+ TruckToy.ProjectilePoolSize = 32;
+ TruckToy.ProjectilePoolIndex = 0;
+
+ for ( %i = 0; %i < TruckToy.ProjectilePoolSize; %i++ )
+ {
+ %projectile = new Sprite() { class = "TruckProjectile"; };
+ %projectile.Animation = "TruckToy:Projectile_FireballAnim";
+ %projectile.setSceneLayer( TruckToy.BackgroundDomain-2 );
+ %projectile.setSceneGroup( TruckToy.ProjectileDomain );
+ %projectile.FlipY = true;
+ %projectile.createCircleCollisionShape( 0.2 );
+ %projectile.setCollisionGroups( TruckToy.GroundDomain );
+ %projectile.CollisionCallback = true;
+
+ // Park it: no render, no physics, won't fall.
+ %projectile.setVisible( false );
+ %projectile.setActive( false );
+
+ SandboxScene.add( %projectile );
+ TruckToy.ProjectilePool[%i] = %projectile;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+function TruckToy::createExplosionPool(%this)
+{
+ // Pre-build a fixed pool of impact explosions. A ParticlePlayer is heavier
+ // to spin up than a Sprite (it binds the asset and builds emitter/particle
+ // pools), so creating one per impact is the main remaining hitch. We build
+ // them once and replay them instead.
+ //
+ // Uses TruckToy:explosion, a local copy of ToyAssets:ImpactExplosion with
+ // LifeMode="STOP" instead of "KILL" -- KILL would make each player
+ // safeDelete() itself after firing, which would empty the pool.
+ //
+ // Worst case airborne = ceil(Lifetime 1s / fastest spawn 0.1s) = 10,
+ // plus headroom -> 16.
+ TruckToy.ExplosionPoolSize = 16;
+ TruckToy.ExplosionPoolIndex = 0;
+
+ for ( %i = 0; %i < TruckToy.ExplosionPoolSize; %i++ )
+ {
+ %explosion = new ParticlePlayer();
+ %explosion.BodyType = static;
+ %explosion.Size = 10;
+ %explosion.SceneLayer = TruckToy.BackgroundDomain-1;
+ %explosion.ParticleInterpolation = true;
+ %explosion.Particle = "TruckToy:explosion";
+ SandboxScene.add( %explosion );
+
+ // Adding to the scene auto-plays the player, so stop it immediately
+ // (no wait, no kill) to park it ready for reuse.
+ %explosion.stop( false, false );
+
+ TruckToy.ExplosionPool[%i] = %explosion;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
function TruckToy::createProjectile(%this)
{
// Fetch the truck position.
%truckPositionX = TruckToy.TruckBody.Position.x;
- %projectile = new Sprite() { class = "TruckProjectile"; };
- %projectile.Animation = "ToyAssets:Projectile_FireballAnim";
+ // Take the next projectile from the pool (ring buffer).
+ %projectile = TruckToy.ProjectilePool[TruckToy.ProjectilePoolIndex];
+ TruckToy.ProjectilePoolIndex = (TruckToy.ProjectilePoolIndex + 1) % TruckToy.ProjectilePoolSize;
+
+ // Cancel any pending recycle left over from this sprite's previous use.
+ if ( isEventPending( %projectile.RecycleEvent ) )
+ cancel( %projectile.RecycleEvent );
+
+ // Reset physics state and reposition.
%projectile.setPosition( getRandom( %truckPositionX - (TruckToy.CameraWidth * 0.2), %truckPositionX + (TruckToy.CameraWidth * 0.5) ), 12 );
- %projectile.setSceneLayer( TruckToy.BackgroundDomain-2 );
- %projectile.setSceneGroup( TruckToy.ProjectileDomain );
- %projectile.FlipY = true;
+ %projectile.setLinearVelocity( 0, 0 );
+ %projectile.setAngularVelocity( 0 );
+ %projectile.setAngle( 0 );
%projectile.Size = getRandom(0.5, 2);
- %projectile.Lifetime = 2.5;
- %projectile.createCircleCollisionShape( 0.2 );
- %projectile.setCollisionGroups( TruckToy.GroundDomain );
- %projectile.CollisionCallback = true;
- SandboxScene.add( %projectile );
+
+ // Wake it up and (re)start the fireball animation.
+ %projectile.setActive( true );
+ %projectile.setVisible( true );
+ %projectile.setAwake( true );
+ %projectile.playAnimation( "TruckToy:Projectile_FireballAnim" );
+
+ // Recycle it if it misses everything (mirrors the old 2.5s Lifetime).
+ %projectile.RecycleEvent = %projectile.schedule( TruckToy.ProjectileLifetime * 1000, "recycle" );
+}
+
+// -----------------------------------------------------------------------------
+
+function TruckProjectile::recycle(%this)
+{
+ // Return the projectile to the pool: stop its pending recycle timer (if
+ // any), kill its momentum, then park it invisible + inactive for reuse.
+ if ( isEventPending( %this.RecycleEvent ) )
+ cancel( %this.RecycleEvent );
+ %this.RecycleEvent = "";
+
+ %this.setLinearVelocity( 0, 0 );
+ %this.setAngularVelocity( 0 );
+ %this.setActive( false );
+ %this.setVisible( false );
}
// -----------------------------------------------------------------------------
function TruckProjectile::onCollision(%this, %object, %collisionDetails)
{
- // Create an impact explosion at the projectiles position.
- %particlePlayer = new ParticlePlayer();
- %particlePlayer.BodyType = Static;
- %particlePlayer.Position = %this.Position;
- %particlePlayer.Size = 10;
- %particlePlayer.SceneLayer = TruckToy.BackgroundDomain-1;
- %particlePlayer.ParticleInterpolation = true;
- %particlePlayer.Particle = "ToyAssets:ImpactExplosion";
- %particlePlayer.SizeScale = getRandom(TruckToy.ExplosionScale, TruckToy.ExplosionScale * 1.5);
- SandboxScene.add( %particlePlayer );
+ // Replay an impact explosion from the pool at the projectile's position
+ // (ring buffer) -- no allocation during play.
+ %explosion = TruckToy.ExplosionPool[TruckToy.ExplosionPoolIndex];
+ TruckToy.ExplosionPoolIndex = (TruckToy.ExplosionPoolIndex + 1) % TruckToy.ExplosionPoolSize;
+ %explosion.setPosition( %this.Position );
+ %explosion.SizeScale = getRandom(TruckToy.ExplosionScale, TruckToy.ExplosionScale * 1.5);
+ %explosion.play( true );
// Start the camera shaking.
SandboxWindow.startCameraShake( 10 + (3 * TruckToy.ExplosionScale), 1 );
- // Delete the projectile.
- %this.safeDelete();
+ // Return the projectile to the pool (instead of deleting it).
+ %this.recycle();
}
// -----------------------------------------------------------------------------
@@ -729,7 +825,7 @@
// Rear tire.
%tireRear = new Sprite();
%tireRear.setPosition( %posX-1.4, %posY-1.0 );
- %tireRear.setImage( "ToyAssets:tires" );
+ %tireRear.setImage( "TruckToy:truckTire" );
%tireRear.setSize( 1.7, 1.7 );
%tireRear.setSceneLayer( TruckToy.TruckDomain-1 );
%tireRear.setSceneGroup( TruckToy.ObstacleDomain );
@@ -743,7 +839,7 @@
// Front tire.
%tireFront = new Sprite();
%tireFront.setPosition( %posX+1.7, %posY-1.0 );
- %tireFront.setImage( "ToyAssets:tires" );
+ %tireFront.setImage( "TruckToy:truckTire" );
%tireFront.setSize( 1.7, 1.7 );
%tireFront.setSceneLayer( TruckToy.TruckDomain-1 );
%tireFront.setSceneGroup( TruckToy.ObstacleDomain );
diff --git a/toybox/TruckToy/1/scripts/background.cs b/toybox/TruckToy/1/scripts/background.cs
new file mode 100644
index 000000000..111b96d99
--- /dev/null
+++ b/toybox/TruckToy/1/scripts/background.cs
@@ -0,0 +1,198 @@
+//-----------------------------------------------------------------------------
+// TruckToy parallax background.
+//
+// A small, data-driven parallax system. Each layer is a Scroller plus a parallax
+// "factor": 0 = pinned to the screen (a far backdrop), 1 = moves with the world
+// (foreground speed), values in between scroll proportionally.
+//
+// Every render frame each layer is cover-fit to the camera's visible size
+// (getCameraArea extent) and centred on the post-view-limit render position
+// (getCameraRenderPosition). The texture is then scrolled by centerX * factor,
+// so the parallax is camera-driven: it stops when the truck stops. We update per
+// render frame (RenderCallback) rather than per physics tick so the layers track
+// the interpolated camera smoothly instead of "ticking" between ticks.
+//
+// To add a layer: drop in art that tiles seamlessly left<->right (a factor-0
+// layer needn't tile) and add one createParallaxLayer() call below, far -> near.
+//-----------------------------------------------------------------------------
+
+function TruckToy::createBackground( %this )
+{
+ // Rebuild the registries from scratch (reset() clears the scene, so the old
+ // Scroller objects / decorations are already gone).
+ %this.ParallaxCount = 0;
+ %this.ParallaxObjCount = 0;
+
+ // Layers, ordered far -> near. %aspect must match the art's width:height so
+ // the fit-to-height sizing doesn't distort it (1024x512 -> 2.0, 1536x512 -> 3.0).
+ // Nearer layers use a higher factor and a lower scene layer (drawn in front).
+ // image factor aspect yOffFrac repeatX sceneLayer
+ %this.createParallaxLayer( "TruckToy:background_0", 0.05, 2.0, 0.0, 1, TruckToy.BackdropDomain );
+ %this.createParallaxLayer( "TruckToy:background_1", 0.12, 2.0, 0.0, 1, TruckToy.BackdropDomain - 1 );
+
+ // Ground band sitting on/above the floor, looping seamlessly in X. It's drawn
+ // BEHIND the floor, so anything below FloorLevel is hidden; bottomY slides it
+ // up/down, worldHeight sets its thickness. (Image 1232x130 -> aspect 9.48.)
+ // image factor worldHeight bottomY aspect sceneLayer
+ %this.createGroundLayer( "TruckToy:background_2", 0.30, 3.25, TruckToy.FloorLevel - 0.5, 9.48, TruckToy.BackdropDomain - 2 );
+
+ // Drive the layers every render frame via SandboxScene::onSceneRender (below).
+ // RenderCallback (a Scene field, not a method) fires per rendered frame, so the
+ // layers track the interpolated camera; UpdateCallback (per physics tick) made
+ // the sky "tick" back into place between ticks.
+ SandboxScene.RenderCallback = true;
+ %this.updateParallax();
+}
+
+//-----------------------------------------------------------------------------
+
+// %aspect = image width/height; width is derived from it when fitting the
+// image to the screen height, so a wrong value distorts the art.
+// %yOffFrac = vertical offset as a fraction of view height (0 = centred).
+function TruckToy::createParallaxLayer( %this, %image, %factor, %aspect, %yOffFrac, %repeatX, %sceneLayer )
+{
+ %layer = new Scroller();
+ %layer.setBodyType( "static" );
+ %layer.setImage( %image );
+ %layer.setRepeatX( %repeatX );
+ %layer.setSceneLayer( %sceneLayer );
+ %layer.setSceneGroup( TruckToy.BackdropDomain );
+ %layer.setCollisionSuppress();
+ SandboxScene.add( %layer );
+
+ // Register in the parallax table (sizing/positioning happens in updateParallax).
+ %i = %this.ParallaxCount;
+ %this.ParallaxLayer[%i] = %layer;
+ %this.ParallaxFactor[%i] = %factor;
+ %this.ParallaxAspect[%i] = %aspect;
+ %this.ParallaxYOffset[%i] = %yOffFrac;
+ %this.ParallaxMode[%i] = "screen";
+ %this.ParallaxCount = %i + 1;
+
+ return %layer;
+}
+
+//-----------------------------------------------------------------------------
+
+// A world-anchored, horizontally-tiling band (e.g. distant terrain near the
+// floor). Unlike the screen-fit layers it has an explicit world height and a
+// fixed world Y, and loops seamlessly in X -- so the art MUST tile left<->right.
+// %worldHeight = band height in world units; %bottomY = world Y of its bottom.
+function TruckToy::createGroundLayer( %this, %image, %factor, %worldHeight, %bottomY, %aspect, %sceneLayer )
+{
+ %layer = new Scroller();
+ %layer.setBodyType( "static" );
+ %layer.setImage( %image );
+ %layer.setSceneLayer( %sceneLayer );
+ %layer.setSceneGroup( TruckToy.BackdropDomain );
+ %layer.setCollisionSuppress();
+ SandboxScene.add( %layer );
+
+ // Register as a ground-mode layer (sizing/positioning happens in updateParallax).
+ %i = %this.ParallaxCount;
+ %this.ParallaxLayer[%i] = %layer;
+ %this.ParallaxFactor[%i] = %factor;
+ %this.ParallaxAspect[%i] = %aspect;
+ %this.ParallaxMode[%i] = "ground";
+ %this.ParallaxHeight[%i] = %worldHeight;
+ %this.ParallaxBottomY[%i] = %bottomY;
+ %this.ParallaxCount = %i + 1;
+
+ return %layer;
+}
+
+//-----------------------------------------------------------------------------
+
+// Make an already-placed object parallax. Its current X is captured as the
+// anchor; each frame it renders at f*anchorX + (1-f)*cameraX. f = 1 leaves it
+// world-fixed (no change), f < 1 drifts slower (reads further back), f > 1 moves
+// faster (reads closer). Only X is touched, so it still bobs with the world in Y.
+// Call this AFTER the object is positioned (end of a create* function, or right
+// after the create* call in reset()).
+function TruckToy::registerParallaxObject( %this, %obj, %factor )
+{
+ %i = %this.ParallaxObjCount;
+ %this.ParallaxObj[%i] = %obj;
+ %this.ParallaxObjAnchorX[%i] = getWord( %obj.getPosition(), 0 );
+ %this.ParallaxObjFactor[%i] = %factor;
+ %this.ParallaxObjCount = %i + 1;
+
+ return %obj;
+}
+
+//-----------------------------------------------------------------------------
+
+function TruckToy::updateParallax( %this )
+{
+ // View size comes from the camera area's extent (correct regardless of
+ // clamping). Screen-fit layers use the height; ground bands use the width.
+ %area = SandboxWindow.getCameraArea();
+ %viewW = getWord( %area, 2 ) - getWord( %area, 0 );
+ %viewH = getWord( %area, 3 ) - getWord( %area, 1 );
+
+ // The CENTRE must come from the render position: getCameraArea reports the
+ // area BEFORE the view limit is applied, so it diverges from what's actually
+ // drawn near the world edges. getCameraRenderPosition is post-limit (and
+ // there is no getCameraRenderArea, hence the split).
+ %render = SandboxWindow.getCameraRenderPosition();
+ %centerX = getWord( %render, 0 );
+ %centerY = getWord( %render, 1 );
+
+ for ( %i = 0; %i < %this.ParallaxCount; %i++ )
+ {
+ %layer = %this.ParallaxLayer[%i];
+ if ( !isObject( %layer ) )
+ continue;
+
+ if ( %this.ParallaxMode[%i] $= "ground" )
+ {
+ // World-anchored band: explicit world height at a fixed world Y, tiled
+ // and looping seamlessly in X. Follows the camera in X (so it always
+ // covers the view) but stays put in Y -- so it bobs with the world like
+ // the floor, while the texture scroll gives the horizontal parallax.
+ %h = %this.ParallaxHeight[%i];
+ %boxW = %viewW * 1.10; // cover the view width
+ %tileW = %h * %this.ParallaxAspect[%i]; // one tile at native aspect
+ %layer.setSize( %boxW, %h );
+ %layer.setRepeatX( %boxW / %tileW ); // tile across the box, no distortion
+ %layer.setPosition( %centerX, %this.ParallaxBottomY[%i] + (%h * 0.5) );
+ %layer.setScrollPositionX( %centerX * %this.ParallaxFactor[%i] );
+ }
+ else
+ {
+ // Screen-fit backdrop: full image height maps top-to-bottom, pinned to
+ // the screen vertically; slight overscan (~2% off top & bottom) hides
+ // camera shake / the 1-frame render lag. Width follows the image aspect
+ // so it's not distorted -- draw the art wider than the screen for scroll
+ // room (tile via repeatX if the edges are seamless).
+ %h = %viewH * 1.04;
+ %w = %h * %this.ParallaxAspect[%i];
+ %layer.setSize( %w, %h );
+ %layer.setPosition( %centerX, %centerY + ( %this.ParallaxYOffset[%i] * %viewH ) );
+ %layer.setScrollPositionX( %centerX * %this.ParallaxFactor[%i] );
+ }
+ }
+
+ // Parallax the registered decoration objects: render each at
+ // f*anchorX + (1-f)*cameraX (the layer model, applied to X only -- Y is left
+ // alone so they still bob with the world).
+ for ( %j = 0; %j < %this.ParallaxObjCount; %j++ )
+ {
+ %obj = %this.ParallaxObj[%j];
+ if ( !isObject( %obj ) )
+ continue;
+
+ %f = %this.ParallaxObjFactor[%j];
+ %obj.setPositionX( (%f * %this.ParallaxObjAnchorX[%j]) + ((1 - %f) * %centerX) );
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+// Per-frame scene hook. The scene fires this when RenderCallback is enabled
+// (set in createBackground). Guarded so it's harmless if another toy is loaded.
+function SandboxScene::onSceneRender( %this )
+{
+ if ( isObject( TruckToy ) && TruckToy.ParallaxCount > 0 )
+ TruckToy.updateParallax();
+}