FOV sensitive Lock-on?

Hey guys,

I was just wondering how I could make a lock on system FOV sensitive? Meaning that if I want to lock onto something it has to be within the FOV of the camera.

So if anything is outside of the FOV it will not target it.

I’m trying to refine the lock-on system I have in order to make it more efficient. I was also wondering how I can set a maximum lock on distance so that the enemy must be within a certain distance to be targetable and they must be actually in the FOV of the camera.

Here’s my targetting code so far, for our lock on system.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Targetting : MonoBehaviour 
{
	GameObject[] enemies;
	public Transform selectedTarget;
	public Transform nearestEnemy;
	public Vector3 enemyCenter;
	
	public float minimumTargetDistance = 100.0f;
	
	private float lastFrameLockOn;
	
	GameObject[] lockOnTransforms;

	//Transform of the UI element
	public Transform lockOn;
	
	// Use this for initialization
	void Start () 
	{	
		lastFrameLockOn = Input.GetAxis("LockOn");
		selectedTarget = null;
	}
	
	// Update is called once per frame
	void Update () 
	{
		if(Input.GetAxis("LockOn") > 0.5f )
		{
			if(Input.GetAxis("LockOn") > 0.5f && lastFrameLockOn < 0.5f)
			{
				targetCloseEnemies();
			}
			
			if(selectedTarget)
			{
				transform.LookAt(selectedTarget.position);
			}
			
			if(nearestEnemy)
			{
				if(selectedTarget != nearestEnemy)
				{
					TargetEnemy(nearestEnemy);
				}
			}
			
		}
		if(Input.GetAxis("LockOn") <= 0.5f)
		{
			selectedTarget = null;
			nearestEnemy = null;
			enemyCenter = Vector3.zero;
			DestroyLockOns();
		}
		
		lastFrameLockOn = Input.GetAxis("LockOn");
	}
	
	private void targetCloseEnemies()
	{
		// Find all enemies within the scene and add them to a list
		enemies = GameObject.FindGameObjectsWithTag("Enemy");
		
		//Add enemies that are within range to a new list of targetable enemies
		foreach(GameObject enemy in enemies) // list of all enemies
		{
			float enemyDistance = Vector3.Distance(transform.position, enemy.transform.position); // distance of new enemy to player
			if(enemyDistance <= minimumTargetDistance) // checks if the new enemy is close enough to target
			{
				
				if(nearestEnemy)
				{
					if(enemyDistance < Vector3.Distance(transform.position, nearestEnemy.position )) // checks if new enemy is closer than existing enemy
					{
						nearestEnemy = enemy.transform;
					}
				}
				else
				{
					
					nearestEnemy = enemy.transform; // if the nearest enemy doesn't exist, the new enemy is assigned to nearestenemy
				}
			}
		}
		
		if(nearestEnemy)
		{
			Bounds bounds = new Bounds (nearestEnemy.transform.position, Vector3.one);

		    Renderer[] renderers = nearestEnemy.GetComponentsInChildren<MeshRenderer>();
		
		    foreach (Renderer renderer in renderers)
		
		    {
		        bounds.Encapsulate (renderer.bounds);
		    }
			
			renderers = nearestEnemy.GetComponentsInChildren<SkinnedMeshRenderer>();
		
		    foreach (Renderer renderer in renderers)
			{
		        bounds.Encapsulate (renderer.bounds);
		    }
			
			Debug.Log ("bounds center: "+bounds.center);
			
			enemyCenter = bounds.center;
			
		}
	}
	
	public void TargetEnemy(Transform target)
	{	
		
		selectedTarget = target;
		
		DestroyLockOns();
			
		if (selectedTarget)
		{
			Transform lockOnClone = Instantiate(lockOn, Vector3.zero, Quaternion.identity) as Transform;
			lockOnClone.parent = selectedTarget.transform;
			lockOnClone.position = enemyCenter;
		}
	}
	
	void DestroyLockOns()
	{
		lockOnTransforms = GameObject.FindGameObjectsWithTag("LockOn");
		//Debug.Log ("found " + lockOnTransforms.Length + " lockons");
		foreach(GameObject lockOnTransform in lockOnTransforms)
		{
			Debug.Log ("Destroying lockon");
			Destroy(lockOnTransform);
		}
	}
}

Hey there,

there is a neat way to do this using Camera.WorldToViewportPoint - Unity - Scripting API: Camera.WorldToViewportPoint

That returns a value between (0,0) and (1,1) when an object is somewhere on screen. If the object is outside, the values will be outside this range, see the example code in the reference.

This measures from the center of an object, not the bounds; so it might be necessary to include some tolerance in the check (maybe something like (0.05, 0.05) to (0.95, 0.95), that way the object has to be further on screen. It’s also possible to use something like (-0.05, -0.05) to (1.05, 1.05), that way you’d also include objects that are somewhat off screen. Try and see what feels fun :slight_smile:

The method is not too expensive, but as you’d have to call it every frame for every possible target: Try and restrict the amount of objects you check with this, maybe only include enemies that’d be in range. In any case, cache the reference to the camera you’re using for this. In my game, that brought a significant boost in performance.

Happy coding!