I'm having issues trying to resolve this issue I have from migrating my old Unity5 game to Unity 2020. I've got everything running again, except for this issue with my buttons not working because of an update to "HitTest" being obsolete. What can I do to make this work without completely starting from scratch?
foreach (Touch touch in Input.touches)
{
if (touch.phase == TouchPhase.Stationary && hitButton.HitTest(touch.position))
{
GetComponent<Rigidbody2D>().MoveRotation(80);
}
I would make a Canvas as a child of the gameobject with the rigidbody2d/collider2d components, then put the button on that canvas, and then in your code above, keep a reference to the canvas and the button that lives there.
Then, you can use GraphicRaycaster.Raycast. Modified version of the source code in the Unity Docs:
// Attach this script to your Canvas GameObject.
// Also attach a GraphicsRaycaster component to your canvas by clicking the
// Add Component button in the Inspector window.
// Also make sure you have an EventSystem in your scene
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections.Generic;
public class RaycasterTester : MonoBehaviour
{
GraphicRaycaster m_Raycaster;
void Start()
{
//Fetch the Raycaster from the GameObject (the Canvas)
m_Raycaster = GetComponent<GraphicRaycaster>();
}
public bool TestTouch(Touch touch, GameObject target)
{
//Set up the new Pointer Event
PointerEventData pointerEventData = new PointerEventData(EventSystem.current);
//Set the Pointer Event Position to that of the touch position
pointerEventData.position = touch.position;
//Create a list of Raycast Results
List<RaycastResult> results = new List<RaycastResult>();
//Raycast using the Graphics Raycaster and touch position
m_Raycaster.Raycast(pointerEventData, results);
foreach (RaycastResult result in results)
{
if (result.gameObject == target) return true;
}
return false;
}
}
So basically the hierarchy looks something like this at runtime:
Flipper object [ Rigidbody2D, Collider2D, questionScript (references RaycasterTester and Button) ]
L Canvas object [ Canvas (world space), GraphicRaycaster, RaycasterTester ]
L Button object [ Button, Image, hitButtonScript (?) ]
(somewhere in scene) [ EventSystem ]
Then, in the Question Script, get a reference to the instance of the above script then call the TestTouch method:
foreach (Touch touch in Input.touches)
{
if (touch.phase == TouchPhase.Stationary
&& raycasterTester.TestTouch(touch, hitButton.gameObject))
{
GetComponent<Rigidbody2D>().MoveRotation(80);
// break to avoid being turned by multiple touches?
// break;
}
}
By the way, if the question code is happening in Update, it might be best to call GetComponent<Rigidbody2D> in Start (or, if the Rigidbody2D is ever removed and/or replaced, at those times as well) and cache the results, since it can be an expensive operation.
Actually better than checking this manually would indeed be a UI.Button + additionally implementing a custom extension using the IPointerDownHandler and IPointerUpHandler etc interfaces (note: the linked API is 2018, but this applies to 2020 as well, they just moved the API to a package and there it is not so well explained) like
public class HoldButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerEnterHandler, IPointerExitHandler
{
// Called once when the button goes down (comparable to GetKeyDown)
public UnityEvent OnButtonDown;
// Called every frame while the button is pressed (comparable to GetKey)
public UnityEvent WhilePressed;
// Called once when the button goes up (comparable to GetKeyUp)
public UnityEvent OnButtonUp;
// Called if you hover with the mouse or drag an existing touch into the button
public void OnPointerEnter(PointerEventData pointerEventData)
{
// Not sure if needed for OnPointerExit to work, doing nothing else
}
// Called when mouse or touch leaves the button
public void OnPointerExit(PointerEventData pointerEventData)
{
OnButtonUp.Invoke();
StopAllCoroutines();
}
// Called if you press the mouse or begin a touch over this button
public void OnPointerDown(PointerEventData pointerEventData)
{
OnButtonDown.Invoke();
StartCoroutine (WhilePressedRoutine());
}
// Called if you release mouse or touch over this button
public void OnPointerUp(PointerEventData pointerEventData)
{
OnButtonUp.Invoke();
StopAllCoroutines();
}
private IEnumerator WhilePressedRoutine()
{
while(true)
{
WhilePressed.Invoke();
yield return null;
}
}
}
In these UnityEvents you can reference your handler methods just like in the UI.Button.onClick via the Inspector or on runtime via script.
So you can either attach this on a UI element (like a Button) and let the EventSystem of the scene call the pointer handlers.
Or you can even attach this to normal 3D objects! In such case this requires additionally
PhysicsRaycaster component on your CameraOr for a 2D object accordingly
Physics2DRaycaster on your CameraThese interfaces work for both, mouse and touch input (except for the pointer enter probably because a touch can't just hover - at least not on all phones ;) )