Game.Rendering.CameraCollisionSystem
Assembly: Assembly-CSharp
Namespace: Game.Rendering
Type: Class
Base: GameSystemBase
Summary:
CameraCollisionSystem performs collision detection for the in-game camera to prevent clipping into world geometry. It queries nearby scene entities using a static quad-tree, raycasts against mesh geometry (including handling LODs, cached/shared meshes, stacks, procedural bones and skeletons), merges collision intervals and selects a camera position that keeps the view clear of terrain and water. The system is implemented with Unity Jobs + Burst for performance and integrates with TerrainSystem, WaterSystem and the engine's search system. It exposes a CheckCollisions API that other systems or tools can call to request a safe camera position. It is intended for internal use in the rendering/camera pipeline but can be used by mods that want to replicate or hook into Skylines 2 camera collision behavior.
Fields
-
private CityConfigurationSystem m_CityConfigurationSystem
Holds a reference to the CityConfigurationSystem for configuration flags (e.g. left/right-hand traffic). -
private ToolSystem m_ToolSystem
Reference to the ToolSystem used to check editor/action mode (camera behavior differs in editor). -
private SearchSystem m_ObjectSearchSystem
Reference to the SearchSystem to get the static search/quad-tree for nearby entities. -
private TerrainSystem m_TerrainSystem
Reference to TerrainSystem used to sample terrain heights for water/terrain clearance checks. -
private WaterSystem m_WaterSystem
Reference to WaterSystem used to sample water surface height to avoid placing camera under water. -
private float3 m_PreviousPosition
Cached previous camera position used for smoothing and selecting an optimal new camera position. -
private quaternion m_Rotation
Cached camera rotation used to project camera frustum line and field-of-view offsets. -
private float m_MaxForwardOffset
Maximum forward offset (how far forward the camera can go) used to compute search line. -
private float m_MaxBackwardOffset
Maximum backward offset used to compute search line. -
private float m_MinClearDistance
Minimum clearance distance (near clipping clear range) used in collision checks and camera placement. -
private float m_NearPlane
Near plane distance (in world units) used to compute near-plane bounds along the search line. -
private float m_Smoothing
Smoothing factor applied to camera offset changes over time (exponential smoothing). -
private float2 m_FieldOfView
Camera field-of-view in degrees (X and Y) used to expand search corridor based on frustum. -
private NativeReference<Result> m_Result
Native persistent storage for the computed Result struct (position + offset). Allocator.Persistent; disposed in OnDestroy. -
private TypeHandle __TypeHandle
Generated container containing ComponentLookup / BufferLookup handles used when scheduling jobs.
Properties
- No public properties exposed.
Constructors
public CameraCollisionSystem()
Default constructor (marked [Preserve] in compiled code). System initialization logic is performed in OnCreate; the constructor does not allocate native resources directly.
Methods
-
[Preserve] protected override void OnCreate()
Initializes system references (CityConfigurationSystem, ToolSystem, SearchSystem, TerrainSystem, WaterSystem) and allocates the persistent NativeReference. Called when the system is created. -
[Preserve] protected override void OnDestroy()
Disposes the persistent NativeReferenceand performs base cleanup. -
public void CheckCollisions(ref float3 position, float3 previousPosition, quaternion rotation, float maxForwardOffset, float maxBackwardOffset, float minClearDistance, float nearPlane, float smoothing, float2 fieldOfView)
Primary API to request camera collision handling. If not in editor mode, this sets up internal parameters, schedules jobs (FindEntitiesFromTreeJob, ObjectCollisionJob, SelectCameraPositionJob) and updates the position parameter with the computed safe camera position. It blocks until the scheduled jobs complete (jobs are scheduled and completed inside Update). -
[Preserve] protected override void OnUpdate()
Internal update used when CheckCollisions has been invoked. Builds the search line, computes FOV offsets and normalized ranges, creates native lists/queues, schedules the three main jobs, registers readers with ObjectSearchSystem/TerrainSystem/WaterSystem, and completes the job chain. After completion, result is stored in m_Result. -
private void __AssignQueries(ref SystemState state)
Generated helper used in compiled systems. Here it constructs/disposes an EntityQueryBuilder (no persistent queries in this system). -
protected override void OnCreateForCompiler()
Generated method that initializes queries and assigns component/buffer handles via __TypeHandle.__AssignHandles. Used by the runtime when compiling IL to system state. -
private static void CheckCollisions(NativeList<Collision> collisions, float minClearRange, float2 limits)
Static helper that merges and filters an unsorted list of Collision entries into consolidated collision intervals, respects minimum clear range and ensures clipping limits (limits represent normalized near/far bounds). -
private static bool Intersect(Line line, Bounds3 bounds, out float2 t)
Utility to test intersection between an expanded/scaled bounding box and line segment, outputting normalized min/max t on the line. -
private static void CheckTriangleIntersect(Line line, Triangle3 triangle, NativeList<Collision> collisions)
Projects triangle into the line/frustum plane space, computes intersection area and line bounds and adds Collision entries when intersections occur. -
private static void CheckMeshIntersect(Line line, DynamicBuffer<MeshVertex> vertices, DynamicBuffer<MeshIndex> indices, NativeList<Collision> collisions)
Iterates indices in simple mesh and tests each triangle with CheckTriangleIntersect. -
private static void CheckMeshIntersect(Line line, DynamicBuffer<MeshVertex> vertices, DynamicBuffer<MeshIndex> indices, DynamicBuffer<MeshNode> nodes, NativeList<Collision> collisions)
Spatially accelerated mesh intersection using mesh nodes; traverses node tree using a manual stack and tests triangles only where node bounds intersect the line. -
private static void CheckMeshIntersect(Line line, DynamicBuffer<MeshVertex> vertices, DynamicBuffer<MeshIndex> indices, DynamicBuffer<MeshNode> nodes, DynamicBuffer<ProceduralBone> prefabBones, NativeList<Collision> collisions)
Handles procedurally skinned meshes where multiple bind nodes exist. Iterates procedural bones and tests subtrees. -
private static void CheckMeshIntersect(Line line, DynamicBuffer<MeshVertex> vertices, DynamicBuffer<MeshIndex> indices, DynamicBuffer<MeshNode> nodes, DynamicBuffer<ProceduralBone> prefabBones, DynamicBuffer<Bone> bones, Skeleton skeleton, NativeList<Collision> collisions)
Full skinned-mesh handling that transforms the camera line into bone-local space (using bind poses and bone hierarchy), then traverses nodes to compute collisions for animated/skinned meshes. -
Nested Job types (Burst-compiled):
- FindEntitiesFromTreeJob : IJob
Collects Entity IDs from the static search tree whose expanded quad-tree bounds intersect the camera search line (considering FOV expansion). Writes to a NativeList. - ObjectCollisionJob : IJobParallelForDefer
For each candidate entity, obtains transform/prefab/flags and early-exits for non-physical or marker-only geometry; constructs a Line in object-local space, computes object bounds, and if they intersect schedules per-mesh raycasts (via the CheckMeshIntersect variants). Enqueues Collision results into a native queue (parallel writer). Handles many prefab flags: stacks, quantity objects, growth scale (trees), LODs, shared meshes, impostors, etc. - SelectCameraPositionJob : IJob
Dequeues collisions, runs CheckCollisions to merge intervals, determines the best candidate normalized position along the search line respecting minClearRange, near plane, terrain and water heights, performs smoothing against previous position and writes final Result (position and offset).
Notes: - Jobs use many ComponentLookup and BufferLookup handles (stored in TypeHandle). The system uses InternalCompilerInterface to get handles at scheduling time. - The system samples water and terrain heights via WaterSystem and TerrainSystem; SelectCameraPositionJob uses these to ensure the chosen camera position is above water/terrain by minClearRange. - The algorithm uses normalized distances (0..1 along a precomputed search line) and then maps them back to world positions.
Usage Example
// Example: call from a camera controller or mod to get a safe camera position.
// Assume 'world' is the ECS World and 'system' is obtained via World.GetExistingSystemManaged<CameraCollisionSystem>()
var cameraSystem = world.GetOrCreateSystemManaged<Game.Rendering.CameraCollisionSystem>();
float3 currentPos = cameraTransform.position;
float3 previousPos = lastCameraPosition;
quaternion rotation = cameraTransform.rotation;
float maxForward = 100f; // max forward offset
float maxBackward = 10f; // max backward offset
float minClear = 1.5f; // minimum clearance from geometry
float nearPlane = 0.3f; // near plane distance
float smoothing = 0.9f; // smoothing factor
float2 fov = new float2(60f, 40f); // horizontal/vertical FOV in degrees
// This will update currentPos to a safe position when the method returns (if not in editor mode)
cameraSystem.CheckCollisions(ref currentPos, previousPos, rotation, maxForward, maxBackward, minClear, nearPlane, smoothing, fov);
// Apply the adjusted camera position
cameraTransform.position = currentPos;
{{ The CameraCollisionSystem is designed to be used from game code that manages the camera. It is high-performance (Burst + Jobs) and interacts with low-level mesh/vertex buffers; take care when modifying or scheduling similar jobs in mods to avoid unsafe concurrent access to component buffers. If you need to extend or override behavior, prefer using the public CheckCollisions API rather than calling internal job types directly. }}