Search Unity

Question How To set the padding of the interactive area at runtime?

Discussion in 'UGUI & TextMesh Pro' started by seoyeon222222, Jul 31, 2022.

  1. seoyeon222222

    seoyeon222222

    Joined:
    Nov 18, 2020
    Posts:
    187
    The purpose is simple.
    When interacting(onhover, onclick etc..) with UGUI objects such as buttons,
    - using the mouse : use the correct area
    - using the game pad : increase the range of interaction

    here is example (Apex Legends)

    when using the mouse
    Interact precisely according to the position of the pointer on the cursor.
    apex1.gif


    when using the GamePad
    apex2.gif

    upload_2022-8-1_6-24-35.png


    Is there any way to increase the interactive area only with the offset value?

    It may be possible to add an alpha 0 image that is the same as the ui shape,
    increase the scale, and receive an interactive event through it.
    However, this method use two image resources and requires unnecessary alpha-texture rendering and cumbersome work.
    Is there any good way?
     
  2. karliss_coldwild

    karliss_coldwild

    Joined:
    Oct 1, 2020
    Posts:
    602
    You are probably looking for this thing.
    upload_2022-8-1_10-23-24.png


    Although as a player I would prefer if game implemented proper selected object logic where pressing a direction button or joystick jumps between interactable objects instead of emulated pointer. UGUI has all the required core systems in place.
    But I understand that for somes the games which where designed for mouse first making sure all the menus have navigation properties properly setup and there is no chance of loosing focus is tedious, so the cursor emulation approach might be easier to get working robustly.
     
  3. karliss_coldwild

    karliss_coldwild

    Joined:
    Oct 1, 2020
    Posts:
    602
    Note that there is "Cull transparent mesh" setting which is enabled by default. So transparent clicking area doesn't necessarily mean that it will waste GPU resources for rendering it if setup correctly. There is also always an option to create custom component which implements ICanvasRaycastFilter interface without drawing anything (although I don't think it's worth the effort unless you have some additional features you want to implement).


    Completely different approach would be handling it in InputModule. I am not sure what approach you used for implementing the simulated mouse cursor. I guess it could be done by either generating pointer events which can be used existing InputModule with inputOverride or something similar, or modifying the InputModule so that it reads gamepad data not just mouse. In the second case it could be possible to extend it so that it instead of just performing single raycast it does multiple of them within radius of simulated gamepad cursor.
     
  4. seoyeon222222

    seoyeon222222

    Joined:
    Nov 18, 2020
    Posts:
    187
    Thank you for your answer.
    I'll find the way in the second method.

    for example
    If the
    cursor position : (240, 420)
    offset : 50px

    1. Calculate a circle with a radius of 50px
    2. Get the UI Element List in the circle
    3. Get the UI Element closest to the origin (240, 420)
    4. Manage events for determined UI elements
    5. Do it Every Frame
    Is it like this?

    Can I get a good example or information about this?
     
  5. karliss_coldwild

    karliss_coldwild

    Joined:
    Oct 1, 2020
    Posts:
    602
    For that approach my recommendation is don't do it if you don't have good enough code reading skills to use ugui itself as example. Even if someone gave you the code, there is high chance than unity update could easily break that (this is on the edge of tinkering with library internals that you shouldn't touch unless you know what you are doing), you wouldn't be able to debug that and then you would be in deep trouble. There is a saying that debugging code is twice as hard as writing it. So if you are as clever as possible when writing it, you won't be able to debug it.


    It would be much simpler to have a component which does something like this either in every frame or by subscribing to corresponding event in whatever event system you use.
    ```
    var image = GetComponent<Image>();

    if (mouseMode) {
    image.raycastPadding = Vector4.zero;
    } else { // gamepad mode
    image.raycastPadding = Vector4.one * amount;
    }
    ```
    Then attach this component to all your button and other interactable object prefabs. The amount of work for attaching the component to all your button prefabs shouldn't be too bad since component doesn't need any complicated object specific configuration and you should probably have most of the buttons made from few prefabs so that you can easily tweak the common style without having to modify each individually. Even if you miss one or two of them it's not critical since the UI will still be usable, just require little bit more time to aim which is fine for rarely used buttons.
     
  6. seoyeon222222

    seoyeon222222

    Joined:
    Nov 18, 2020
    Posts:
    187

    Thank you. I think Raycast Padding is close to the answer.
    There is no problem to apply the modified Raycast Padding value to the entire UI Element at runtime.

    The problem is...
    I think RaycastPadding works differently than I thought.
    The information I looked up was to use negative value to expand the area.

    But this alone did not solve the problem.
    The area of RaycastPadding is not visible.
    So I used Gizmo to visualize this.
    (https://forum.unity.com/threads/ui-image-component-raycast-padding-needs-a-gizmo.1019260/)

    upload_2022-8-2_6-18-51.png

    Raycast Padding (-50, -50, -50, -50)
    BtnTest.gif

    The interaction range has been extended by offset (50)
    The problem is that it is no longer working inside the button.


    Another test case to clarify the problem.
    upload_2022-8-2_6-24-20.png
    BtnTest3.gif
    The best behavior for the intent is that the blue rectangle acts as an Interact Trigger Area.

    But there are two strange things about this.
    - Right area of button not in range acts as Interact Area
    - Depending on the direction of movement of the pointer
    (in the order of which area it is going through), different results are displayed inside the button

    It's weird.....
    RaycastPadding's documents are not detailed, and it is difficult to get a lot of information about them...
    Is it a bug? Or is there something I missed?
     
    wmadwand likes this.
  7. seoyeon222222

    seoyeon222222

    Joined:
    Nov 18, 2020
    Posts:
    187
  8. karliss_coldwild

    karliss_coldwild

    Joined:
    Oct 1, 2020
    Posts:
    602
    I wasn't able to repeat hover not working inside the button when padding is used. What version of unity are you using? There was bug in Unity ~2021.2.X-2021.3.5 and 2022 causing pointer enter exit events not working in the way button expects. It could cause similar effect to what you are seeing.
     
    seoyeon222222 likes this.
  9. seoyeon222222

    seoyeon222222

    Joined:
    Nov 18, 2020
    Posts:
    187

    I am using 2021.3.0f1 version.
    I think that's the bug you mentioned
    Thank you for the detailed information!
    It was helpful. :)
     
  10. karliss_coldwild

    karliss_coldwild

    Joined:
    Oct 1, 2020
    Posts:
    602
    seoyeon222222 likes this.