Forum rules - please read before posting.

Allowing detection of specific hotspots through colliders.

edited August 2020 in Technical Q&A

I'm currently trying to work out a method for detecting specific hotspots through colliders, from any distance.

AC: v1.70.1

Unity: 2018.4.1f1

To cut a long story short- 3D game, First person, mouse and keyboard, hotspot detection method: Mouse Over.

I'm using hotspots as a navigation method, I have a custom script that runs the Use interaction when the mouse is hovering over hotspots with a specific tag. The use interaction updates a 'distance' estimate.

This is all working as intended.

I would like to be able to detect a hotspot from any distance and through any collider. I've found that setting collider objects to a layer other than Default allows this however it's not an ideal solution. I only want certain hotspots to be detectable through colliders, not all.

I've tried changing the layer the hotspot is using but it appears hotspots are disabled when not on the Default layer.

Any ideas?

Comments

  • For a Hotspot to be considered "on", it must be placed on the layer defined in the Settings Manager's Hotspot layer field. By default, this is set to "Default" - hence the behaviour you're getting.

    There's a couple of ways you could go about this:

    1) Dynamically turn your Hotspots on/off according to how far away they are from the player. A script to do this, attached to each Hotspot, could also have a "Max Distance" field that you set in ths Inspector. Something like:

    using UnityEngine;
    using AC;
    
    public class DynamicHotspotDistance : MonoBehaviour
    {
    
        [SerializeField] private float maxDistance = 10f;
        private Hotspot hotspot;
    
        void Update ()
        {
            if (hotspot == null) hotspot = GetComponent <Hotspot>();
    
            float trueDistance = Vector3.Distance (KickStarter.CameraMain.transform.position, transform.position);
            if (trueDistance > maxDistance)
            {
                hotspot.TurnOff ();
            }
            else
            {
                hotspot.TurnOn ();
            }
        }
    
    }
    

    2) Set your Hotspot detection method to Custom Script, and call AC.KickStarter.playerInteraction.SetActiveHotspot () in a script to manually select Hotspots at runtime. This would be more involved, but would be less "hacky" than the above since you'd be in total control over the system.

  • Hey Chris, thanks for the prompt reply.

    I'm adding this feature quite far into development, so have to think about things carefully as not to break stuff. I like your solution above for dynamically turning hotspots on based on distance, however it seems this will conflict with actionlist functions where I turn hotspots on/off for gameplay progression reasons. (e.g it could turn a hotspot on that should be permanently off).

    I guess you would need to keep track of when hotspots should be on/off with variables and take those into account in the DynamicHotspotDistance script. This seems a bit over complicated though!

    I'm having a look at AC's DetectHotspots script and will see if I can make my own custom script for detection. Thanks for your help so far.

  • It seems this will conflict with actionlist functions where I turn hotspots on/off for gameplay progression reasons

    Yes, exactly - option 2 would be the more robust solution because of this.

    A note on the DetectHotspots script - this works on the assumption that all Hotspots are the detected by the same distance from the Player, since they must enter the Player's collider to be detected.

    If distance on some Hotspots is irrelevant, but (I'm guessing) you still want to account for e.g. walls that are in the way of the camera and the Hotspots, then you probably want to look into a Raycasting solution instead.

    Also, if distance detection is very binary (it either has to be within a certain distance, or it doesn't matter), then you could mark Hotspots of the latter type with a Tag e.g. "AlwaysDetect" and then account for that:

    using UnityEngine;
    using AC;
    
    public class RayDetectHotspot : MonoBehaviour
    {
    
        public float normalDistance = 5f;
    
        void Update ()
        {
            if (!KickStarter.stateHandler.IsInGameplay ())
            {
                return;
            }
    
            int layerMask = 1 << LayerMask.NameToLayer (KickStarter.settingsManager.hotspotLayer);  
            Ray ray = KickStarter.CameraMain.ScreenPointToRay (KickStarter.playerInput.GetMousePosition ());
            RaycastHit hit;
    
            if (Physics.Raycast (ray, out hit, KickStarter.settingsManager.hotspotRaycastLength, layerMask))
            {
                Hotspot hitHotspot = hit.collider.gameObject.GetComponent <Hotspot>();
                if (hitHotspot != null)
                {
                    bool hasTag = hit.collider.gameObject.CompareTag ("AlwaysDetect");
                    if (hasTag || hit.distance < normalDistance)
                    {
                        KickStarter.playerInteraction.SetActiveHotspot (hitHotspot);
                    }
                }
            }
        }
    }
    
  • Hey, sorry I missed this reply before. I cobbled together a similar solution to the above which seems to be working well. I really appreciate the help, if I run into any issues with my script I can compare it with this one to see what can be improved.

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.