Forum rules - please read before posting.

Changing a multiple interaction hotspot into a single 'use' interaction hotspot during game

edited October 2021 in Technical Q&A

Hi, my PNC adventure game's interaction method is "Choose Hotspot then Interaction".

Whenever there's a hotspot with only one possible interaction, I like to check the "Single 'use' interaction" checkbox to smoothen the gameplay experience, saving the player one click. Thanks for that feature!

However, as you can imagine, I also want to have objects with multiple 'use' interactions. But I like this idea of keeping things tidy by disabling ones that are found ineffective. For any of those hotspots, that checkbox needs to be unchecked.

Let's say there's a CUPBOARD you can open and push. After choosing "push" you get the typical "It won't budge" response and the push interaction is disabled. You're then left with only one interaction possibility (open). From that point onwards, I'd like to make the hotspot work like a single 'use' interaction one. Otherwise, they player has to click twice there.

Is there a way to do this? As far as I know, this can't be done via an ActionList action. Would a custom code solution help... or lead into breaking things, as the hotspot wouldn't have a single 'use' interaction all the way?

I can, of course, simply add a CUPBOARD2 hotspot that would take the first one's place after "push" has been attempted and CUPBOARD2 would only have that single 'use' interaction (open). This just seems like a lot of hassle; a whole lot of duplicates for a game that would be doing this a lot.

Comments

  • Hi Luuk,
    create an C# script named "ActionHotspotOneClick.cs" with this content:

    using UnityEngine;
    using System.Collections.Generic;
    
    #if UNITY_EDITOR
    using UnityEditor;
    #endif
    
    namespace AC
    {
    
        [System.Serializable]
        public class ActionHotspotOneClick : Action
        {
    
            // Declare properties here
            public override ActionCategory Category { get { return ActionCategory.Hotspot; }}
            public override string Title { get { return "Toggle Hotspots OneClick state"; }}
            public override string Description { get { return "This action changes the hotspots OneClick type."; }}
    
    
            // Declare variables here
            public int parameterID = -1;
            public int constantID = 0;
            public Hotspot hotspot;
            protected Hotspot runtimeHotspot;
            public bool newOneClickState = false;
    
            public override void AssignValues(List<ActionParameter> parameters)
            {
                runtimeHotspot = AssignFile<Hotspot>(parameters, parameterID, constantID, hotspot);
            }
    
            public override float Run ()
            {
                if (runtimeHotspot == null)
                {
                    return 0f;
                }
    
                DoChange(runtimeHotspot);
                return 0f;
            }
    
            protected void DoChange(Hotspot _hotspot)
            {
                if (newOneClickState == true)
                {
                    _hotspot.oneClick = true;
                }
                else
                {
                    _hotspot.oneClick = false;
                }
            }
    
    
            public override void Skip ()
            {
                 Run ();
            }
    
    
    #if UNITY_EDITOR
    
            public override void ShowGUI(List<ActionParameter> parameters)
            {
                parameterID = Action.ChooseParameterGUI ("Hotspot to affect:", parameters, parameterID, ParameterType.GameObject);
                if (parameterID >= 0)
                {
                    constantID = 0;
                    hotspot = null;
                }
                else
                {
                    hotspot = (Hotspot) EditorGUILayout.ObjectField ("Hotspot to affect:", hotspot, typeof (Hotspot), true);
    
                    constantID = FieldToID <Hotspot> (hotspot, constantID);
                    hotspot = IDToField <Hotspot> (hotspot, constantID, false);
                }
    
                newOneClickState = EditorGUILayout.Toggle ("Is OneClick:", newOneClickState);
            }
    
            public override void AssignConstantIDs (bool saveScriptsToo, bool fromAssetFile)
            {
                if (saveScriptsToo)
                {
                    AddSaveScript <RememberHotspot> (hotspot);
                }
                AssignConstantID <Hotspot> (hotspot, constantID, parameterID);
            }
    
    
            public override string SetLabel ()
            {
                if (hotspot != null)
                {
                    return hotspot.name + " - " + newOneClickState;
                }
                return string.Empty;
            }
    
    
            public override bool ReferencesObjectOrID (GameObject _gameObject, int id)
            {
                if (parameterID < 0)
                {
                    if (hotspot != null && hotspot.gameObject == _gameObject) return true;
                    if (constantID == id) return true;
                }
                return base.ReferencesObjectOrID (_gameObject, id);
            }
    
    #endif
        }
    
    }
    

    Copy this script into a folder e.g. Assets\AdventureCreator\Scripts\Custom.
    Add this folder in the "Action Manager" as a custom folder. You should already see the new action now if you click on "Hotspot".

    Now you can use the action in your action list under "Hotspot"->"Toggle Hotspots OneClick state".

  • For older AC Version you need to use a constrctor:

            public ActionHotspotOneClick()
            {
                this.isDisplayed = true;
                category = ActionCategory.Hotspot;
                title = "Toggle Hotspots OneClick state";
                description = "This action changes the hotspots OneClick type.";
            }
    

    instead of override properties. So replace this with the above:

    // Declare properties here
            public override ActionCategory Category { get { return ActionCategory.Hotspot; }}
            public override string Title { get { return "Toggle Hotspots OneClick state"; }}
            public override string Description { get { return "This action changes the hotspots OneClick type."; }}
    
  • edited October 2021

    Yes, I have the 1.72.x, we've done a few customizations to the project so updating to the latest AC version is a bit tricky (I'm aware the forum rules state one should – sorry).

    I sorted this thing out with the amazing @KaiB in private (though the end result is there, above). Thank you so much once again! :)

  • A further problem presented itself: the script works fine otherwise but the OneClick states of any hotspots are reseted after a Scene Switch. What would need to be added is a "Remember OneClick state" component or something similar to prevent this from happening. Is that possible? It would also need to be recognized when saving the game.

  • edited December 2021

    What would need to be added is a "Remember OneClick state" component or something similar to prevent this from happening.

    As the oneClick variable isn't changed without custom scripting, the RememberHotspot component won't store changes made to it at runtime. In this case, yes: a custom Remember script will be necessary. Such a script, however, will work both when re-entering the scene and when loading a save-game file.

    A tutorial on this topic can be found here, but this ought to do it:

    using UnityEngine;
    
    namespace AC
    {
    
        public class RememberOneClick : Remember
        {
    
            public override string SaveData ()
            {
                OneClickData data = new OneClickData();
                data.objectID = constantID;
                data.savePrevented = savePrevented;
    
                data.oneClick = GetComponent<Hotspot>().oneClick;
    
                return Serializer.SaveScriptData <OneClickData> (data);
            }
    
    
            public override void LoadData (string stringData)
            {
                OneClickData data = Serializer.LoadScriptData <OneClickData> (stringData);
                if (data == null) return;
                SavePrevented = data.savePrevented; if (savePrevented) return;
    
                GetComponent<Hotspot>().oneClick = data.oneClick;
            }
    
        }
    
    
        [System.Serializable]
        public class OneClickData : RememberData
        {
    
            public bool oneClick;
    
            public OneClickData () { }
    
        }
    
    }
    
  • @ChrisIceBox Thanks a lot for the script, though after trying it, it doesn't seem to work. Unity now recognizes a "Remember One Click" component which I added to the GameObject in question that has the Hotspot with the OneClick feature, but there doesn't seem to be an effect. After a Scene Switch, the OneClick state is reseted, it isn't remembered.

    One possible reason is that our project is using AC v1.72.4 – @KaiB took this into account and created a separate script, as noted earlier in this thread. Might this be why the script you provided doesn't work for me?

    We aren't currently able to update to a new AC version, as our coder (who's currently not available) has done some customizations we'd lose with the update (including, for example, a new standard movement method, AC expects animations for that). To my understanding these changes shouldn't affect this script, though.

  • It appears to work fine in my own testing - and the Remember system was unchanged since v1.72.4.

    How does it behave on a fresh Hotspot that's unaffected by the Action? Create a new Hotspot, add the component to it, and then run the game: you should be able to save the game, toggle the Single 'Use' interaction? in the Hotspot's Inspector, then have it reverted when loading back.

  • edited December 2021

    @ChrisIceBox Now that I tried it, when it comes to saving and loading, it works on both a fresh Hotspot and one with the actual Hotspot>Toggle OneClick state (available thanks to @KaiB's script above). When I save the game in that room, then load it, the OneClick state is remembered and that feature works like it should.

    So it ONLY breaks when you leave the room and enter it again. That's when all the hotspots are reseted to the state they're in when first entering that room.

    P.S. This was actually the first time I tried the save/load feature altogether. Another peculiar thing (and actually a huge problem) I noticed is that if I save the game and then load that save, all the hotspot labels in every room go blank. The issue persists after relaunching Unity and if I make a build of the game. Fellow AC devs told me this isn't normal so I guess it isn't because of another "Remember" I've forgotten to add to each Hotspot... a quick googling didn't help, either. EDIT: Looks like there's a custom "hotspot override" thing in place that the save/load feature doesn't recognize yet. My coder should be able to fix that. My apologies – ignore this last paragraph.

  • edited December 2021

    The effects of a Remember component should be applied both when loading a save-game file and re-entering a scene. In my testing, the same Hotspot has its checkbox state restored correctly after switching scene and back.

    When re-entering a scene, the data from a Remember component is applied before the OnStart cutscene process - so if you're setting its value in there, this'll occur after the Remember component has restored things. Is it possible that there's a conflict of that kind occuring in your scene? Are other Remember components applying their data correctly at this time?

  • @ChrisIceBox Considering your last question, you're correct – the same goes for all Remember components in that room – they, too, are reset after leaving the room and coming back. This happens in another room, too. But there's one room where Remember components work as they should. I can't seem to find a difference between them that would cause the opposite behaviour. None of these rooms' OnStart cutscenes interfere with hotspot settings.

    What's interesting is that saving the game really saves the current state of the Remember component for good. I made a GameObject with a hotspot that changes between OneClick state and a normal one (with two interactions available) with every click. If the OneClick's default state is ON and I click the hotspot once to set it to OFF, leave the room and come back, it's reset to ON. But If I set it to OFF, save the game, THEN leave the room and come back, it remains OFF.

    But if I then set it back to ON, leave the room and come back, it resets back to OFF (so it then doesn't stick to ON (or even return back to its default state), instead it returns to the last saved=remembered state in the loaded savegame). So definitely re-entering the room is doing something weird here...

  • Indeed, it's not right.

    You mentioned making customisations to the project - did this involve editing AC's code directly? The behaviour you're getting isn't something I can recreate without knowing the steps you've taken to arrive at it.

  • Possibly, or even probably, yes. I'll ask my coder about it once he becomes available. Thank you immensely for the help with pinpointing the issue, I believe we can sort it out on own.

  • edited December 2021
    I'm a bit embarrassed to admit this, but this was due to a custom Scene switcher my coder had made a year ago when first building the rooms for our game, he probably wasn't aware of AC's native scene switching action so used a custom script of his own. I guess it didn't load the data for the room properly. I had earlier changed it to AC's own Scene>Switch in the room that worked, but since forgotten about it. Did the same now for all the room exits and Remember states now universally work as they should. Apologies for the extra hassle and thanks again @ChrisIceBox for the help! Merry Christmas!
  • No problem - thanks for the follow-up!

    In order to save scene data when switching scene, you will have to involve AC. However using the Action itself isn't strictly necessary, and it can be done through script if you prefer:

    AC.KickStarter.sceneChanger.ChangeScene ("MySceneName", true);
    
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.