Forum rules - please read before posting.

[Feature Request] Make Highlights be ConstantID referenceable.

I am working on decoupling set geometry from AC scenes so I can do a bit more complex content without requiring completely unique scenes for every variation and can work with prefab variants. But Hotspot Highlights were a hurdle to this (I've modified the AC scripts in the meantime to handle this suggestion).

It would be nice as a built-in feature for Hotspots to be able to reference Highlights by ConstantID, as Highlights need to actually be on the geometry they are going to highlight if you want geo-highlighting instead of generic shape, unlike the other components like Marker, Hotspot, Trigger, Interaction, etc.. which are fine since they can sit as their own objects.

Here are my changes so I wouldn't have to break any references to the public .highlight field that people might have had:

Hotspots.cs:
Add:

[FormerlySerializedAs("highlight")]
public Highlight highlightReference;
[SerializeField, HideInInspector] public int highlightID = -1;

Change the public Highlight highlight; line to:

public Highlight highlight
{ 
    get
    {
        if(highlightReference == null && highlightID > -1)
        {
            return KickStarter.stateHandler.ConstantIDManager.GetComponent<Highlight>(highlightID);
        }
        return highlightReference;
    }
    set
    {
        highlightReference = value;
        if(value != null)
        {
            var constID = value.GetComponent<ConstantID>();
            if(constID != null) { highlightID = constID.constantID; }
        }
    }
}

HotspotEditor.cs
Replace the _target.highlight = ... line on line 78:

var highlight = (Highlight)CustomGUILayout.ObjectField<Highlight>("Object to highlight:", _target.highlightReference, true, string.Empty, "The Highlight component that controls any highlighting effects associated with the Hotspot");
if(highlight != null)
{
    var highlightID = highlight.GetComponent<ConstantID>();

    if (highlightID == null && PrefabUtility.IsPartOfAnyPrefab(highlight.gameObject))
    {
        highlightID = highlight.gameObject.AddComponent<ConstantID>();
        Debug.LogWarning("Target Highlight is part of a Prefab. Cannot be assigned without a constant ID! One has been added, make sure to save the override!");
    }
    if (highlightID != null) { _target.highlightID = highlightID.constantID; }          
}
_target.highlightReference = highlight;

If there's any issues with doing it this way I'd love to know! Cheers!

Comments

  • Thanks for sharing - though I'd like to hear more about the original situation that led you to this.

    Are you looking to keep your Hotspots and their on-screen visuals separate, or is attaching the Hotspot component directly to the same object that has the Highlight not an option?

    Here's the code adapted to a separate script that you can attach to Hotspots:

    using UnityEngine;
    using AC;
    
    [ExecuteInEditMode]
    public class HighlightID : MonoBehaviour
    {
    
        public int recordedID;
    
        private void OnEnable ()
        {
            AssignHighlight ();
            EventManager.OnInitialiseScene += AssignHighlight;
        }
    
        private void OnDisable ()
        {
            EventManager.OnInitialiseScene -= AssignHighlight;
        }
    
        private void AssignHighlight ()
        {
            if (Application.isPlaying && recordedID != 0 && GetComponent<Hotspot> ().highlight == null)
            {
                Highlight highlight = KickStarter.stateHandler.ConstantIDManager.GetComponent<Highlight> (recordedID);
                if (highlight) GetComponent<Hotspot> ().highlight = highlight;
            }
        }
    
        #if UNITY_EDITOR
    
        private void Update ()
        {
            if (Application.isPlaying) return;
            Highlight highlight = GetComponent<Hotspot> ().highlight;
            if (highlight == null)
            {
                recordedID = 0;
                return;
            }
            ConstantID constantID = highlight.GetComponent<ConstantID> ();
            if (constantID == null) constantID = highlight.gameObject.AddComponent<ConstantID> ();
            recordedID = constantID.constantID;
            Debug.Log ("Recorded " + recordedID);
        }
    
        #endif
    
    }
    
  • Basically, I want to decouple my environment prefabs from my AC scenes so that I can use them as part of Timeline cutscenes and freely load in different variants of my environments for different scenarios as well without the scene logic losing its references.

    But because they're prefabs, I can't have ActionLists on them to be triggered unless I move everything to ActionList assets. So I thought I'd just put the Highlight. I could also put the Hotspot I guess, which might be better, but then instead I need to be able to reference the Interactions they triggered by ConstantID instead of being a hard-coded reference. Or does Hotspot allow you to reference by ConstantID just like an actionlist asset can?

    Thanks!

  • Or does Hotspot allow you to reference by ConstantID just like an actionlist asset can?

    The script above should allow for that. But if you're separating environment prefabs, does a typical prefab include both the visual element as well as the Hotspot? Or are you keeping the interactivity separate? If they're both part of the same prefab, you shouldn't need to rely on a Constant ID reference for the Highlight.

  • Right now, the Prefab has the Visual/Highlight elements and then Hotspots are in the scene, using the modifications I had initially posted.

    What would you advise for that when I want the Hotspots to still be able to activate "Interactions" that exist in the scene, not on the prefab? Having the Hotspots on the prefab probably would be more ideal yeah... assuming I can get those interaction calls.

    Cheers

  • If you're prefabbing a Hotspot, I generally recommend that the prefab also includes the visual/Highlight elements, and that the Hotspot relies on ActionList asset files for its Interactions. This workflow is covered in more detail in this tutorial.

    Existing scene lists can be converted to asset files, but If you needed the Interaction ActionLists to be scene-based, you could either update the script to account for those as well (apologies, I misread your last question), but the built in way would be to have the Hotspot Interactions run ActionList asset files, which themselves just contain an ActionList: Run Action that references a list in the scene.

    While you could then rely on the Constant ID system to have such lists be referenced, you'd still have to end up making a separate ActionList asset file for each Hotspot interaction, effectively doubling the number of lists involved. Instead, you can rely on ActionList parameters to control which list is ultimately called.

    To do this, create a single ActionList asset named e.g. "RunSceneList", and inside it define a GameObject parameter named e.g. "ListToRun". Then create an ActionList: Run Action that uses this parameter to override which "In Scene" list is run.

    Next, go to your Hotspot and set the Interaction Source field to Asset File. For each Interaction, you can then assign "RunSceneList" as the list to run.

    Finally, to re-connect the scene lists you want each Interaction to ultimately run, attach a Set Interaction Parameters component to the Hotspot, which allows you to set an Interaction asset's parameters at the time the Interaction is run. Here, you can assign the scene-based ActionList that the "ListToRun" parameter value should be set to.

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.