Keep all 2D levels and logic unchanged while enabling 3D/4D presentation via an optional spatializer. This matches the current Sphere behavior (projected 2D gameplay) and avoids forcing extra layers on 2D content.
BaseLevel subclasses (Standard/Clock/DarkMode/etc).LevelDataSO
LevelType = Standard | Clock | DarkMode | ...
Dimension = 2 | 3 | 4
BoundaryType = Rect | Circle | Custom | ...
The spatializer can validate boundary compatibility (e.g., Sphere expects Circle).
LevelType.Dimension > 2.Line.Pts each tick.You can treat each spatializer as a preset that includes:
This keeps the "optional spatializer" model while letting each spatializer compose small feature modules internally without exposing modifiers to 2D levels.
Move these from SphereLevel.cs into SphereSpatializer:
ProjectWorldToLocal, ProjectLocalToWorldUpdateDots, GetBackfaceHidePosUpdateLines, ApplyProjectedLinePtsUpdateRotation, HandleAxisInput, ShowAxisMessageEnsureEquatorLine, RefreshEquatorStyle, UpdateEquatorLine, ShowEquator/HideEquatorResetMenuPreview, tween handlingPrimeSphere, CacheDots, SyncLnsLine.Pts after connection (no change needed).LoadLevelVisuals
-> spawn boundary/dots/obstacles (unchanged)
-> rules = LevelFactory.Create(LevelType)
-> if Dimension > 2: spatializer = SpatializerFactory.Create(Dimension)
-> spatializer.Init(LevelMgr, LevelDataSO)
-> rules.Init(LevelMgr, LevelDataSO)
-> GameEvents.TriggerLevelLoaded
Update
-> rules.Tick(dt)
-> spatializer?.Tick(dt)
Connection
-> LevelMgr.CreateLine(...) adds Line with 2D pts
-> spatializer keeps Line.Pts updated (projected 2D)
-> EffectsFactory shows arrow using Line.Pts (unchanged)
Exit
-> spatializer?.Dispose()
-> rules.Dispose()
-> LevelMgr clears visuals (unchanged)