Follow Third Person Camera

2 Likes
/* Folowed Third Person Camera by KlnHomeAlone@gmail.com for Xenko*/
/* Inspired by Jm991 https://github.com/jm991/UnityThirdPersonTutorial */
using SiliconStudio.Core.Mathematics;
using SiliconStudio.Xenko.Engine;
using SiliconStudio.Xenko.Physics;
using System;

namespace ThirdPersonCamera
{
    public class FollowCamera : SyncScript
    {
        private Vector3 _targetPosition;
        private Vector3 _characterOffset;
        private Simulation _simulation;
        private CharacterComponent _characterController;
        private float _compensationOffset = 0.1f;

        public Entity Follow { get; set; }
        public float DistanceAway { get; set; } = 3.5f;
        public float DistanceUp { get; set; } = 4f;

        public float Smooth { get; set; } = 0.2f;
        public override void Start()
        {
            _simulation = this.GetSimulation();
            _characterController = Follow.Get<CharacterComponent>();
        }
        public override void Update()
        {
            var charRotation = Matrix.RotationQuaternion(_characterController.Orientation);
            _characterOffset = Follow.Transform.Position + charRotation.Up * DistanceUp;
            _targetPosition =  _characterOffset + charRotation.Forward * DistanceAway;
            CompensateForWalls(_characterOffset, ref _targetPosition);
            SmoothPosition(Entity.Transform.Position, _targetPosition);
            Entity.LookAt(Follow.Transform.Position);
        }

        private void CompensateForWalls(Vector3 characterOffset, ref Vector3 toTarget)
        {
            Vector3 camPosCache = Entity.Transform.Position;
            var near = camPosCache;
            var far = Follow.Transform.Position;
            far.Y += 1.3f; //Character Height usually it's a capsule collider height
            var result = _simulation.Raycast(near, far);
            if (!result.Succeeded || result.Collider == null) return;
            var colliderComponent = result.Collider;
            if (colliderComponent is CharacterComponent) return;
            do
            {
                var normal = result.Normal;
                if (normal != Vector3.Zero)
                {
                    toTarget -= (_compensationOffset * normal);
                }
                near = toTarget;
                result = _simulation.Raycast(near, far);
                if (!result.Succeeded || result.Collider == null) return;
                colliderComponent = result.Collider;
            }
            while (!(colliderComponent is CharacterComponent));
        }

        private void SmoothPosition(Vector3 fromPos, Vector3 toPos)
        {
            var distance = toPos - fromPos;
            if (distance.Length() < Smooth) return;
            // Making a smooth transition between camera's current position and the position it wants to be in
            Entity.Transform.Position = Vector3.SmoothStep(fromPos, toPos, Smooth);
        }
    }
    public static class EntityExtensions
    {
        public static void LookAt(this Entity e, Vector3 target)
        {
            float altitude = 0;
            float azimuth = GetLookAtAngles(e.Transform.Position, target, out altitude);
            var result = Quaternion.RotationYawPitchRoll(azimuth, -altitude, 0);
            e.Transform.Rotation = result;
        }
        private static float GetLookAtAngles(Vector3 source, Vector3 destination, out float altitude)
        {
            var x = source.X - destination.X;
            var y = source.Y - destination.Y;
            var z = source.Z - destination.Z;

            altitude = (float)Math.Atan2(y, Math.Sqrt(x * x + z * z));
            var azimuth = (float)Math.Atan2(x, z);
            return azimuth;
        }
    }
}
1 Like
  1. Copy the script into your project
  2. Get sure that you have set an entity with character controller attached
  3. Reference that entity in the Follow field
  4. Set desired Distance Away and Distance Up and desired smoothness.
  5. Enjoy!!!

This camera also detects walls and adjusts its position.

3 Likes

Thanks for your contribution, very much appreciated!