Orbital Camera Controller

Started by gasleet 3 posts 229 views

Reply on sbox.game
  1. edited Jan 2026 #1
    gasleet 6,923
    Simple Camera Controller. Feel free to use, extend and share. ❤
    Uses a CameraComponent and GameObject as Property. <- You could also get these in OnEnabled().
    using Sandbox;
    using System;
    
    public sealed class OrbitalCameraController : Component
    {
    	[Property, Description("Camera to control")] CameraComponent MainCamera;
    	[Property, Description("GameObject to follow")] GameObject Player;
    
    	[Property, Description("Starting distance")] int DistanceToPlayer = 2000;
    	[Property, Description( "Minimal distance to player" )] int MinDistanceToPlayer = 600;
    	[Property, Description( "Maximal distance to player" )] int MaxDistanceToPlayer = 10000;
    	[Property, Description("Units one step zooms")] int ZoomStrength = 200;
    
    	float Pitch = 0;
    	float Yaw = 0;
    
    	protected override void OnUpdate()
    	{
    		// Capture mouse and add to pitch and yaw angles
    		Angles mouseMove = Input.AnalogLook;
    		Pitch = (Pitch + mouseMove.pitch).Clamp( -85, 85 ); // Up&Down clamped in degrees
    		Yaw += mouseMove.yaw;
    		Rotation rotation = Rotation.From( Pitch, Yaw, 0 );
    
    		SceneTraceResult checkingSightline = Scene.Trace
    			.Ray( MainCamera.WorldPosition, Player.WorldPosition )
    			.Radius(1)
    			.IgnoreGameObjectHierarchy(GameObject) // Ignores itself. Use tags depending on your setup
    			.Run();
    		// DebugOverlay.Trace( checkingSightline );
    
    		if ( Input.MouseWheel.y < 0 ) { DistanceToPlayer = Math.Min( DistanceToPlayer + ZoomStrength, MaxDistanceToPlayer ); }
    		if ( Input.MouseWheel.y > 0 ) { DistanceToPlayer = Math.Max(DistanceToPlayer - ZoomStrength, MinDistanceToPlayer); }
    
    		if ( checkingSightline.Hit ) // If sightline is blocked change distance to be in front of hit collider
    		{
    			DistanceToPlayer = Math.Max( (int)(checkingSightline.HitPosition - Player.WorldPosition).Length, MinDistanceToPlayer );
    		}
    
    		// Apply Position and Rotation
    		MainCamera.WorldPosition = Player.WorldPosition - rotation.Forward * DistanceToPlayer;
    		MainCamera.WorldRotation = rotation;
    		
    	}
    }

    Not sure if this is the nicest way of doing this, but I'm happy with it. 🙂 Please report any bugs or give tips!
    Remember to edit the Pitch.Clamp(-85, 85) for your usecase.
    edited:
    image.png 186.8 KB
    This is how it looks. Just orbits 🛸 and zooms 🔎 
  2. #2
    Braxen 🐟 190
    something i've yet to figure out is how to have it lerp smoothly but still stay at a distance, without parenting the camera to a center pivot object and rotating that instead
  3. #3
    gasleet Started this 6,923
    I'm not exactly sure what you mean. The camera orbiting nothing?