Skip to content

t1k:unity:dots-rendering:perspective-2d-sideview

FieldValue
Moduledots-rendering
Version2.1.7
Efforthigh
Tools

Keywords: 2D, DOTS, perspective, side-view

/t1k:unity:dots-rendering:perspective-2d-sideview

  • Side-view, side-scrolling, 2.5D, Z-to-Y remap, parallax
  • SideViewTransformSystem, SideViewRestoreSystem, SideViewConfig, SideViewGameZ
  • Camera facing -Z, orthographic
  • Simulation: XZ plane (always). NavMesh, physics, AI all operate on XZ
  • Presentation: Camera looks along -Z. Visual Y = f(simulation Z). X is shared
  • CRITICAL: Visual transform must NEVER feed back to simulation. Save/restore is mandatory
  • Orthographic, position (0, 0, -100), rotation identity (facing +Z)
  • Pan X only (tracks battle center X). Y and Z are fixed
  • transparencySortAxis = (0, 0, 1) — higher Z renders behind lower Z
  • Auto-zoom via X extents: targetSize = (extentX + Padding) / aspect -> See references/sideview-navigation-guide.md
  • Same quad mesh + URP/Unlit cutout as 2D top-down (shared Quad2D asset)
  • Quads face -Z (toward camera) — use Unity default Quad primitive or custom mesh
  • Parallax backdrop: multiple layers at different Z depths with UV scrolling
  • Backdrop materials: transparent (not cutout) since they are static background, not DOTS entities -> See references/sideview-transform-guide.md

This is the most critical pattern for side-view. Without it, Z collapses exponentially.

  1. SideViewRestoreSystem — SimulationSystemGroup, OrderFirst = true

    • Restores canonical Z from SideViewGameZ.Value before any simulation
    • Resets Y to 0 (simulation ground plane)
    • Adds SideViewGameZ to newly spawned entities via ECB
  2. SideViewTransformSystem — PresentationSystemGroup

    • Saves canonical Z into SideViewGameZ.Value
    • Maps: Y = BaseY + Z * DepthScale
    • Spreads Z: Z *= DepthSpread (prevents depth-buffer fighting)
Frame start → RestoreSystem (Z = saved, Y = 0)
→ Navigation/Physics/AI (operate on canonical XZ)
→ All simulation systems
Frame end → TransformSystem (save Z, remap Y, spread Z)
→ Rendering sees visual positions
  • XZ NavMesh on invisible ground plane (MeshRenderer disabled)
  • Obstacles are invisible cubes with NavMeshObstacle.carving = true
  • Same NavigationAuthoring.EnableGrounding = false as 2D top-down
  • RangedAttackAuthoring.ArcHeight = 0, IsFlat = true -> See references/sideview-navigation-guide.md
  • Same SpriteAnimationAuthoring stack as 2D top-down
  • Side-profile character sprites (facing left/right)
  • DeathFadeSystem works identically
public struct SideViewConfig : IComponentData {
public float DepthScale; // Z→Y multiplier (0.3 = Z10 → Y3)
public float BaseY; // Ground line Y offset
public float DepthSpread; // Z spread to prevent Z-fighting (0.1)
}

Add via SideViewAuthoring MonoBehaviour in SubScene.

// Camera controller with parallax layers
public struct ParallaxLayer {
public Renderer Quad;
public float Factor; // 0.0 = static, 1.0 = full scroll
}
// On camera move: mat.mainTextureOffset.x += dx * Factor * 0.1f

Layers at increasing Z: Sky (50), Mountains (40), Trees (30), Ground (10).

#IssueFix
1Z-position feedback loop — Z *= 0.1 each frame → collapse to 0SideViewRestoreSystem must run OrderFirst in SimulationSystemGroup
2Projectiles/AoE invisible — missing SideViewGameZRestoreSystem adds SideViewGameZ to ALL entities with LocalTransform, not just GameEntityTag
3Depth-buffer Z-fighting between overlapping quadsDepthSpread multiplier separates Z positions for depth buffer
4NavMesh ground visible as edge-on planeSet MeshRenderer.enabled = false on ground
5Obstacles visible in side-viewSet MeshRenderer.enabled = false on obstacle cubes
  • dots-ecs — ECS fundamentals
  • dots-rpg — SideViewConfig, SideViewGameZ, SpriteAnimation components
  • dots-perspective-2d-topdown — Shared rendering patterns (cutout materials, quad mesh)
  • agents-navigation — Pathfinding on XZ plane
  • dots-graphics — MaterialProperty overrides
FileCoverage
references/sideview-transform-guide.mdSave/restore pattern, config, Z-fighting, system ordering
references/sideview-navigation-guide.mdXZ NavMesh with XY display, invisible ground, camera setup