With the new reactive pattern in ECS could player input go directly into an ECS system?
Poor old @Rene-Damm … he has no break from the harsh realities of input just when he neared completing something… bang… hit with ECS input.
See the samples topic. Get twostick example, with Hybrid ECS, or Pure ECS. You will see how to get inputs. There are also other examples.
Don’t they just hook into existing input API calls, I was thinking of an ECS input system that is built in and generates entities as soon as a player input is registered then all the developer has to do is write an input system that detects the inputs they are interested in?
OK this could be a bit more abstract with raw inputs being configured into game inputs similar to the existing input system but these game inputs (e.g. wasd space to 3d movement vector) then can be processed by the users input system.
This way you are not having to write an input handler that then passes commands to a set of subsystems for movement or actions just a movement or action system that takes input entities.
They indeed do hook into existing API. But that not stopping you from building a ECS system, which just handle them as you want. Maybe is not the way you would like, but I don’t think is any much more complex, or time consuming, than anything else. You can nicely store I/O data in entity if you wish. And maybe in future, remap if needed. But I don’t think, inputs are major concerns atm. Rather convenience. Not that you need jobify them, or so.
The thing is if an ECS input layer is added wouldn’t that allow for networked inputs/commands to be passed into your game using the same mechanism?
ECS could even have an “input” world…
Search “ECS” in the new input system update thread and you will see a glimpse of hope.
Hehe. Yeah, ECS kinda started happening while we were trying really hard to shape up the new input stuff into final form. Still, we’ve (naturally) been thinking about how input fits into the ECS world. No work has started yet so ATM it’s still just thoughts.
While the new input stuff is largely divorced from the MonoBehaviour/ScriptableObject world, there’s still a couple things that don’t make it a natural fit for ECS. Meaning that you’ll end up having to pick up and collect input on the main thread somewhere (can be an ECS system but can’t be a job) and then go from there.
I have some pictures in my head for what a fully jobified, ECS’d input system (running on the same new native backends the new input system has today) might look like but it’s something that probably won’t get worked on before we’ve shipped 1.0 of the new input system.
I’m rocking my own ECS input management framework in the meantime. I may put it on github when it’s working, could be a decent stopgap until input ECS is a thing. If nothing else I’m learning a lot about applying hybrid ECS to a lower-level system instead of monobehaviour.
My aim is to have an input world that buffers device events and extracts action changes on the main thread, associating devices and extracted events with player ids based on configuration. Resultant events can then be denoised, buffered, and analyzed via jobs, emitting command events to other target worlds to drive their own logic (such as base player inputs, combo completion, input buffer debug display, etc).
I have player id registration working and am working on the logic for device tracking and binding this week.
One thing that could be helpful for anyone going towards ECS and away from MonoBehaviour is that the new system gives you control over updates. Including turning all the default updates off.
// Disable all default updates and use the system in a mode where
// you explicitly control updates.
// NOTE: In the editor, you may want to leave InputUpdateType.Editor on
// (actually, not doing so probably has some adverse effect ATM with the input
// buffers growing and growing; another thing that needs to be protected against)
InputSystem.updateMask = InputUpdateType.None;
// Now, in your ECS system's update function, you can explicitly
// flush out input under your control. It's still bound to the main
// thread but at least now you're decoupled from the MB update
// model.
InputSystem.Update();
ATM this kind of implicitly exists within the current API but I’d like to make it a little more explicit by adding InputUpdateType.Manual.
Hi @Rene-Damm ,
with the soonish release of input system, do you have a better vision of ECS integration ?
@Rene-Damm if we do manual Update then how do we get all those inputs and assign key mappers?
FYI, for anyone coming across this thread using Input System 1.0.0 preview.1, read the docstring for InputSystem.Update
- you can disable automatic input system updates with:
InputSystem.settings.updateMode = InputSettings.UpdateMode.ProcessEventsManually;
Pretty much the same way you’d do it with automatic updates. I believe the InputSystem keeps an internal queue of device input events caught since the last update call, and these input events are all synchronously processed on the main thread when you call InputSystem.Update
(i.e. piped through action maps to update the state as well as call delegates). So the only thing that should change is when Update
is called.
You could, for example, hook it up by calling InputSystem.Update()
in a jobless ComponentSystem
and proceed to copy the input state you need into ECS components.
To keep track of and access the actual input state, you still need to instantiate and manage the lifetime of an input action collection (not sure if there are alternative options though). A quick and easy way to manage the lifetime and access of the input collection would be to toss it in a MonoBehavior that guards it like a singleton, and then toss that MonoBehavior onto an empty object in the regular scene graph:
using UnityEngine;
using UnityEngine.InputSystem;
public class InputManager : MonoBehaviour
{
private static InputManager _instance;
public static InputManager instance => _instance;
public InputActions input;
private void Awake()
{
InputSystem.settings.updateMode = InputSettings.UpdateMode.ProcessEventsManually;
_instance = this;
input = new InputActions();
input.Enable();
}
private void OnDestroy()
{
input.Disable();
_instance = null;
}
}
This way, a minimal system that copies the input state might look something like this:
[UpdateBefore(typeof(TankMovementSystem)), UpdateBefore(typeof(TankRotateSystem))]
public class TankPlayerInputIntentSystem : ComponentSystem
{
protected override void OnUpdate()
{
InputSystem.Update();
if (InputManager.instance == null) return;
var input = InputManager.instance.input;
Entities.ForEach((
ref PlayerTankComponent playerTank, ref TankMovementIntentComponent tankMovementIntent) =>
{
tankMovementIntent.movement = input.TankControls.Movement.ReadValue<Vector2>();
});
}
}
@bdero Nice example, is there a particular reason for InputManager to be a MonoBehavior?