handsomejack
handsomejack

Reputation: 33

Unity best way to find distance between NPCs and player

I've written some code to find distance between player and some NPCs and if any of them has < minDistanceToTalk, I activate a text which says "Press E to talk to character" I'm running this on every update method and code checks distance to every NPCs. Is this bad for performance?

Note: I will have 3 NPCs maximum so I think it's okay to do this calculation but what if I had 1000 NPCs?

    void Update()
    {
        for (int i = 0; i < characters.Length; i++)
        {
            distances[i] = Vector3.Distance(player.transform.position, characters[i].transform.position);
            if (distances[i] < minDistanceToTalk)
            {
                playerCloseCharacter = true;
                currentCharacter = characters[i];
                talkWithCharacterText.gameObject.SetActive(true);
            }
        }

        if (!playerCloseCharacter)
        {
            talkWithCharacterText.gameObject.SetActive(false);
        }
        playerCloseCharacter = false;
    }

Upvotes: 1

Views: 1917

Answers (1)

Bola Gadalla
Bola Gadalla

Reputation: 400

YES THAT IS VERY BAD FOR PERFORMANS LOL, this update runs 60+ frames per second, imagine every second 60 * 3 = 120 operations. And for 1000 NPC thats 1000 * 60 = 60000 operations per second, this will be building up and slow performance. Try your best not to put for loops in update, update it self is like a for loop in the sense its a continues run.

There are two ways to go about this:

[EASY WAY] You could create a sphere collider that covers a certain distance that you want the player to be within to interact with the NPC, that collider will be on the NPC and set the isTrigger to true on the collider. And then create a script onto that that would check for the player if they are near. For example:

private void OnTriggerEnter(Collider other)
{
    Player player = other.GetComponent<Player>();
    if(player != null)
    {
        // Do stuff if the player is within the collider
    }
}

Or you can place this code on the player or within the "Player.cs" script that you might have. You would do the same exact thing, but instead of Player player = other.GetComponent<Player>(); you would do NPC npc = other.GetComponent<NPC>(); and then in the if statement would be if(npc != null) do what you want within. Thats the easy way, you will have a lot of colliders but thats WAYYY better then looping through all the NPCs. https://docs.unity3d.com/ScriptReference/Collider.OnTriggerEnter.html

[MOST PERFORMANT] I dont have the code for this but here is the documentation about it: https://docs.unity3d.com/ScriptReference/Physics.Raycast.html

What you would do is basically cast a ray around you in a circle up to a certain distance, and that ray would return any thing it collides with (note objects has to have some sort of colliders to be detected). And so you can check weather that thing that it collided is an NPC or not, and if it is, you can do stuff that you want or call functions on the NPC itself. This is performant because you wouldnt need to create multiple colliders like the first implementation, rather you are cast an invisible ray that doesnt have to be rendered and so it saves on performance. You can also just a cast a ray at a certain layer mask and ignore all other masks, so thats even better for performance because you save on operations that you wouldnt use.

I actually found a good youtube video about it: https://www.youtube.com/watch?v=XYIyRKI3HW0

good luck!

Upvotes: 2

Related Questions