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
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Check if a gameobject is in front of my player character

Discussion in 'Scripting' started by devprincess, Jan 16, 2013.

  1. devprincess

    devprincess

    Joined:
    Sep 7, 2012
    Posts:
    116
    Hi guys, I've been looking like crazy for this problem.. I have a gameobject (cube) in front of my main character (player) and I want to check if it is in front of the cube or not. I've been doing this in my code:

    Code (csharp):
    1. Vector3 directionToTarget = transform.position - enemy.position;
    2. float angle = Vector3.Angle(transform.forward, directionToTarget);
    3. if (Mathf.Abs(angle) < 90)
    4.     Debug.Log("target is in front of me");
    But it still doesnt work because I get really far from the object and still prints me the message I put. Please any quick suggestion I'd appreciate it a lot! Thanks in advance!
     
  2. shaderop

    shaderop

    Joined:
    Nov 24, 2010
    Posts:
    942
    You could also check for the distance between the player and the cube, like so:

    Code (csharp):
    1. Vector3 directionToTarget = transform.position - enemy.position;
    2. float angle = Vector3.Angle(transform.forward, directionToTarget);
    3. float distance = directionToTarget.magnitude;
    4.  
    5. if (Mathf.Abs(angle) < 90  distance < 10)
    6.     Debug.Log("target is in front of me");
    Replace distance < 10 with whatever search radius you need.You might also want to use one of the cast/check functions in the Physics class to do the all heavy lifting for you.
     
    Last edited: Jan 16, 2013
    fabiolamin, jrm808242 and betaFlux like this.
  3. jister

    jister

    Joined:
    Oct 9, 2009
    Posts:
    1,749
  4. UnityCoder

    UnityCoder

    Joined:
    Dec 8, 2011
    Posts:
    534
    You can also use Raycasthit for that. Check Raycasthit in Unity documentation.
     
  5. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    It's not really clear what your definition of "in front of" is. It sounds like you also want to take into account how far away the object is. While you could cast a ray - I would check the distance first and if the object is "close enough" I would then check the dot product of the 2 position vectors to determine whether or not one is in front of the other.
     
  6. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    take the vector pointing from player to object

    var v = obj.position - player.position;

    The length of this is the distance.

    Now take this and get the angle between it and the player 'forward' vector. This is the acos( v1 DOT v2 / (mag(v1) * mav(v2)) )... if you just normalize the vector calculated above, the mags of each is 1, cancelling out the division leaving: acos(v1 DOT v2).

    If this angle is less than half of an angle of view you define as being "in front", then it's in front.
     
  7. devprincess

    devprincess

    Joined:
    Sep 7, 2012
    Posts:
    116
    Thanks guys finally I'm checking distance and angle as suggested before. Already working now. Thanks anyways! :)
     
  8. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    cough, cough... Vector3.Dot works better and faster.

    Code (csharp):
    1.  
    2. function isInFront(obj:GameObject){
    3. return Vector3.Dot(Vector3.forward, transform.InverseTransformPoint(obj.transform.position)) > 0;
    4. }
    5.  
     
  9. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    2 things bigmisterb

    1) you're implying we didn't suggest using dot product... which we did

    2) you don't test the angle though (which we get from the dot product), which means you give a 180 degree angle of view to determine 'in front of'. Something directly to the player's right could be "in front of" based on your example. Which is all fine and well if you desire a 180 degree angle of view... but if you want say a 70 degree angle of view, well you need to take the arccos of that dot product divided by the magnitudes... that gives you the angle off, and compare if it's less than half the desired angle of view.

    so yeah... cough cough
     
  10. Cameron_SM

    Cameron_SM

    Joined:
    Jun 1, 2009
    Posts:
    915
    If both Dot vectors are normalised then you don't need to bother with acos, a simple bias and scale with a boundary condition should get you there much faster.
     
  11. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    Why do you need an angle? Vector3.Dot is simple... above zero, in front, below zero behind.
     
  12. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    I explained that bigmisterb, Testing if the dot-product is greater than 0 on its own will result in a 180 degree field of view, so an object directly to your right will be considered 'in front'... so it depends on what you consider 'in front'. If you want to consider the player having a 180 degree field of view, then that's a good short cut... but as with any short cut you must understand the short-comings of said short-cut.


    @Cameron - agreed, you can short cut the acos... what you're basically doing though is hardcoding the trig result so that you don't have to operate it all the time. This is a good short cut.


    In the end what I and KelsoMRK defined was the generic math formula for how to determine this. If you'd like to reduce out variables from said formula because in your UNIQUE instance you can, then do so, to speed up the process. But as with all short-cuts, you should know what the short-cut is based on so that you understand its short-comings and you can adapt it to meet your needs if those needs alter.
     
    Last edited: Jan 17, 2013
  13. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    lol.. OMG, the poster did not ask for "If my angle up and down is less than x and my angle left and right is greater than X" She simply said....

    You guys are giving a lot of mathematical BS for a problem that is solved in 2 lines of code... In front and how close. Vector3.Dot and Vector3.Distance.

    The tools are there for you guys to use.


    Now.. Proof:
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class TEST1 : MonoBehaviour {
    6.     void Update(){
    7.         for(int i=0; i<10000000; i++){
    8.             //Vector3.Dot(Vector3.forward, Vector3.right); // This runs 2.3 frames per second.
    9.             //Vector3.Angle(transform.forward, Vector3.right); // this runs 0.3 frames per second.
    10.         }
    11.     }
    12. }
    13.  
     
  14. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    OP already solved their problem.

    in front of was never defined.

    And yes, your answer works for a special definition of 'in front of', because it's a reduction of the so called "BS math".

    You obviously don't understand the theory behind the tools that were given to you.
     
  15. Safalya

    Safalya

    Joined:
    Mar 16, 2015
    Posts:
    11
    I think a combination of Vector3.Dot + Vector3.Distance + Vector3. Angle is a better option.:)
     
  16. Max_Bol

    Max_Bol

    Joined:
    May 12, 2014
    Posts:
    168
    I would like to thank everyone in this topic as this allowed me to do something AWESOME! :D
    So I'll share my little work with you. (Might give some evil idea to some).

    I was looking around to find a solution (easy to implement and modify) so that I could take some specific things disappear from the camera based on the orientation of a gameobject (a head to be precise). The thing is that I could not use the trick of detecting the gameobject from the front of the player via the player's head because it had to manage the gameobject even when they are not forward (so that they can become visible and invisible).

    So the solution was to do it in reverse! Since it's not "all" the game object that can disappear, but only some (NPCs for example) I created the following script which is placed on every game object that can become invisible if not forward of the player. That way, I remove the insane problem of detecting if every game object needs or not to be disabled simply by not placing this script on those who shall stay visible at all time (like the background/environment).

    Then the only thing I had to change was the "order" as well as storing the player's head into a persistent script. In this case, it's a script called GameInformation which is always present (and can't be destroyed) while it stores any temporary data I need to keep at all time in the game (things like game options, boolean and floats that should be kept between scene like the distance between the character and the camera in 3rd person view, etc.) When a scene start, I update it with a script placed on the bone of the character's head that tells GameInformation that it's the "PlayerHead".

    Then this little script does the rest for each toggled game object.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class FoWCaster : MonoBehaviour {
    5.  
    6.     public FoWCaster Instance;
    7.     private bool isVisible;
    8.  
    9.     private Renderer _renderer;
    10.  
    11.     void Awake(){
    12.         Instance = this;
    13.         _renderer = GetComponent<Renderer> ();
    14.     }
    15.  
    16.     void Update () {
    17.         if (_renderer.enabled != isVisible) {
    18.             UpdateVisibility();
    19.         }
    20.  
    21.         Vector3 directionToTarget = GameInformation.PlayerHead.transform.position - transform.position;
    22.         float angle = Vector3.Angle(GameInformation.PlayerHead.transform.forward, directionToTarget);
    23.         float distance = directionToTarget.magnitude;
    24.  
    25.         if (Mathf.Abs (angle) < 90 && distance < 100) {
    26.             isVisible = false;
    27.         } else {
    28.             isVisible = true;
    29.         }
    30.  
    31.     }
    32.  
    33.     void UpdateVisibility(){
    34.         _renderer.enabled = isVisible;
    35.     }
    36. }
    And BAM! Now everything that is not in front of the head with this script disappears! I could actually do something else like changing the texture or anything I really want (just have to change the stuff in UpdateVisibility();)

    This is especially useful for concept in which you allow a player to change from 1st person view and 3rd person view, but don't want the said player to see more in 3rd person view than what he or she sees in 1st person view. Or even better, if you wish to not implement a FoV limit yet don't want people with huge wide screens (or more than one screen) to see more than those with thinner or single screens. (They could see the background, but not the enemy players that are out of bound)

    This is how great this topic have helped me. Thanks!

    PS. If you wonder what FoWCaster means as it's the name of the script... it just means "Fog of War Caster".