I have a script that records the mouse position every time an Input.GetMouseButton(0) event occurs. I store the time of the click, and the current cursors position. I want to take that information, and playback the inputs on request.
I want to take the Vector2 coordinates and tell Unity to “Simulate a mouse down event at this Vector2 location at this time”.
Current attempted solutions:
-
The only solutions I have found for this problem talk about using ExecuteEvents.Execute to fire off an event, but that requires you to specify a GameObject in which to trigger the event on, which I don’t want to store.
-
The other solution was to implement methods from user32.dll and move the actual windows cursor and trigger mouse clicks from there. That currently only works if the user running the simulation again has the game window in the exact same location, and same screen as when the simulation was recorded.
-
A 3rd solution was to have a script on every intractable object that monitors for a MouseDown event, but I want to avoid this solution at all costs.
This is what my class currently looks like:
public class IntegrationTestBehaviour : MonoBehaviour
{
[SerializeField]
public MouseInputInstance[] Inputs;
private List<MouseInputInstance> InputRecord;
private bool _recording;
private float _recordingStartTime;
public void RecordInputs()
{
_recording = true;
_recordingStartTime = Time.time;
InputRecord = new List<MouseInputInstance>();
}
public void PlaybackInputs()
{
for (int i = 0; i < Inputs.Length; i++)
{
StartCoroutine(HandleInputInstance(Inputs*));*
}
}
void Update()
{
if (!_recording)
return;
if (Input.GetKeyDown(KeyCode.Return))
{
_recording = false;
Inputs = InputRecord.ToArray();
}
if (Input.GetMouseButtonDown(0))
{
InputRecord.Add(new MouseInputInstance()
{
ClickTime = Time.time - _recordingStartTime,
CursorPosition = Input.mousePosition
});
}
}
private IEnumerator HandleInputInstance(MouseInputInstance mouseInput)
{
yield return new WaitForSeconds(mouseInput.ClickTime);
// TODO: Simulate mouse click at mouseInput.CursorPosition
}
[Serializable]
public class MouseInputInstance
{
[SerializeField]
public Vector2 CursorPosition;
public float ClickTime;
}
}
With the following CustomInspector
[CustomEditor(typeof(IntegrationTestBehaviour))]
public class IntegrationTestBehaviourCustomInspector : Editor
{
private IntegrationTestBehaviour _target;
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
_target = (IntegrationTestBehaviour)target;
if (!EditorApplication.isPlaying)
return;
if (GUILayout.Button(“Start Recording”))
{
_target.RecordInputs();
}
if (GUILayout.Button(“Playback Recording”))
{
_target.PlaybackInputs();
}
}
}