I have created a simple clone of OnScreenStick to customize its behavior to suit my purposes. I am finding that calling SendValueToControl does not trigger the corresponding Action setup in my PlayerInput.
I have set the control path of the joystick to Gamepad/LeftStick:
I am testing this on my PC with a keyboard&mouse. I do not have a gamepad connected. Here is the Move action which I expect to fire:
I am using the “Unity Events” configuration of PlayerInput on my Player object to handle the Move action. I can confirm that pressing WASD properly fires the action, but calling SendValueToControl from the OnScreenStick does not. Here is my OnScreenJoystick code, which is nearly identical to the OnScreenStick code:
using UnityEngine.EventSystems;
using UnityEngine.Serialization;
using UnityEngine.InputSystem.Layouts;
using UnityEngine;
using UnityEngine.InputSystem.OnScreen;
using UnityEngine.InputSystem;
public class OnScreenJoystick : OnScreenControl, IPointerDownHandler, IPointerUpHandler, IDragHandler
{
private float m_MovementRange;
public float movementRange
{
get => m_MovementRange;
}
[InputControl(layout = "Vector2")]
[SerializeField]
private string m_ControlPath;
[SerializeField]
private GameObject joystickBoundsImageTemplate;
private GameObject joystickBoundsImage;
[SerializeField]
private GameObject joystickCenterImageTemplate;
private GameObject joystickCenterImage;
private Vector2 m_PointerDownPos;
protected override string controlPathInternal
{
get => m_ControlPath;
set => m_ControlPath = value;
}
private void OnEnable()
{
if (joystickBoundsImageTemplate == null)
throw new System.ArgumentNullException(nameof(joystickBoundsImageTemplate));
if (joystickCenterImageTemplate == null)
throw new System.ArgumentNullException(nameof(joystickCenterImageTemplate));
FillScreen();
}
public void FillScreen()
{
Rect parentRect = (transform.parent as RectTransform).rect;
((RectTransform)transform).SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, parentRect.width);
((RectTransform)transform).SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, parentRect.height);
}
public void OnPointerDown(PointerEventData eventData)
{
if (eventData == null)
throw new System.ArgumentNullException(nameof(eventData));
RectTransformUtility.ScreenPointToLocalPointInRectangle(
transform.parent.GetComponentInParent<RectTransform>(),
eventData.position,
eventData.pressEventCamera,
out m_PointerDownPos
);
Debug.Log($"Pointer down at {m_PointerDownPos}");
if (joystickBoundsImage == null)
joystickBoundsImage = Instantiate(joystickBoundsImageTemplate, transform);
((RectTransform)joystickBoundsImage.transform).anchoredPosition = m_PointerDownPos;
joystickBoundsImage.SetActive(true);
if (joystickCenterImage == null)
joystickCenterImage = Instantiate(joystickCenterImageTemplate, transform);
((RectTransform)joystickCenterImage.transform).anchoredPosition = m_PointerDownPos;
joystickCenterImage.SetActive(true);
Rect bounds = ((RectTransform)joystickBoundsImage.transform).rect;
m_MovementRange = Mathf.Min(bounds.width, bounds.height) / 2;
}
public void OnDrag(PointerEventData eventData)
{
if (eventData == null)
throw new System.ArgumentNullException(nameof(eventData));
Debug.Log($"OnDrag");
RectTransformUtility.ScreenPointToLocalPointInRectangle(
transform.parent.GetComponentInParent<RectTransform>(),
eventData.position,
eventData.pressEventCamera,
out var position
);
Debug.Log($"Dragged to {position}");
var delta = position - m_PointerDownPos;
delta = Vector2.ClampMagnitude(delta, movementRange);
((RectTransform)joystickCenterImage.transform).anchoredPosition = m_PointerDownPos + delta;
var newPos = new Vector2(delta.x / movementRange, delta.y / movementRange);
Debug.Log($"Sending position to control: {newPos}");
SendValueToControl(newPos);
}
public void OnPointerUp(PointerEventData eventData)
{
if (joystickCenterImage != null)
joystickCenterImage.SetActive(false);
if (joystickCenterImage != null)
joystickBoundsImage.SetActive(false);
SendValueToControl(Vector2.zero);
Debug.Log($"Pointer up at {m_PointerDownPos}");
}
}
In the Input Debugger, I do not see a gamepad device, which leads me to believe perhaps the OnScreenControl is not correctly creating a virtual gamepad device:
Here’s the PlayerInput configuration for reference:
From what I can tell, OnScreenStick is broken. I have been wrestling with the new Input System for days. Is there something I’m doing wrong?