OpenRA Coordinate System - guidebee/OpenRA GitHub Wiki

General/OpenRA Coordinate System

OpenRA uses multiple coordinate systems to represent positions in the game world. This document explains the different coordinate types and how they relate to each other.

Coordinate Types

OpenRA has several coordinate types that serve different purposes:

1. World Position (WPos)

WPos represents a precise 3D position in the game world.

  • Components: X, Y, Z as integers
  • Units: The world is measured in "world units" (approximately 1/24th of a cell)
  • Usage: Used for exact positioning of units, buildings, and other game entities
  • Example: new WPos(1024, 2048, 0) represents a position at x=1024, y=2048, z=0

2. Cell Position (CPos)

CPos represents a cell on the game map grid, the fundamental unit of the map.

  • Components: X, Y coordinates and a Layer value
  • Storage: Packed into a 32-bit integer (12 bits for X, 12 bits for Y, 8 bits for Layer)
  • Range: X and Y can range from -2048 to 2047
  • Layer: Represents different map layers (0 is ground, other values for bridges, tunnels, etc.)
  • Example: new CPos(5, 10) represents the cell at x=5, y=10 on the ground layer

3. Map Position (MPos)

MPos represents a position in the map's internal coordinate system.

  • Components: U, V coordinates
  • Usage: Used for internal map operations and storage
  • Conversion: Can be converted to/from CPos using appropriate transformation

4. Projected Position (PPos)

PPos represents a projected map position.

  • Components: U, V coordinates
  • Usage: Used for projection operations, particularly for handling terrain height
  • Relationship: Closely related to MPos, but accounts for terrain elevation

Coordinate Transformations

Between CPos and MPos

For rectangular maps:

  • CPos(x,y) directly maps to MPos(u,v) where u=x and v=y

For isometric maps:

  • From CPos to MPos:

    u = (x - y) / 2
    v = x + y
    
  • From MPos to CPos:

    x = (v + 2u) / 2
    y = (v - 2u) / 2
    

    With special handling for odd v values

Between WPos and CPos

For rectangular maps:

  • From WPos to CPos:

    x = pos.X / 1024
    y = pos.Y / 1024
    
  • From CPos to WPos (center of cell):

    x = 1024 * cell.X + 512
    y = 1024 * cell.Y + 512
    z = height value for the cell
    

For isometric maps:

  • The transformations are more complex due to the isometric projection
  • Cell size along the diagonal is 724 units (512 * sqrt(2))

Grid Types

OpenRA supports two main grid types:

  1. Rectangular (MapGridType.Rectangular):

    • Traditional grid where cells are square
    • Cell size is 1024x1024 world units
    • Straightforward coordinate transformations
  2. Rectangular Isometric (MapGridType.RectangularIsometric):

    • Isometric grid where cells appear diamond-shaped
    • More complex coordinate transformations
    • Diagonal cell size is 1448 units (2 * 724)

Terrain Height

  • Terrain height is stored in a Height layer in the map
  • Height is measured in steps, where each step is 724 units (isometric) or 512 units (rectangular)
  • The Ramp layer in the map stores information about terrain slopes

Screen Projection

The WorldRenderer class handles projection from world coordinates to screen coordinates:

  • ScreenPosition(WPos): Converts a world position to screen coordinates
  • ProjectedPosition(int2): Converts screen coordinates to a world position

Practical Usage

When working with the OpenRA coordinate system:

  1. Use the appropriate coordinate type for your use case:

    • WPos for precise world positioning
    • CPos for cell-based operations
    • MPos/PPos for map operations
  2. Use the provided conversion methods when transitioning between coordinate types

  3. Be aware of the grid type (rectangular vs. isometric) as it affects coordinate transformations

  4. When dealing with terrain height, remember that it affects the Z component of world positions

Example Conversions

// Get the center of a cell
WPos cellCenter = map.CenterOfCell(new CPos(10, 15));

// Find the cell containing a world position
CPos cell = map.CellContaining(new WPos(5120, 7680, 0));

// Convert between CPos and MPos
MPos mapPos = cell.ToMPos(map.Grid.Type);
CPos cellPos = mapPos.ToCPos(map.Grid.Type);

Conclusion

OpenRA's coordinate system is designed to efficiently handle both rectangular and isometric game maps while supporting features like terrain height, multiple map layers, and proper screen projection. Understanding the different coordinate types and their relationships is essential for modding and development work with the OpenRA engine.