Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question Lock on target using Third Person Controller Asset

Discussion in 'Cinemachine' started by cerberusheart, Oct 17, 2022.

  1. cerberusheart

    cerberusheart

    Joined:
    May 28, 2021
    Posts:
    3
    Hi all,

    I have been looking for a solution for days now and I'm struggling. I'm using Unity's free starter asset for my third person controller. It uses Cinemachine for the camera. I'm trying to add a lock on system. I've followed several tutorials and I'm still not getting it how I want it.

    Basically, I'm looking for a standard Action-RPG/Souls-like control scheme. The third person controller that Unity provides covers a lot but now when I'm trying to do the lock on, I'm failing.

    I have done a state driven camera with two cameras: the 3rd person camera that comes with the asset and a framing transpose (body)/ composer (aim) for the second. I have created an empty game object for enemy locator.

    This is the class I'm using for the lock on.
    Code (CSharp):
    1. public class EnemyLockOn : MonoBehaviour
    2. {
    3.     public Transform currentTarget;
    4.     Animator anim;
    5.  
    6.     [SerializeField] LayerMask targetLayers;
    7.     [SerializeField] Transform enemyTargetLocator;
    8.  
    9.     [Tooltip("StateDrivenMethod for switching cameras")]
    10.     [SerializeField] Animator cinemachineAnimator;
    11.  
    12.     [Header("Settings")]
    13.     [SerializeField] float noticeZone = 10;
    14.     [SerializeField] float maxNoticeAngle = 60;
    15.     [SerializeField] ThirdPersonController controller;
    16.     [SerializeField] float rotationSmoothSpeed = 2;
    17.  
    18.  
    19.     bool isLockedOn;
    20.     Transform cam;
    21.     InputHandler inputHandler;
    22.     float currentYOffset;
    23.     Vector3 pos;
    24.  
    25.     private void Start()
    26.     {
    27.         cam = Camera.main.transform;
    28.         anim = GetComponent<Animator>();
    29.         inputHandler = GetComponent<InputHandler>();
    30.     }
    31.  
    32.     private void Update()
    33.     {
    34.         if (inputHandler != null && inputHandler.lockOn)
    35.         {
    36.             if (currentTarget)
    37.             {
    38.                 ResetTarget();
    39.                 return;
    40.             }
    41.  
    42.             if (currentTarget = ScanForTargets()) FoundTarget(); else ResetTarget();
    43.         }
    44.  
    45.         if (isLockedOn)
    46.         {
    47.             if (!TargetInRange()) ResetTarget();
    48.             LookAtTarget();
    49.         }
    50.     }
    51.  
    52.     private void LookAtTarget()
    53.     {
    54.         if (currentTarget == null)
    55.         {
    56.             ResetTarget();
    57.             return;
    58.         }
    59.  
    60.         pos = currentTarget.position + new Vector3(0, currentYOffset, 0);
    61.         enemyTargetLocator.position = pos;
    62.         var dir = currentTarget.position - transform.position;
    63.         dir.y = 0;
    64.         var rotation = Quaternion.LookRotation(dir);
    65.         transform.rotation = Quaternion.Slerp(transform.rotation, rotation, rotationSmoothSpeed * Time.deltaTime);
    66.     }
    67.  
    68.     private bool TargetInRange()
    69.     {
    70.         float dis = (transform.position - pos).magnitude;
    71.         if (dis / 2 > noticeZone) return false; else return true;
    72.     }
    73.  
    74.     private void FoundTarget()
    75.     {
    76.         //anim.SetLayerWeight(1, 1);
    77.         //cinemachineAnimator.Play("Target Camera");
    78.         isLockedOn = true;
    79.         controller.LockCameraPosition = true;
    80.     }
    81.  
    82.     private void ResetTarget()
    83.     {
    84.         isLockedOn = false;
    85.         //anim.SetLayerWeight(1, 0);
    86.         //cinemachineAnimator.Play("Follow Camera");
    87.         currentTarget = null;
    88.         controller.LockCameraPosition = false;
    89.     }
    90.  
    91.     Transform ScanForTargets()
    92.     {
    93.         var hits = Physics.OverlapSphere(transform.position, noticeZone, targetLayers);
    94.         var closestAngle = maxNoticeAngle;
    95.         Transform closestTarget = null;
    96.  
    97.         foreach (var hit in hits)
    98.         {
    99.             var dir = hit.transform.position - cam.position;
    100.             dir.y = 0;
    101.  
    102.             var angle = Vector3.Angle(cam.forward, dir);
    103.  
    104.             if (angle < closestAngle)
    105.             {
    106.                 closestTarget = hit.transform;
    107.                 closestAngle = angle;
    108.             }
    109.         }
    110.  
    111.         if (!closestTarget) return null;
    112.  
    113.         var collider = closestTarget.GetComponent<CapsuleCollider>();
    114.         var h = collider.height * closestTarget.localScale.y;
    115.         var half_h = (h / 2) / 2;
    116.         currentYOffset = h - half_h;
    117.  
    118.         var targetPosition = closestTarget.position + new Vector3(0, currentYOffset, 0);
    119.         //blocked
    120.  
    121.         return closestTarget;
    122.     }
    123.  
    124.     private void OnDrawGizmos()
    125.     {
    126.         Gizmos.DrawWireSphere(transform.position, noticeZone);
    127.     }
    128. }
    This was taken from a tutorial (I'm not that smart, haha). I get weird behaviour when I use it. Either when I attack, the character moves in a rotational manner or other weird artifacts.

    Basically, how do I make sure the camera can transition from 3rd person to lock on mode using state machine (because I like the concept of it) and have the camera exactly like it is in 3rd person mode, except I can't rotate the camera manually, it always looks at the enemy, the character rotates to face the enemy, and all my attacks are forward towards the enemy just like any standard Souls-like or Action-RPG games out there with a lock on system.

    For reference, the tutorial I followed the most was this one:
     
  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,267
    You need to be alittle more specific about what the problem is. Can you show a video?

    Generally FramingTansposer/Composer is a good way to do a lock-on. One thing to note: be conservative with the Screen/X/Y parameters, or you might get weird rotations. Start with all at center (0.5 value). Do you still get weird rotations? If not, move them a little at a time towards your desired configuration. You can do this while the game is playing.
     
  3. cerberusheart

    cerberusheart

    Joined:
    May 28, 2021
    Posts:
    3
    Hi, thank you for the reply!

    Here's a video of one of the issues I have:
     
  4. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,267
    It's probably because your vcams are children of the main camera. Unparent them.
     
  5. cerberusheart

    cerberusheart

    Joined:
    May 28, 2021
    Posts:
    3
    Thank you! I'm now playing with some settings to try and get it just right! Thank you again.
     
    Gregoryl likes this.