- Home /
How do I override or place inputs in the input object for automation?
Hey everyone!
I'm working within a company that is building Unity games and I'm responsible for generating an in-house solution that will provide us with a way to be able to automate testing of a running instance of Unity. The intention is to build a Silenium for Unity.
The diversity of types of games that Unity can help build makes it hard to be generic though. The only game that is close to completion is a client-server game, and largely handles input on the client by pulling data from the Input global during the update cycle, and sends commands accordingly. I can see our other games in development being objects that operate off of specific commands, such as swiping and clicking on game objects with listeners.
What I really want to be able to do here is to be able to have a suite run without a mouse driven by a human, meaning I'd like to be able to say mouseRightClick and move the mouse to a particular location. Otherwise I have to have the framework try to autodiscover components that read from the input and try to invoke the (sometimes private) functions that they invoke to simulate clicks through reflection and event messaging.
Is there any alternative to this larger task available? Does anyone know of any plugins that would be available to handle input conversion from a mouse, touch, keyboard, etc?
I know that generally speaking, the Input global is read only for things like mousePosition for a reason, as it would enable serious cheating if it went out with a production build, but the idea is that we wouldn't include it within the build. This is always the difficult part with automation (because it is contained cheating, really)
Answer by Alec Thilenius · Dec 19, 2012 at 07:53 AM
The mobile guys may feel different, but for PC I would recommend just rewriting the entire input system. This was the easier choice for me when I started trying to use an xBoX controller. The XBox controller support is just terrible.
Update: It looks like you really don't want to rebase, so I would recommend doing what Yoyo said. There is no way to start mucking with the Unity3D input system, so you really have no other choice. Make a wrapper around the Unity input system. It wont be nearly as hard as you think. A simple text search will find you all the references to "Input." For the wrapper itself, ill post a some of the code I used to use when I was trying to use Unity for Xbox input.
Note: This is NOT a static class. Statics are evil, so the only place I use them is in a single "Globals" class that has an accessor to the one and only instantiation of this "InputProcessor" script. Accessing it then looks like:
"Globals.InputProcessor."
Remember that if you want to use touch input, your going to have to write a wrapper no matter what. Unity's raw touch input will not be sufficient for much of anything but feeding data to a wrapper.
public class ButtonState
{
public bool Fire;
public bool Scope;
public bool SelectFire;
public bool Reload;
public bool Jump;
public bool Sprint;
public bool Crouch;
public bool Prone;
public bool CycleWeapon;
public bool Weapon1;
public bool Weapon2;
public bool Weapon3;
public bool Weapon4;
}
...
public class InputProcessor : MonoBehaviour {
public SensitivityState[] SensitiviyLevels = new SensitivityState[1];
public Vector2 Look
{
get { return new Vector2(LookHorizontal, LookVertical); }
}
public float LookHorizontal
{
get
{
if (!enabled)
return 0f;
return Input.GetAxis("Horizontal") * mouseLevel + Mathf.Pow(Input.GetAxis("XBoxHorizontal"), 3f) * xBoxlevel;
}
}
public float LookVertical
{
get
{
if (!enabled)
return 0f;
return Input.GetAxis("Vertical") * mouseLevel + Mathf.Pow(Input.GetAxis("XBoxVertical"), 3f) * xBoxlevel;
}
}
// These values are clamped to a unit circle
public Vector2 Movement
{
get
{
Vector2 Vec2 = Vector2.zero;
if (!enabled)
return Vec2;
Vec2.y = Input.GetAxis("Forward") + Input.GetAxis("XBoxForward");
Vec2.x = Input.GetAxis("Strafe") + Input.GetAxis("XBoxStrafe");
return Vector2.ClampMagnitude(Vec2, 1.0f);
}
}
public float MoveForward { get { return Movement.y; } }
public float MoveStrafe { get { return Movement.x; } }
public ButtonState ButtonDown = new ButtonState();
public ButtonState ButtonUp = new ButtonState();
public ButtonState Button = new ButtonState();
...
void Update ()
{
// Button Downs
ButtonDown.Fire = Input.GetButtonDown("Fire") || fireTracker.Down;
ButtonDown.Scope = Input.GetButtonDown("Scope") || scopeTracker.Down;
ButtonDown.SelectFire = Input.GetButtonDown("SelectFire");
ButtonDown.Reload = Input.GetButtonDown("Reload");
...
// Button Ups
ButtonUp.Fire = Input.GetButtonUp("Fire") || fireTracker.Up;
ButtonUp.Scope = Input.GetButtonUp("Scope") || scopeTracker.Up;
ButtonUp.SelectFire = Input.GetButtonUp("SelectFire");
ButtonUp.Reload = Input.GetButtonUp("Reload");
...
// Buttons
Button.Fire = Input.GetButton("Fire") || fireTracker.Depressed;
Button.Scope = Input.GetButton("Scope") || scopeTracker.Depressed;
Button.SelectFire = Input.GetButton("SelectFire");
Button.Reload = Input.GetButton("Reload");
...
First off, thanks for your input! I appreciate you taking the time to look at this question.
Unfortunately, our company is looking to host games in both web and mobile (particularly iOS to start for a couple) with Unity. Additionally, asking the game $$anonymous$$m for a rewrite for automation is pretty costly. Your suggestion would only be able to apply to games going forward.
Nevertheless, I will take that feedback into consideration :-)
I'll update my response to better suit what your after then.
Thanks, I will use a wrapper similar to what you have demonstrated here for my tools.
Searching for "Input" is a good start; remember to look for "Event.current" as well.
BTW, since you want to support mobile and web, a wrapper is a good idea anyway as it can abstract out the touch interface.
Answer by yoyo · Dec 19, 2012 at 04:59 AM
I would suggest writing a wrapper for Unity's input system, and have your games get all their input from the wrapper, rather than from Unity directly. Once you have your own wrapper you have control over all the code and can automate to your heart's content.
First off, thanks for your input! I appreciate you taking the time to look at this question.
Unfortunately, our company is looking to host games in both web and mobile (particularly iOS to start for a couple) with Unity. So therefore, there are two problems with scrapping the input system:
1) Asking a game $$anonymous$$m with a deadline of next quarter to change their code is exactly what we're looking to try to avoid my building a generic test harness.
2) Even if the current game that is close to production does accept this choice, it is difficult to coordinate the same practices for games that are starting up and getting their own structures laid out to uphold this wrapper.
It certainly would be easier for games moving forward, beyond the current one. It could be a requirement for the game to implement some libraries to allow automation injection, and if that's the only solution, then that's the way it will have to be.
I suppose I could use a config file that will allow test developers to pick which functions they use for input for reflection? Problem there is that it will require modification synchronously with the game $$anonymous$$m, as well as requires tight coupling between the game devs and the automation writers.
We sort of are trying to work within a Services model. It makes the automation $$anonymous$$m's job that much harder to get off the ground with something like this.
Either way, I appreciate your inputs on this!
Answer by Tortuap · Sep 08, 2018 at 03:41 PM
For games using UI event system, using BaseInputModule.inputOverride might be a solution.
Your answer
Follow this Question
Related Questions
Camera Screen to world point returns cameras transform position. 8 Answers
Simulate mouse input 1 Answer
Help with initiating an automated sequence 1 Answer
How can I achive faster response time from Input? 3 Answers
[FULL-SCREEN] INPUT.MOUSEPOSITION OUTPUT DOES NOT MATCH THE DISPLAYED VIEW ON THE SCREEN 0 Answers