Nine complete scripts from the supplied guide: a camera test helper and eight runtime/API examples. Keep references to the environment you intend to control; there is no package singleton or HTTP/API-key setup.
Before using an example#
Create a matching .cs file under your own scripts folder, attach the component, then assign its Inspector references. Custom asmdefs need ERAGANX.Parallax2D; sample-specific classes also need Samples/UI/Input dependencies.
Namespaces are grouped by purpose: ERAGANX.Parallax2D.Core, .Runtime, .Layers, .Scrolling, .Environment, .Lighting and .Effects. Use the namespaces shown by each script. Setters sanitize values; keep direct fields finite. Calls do not automatically enable all controllers or create missing art/materials/bands.
1. Test camera movement#
Use GuideCameraMove.cs on Main Camera for the first depth exercise. Disable/remove it when your production follow system owns movement.
using UnityEngine;
public sealed class GuideCameraMove : MonoBehaviour
{
public Vector2 velocity = new Vector2(1f, 0f);
void LateUpdate()
{
transform.position +=
(Vector3)(velocity * Time.deltaTime);
}
}2. Create a runtime layer#
Use a fresh environment and assign Manager, renderedCamera and a tileable sprite. For an already authored layer, keep its existing reference instead of adding a duplicate.
using UnityEngine;
using ERAGANX.Parallax2D.Core;
using ERAGANX.Parallax2D.Runtime;
using ERAGANX.Parallax2D.Layers;
public sealed class GuideRuntimeLayers : MonoBehaviour
{
public Parallax2DManager manager;
public Camera renderedCamera;
public Sprite tileableSprite;
public Parallax2DQualityController quality;
private Parallax2DLayer hills;
void Start()
{
if (!manager || !renderedCamera || !tileableSprite)
return;
manager.SetCamera(renderedCamera);
hills = manager.AddLayer(tileableSprite,
"Runtime Hills", LayerPlacement.Background);
hills.SetSpeed(new Vector2(0.8f, 0.1f));
hills.sortingOrder = -80;
hills.SetLooping(LoopAxes.Horizontal);
hills.SetVisible(true);
if (quality) quality.Refresh();
}
public void ShowHills(bool show)
{
if (hills) hills.SetVisible(show);
}
public void RemoveHills()
{
if (manager && hills)
manager.RemoveLayer(hills, destroyObject: true);
hills = null;
if (quality) quality.Refresh();
}
}Download GuideRuntimeLayers.cs
AddLayer creates a child SpriteRenderer/Layer. RemoveLayer defaults to destroyObject: false, retaining the disabled/unregistered object; RefreshLayers can register it again. Explicit true destroys in Play Mode. Refresh quality after runtime structural changes.
3. Endless runner background#
Keep the rendered camera stationary and enable Horizontal looping on tileable backgrounds. Set Auto Scroll Multiplier zero for gameplay ground layers that must remain still.
using UnityEngine;
using ERAGANX.Parallax2D.Core;
using ERAGANX.Parallax2D.Runtime;
using ERAGANX.Parallax2D.Layers;
public sealed class GuideEndlessRunner : MonoBehaviour
{
public Parallax2DManager manager;
public Camera renderedCamera;
public Parallax2DLayer groundLayer;
public float runSpeed = 6f;
void Start()
{
if (!manager || !renderedCamera) return;
manager.SetCamera(renderedCamera);
manager.SetMotionMode(ParallaxMotionMode.AutoScroll);
manager.SetScrollVelocity(new Vector2(runSpeed, 0f));
manager.scrollPaused = false;
if (groundLayer) groundLayer.autoScrollMultiplier = 0f;
}
public void SetRunSpeed(float speed)
{
runSpeed = Mathf.Max(0f, speed);
if (manager)
manager.SetScrollVelocity(new Vector2(runSpeed, 0f));
}
public void SetScrollPaused(bool paused)
{
if (manager) manager.scrollPaused = paused;
}
}Download GuideEndlessRunner.cs
At run speed six and multiplier one, factors 0.85/0.65/0.30 drift -0.9/-2.1/-4.2 world units/s. Scroll pause is independent from camera/player pause.
4. Clock calls and events#
Assign Clock. Pair subscriptions/unsubscriptions and avoid logging every frequent hour update.
using UnityEngine;
using ERAGANX.Parallax2D.Environment;
public sealed class GuideClockEvents : MonoBehaviour
{
public Parallax2DTimeController clock;
public float DisplayHour { get; private set; }
void OnEnable()
{
if (!clock) return;
DisplayHour = clock.Hour;
clock.OnSunrise += HandleSunrise;
clock.OnNightStarted += HandleNight;
clock.OnTimeChanged += HandleTime;
}
void OnDisable()
{
if (!clock) return;
clock.OnSunrise -= HandleSunrise;
clock.OnNightStarted -= HandleNight;
clock.OnTimeChanged -= HandleTime;
}
void HandleSunrise() { Debug.Log("Sunrise"); }
void HandleNight() { Debug.Log("Night started"); }
void HandleTime(float hour) { DisplayHour = hour; }
public void SetNight()
{
if (!clock) return;
clock.automatic = false;
clock.SetTime(0f);
}
public void ResumeCycle()
{
if (!clock) return;
clock.automatic = true;
clock.Resume();
}
}Bind SetNight/ResumeCycle to UI Buttons. AdvanceHours(3) advances game hours; SetTime(savedHour, false) restores saved time without events.
5. Weather, lighting and effects#
Enable relevant sections and assign their resources in Edit Mode first. ApplyWeather only updates the Environment controller's assigned Wind/Fog/Cloud references; handle multiple independent effects explicitly.
using UnityEngine;
using ERAGANX.Parallax2D.Environment;
using ERAGANX.Parallax2D.Lighting;
using ERAGANX.Parallax2D.Effects;
public sealed class GuideAtmosphere : MonoBehaviour
{
public Parallax2DEnvironmentController environment;
public Parallax2DLightingController lighting;
public Parallax2DCloudController clouds;
public Parallax2DParticleController particles;
public Parallax2DCelestialController celestial;
public void SetStormMood()
{
if (environment)
environment.ApplyWeather(1.2f, 0.65f, 0.9f);
if (lighting)
{
lighting.SetSunlightIntensity(0.5f);
lighting.SetMoonlightIntensity(0.3f);
}
if (clouds) clouds.velocity = new Vector2(0.6f, 0f);
}
public void SetClearMood()
{
if (environment)
environment.ApplyWeather(0.25f, 0.1f, 0.3f);
if (lighting) lighting.SetSunlightIntensity(1f);
}
public void UseLeaves()
{
if (!particles) return;
particles.kind = AmbientParticleKind.Leaves;
particles.Configure();
particles.emissionRate = 5f;
}
public void ShowSunAndMoon(bool show)
{
if (celestial) celestial.SetVisible(show);
}
}Fog density and cloud opacity/velocity are public fields, not invented setter methods. For example, set fog.enabled = true, fog.density = 0.4f or clouds.opacity = 0.8f on valid references. Retune particle emission after Configure.
6. Apply and capture presets#
Create and assign the preset assets. Cancel an active transition before instant application, and coordinate external clock ownership.
using UnityEngine;
using ERAGANX.Parallax2D.Runtime;
using ERAGANX.Parallax2D.Layers;
public sealed class GuidePresets : MonoBehaviour
{
public Parallax2DManager manager;
public Parallax2DLayer selectedLayer;
public Parallax2DLayerPreset layerPreset;
public Parallax2DEnvironmentPreset environmentPreset;
public Parallax2DPreset compositePreset;
public Parallax2DQualityController quality;
private Parallax2DEnvironmentPreset sessionSnapshot;
public void ApplyLayer()
{
if (layerPreset && selectedLayer)
layerPreset.ApplyTo(selectedLayer);
}
public void ApplyEnvironment()
{
if (!environmentPreset || !manager) return;
environmentPreset.ApplyTo(manager,
createMissingLayers: false);
if (quality) quality.Refresh();
}
public void ApplyComposite()
{
if (compositePreset && manager)
compositePreset.ApplyTo(manager);
}
public void CaptureSession()
{
if (!manager) return;
if (!sessionSnapshot)
sessionSnapshot = ScriptableObject
.CreateInstance<Parallax2DEnvironmentPreset>();
sessionSnapshot.CaptureFrom(manager);
}
void OnDestroy()
{
if (sessionSnapshot) Destroy(sessionSnapshot);
}
}CaptureSession stores an in-memory ScriptableObject snapshot; it does not save an .asset file. Existing artwork is retained. Persistent capture requires Editor tooling.
7. Smooth environment transition#
Add Parallax2DTransition to the environment root, assign its Manager and prepare a matching Night Environment Preset. Assign the same Clock used by that Manager.
using UnityEngine;
using ERAGANX.Parallax2D.Runtime;
using ERAGANX.Parallax2D.Environment;
public sealed class GuideTransition : MonoBehaviour
{
public Parallax2DTransition transition;
public Parallax2DEnvironmentPreset nightPreset;
public Parallax2DTimeController clock;
private bool ownsClock;
private bool savedAutomatic;
public void BeginNight()
{
if (!transition || !nightPreset || !clock) return;
if (!ownsClock) savedAutomatic = clock.automatic;
ownsClock = true;
clock.automatic = false;
transition.TransitionTo(nightPreset, 3f,
applyDiscreteSettingsOnComplete: true);
}
void Update()
{
if (ownsClock &&
(!transition || !transition.IsTransitioning))
RestoreClock();
}
public void StopTransition()
{
if (transition) transition.Cancel();
RestoreClock();
}
void RestoreClock()
{
if (ownsClock && clock)
clock.automatic = savedAutomatic;
ownsClock = false;
}
void OnDisable()
{
if (ownsClock) StopTransition();
}
}BeginNight temporarily owns Automatic state, restoring it on completion/cancel/disable. Paused is controlled separately. See transition limits.
8. Quality, reset and camera switch#
Assign Manager/Quality and optional custom quality/alternate camera references.
using UnityEngine;
using ERAGANX.Parallax2D.Core;
using ERAGANX.Parallax2D.Runtime;
public sealed class GuideRuntimeControls : MonoBehaviour
{
public Parallax2DManager manager;
public Parallax2DQualityController quality;
public Parallax2DQualityPreset customQuality;
public Camera alternateCamera;
public void LowQuality()
{
if (quality) quality.SetQuality(QualityTier.Low);
}
public void HighQuality()
{
if (quality) quality.SetQuality(QualityTier.High);
}
public void ApplyCustomQuality()
{
if (!quality || !customQuality) return;
quality.customPreset = customQuality;
quality.Apply();
}
public void SwitchCamera()
{
if (manager && alternateCamera)
manager.SetCamera(alternateCamera,
preservePositions: true);
}
public void RebaseAfterOriginShift()
{
if (manager) manager.Rebaseline();
}
public void ResetLayerGeometry()
{
if (manager) manager.ResetEnvironment();
}
}Download GuideRuntimeControls.cs
ResetEnvironment resets layer geometry/drift and rebases to the current camera, not clock, presets, particles, player or save state. SetCamera does not enable/disable rendered cameras. For floating origin, shift camera/gameplay/environment together before Rebaseline; float coordinates have finite precision.
9. Custom camera movement source#
Supply an unshaken position while keeping the real rendered camera assigned for tile coverage.
using UnityEngine;
using ERAGANX.Parallax2D.Core;
public sealed class GuideCameraSource : MonoBehaviour,
IParallaxCameraSource
{
public Transform unshakenCameraTarget;
public Vector3 CameraPosition => unshakenCameraTarget
? unshakenCameraTarget.position
: transform.position;
}Assign the component under Camera Adapter > Advanced > Movement Source; keep Override Position off unless it should take priority. CameraFrame.Position drives parallax; ViewPosition is the real camera position.
Manager normally samples and advances/evaluates in LateUpdate at execution order 10000. If you deliberately use a manual driver, disable Manager's automatic LateUpdate and advance once after camera movement:
// In a manual LateUpdate driver; Manager automatic evaluation is disabled.
if (manager.cameraAdapter.TryGetFrame(Time.deltaTime, out var frame))
{
manager.AdvanceScroll(Time.deltaTime);
manager.Evaluate(frame);
}Default setups need no extra Evaluate/Tick/Advance calls. Duplicating normal lifecycle updates can advance time/drift twice. These examples reproduce the supplied guide; this website does not claim new compilation/player tests.