Skip to content

Game.CinemachineRestrictToTerrain

Assembly: Assembly-CSharp
Namespace: Game

Type: class

Base: CinemachineExtension

Summary:
CinemachineRestrictToTerrain is a Cinemachine extension that keeps a Cinemachine virtual camera above the terrain (and water surface) and optionally inside the map bounds. It also integrates with the game's camera collision system to avoid intersecting scene objects. The component reads Terrain and Water data from the game's ECS systems and uses CameraCollisionSystem to adjust the camera position when object collisions are enabled.


Fields

  • public float m_MapSurfacePadding = 1f
    Adds vertical padding (meters) above the sampled terrain/water surface. The camera's Y is clamped to at least (surface height + m_MapSurfacePadding).

  • public bool m_RestrictToMapArea = true
    When true, positions are clamped to the map bounds (or editor camera bounds in editor mode) before sampling heights.

  • private CameraCollisionSystem m_CollisionSystem
    Reference to the game's CameraCollisionSystem (resolved in Start). Used to query collisions and obtain a collision-adjusted camera position.

  • private CameraUpdateSystem m_CameraSystem
    Reference to CameraUpdateSystem (resolved in Start). Used to access the active Camera (near clip plane, FOV, aspect).

  • private TerrainSystem m_TerrainSystem
    Reference to TerrainSystem (resolved in Start). Used to obtain TerrainHeightData for sampling terrain heights and bounds.

  • private WaterSystem m_WaterSystem
    Reference to WaterSystem (resolved in Start). Used to get water surface data (if loaded) to sample water height.

Properties

  • public bool enableObjectCollisions { get; set; } = true
    Enable/disable collision checks against scene objects. When true, PostPipelineStageCallback calls CheckForCollision to let CameraCollisionSystem adjust the camera position to avoid geometry.

  • public Vector3 previousPosition { get; set; }
    Stores the camera position from the last Refresh() call. Used as the "last position" passed to collision checks (to help sweep tests between previous and current positions).

Constructors

  • public CinemachineRestrictToTerrain()
    No explicit constructor is defined in the class; the component uses the default MonoBehaviour construction/initialization semantics. Initialization of system references happens in Start().

Methods

  • protected void Start()
    Resolves and caches references to world systems via World.DefaultGameObjectInjectionWorld.GetOrCreateSystemManaged:
  • CameraCollisionSystem
  • CameraUpdateSystem
  • TerrainSystem
  • WaterSystem These systems are later used for height sampling, bounds clamping and collision checking.

  • public void Refresh()
    Stores the current transform.position into previousPosition. Call this when you want to reset the collision sweep origin (for example after teleporting the camera) to avoid large unwanted sweeps.

  • protected override void PostPipelineStageCallback(CinemachineVirtualCameraBase vcam, CinemachineCore.Stage stage, ref CameraState state, float deltaTime)
    Called by Cinemachine during camera pipeline stages. This implementation acts only during the Body stage:

  • Calls ClampToTerrain(state.RawPosition, m_RestrictToMapArea, out terrainHeight) to clamp to bounds and ensure camera is above terrain/water plus padding.
  • If enableObjectCollisions is true, calls CheckForCollision with the clamped position and previousPosition; if a collision-adjusted position is returned, it replaces state.RawPosition. This is the main integration point with Cinemachine: it adjusts the raw camera position produced by Cinemachine before it is applied.

  • public bool CheckForCollision(Vector3 currentPosition, Vector3 lastPosition, Quaternion rotation, out Vector3 position)
    Performs object collision checks via CameraCollisionSystem.CheckCollisions, returning an adjusted position:

  • Requires m_CollisionSystem and m_CameraSystem (and activeCamera) to be present; otherwise returns false and sets position = Vector3.zero.
  • Computes near clip plane and an fov float2 where y is vertical FOV and x is horizontal FOV (using Camera.VerticalToHorizontalFieldOfView).
  • Calls m_CollisionSystem.CheckCollisions with parameters:
    • ref position (current)
    • last position
    • rotation
    • max distances and tolerances (hard-coded values seen in the code: 200f, 200f, nearClipPlane * 2f + 1f, nearClipPlane, 0.001f)
    • the computed fieldOfView
  • On success, returns true and outputs the potentially modified position from the collision system.

  • public Vector3 ClampToTerrain(Vector3 position, bool restrictToMapArea, out float terrainHeight)
    Clamps/adjusts a world position so the camera remains within map bounds and above terrain/water:

  • Obtains TerrainHeightData from m_TerrainSystem. If not created, terrainHeight stays 0 and the position is returned unchanged.
  • If restrictToMapArea is true:
    • Uses TerrainUtils.GetBounds(ref data) or TerrainUtils.GetEditorCameraBounds(...) when in editor mode to compute bounds.
    • The bounds' max Y is adjusted to be at least min.y + max(height, 4096f) before clamping; then position is clamped into those bounds.
  • If WaterSystem is loaded:
    • Obtains WaterSurfaceData from m_WaterSystem.GetSurfaceData(out deps) and Complete()s the returned JobHandle.
    • If created, samples water surface height via WaterUtils.SampleHeight(ref data2, ref data, position). Otherwise samples terrain height via TerrainUtils.SampleHeight(ref data, position).
  • Sets position.y = Max(position.y, terrainHeight + m_MapSurfacePadding) and returns the clamped/adjusted position.
  • Outputs the sampled terrainHeight (or water height) via the out parameter.

Usage Example

// Attach this component to a Cinemachine Virtual Camera gameObject (it inherits CinemachineExtension).
// Example: call Refresh() when you teleport the camera to avoid large collision sweeps.

public class MyCameraController : MonoBehaviour
{
    public CinemachineVirtualCamera vcam;
    private CinemachineRestrictToTerrain restrict;

    void Awake()
    {
        // Ensure the extension component exists on the vcam
        restrict = vcam.GetComponent<CinemachineRestrictToTerrain>();
        if (restrict == null)
            restrict = vcam.gameObject.AddComponent<CinemachineRestrictToTerrain>();

        // Optional: tweak padding and behavior
        restrict.m_MapSurfacePadding = 2f;
        restrict.m_RestrictToMapArea = true;
        restrict.enableObjectCollisions = true;
    }

    // If you instantly move the camera (teleport), call Refresh() to update previousPosition
    public void TeleportCamera(Vector3 newPos)
    {
        vcam.transform.position = newPos;
        restrict.Refresh(); // prevents sweeping collision tests from using stale previousPosition
    }
}

Notes and Dependencies: - Requires Cinemachine (CinemachineExtension / CinemachineVirtualCameraBase). - Uses Unity.Entities world systems: CameraCollisionSystem, CameraUpdateSystem, TerrainSystem, WaterSystem. - Uses utility classes: TerrainUtils, WaterUtils, MathUtils, Bounds3, TerrainHeightData, WaterSurfaceData. - Designed for Cities: Skylines 2 game systems and rendering pipeline; behavior depends on those game systems being present and initialized.