Forum rules - please read before posting.

[SOLVED IN 1.39] A way to combine hotspot modes?

edited October 2014 in Technical Q&A
I was wondering if it was possible to combine elements from two different interaction methods?

See for a while now I've used the Context Sensitive setting in my Unity2D game and had a menu with icons that appears around the cursor to illustrate what actions the left and right mouse buttons do. The icons are made with Interaction elements, so they aren't buttons, they appear based on what actions the hotspot has defined. So if the hotspot has no interactions, no icons appear.

Now I've changed the interaction method to Choose Hotspot Then Interaction, in order to lock the cursor menu in the center of the hotspot so I can click on the icons. But none of the appear types really do it for me - I'd rather the menu appear as I hover over the hotspot instead of having to click once before it appears.

This is totally possible by setting the menu to appear On Hotspot instead of On Interaction, however this means that the context-senstive cursor icons don't work, they are just all turned on regardless of whether the hotspot has an action defined for that particular cursor or not. And on top of that I have a label with the hotspot description to which I append the cursor prefixes, but that also doesn't work in this half-and-half mode.

Is there a way to do this or can these two modes just not really be combined in this way?


Here's a Vine to clarify:
So not all three icons should be active for every hotspot. That's the code that's missing in the On Hotspot setting.


Addendum: the cursor menu, when set to appear centered on a hotspot, displays at the feet of NPC characters with the hotspot script, even though they also have a box collider with the pivot point in the center. Any way to fix that, or define a marker/gameobject within the character prefab that the hotspot should adhere to?

Comments

  • This may be possible already by injecting some custom code into the MenuSystem script.

    Inside the OnMenuEnable function, check for the menu in question and call:

    _menu.MatchInteractions (playerInteraction.GetActiveHotspot ().useButtons);

    PlayerInteraction is attached to the GameEngine prefab, just use a GameObject.FindWithTag (Tags.gameEngine) to reference it.

    As for the menu appearing at an NPC's feet, I'll sort that in 1.39.
  • That totally worked! Super rad, thanks :)
  • edited September 2014
    Okay one small addendum: is it possible to keep the menu visible while the cursor has already left the hotspot? If the collider is too small you can't click on certain buttons in the interaction menu because that part falls outside of the colliders bounding box so then the menu turns off.

    Ideally the hotspot is the first contact point, then when the menu opens that takes precedence as the collider for the cursor. Like in proper Choose Hotspot Then Interaction mode you have the setting Cancel Interaction With > hover or click (which does nothing in this case). Is it possible to combine that with a menu that is set to appear On Hotspot?

    [UPDATE] Just figured it out!

    By using the same method I also changed the AppearType of the menu once it becomes visible, using:

    _menu.appearType = AppearType.OnInteraction;

    Then I used this bit of code to re-enable the OnHotspot AppearType when the menu turns off (aka the mouse moves off of it):

    void Update ()
    {
    Menu interactionMenu = PlayerMenus.GetMenuWithName("Interaction");
    if (interactionMenu.IsVisible() == false && interactionMenu.IsFading() == false)
    interactionMenu.appearType = AppearType.OnHotspot;
    }

    The fading check was especially important, otherwise it functioned just like before.

    AC has a solution for everything :)
  • Ha okay so one other thing - when I move the mouse off of the interaction menu now but am still hovering over the hotspot, the menu starts flickering until I put the cursor over the menu again, or move off the hotspot entirely.

    This happens ofcourse because according to the OnInteraction appeartype it has to close the menu when the mouse moves off of it, but when it does it switches back to OnHotspot and turns the menu promptly back on.

    Is there a way to query whether the cursor is over a hotspot collider or something? Some extra parameter to control the switching, to say 'don't turn off if still over hotspot'.

    P.S. completely turning off the transition for the menu doesn't work, then instead of flickering it just disappears, but all the other On Gameplay menus start to flicker.
  • The PlayerInteraction script has a public function called GetActiveHotspot ().  If it doesn't return null, the cursor's over a Hotspot.  See if that does the trick.
  • edited September 2014
    Thanks, that was what I needed. I actually used IsMouseOverHotspot since I don't really need to know which hotspot the cursor is over. I also switched to forcing appeartype DuringGameplay for the menu once it opens so that I can tell it exactly when it's allowed to turn off.

    That makes the code:

    void Update () {
    Vector2 cursor = Input.mousePosition;
    if (playerInteraction.IsMouseOverHotspot() == false) {
    //turn off menu and reset the AppearType once the mouse leaves both the hotspot AND the menu bounding box.
    if ((cursor.x < interactionMenu.GetRect().xMin)||(cursor.x > interactionMenu.GetRect().xMax)) {
    interactionMenu.TurnOff(true);
    interactionMenu.appearType = AppearType.OnHotspot;
    }
    }
    }

    I initially had it check for cursor.y aswell, but that reintroduced some weird flickering for some reason, and the important bit of the menu is in its width, not so much its height, so I figured this will do.

    I'm no coding genius but it feels pretty cool that this is possible with some hacking :) Thanks for the tips!
  • edited September 2014
    So, a few refinements:

    I had to come back on my decision to use DuringGameplay because it would throw nullrefs after an interaction was run. In fact I didn't need to modify the AppearType at all anymore thanks to that new IsMouseOverHotspot check in the update.

    However, that makes the fact that checking the Rect against the Y axis doesn't work an actual problem. It's weird because using xMin and xMax works flawlessly, but yMin and yMax doesn't do anything.

    Any idea why that is?


    Besides that I also moved the MatchInteractions function from OnMenuEnable to Update, because sometimes two hotspots were so close together that the Rect of the menu bridged them, and so the icons for the new hotspot got sourced from the old hotspot because technically the menu was never told to turn off between hotspot A and B.
  • There's actually a dedicated function for checking inside the Rect, because it incorporates things like aspect ratio correction, etc.  Try this:

    menu.GetRect ().Contains (playerInput.invertedMouse)

    Where PlayerInput is a script attached to GameEngine.

    Regarding MatchInteractions, I would put a check in there to see if the active Hotspot has changed.  MatchInteractions is an expensive function, so I wouldn't run it every frame if possible.
  • That's a pretty cool function! Sadly it doesn't work in this case. Or, well, it runs, but it has the same problem as manually checking the Rect - once the Y axis gets involved the menu turns off as soon as the cursor leaves the hotspot, in any direction. So it basically acts like an OverHotspot menu would normally. Checking only against the X axis like I did before works (for the width), but against the Y axis, or both combined, does nothing.

    This is the relevant bit of script currently:


    void Update () {
    if (hotSpot != null && hotSpot != oldHot) {
    interactionMenu.MatchInteractions(hotSpot.useButtons);
    oldHot = hotSpot;
    }
    if (hotSpot == null) {
    if (interactionMenu.GetRect().Contains(playerInput.GetInvertedMouse()))
    interactionMenu.TurnOff(true);
    }
    }


    And as you can see I locked off that MatchInteractions call with a second variable that stores the current hotspot too but only updates once when GetActiveHotspot registers a change...I think. That should work right?
  • The code suggests that you want the menu to turn off if the mouse is inside it - should it not be the reverse?
  • edited September 2014
    Oh yes woops I see now how it would parse it that way. I thought GetInvertedMouse somehow meant the cursor was OUTSIDE of the Rect.

    I've moved things around a bunch of times using all these methods, but nothing so far worked as well as when I manually checked the Rect, so I went back to that and made it a bit more robust. But again, it works great except for when I add a check for yMin and yMax.

    What is a more critical problem however is that the icons don't do anything if the cursor is off the hotspot but still on the menu. Probably because the interaction icons/cursors rely on the ActiveHotspot? (which at that point is null). I tried storing the Hotspot in a variable and using that to match interactions but it didn't make a difference.

    Current code:

    void Update () {
    cursor = Input.mousePosition;
    hotSpot = playerInteraction.GetActiveHotspot();

    if (hotSpot != null) {
    if (interactionMenu.IsOff()) {
    //turn on the interaction menu
    interactionMenu.TurnOn(false);
    interactionMenu.appearType = AppearType.DuringGameplay;
    }
    if (hotSpot != oldHot) {
    //refresh icons when moving between hotspots
    interactionMenu.MatchInteractions(hotSpot.useButtons);
    oldHot = hotSpot;
    }
    }
    else if (hotSpot == null) {
    if ((cursor.x < interactionMenu.GetRect().xMin)||(cursor.x > interactionMenu.GetRect().xMax)) {
    //turn off menu when cursor leaves both hotspot AND menu Rect
    if (interactionMenu.IsOn()) {
    interactionMenu.TurnOff(false);
    interactionMenu.appearType = AppearType.OnHotspot;
    }
    }
    }
    }
  • Play the 2D demo again.  Am I right in thinking that you basically want a control scheme like that, only that the Interaction Menu appears without the need to click the Hotspot?  The problems of the mouse leaving the Hotspot and not the Menu etc, were all solved for the demo's case - if that lack of a click is the only issue here it might be possible to do just add some kind of setting.
  • Ah that's correct yep. My idea is basically the same as an OnInteraction menu with the mode set to Cursor Leaves Menu. Since I figured the one element that I wanted to add (appear on hover instead of on click) was not supported, I'd try to rebuild the functionality using the onHotspot appeartype, but maybe that was a bit of a stretch :)

    I went back and adjusted the menu to work identical to the 2D demo menu, but left the code in Update that manually forces the menu on when hovering over a hotspot, and that worked pretty darn well actually. I don't know why I didn't think of that before, I don't even need the matchInteractions stuff then.

    The only problem there is that the Cursor Leaves Menu thing still tries to force the menu off when you move off the Rect but are still on the hotspot, which causes flickering. Either a fix for that or a setting in AC that triggers it on hover instead of click and I should be all set!
  • If that's the case, have you tried just setting the menu's Appear type to "Manual"?  You'd then have total control over when it's displayed.
  • I did yeah, it indeed sounded like that would be the ideal setting, but on Manual mode none of the icons work (even with MatchInteractions). Plus the menu flickers weirdly if I add a Rect cursor check for the Y-axis.
  • I'll have a look at this myself for 1.39.  No promises, but it may be possible to add an official setting.
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.