Skip to content

Latest commit

 

History

History
114 lines (92 loc) · 3.52 KB

spring-arm-camera.md

File metadata and controls

114 lines (92 loc) · 3.52 KB

HOWTO: Create Spring Arm camera

1. Create script

Firstly, create a new script and add code that reads mouse input to rotate camera and performs the physics collision raycast to adjust camera placement (prevent intersecting with world collisions).

/// <summary>
/// Arc-ball 3rd person-style camera controller script that handles collisions with world.
/// </summary>
public class SpringArmCamera : Script
{
    private Float2 _mouse = new Float2(45, 45);

    /// <summary>
    /// Target actor to follow.
    /// </summary>
    public Actor TargetActor;

    /// <summary>
    /// Target camera actor.
    /// </summary>
    public Camera CamerActor;

    /// <summary>
    /// Initial spring arm radius to roam around.
    /// </summary>
    public float Distance = 1000;

    /// <summary>
    /// The minimum distance for spring arm correction.
    /// </summary>
    public float MinDistance = 10.0f;

    /// <summary>
    /// The maximum distance for spring arm correction.
    /// </summary>
    public float MaxDistance = 2000.0f;

    /// <summary>
    /// Mouse movement speed scale.
    /// </summary>
    public float MouseSpeed = 0.5f;

    /// <summary>
    /// Mouse wheel movement speed scale.
    /// </summary>
    public float MouseWheelSpeed = 1.0f;

    /// <summary>
    /// The physics layers that with which spring arm will collide.
    /// </summary>
    public LayersMask CollisionLayers = LayersMask.Default;

    /// <summary>
    /// The additional distance to apply when colliding with geometry in order to prevent camera intersecting with it.
    /// </summary>
    public float CollisionDistanceBias = 10.0f;
    
    /// <inheritdoc />
    public override void OnStart()
    {
        // Auto-link actors
        if (!TargetActor)
            TargetActor = Actor;
        if (!CamerActor)
        {
            CamerActor = Scene.FindActor<Camera>();
            if (CamerActor == null)
                Debug.LogError("Missing camera");
        }
    }

    /// <inheritdoc />
    public override void OnUpdate()
    {
        if (!CamerActor || !TargetActor)
            return;

        // Update input
        _mouse += Input.MousePositionDelta * MouseSpeed;
        _mouse.Y = Mathf.Clamp(_mouse.Y, -89, 89);
        Distance += Input.MouseScrollDelta * -20.0f * MouseWheelSpeed;
        Distance = Mathf.Clamp(Distance, MinDistance, MaxDistance);

        // Update arc-ball camera
        Quaternion rotation = Quaternion.Euler(-_mouse.Y, _mouse.X, 0);
        Vector3 targetPosition = TargetActor.Position;
        Vector3 direction = Vector3.Transform(Vector3.Forward, rotation) * Distance;
        Vector3 newPosition = targetPosition + direction;
        direction = (newPosition - targetPosition).Normalized;
        CamerActor.Position = targetPosition + direction * Distance;
        CamerActor.LookAt(targetPosition, Vector3.Up);
        
        // Snap Camera if it intercepts with an environment
        if (Physics.RayCast(targetPosition, direction, out RayCastHit hit, Distance, CollisionLayers))
        {
            var bias = CollisionDistanceBias + CamerActor.NearPlane;
            var distance = Mathf.Max(hit.Distance - bias, MinDistance);
            CamerActor.Position = targetPosition + direction * distance;
        }
    }
}

2. Setup

Add script to the player actor and optionally link the camera actor to control. Otherwise script will pick the first camera it founds on a scene.

3. Test it out!

Finally, start the game and test the result.

Spring Arm Camera Script Flax Engine