I'm new to Unity New Input System, I have recently migrated my project from the old input system to the new input system but I'm facing some difficulties using it.
I have a class called InputManager
that manages all the input actions for my game, and another class called PlayerInteractions
that holds all the player's interactions, such as picking up objects, opening and closing drawers/doors and so on.
playerInteraction
class was working perfectly using the old input system, but when I changed it to the new input system I couldn't handle the function calls properly so it didn't work completely. I managed to make picking up objects work but the opening/closing part didn't work because for that I'm calling another function from a class called InteractiveObjects
that is attached to all objects that can be opened/closed such as door/drawers...
and it was hard for me to handle these function calls since I'm not good enough at the New Input System.
Here is a snippet of the PlayerInteractions Class
private InteractiveObjects interactiveObjects;
bool PickingUp, Open;
void Update()
{
raycastPos = mainCamera.ScreenToWorldPoint(new Vector3(Screen.width / 2, Screen.height / 2, 0));
RaycastHit hit;
if (Physics.SphereCast(raycastPos, sphereCastRadius, mainCamera.transform.forward, out hit, maxDistance, 1 << interactableLayerIndex))
{
lookObject = hit.collider.transform.gameObject;
}
else
{
lookObject=null;
}
if (PickingUp)
{
if (currentlyPickedUpObject == null)
{
if (lookObject != null)
{
PickupObject();
}
}
else
{
BreakConnection();
}
}
PickingUp = false;
if (hit.transform)
{
interactiveObjects = hit.transform.GetComponent<InteractiveObjects>();
}
else
{
lookObject = null;
interactiveObjects = null;
}
if (Open)
{
if (interactiveObjects)
{
interactiveObjects.PerformAction();
}
}
Open = false;
}
public void OnPickingUp()
{
PickingUp = true;
}
public void OnOpen()
{
Open = true;
}
This part from above:
if (Open)
{
if (interactiveObjects)
{
interactiveObjects.PerformAction();
}
}
was like this:
if (Input.GetKeyDown(KeyCode.E))
{
if (interactiveObjects)
{
interactiveObjects.PerformAction();
}
}
and the InteractiveObject
class was something like this:
public void PerformAction()
{
if (aSource)
{
aSource.Play();
}
if (Input.GetKeyDown(KeyCode.E))
{
if (isOpen)
{
iTweenArgs["position"] = closedPosition;
iTweenArgs["rotation"] = closedPosition;
}
else
{
iTweenArgs["position"] = openPosition;
iTweenArgs["rotation"] = openPosition;
}
isOpen = !isOpen;
switch(movementType)
{
case MovementType.Slide:
iTween.MoveTo(gameObject, iTweenArgs);
break;
case MovementType.Rotate:
iTween.RotateTo(gameObject, iTweenArgs);
break;
}
}
if(Input.GetKeyDown(KeyCode.E))
was changed to if (Open)
.
Here is the full IneractiveObject
class after the change:
public class InteractiveObjects : MonoBehaviour
{
[SerializeField] private Vector3 openPosition, closedPosition;
[SerializeField] private float animationTime;
[SerializeField] private bool isOpen = false;
[SerializeField] private MovementType movementType;
bool Open;
private enum MovementType { Slide, Rotate };
private Hashtable iTweenArgs;
private AudioSource aSource;
void Start()
{
iTweenArgs = iTween.Hash();
iTweenArgs.Add("position", openPosition);
iTweenArgs.Add("time", animationTime);
iTweenArgs.Add("islocal", true);
aSource = GetComponent<AudioSource>();
}
public void PerformAction()
{
if (aSource)
{
aSource.Play();
}
if (Open)
{
if (isOpen)
{
iTweenArgs["position"] = closedPosition;
iTweenArgs["rotation"] = closedPosition;
}
else
{
iTweenArgs["position"] = openPosition;
iTweenArgs["rotation"] = openPosition;
}
isOpen = !isOpen;
switch (movementType)
{
case MovementType.Slide:
iTween.MoveTo(gameObject, iTweenArgs);
break;
case MovementType.Rotate:
iTween.RotateTo(gameObject, iTweenArgs);
break;
}
}
Open = false;
}
public void OnOpen()
{
Open = true;
}
}
InputManager
class:
public class InputManager : MonoBehaviour
{
[SerializeField] Movement movement;
[SerializeField] PlayerInteractions playerInteractions;
[SerializeField] MouseLook mouseLook;
PlayerControls controls;
PlayerControls.GroundMovementActions groundMovement;
Vector2 horizontalInput;
Vector2 mouseInput;
private void Awake()
{
controls = new PlayerControls();
groundMovement = controls.GroundMovement;
// groundMovement.[action].performed = context => do something
groundMovement.HorizontalMovement.performed = ctx => horizontalInput = ctx.ReadValue<Vector2>();
groundMovement.Jump.performed = _ => movement.OnJumpPressed();
groundMovement.Running.performed = _ => movement.OnRunning();
groundMovement.PickingUp.performed = _ => playerInteractions.OnPickingUp();
groundMovement.MouseX.performed = ctx => mouseInput.x = ctx.ReadValue<float>();
groundMovement.MouseY.performed = ctx => mouseInput.y = ctx.ReadValue<float>();
groundMovement.Open.performed = _ => playerInteractions.OnOpen();
}
private void Update()
{
movement.ReceiveInput(horizontalInput);
mouseLook.ReceiveInput(mouseInput);
}
private void OnEnable()
{
controls.Enable();
}
private void OnDestroy()
{
controls.Disable();
}
}
So the InputManager
class is calling a function from playerInteractions
which is also calling a function from InteractiveObjects
for opening/closing feature. that didn't work for me but I don't know how to fix this. please help.
CodePudding user response:
The solution is here, you no longer need Open
Boolean and you can call the function directly through the new input system. for this job; Enter only the contents of if on OnOpen
.
public void OnOpen()
{
if (isOpen)
{
iTweenArgs["position"] = closedPosition;
iTweenArgs["rotation"] = closedPosition;
}
else
{
iTweenArgs["position"] = openPosition;
iTweenArgs["rotation"] = openPosition;
}
isOpen = !isOpen;
switch(movementType)
{
case MovementType.Slide:
iTween.MoveTo(gameObject, iTweenArgs);
break;
case MovementType.Rotate:
iTween.RotateTo(gameObject, iTweenArgs);
break;
}
}
This not only simplifies the structure of the code. Rather, it prevents the if condition from being repeated in the update. Now run OnOpen
as you set it by pressing the B key:
controls.GroundMovement.Open.performed = _ => playerInteraction.OnOpen();
How do conditions work continuously?
There are several ways to build functions that work continuously. This is an example that works by defining Func<bool>
in the target object script:
public class PlayerInteraction : MonoBehaviour
{
public Func<bool> IsPressingOpen;
public void Update()
{
if (IsPressingOpen())
{
// do something...
}
}
}
And it is enough to set the function according to the result of key pressing
:
playerInteraction.IsPressingOpen = () => controls.GroundMovement.Open.IsPressed();
Hope this answer is comprehensive and practical.