Forum rules - please read before posting.

Way to check NPC proximity to Player

Hi! I used to have triggers on the ground so that when the Player 'dabbed', if the player was in a trigger zone, the relevant NPC nearby that trigger zone would run an ActionList and say something like 'Wow, cool.' I know, it's dumb, but also kind of funny.
Triggers started crashing things for me and I ended up removing most of them, so I wonder if there's another way to check player proximity to NPC, like an 'Object: Check Distance' action? I've tried using an LLM to write a script for me but it's just not really working.
Checked through the manual and closest I can find is for subtitles is the 'Limit by speaker proximity' option for the Subtitles menu, so I know there's a way AC can measure Player distance to NPC, just not sure how to query that for a specific action list.

The way I think I'd do it is have one ActionList per scene that runs when the player dabs, that runs through checks of player proximity to the NPCs, and then a dialogue line for each NPC that appears if the NPC is close enough to the player.

Comments

  • A custom script is best for this. What was the issue with the one your LLM wrote?

    Also: how did your original system detect that the Player was dabbing? That is, what caused the NPCs to comment at the correct time?

  • The script Grok was making didn't allow me to choose an ActionList Asset in the one field, despite repeated attempts by me to explain the field was only letting me choose scene-based Objects and I needed it to select an ActionList Asset.

    My original system I'll try remember - pressing D or clicking the button ran an ActionList, and if Bru dabbed within a trigger zone, the trigger itself had an ActionList that caused the only NPC standing within that trigger zone to say a response. Most of my NPCs didn't walk around, so I made multiple trigger zones each related to one NPC for their response. I can't forget how exactly I made the trigger check if Dab was pressed, but I think I set the trigger to run continuously to check if Dab was being pressed - not the most elegant solution.

    Script Grok came up with:

    using UnityEngine;
    using AC; // Adventure Creator namespace
    
    public class NPCDabResponse : MonoBehaviour
    {
        public ActionList dabResponseActionList; // Accepts AC ActionList asset (Project window)
        public float maxDistance = 3f; // Maximum distance for NPC response
        private GameObject player;
    
        void Start()
        {
            // Find the player GameObject (AC tags the player with "Player")
            player = GameObject.FindWithTag("Player");
            if (player == null)
            {
                Debug.LogError("Player not found! Ensure the Player GameObject has the 'Player' tag.", this);
            }
            if (dabResponseActionList == null)
            {
                Debug.LogError("No ActionList assigned to NPCDabResponse on " + gameObject.name, this);
            }
        }
    
        void Update()
        {
            // Check if the 'Dab' input is pressed
            if (KickStarter.playerInput.InputGetButtonDown("Dab"))
            {
                if (player == null)
                {
                    Debug.LogWarning("Cannot check distance: Player reference is missing.", this);
                    return;
                }
    
                // Calculate distance between NPC and player
                float distance = Vector3.Distance(transform.position, player.transform.position);
    
                // If player is within range, run the ActionList
                if (distance <= maxDistance)
                {
                    if (dabResponseActionList != null)
                    {
                        dabResponseActionList.Interact(); // Run the AC ActionList asset
                        Debug.Log($"NPC {gameObject.name} triggered ActionList: {dabResponseActionList.name} (Distance: {distance})");
                    }
                    else
                    {
                        Debug.LogWarning("No ActionList assigned to NPCDabResponse on " + gameObject.name, this);
                    }
                }
                else
                {
                    Debug.Log($"Player is too far from NPC {gameObject.name} (Distance: {distance}, Max: {maxDistance})");
                }
            }
        }
    
        // Visualize the maxDistance in the Unity Editor
        void OnDrawGizmosSelected()
        {
            Gizmos.color = Color.green;
            Gizmos.DrawWireSphere(transform.position, maxDistance);
        }
    }
    
  • You just need to replace ActionList with ActionListAsset to have it accept asset files. But I'd also recommend referencing AC's KickStarter.player property in place of a Player GameObject variable:

    using UnityEngine;
    using AC;
    
    public class NPCDabResponse : MonoBehaviour
    {
    
        public ActionListAsset dabResponseActionList;
        public float maxDistance = 3f;
    
        void Update()
        {
            if (KickStarter.playerInput.InputGetButtonDown("Dab") && AC.KickStarter.stateHandler.IsInGameplay())
            {
                float distance = Vector3.Distance(transform.position, KickStarter.player.transform.position);
                if (distance <= maxDistance)
                {
                    if (dabResponseActionList)
                    {
                        dabResponseActionList.Interact();
                    }
                }
            }
        }
    
        void OnDrawGizmosSelected()
        {
            Gizmos.color = Color.green;
            Gizmos.DrawWireSphere(transform.position, maxDistance);
        }
    
    }
    
  • Hi Chris - thanks so much for this. So, I put the script on an NPC and this works, but the issue I'm now facing is the NPC response happens immediately, and cancels out Bru's dab ActionList before the dab can happen.
    Is there a way to get the dab animation and sound to play and complete first before the NPC ActionList happens, please?

  • It shouldn't cancel out the original ActionList - do both ActionLists affect the same object, i.e. the Player?

    This alternatives adds a delay:

    using UnityEngine;
    using AC;
    
    public class NPCDabResponse : MonoBehaviour
    {
    
        public ActionListAsset dabResponseActionList;
        public float maxDistance = 3f;
        public float delay = 3f;
    
        void Update()
        {
            if (KickStarter.playerInput.InputGetButtonDown("Dab") && AC.KickStarter.stateHandler.IsInGameplay())
            {
                float distance = Vector3.Distance(transform.position, KickStarter.player.transform.position);
                if (distance <= maxDistance)
                {
                    Invoke(nameof(RunActionList), delay);
                }
            }
        }
    
        void RunActionList()
        {
            if (dabResponseActionList)
            {
                dabResponseActionList.Interact();
            }
        }
    
        void OnDrawGizmosSelected()
        {
            Gizmos.color = Color.green;
            Gizmos.DrawWireSphere(transform.position, maxDistance);
        }
    
    }
    
  • Thanks Chris, I'll try this soon.

    ActionLists don't both target the player - the player has a Dab ActionList where he dabs (it plays a sfx and player animation), and the NPCDabResponse ActionList is the script attached to the NPC (plays an NPC dialogue response eg "wow, cool" if the player dabs in their general vicinity).

    Was also thinking of something to try - setting the NPCResponse ActionLists to 'Play in Background' with an 'Engine: Wait' at the start, so that the ActionList doesn't interrupt the Dab ActionList. Previously when I pressed 'D' the NPC would immediately respond with "wow, cool" - so it kind of worked - but the player dab animation and sfx wouldn't play at all, so I wonder if having the NPC ActionList 'play in background' might solve that.

  • edited August 30

    Hi Chris - so, I tried the latest script but it didn't work, but what did work was the previous script, so I attached it to the NPC and set the NPC's ActionListReponse to 'Run in background' and set an initial Engine delay of 1.5 seconds.

    The issue I ran into is that when I clicked on 'Gather Speech', the new NPC dialogue wasn't being added to the speech list, I think because it was an ActionList that's not in the scene, and as such I wasn't able to assign voice tracks to it. So I created a new AC 'Interaction' in the Scene with the NPC responses and changed the script to accept an 'ActionList' instead of 'ActionListAsset' and all seems to be working well now, thanks.

    This is waaay better than the trigger zones I had previously. They would only work every once in a while. This seems to work consistently well, yay.

  • edited August 30

    Ah, darn - spoke too soon.
    Set everything up with all the NPCs but sadly it seems like the NPCDabResponse script only works when the scene is loaded up fresh, but is not surviving scene changes for some reason. So, if I walk out of a room to a new room, the new room won't work with the DabResponse from the NPCs. But if I load the new room first, it works fine. And if I leave the room and come back to it, same thing, doesn't survive a scene change and the response from the NPCs no longer works.

    [EDIT] Also, if I enter any room from a previous one, the new room I just entered doesn't work with the DabResponse, and I can see the gizmos have disappeared on the NPCs in the new room, so it only seems to work in the room that's first loaded up with Unity Player.

    I'm using the script by putting the script on each NPC. Each NPCs NPCDabResponse Interaction ActionList is parented to the NPC. Though, I've tried with empty GameObjects, and the same thing, it disappears after a scene change.
    Have tried adding various Remember components to the objects/NPCs but no luck unfortunately.

    Wonder if any way to try fix this please?

    [EDIT 2] Hmm, it seems like the script's functionality disappears very easily, even in Editor view. I have to keep re-selecting either the NPC group or the NPC GameObject in the Hierarchy view for the gizmo to reappear. As soon as I select something else in the Hierarchy, the script gizmo disappears, so I have to have the NPC selected before pressing 'Play' for things to work.

  • edited August 30

    This is the script I'm using btw. Using AC 1.82.2

    using UnityEngine;
    using AC;
    
    public class NPCDabResponse : MonoBehaviour
    {
    
        public ActionList dabResponseActionList;
        public float maxDistance = 3f;
    
        void Update()
        {
            if (KickStarter.playerInput.InputGetButtonDown("Dab") && AC.KickStarter.stateHandler.IsInGameplay())
            {
                float distance = Vector3.Distance(transform.position, KickStarter.player.transform.position);
                if (distance <= maxDistance)
                {
                    if (dabResponseActionList)
                    {
                        dabResponseActionList.Interact();
                    }
                }
            }
        }
    
        void OnDrawGizmosSelected()
        {
            Gizmos.color = Color.green;
            Gizmos.DrawWireSphere(transform.position, maxDistance);
        }
    
    }
    
  • Just replace OnDrawGizmosSelected with OnDrawGizmos to have the Gizmo show at all times.

    No Remember scripts are necessary - you're not changing any data at runtime. Check the component's Inspector after a scene-change - are the values still correct?

  • Will try this, thanks, but the main issue was that the scripts seemed to stop working after a scene change. Yes, values were the same. Once, the ActionList seemed to lose its reference for one NPC, not sure why. No problem having multiple NPCs in one room all using the same script? Though, happens even in rooms with just 1 NPC.

  • There's no restriction on how many instances can be placed. Start with just one though, and place in Debug.Log statements inside each section of the Update loop to see what's being run and what's not.

  • Thanks Chris. The gizmos are now always visible, so that's great. But the action isn't working as intended after a scene switch.

    I'm trying to figure out what's going on, hopefully this video helps:

    The Debug notices come up in console on first scene launch and dab, but it seems like on scene switch, the script stops working - nothing comes up in console. The errors after scene switch are related to a Sorting Map and the tricycle, and a yellow ! error, and I've tried disabling the tricycle when testing, the sorting map error no longer comes up, but it's still the same result.

    I did manage once by chance (not sure how) to get the script to survive the scene change, but can't reproduce it.

    Script:

    using UnityEngine;
    using AC;
    
    public class NPCDabResponse : MonoBehaviour
    {
        public ActionList dabResponseActionList;
        public float maxDistance = 3f;
    
        void Start()
        {
            Debug.Log("NPCDabResponse Start on " + gameObject.name + " in scene " + UnityEngine.SceneManagement.SceneManager.GetActiveScene().name);
        }
    
        void Update()
        {
            if (KickStarter.playerInput.InputGetButtonDown("Dab") && AC.KickStarter.stateHandler.IsInGameplay())
            {
                Debug.Log("Dab input detected for " + gameObject.name);
                float distance = Vector3.Distance(transform.position, KickStarter.player.transform.position);
                Debug.Log("Distance to player: " + distance + " for " + gameObject.name);
                if (distance <= maxDistance)
                {
                    Debug.Log("Player within range for " + gameObject.name);
                    if (dabResponseActionList)
                    {
                        Debug.Log("Triggering ActionList: " + dabResponseActionList.name + " for " + gameObject.name);
                        dabResponseActionList.Interact();
                    }
                    else
                    {
                        Debug.LogWarning("dabResponseActionList is null for " + gameObject.name);
                    }
                }
            }
        }
    
        void OnDrawGizmos()
        {
            Gizmos.color = Color.green;
            Gizmos.DrawWireSphere(transform.position, maxDistance);
        }
    }
    
  • Ah, ok. I think I may have solved it.

    I changed this line:

    if (KickStarter.playerInput.InputGetButtonDown("Dab") && AC.KickStarter.stateHandler.IsInGameplay())

    And removed this:

    && AC.KickStarter.stateHandler.IsInGameplay()

    to end up with this:

    if (KickStarter.playerInput.InputGetButtonDown("Dab"))

    And it seems to be working ok now.

    Lucked out there I think, hopefully doesn't break other stuff but will test more, thanks for the help.

  • edited September 1

    Hi Chris, I'm running into a new problem.

    When I press 'd' the player dabs and the NPC response works well, and it's how I've been testing.

    However, when I trigger the Player Dab from an icon in the Inventory that plays the PlayerDab ActionList, the NPC response isn't working.

    If I could get the Inventory Dab icon to simulate 'pressing d' that should work, but weirdly, I can't seem to get the icon in the inventory to simulate pressing 'd' like I've done with the FlashHotspots icon in the inventory. The player won't dab. The icon button is set up the same way in the Project Settings as FlashHotspots.

    As such, the Dab icon in the inventory is currently set to run an ActionList because I can't seem to get the 'simulate input' button to work.

    I did try adding a 'simulate pressing d' Action in the ActionList, and while the player does dab after pressing the inventory Dab icon, it doesn't trigger the NPCs response.

    I wonder if you have any tips please, for either how to get the inventory Dab icon to properly simulate pressing 'd' because pressing d on the keyboard works (this would be the simplest solution I think), or for how to tweak the script so that the input the script isn't looking for the 'd' keyboard input but more looking for the ActionList that runs, or at the end of the chain of the Player Dab ActionList to 'send a message' Action to trigger the NPCDabResponse script, so that the script is triggered with either 'd' on the keyboard or running the Player Dab ActionList?

    This makes the player Dab but doesn't result in the NPC's NPCDabResponse:

    This doesn't work (nor does changing the input axis to 'dab' or 'd' or changing 'simulate button' to 'axis') ie the player doesn't Dab:

    This 'FlashHotspots' icon does work, but for some reason a similar setup for the Dab icon doesn't work:

    Project Settings:

    Active Input:

  • You can have the script kick in when the Dab_ActionList is run by hooking into the OnBeginActionList custom event:

    using UnityEngine;
    using AC;
    
    public class NPCDabResponse : MonoBehaviour
    {
        public ActionListAsset playerDab;
        public ActionList dabResponseActionList;
        public float maxDistance = 3f;
    
        void OnEnable() => EventManager.OnBeginActionList += OnBeginActionList;
        void OnDisable() => EventManager.OnBeginActionList -= OnBeginActionList;
    
        private void OnBeginActionList(ActionList actionList, ActionListAsset actionListAsset, int startingIndex, bool isSkipping)
        {
            if (actionListAsset && actionListAsset == playerDab)
            {
                float distance = Vector3.Distance(transform.position, KickStarter.player.transform.position);
                if (distance <= maxDistance && dabResponseActionList)
                {
                    dabResponseActionList.Interact();
                }
            }
        }
    
        void OnDrawGizmos()
        {
            Gizmos.color = Color.green;
            Gizmos.DrawWireSphere(transform.position, maxDistance);
        }
    }
    
  • Brilliant, thanks Chris. This seems to do the trick. Stoked, thank you!

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Welcome to the official forum for Adventure Creator.