2
\$\begingroup\$

I'm using Unity 3d and i have to accomplish the following task: get the closest "visible" object to my player in forward direction.

It is a sort of radar.

I don't know where to start. Any advice is welcomed.

Thanks

\$\endgroup\$
  • \$\begingroup\$ what will you do when the object returned is always the ground you're standing on ? this problem needs restrictions to work well enough, like objects only smaller than the player... filter/layers (only living entities?..) \$\endgroup\$ – v.oddou Jun 2 '16 at 1:38
4
\$\begingroup\$

Assuming that you're making a 3D game, you can use Physics.OverlapSphere to get a an array of Colliders that are within a certain range of the player. To check if the object is "visible" to the player, you could simply call Physics.Raycast in the direction of the object(s) returned by OverlapSphere and check if nothing that isn't the object you're checking for blocks the raycast. Here's a code example:

public class RadarController : MonoBehaviour
{
    public int RadarRadius;
    public string DetectableObjectTag;

    public void CheckForVisibleObjects()
    {
        Collider[] objectColliders = Physics.SphereOverlap(this.transform.position, this.RadarRadius);
        for(int index = 0; index <= objectColliders.Length - 1; index++)
        {
            GameObject colliderObject = objectColliders[index].gameObject;
            if(colliderObject.tag == this.DetectableObjectTag)
            {
                RaycastHit hit;
                bool hitOccurred = Physics.Raycast(this.transform.position, colliderObject.transform.position.normalized, out hit);
                if(hitOccurred && hit.gameObject.tag == this.DetectableObjectTag)
                {
                    // Do whatever you need to do with the resulting information
                    // here if the condition succeeds.
                }
            }
        }
    }

    public void Update()
    {
        this.CheckForVisibleObjects();
    }
}

Disclaimer: I am not able to check and see if this code works properly, or if it performs at an ideal rate. If there is an issue, just mention it and I'll see what I can do.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ code example would be amazing to have; or a link to a code example in a tutorial? \$\endgroup\$ – Old account Apr 25 '16 at 16:36
  • 2
    \$\begingroup\$ @omouse Added a code example. \$\endgroup\$ – Ethan Bierlein Apr 26 '16 at 17:10
  • \$\begingroup\$ that maybe fine for an indie game with low standards. but rigorously, visibility is not solved by one raycast. Also about efficiency, there surely is a better algo using directly the physics partitioning structures. \$\endgroup\$ – v.oddou Jun 2 '16 at 1:37
4
\$\begingroup\$

You can use the dot product trick to get a list of instances actually visible by the player (thus lying inside the camera frustum), and check for the distance from your camera object to get the closest one.

First, you can test a certain number of instances so that their distance is low enough for them to be considered "near" the camera (or the player). Instead of testing every object, which can be overkill for your game performance, you can consider a volume around the camera (a sphere, for example) and test only object inside this space partition. The number of instances to work with is now lower, and more tests can be performed.

In mathematics, the dot product of two vectors gives as result a scalar number, which represents the projection of vector v1 upon vector v2. The length of projection depends on the cosine function of the angle between the two vectors. We can see it the other way: given two vectors, if their dot product is a value k, then their mutual orientation in the space (or plane, or any n-dimensional system) is such that the angle between them has a cosine value cos(θ) = k. So, the angle is θ = arccos(k).

If your camera has a FOV angle ranges from to β, assuming angle 0° is in front of the camera and that the frustum is just a cone, if θ is either lower than or greater than β, your object is out of sight.

enter image description here

This said, you consider two vectors, A and B. Vector A is the relative position of an object, and B is the "front" vector of the camera. If the dot product of A and B is lower than or equal to the cosine of β, such object is potentially visible to the player. Otherwise, its position is away from the sight cone.

The final step is to search the list of remaining objects to find the one whose distance is lowest among all. Here's your closest, visible object to focus your attention on!

To sum up: consider a list of candidate object, so that every object is closer than a certain distance from camera. Help comes from space volume instead of checking every single instance. Then, compute dot product of those instances, to get a list of only instances lying in front of the camera. Finally, look for the closest one.

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Typically, to get the closest object from the player, you do something like this (generic pseudo-code):

var listOfObjects = getAllObjects()
var closestObject = null
var distanceSquareOfClosest = infinite

for otherObject in listOfObjets:
  if otherObject != this:
    var distanceSquareOfThisObject = (otherObject.position - this.position).lengthSquare()
    if distanceSquareOfThisObject < distanceSquareOfClosest:
      distanceSquareOfClosest = distanceSquareOfThisObject
      closestObject = otherObject

I don't know how it's done in Unity, but I would assume there is something that lets you get all the objects, and there would be a way for you to check if they're visible or not. You'd modify the if otherObject != this to something like if otherObject != this && otherObject.isVisible.

To find all the game objects, you can take a look here.

| improve this answer | |
\$\endgroup\$
  • 2
    \$\begingroup\$ I don't think the OP means visible as in not invisible but visible to the player. E.g. not hiding behind a wall. Probably hoping for some sort of ray casting implementation. \$\endgroup\$ – Richard Tingle Apr 24 '16 at 21:17
  • \$\begingroup\$ @RichardTingle Yeah; a simple google search revealed tons of resource to do that though.. \$\endgroup\$ – Vaillancourt Apr 24 '16 at 21:24
2
\$\begingroup\$

As mentioned in the comments you probably want a Raycast.

An example of how to implement a forward-facing raycast in a Fixed Update cycle is spelled out exactly in the Unity Scripting API Documentation here. This will return true if the raycast strikes a collider in front of whatever object you attach the script to.

From the documentation above:

using UnityEngine;

public class ExampleClass : MonoBehaviour 
{
    void FixedUpdate() 
    {
        Vector3 fwd = transform.TransformDirection(Vector3.forward);

        if (Physics.Raycast(transform.position, fwd, 10)) 
            print("There is something in front of the object!");
    }
}

After that, to return the object you strike with your raycast, you use a Raycast.Hit to get the transform of whatever you're hitting. We do this because the transform has a variable of gameObject. SO:

        using UnityEngine;

public class ExampleClass : MonoBehaviour 
{

public GameObject storedGameObject; //create a bucket to store the game object in when we find it

    void FixedUpdate() 
    {
    RaycastHit hit; //define the raycasthit 

        Vector3 fwd = transform.TransformDirection(Vector3.forward); //define the forward Vector3

        if (Physics.Raycast(transform.position, fwd, hit)) //use the current transform position to start, shoot outward "fwd", and return a RaycastHit
            {
            storedGameObject = hit.transform.gameObject; //set the bucket to the value of the target's transform.gameobject
        }
    }
}

Full disclosure: I'm at work and can't test this code, but it should be approximately what you need.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.