1
\$\begingroup\$

NOTE: See bottom of the question as I have managed to use a workaround which works to press the two buttons at once on Android (thanks to Douglas Potestas help)

Ive struggled with this in the past and got it working. But its been a long time since I have used Raycasts and I have mostly forgotten. Quick summary before people tell me to use OnPointerEnter etc is that on all of my Android games using OnPointer events you cannot press the two buttons (eg. imaging a NES gamepad pressing A and B with the same thumb like when you play Mario or something). You cannot slide the thumb to press both it only registers the first button hit, and this is not adequate for most of my game ideas.

Basically, I want to check if the thumb is over any amount of buttons at every frame of the game loop.

So I have this very basic code which I hoped would work, but the hit only returns anything if it hits a physical game object such as Cube or Capsule.

I want it to return if it hits a UI Image/Panel/Button (it matters not which one really).

I've tried adding 2d box collider and a 3d cube collider both as trigger and not trigger and made sure its big enough. I've tagged the image/button. I've checked the Raycast Target box. Here is update loop of my OnScreenControlManager.cs

     void Update () {
         Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
         RaycastHit hit;
         float rayLength = Mathf.Infinity;

         if (Physics.Raycast(ray, out hit, rayLength))
         {
             Debug.Log("hit coll = " + hit.collider.tag);
             if (hit.collider.tag == "LeftButton")
             {
                 Debug.Log("hit coll = " + hit.collider.tag);
             }
         }
     }

I definitely had this working about a year ago in Unity 5. I'm now using Unity 2017, hope that isn't anything to do with it.

Have also tried Physics2d.Raycast:

    private void Update()
{
    RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);

    if (hit.collider != null)
    {
        Debug.Log("Target tag: " + hit.collider.tag);
    }
}

Solution which works using new Rects and the Overlaps method. (Note , you cannot use this if the buttons are small and close together

public class OnScreenController : MonoBehaviour

{

Rect touchRect;
public float touchRectExtents;

Bounds buttonLeftBounds;
public GameObject buttonLeft;
Rect buttonLeftRect;

Bounds buttonABounds;
public GameObject buttonA;
Rect buttonARect;

Bounds buttonBBounds;
public GameObject buttonB;
Rect buttonBRect;

public Text aPressed, bPressed;


private void Start()
{
    buttonLeftBounds = buttonLeft.GetComponent<Collider2D>().bounds;

    buttonABounds = buttonA.GetComponent<Collider2D>().bounds;
    buttonBBounds = buttonB.GetComponent<Collider2D>().bounds;
}

private void Update()
{
    touchRect = new Rect(Input.mousePosition.x - touchRectExtents, Input.mousePosition.y - touchRectExtents, touchRectExtents * 2, touchRectExtents * 2);

    buttonLeftRect = new Rect(buttonLeftBounds.center.x - buttonLeftBounds.extents.x, buttonLeftBounds.center.y + buttonLeftBounds.extents.y, buttonLeftBounds.size.x, buttonLeftBounds.size.y);

    buttonARect = new Rect(buttonABounds.center.x - buttonABounds.extents.x, buttonABounds.center.y + buttonABounds.extents.y, buttonABounds.size.x, buttonABounds.size.y);
    buttonBRect = new Rect(buttonBBounds.center.x - buttonBBounds.extents.x, buttonBBounds.center.y + buttonBBounds.extents.y, buttonBBounds.size.x, buttonBBounds.size.y);

    if (touchRect.Overlaps(buttonLeftRect))
    {
        Debug.Log(" LEFT PRESSED");
    }
    if (touchRect.Overlaps(buttonARect))
    {
        aPressed.text = "A PRESSED";
    }
    else
    {
        aPressed.text = "A NOT PRESSED";
    }

    if (touchRect.Overlaps(buttonBRect))
    {
        bPressed.text = "B PRESSED";
    }
    else
    {
        bPressed.text = "B NOT PRESSED";
    }
}

}

EDIT: Still doesnt work :[ although i can now press the two buttons at once with the same touch, i need to add a way to check for other touches. For example if I am using the D-Pad with left thumb, this code doesnt even detect the hit on the buttons because Mouse.inputposition is still over at the D-Pad.

\$\endgroup\$
1
\$\begingroup\$

You probably want Rect.Overlap()

It allows you to check if one rect overlaps another rect.

So you would want to have a rect for the players touch. Which you can crate using the position and radius of Input.Gettouch(). Then do a fingerRect.Overlap(aButtonRect) instead physics.raycast.

If you are only trying to do a specific point instead of an area you can use Rect.Contains().

Which would look something like AbuttonRect.Contains(Input.mouseposition)

\$\endgroup\$
  • \$\begingroup\$ that sounds like it could work. So basically not using Raycast at all? \$\endgroup\$ – Big T Larrity Nov 28 '17 at 3:28
  • \$\begingroup\$ Would it be possible to create the new Rect every frame which would cover the entire thumb? or is it going be just the point at where the touch registered? \$\endgroup\$ – Big T Larrity Nov 28 '17 at 3:29
  • \$\begingroup\$ You would create a rect every frame, or alter it each frame. \$\endgroup\$ – Douglas Potesta Nov 28 '17 at 3:35
  • \$\begingroup\$ sure , i understand that. But The variable "Input.mouseposition" only returns a Vector3 point, which of course cannot cover the both buttons at one, it can only be over one. I think your solution with the rectangle is defintely a good idea though I am going to try it. However it may give me problems if a player tried pressing say down , and the button is too close to up and hits that at same ttime. Still, I think you've given me enough to get something working. Coz at the moment me and my friend have both tried for days with Event Triggers and cant press both A and B at same time. thanks \$\endgroup\$ – Big T Larrity Nov 28 '17 at 3:38
  • 1
    \$\begingroup\$ You can set the size of the rect to be the diameter of the touch. The position of the touch would need to be offset like this offset = Vector2.one*Input.gettouch.radius; then you would do new Rect (input.gettouch.position-offset, offset*2); to get your rect for finger. \$\endgroup\$ – Douglas Potesta Nov 28 '17 at 3:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.