Sphere Level Placement Notes
These notes explain how dot placement works in sphere levels and how to author the (x,y) values in level assets to control when backface dots appear.
How sphere placement works
- The level asset stores only 2D positions (
Pos: {x, y}).
SphereLevel projects each 2D point onto a sphere of radius BoundarySize.x * 0.5:
z = sqrt(radius^2 - (x^2 + y^2)) (always positive).
- For each pair, the dot with the higher
Id is flipped to the back hemisphere by negating z.
- Visibility is based on current depth (
z >= 0 is front, z < 0 is back). There is no per-pair visibility check.
Placement levers
- Radius (
sqrt(x^2 + y^2)) controls how much rotation is needed:
- Near the rim (close to the boundary radius) => small
z => backface dots appear with small rotation.
- Near the center => large
z => requires larger rotation for backface dots to appear.
- Angle (
atan2(y, x)) controls where dots appear around the circle.
- Large angular separation between paired dots makes them feel opposite around the rim.
- Smaller angular separation makes a pair feel closer together even though one is still on the backface.
Authoring guidelines
- Keep pairs on opposite hemispheres via Id ordering (higher Id becomes backface automatically).
- To reduce rotation needed for backface dots, place dots nearer the rim (radius ~ 0.95 * boundary radius).
- To increase rotation needed, place dots closer to center.
- Spread angles to avoid overlap while keeping paired dots at whatever angular separation you want.
Quick checks
- Boundary radius:
BoundarySize.x / 2 (sphere levels expect a circle boundary).
- Desired rim radius: ~
0.95 * BoundaryRadius.
- If two dots overlap visually, adjust their angles while keeping radius near the rim.
- Responsive clamp gotcha: runtime responsive layout clamps dots to
BoundaryRadius - (DotRadius + DotBoundaryPadding) on level load.
- If authored radius is above that clamp radius, menu can show clamped positions and
gameplay can appear to "jump" when sphere projection updates.
- Safe rule: keep every authored dot within
sqrt(x^2 + y^2) <= BoundaryRadius - (DotRadius + DotBoundaryPadding).