Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Resolved Where can I find documentation on accessing properties methods of input system callback context

Discussion in 'Input System' started by djweaver, Aug 23, 2020.

  1. djweaver

    djweaver

    Joined:
    Jul 4, 2020
    Posts:
    105
    I have some code set up using an interface in my auto generated C# input system class. I am using the event methods with a SetCallbacks(this) on my player control class and each method contains a context argument that has access to probably tons of useful data, properties, methods, etc.

    I've read through the official documentation which is just a static reference of different properties and methods associated with actions, input actions, and input action assets. I've examined the generated class, but it really only has JSON and a struct that doesn't really help me in this way. I've also experimented with trying random dot statements attached to the context to try and figure out what I can and can't do, also logging to console... which is practically useless here as the console doesn't return enough information and it is rather vague as to how the console statements correlate to the code. ie. if I log
    context.control
    I get
    Key:/Keyboard/w
    and unity says I printed out an type Object. When I reference the object type Control of a Vector2Control from the Unity docs, it has properties of x and y with their respective values. However, if I use
    context.control.x
    I get an error that x is not a property of of InputControl... what? How was I supposed to know the logged Object was of type InputControl? Well whatever then, now I check the docs on InputControl... and I don't see anything pertaining to what the hell I need to access to get access to the STATE of my keys being pressed, ie. what I assume to be start, performed, canceled. I know I can access the value of my Vector2, and by checking the values I can deduce which key was pressed, at one time, but I need access to the current state continuously. Is my OnMove event being triggered every frame as it held? Or is it only being triggered when state changes? I'm just not finding any real guides or documentation (or tutorials) that really dive into how I'm supposed to use all of this within an Update().

    Do I have to set global variables or objects for each state, to mirror that of what is happening within the callback contexts of each event method, and then use that in the Update()? If thats the case, then why even bother with the callbacks and the asset and not just hardcode in InputActions and use them in my own methods that can be called from Update()?

    After months of experimenting with stuff in Unity, learning this/that, modeling, texturing, coming up with camera logic and game logic, figuring out quaternions and euler angles, I still can't wrap my head around how I'm supposed to organize this "new" input system and what to do with callbacks. I understand asynchronous code in JS, async/await, callbacks, promises, and their need, and thats the only thing that comes to mind when I'm reading about this stuff, but I'm running out of things to read about this system and I haven't yet connected the dots. Is there some secret MDN-like resource that references properties, attributes, and methods in a not so static and arbitrary way? Something that has a practical hierarchy of what is contained within these callback contexts?
     
  2. djweaver

    djweaver

    Joined:
    Jul 4, 2020
    Posts:
    105
    Here is my current code if that helps:
    Code (CSharp):
    1. public class PlayerControl : MonoBehaviour, PlayerInput.IWorldActions
    2. {
    3.  
    4.  
    5.     // Reference to Collider script of Body
    6.     private PlayerBody playerBody;
    7.  
    8.  
    9.     // Reference to PlayerSensor script
    10.     private PlayerSensor playerSensor;
    11.  
    12.     // References for movement system
    13.     private InputAction movement;
    14.     public Transform playerCamera;
    15.    
    16.  
    17.     // Movement system variables
    18.     public float movementSpeed = 2.0f;
    19.     public bool isMoving;
    20.     public Vector2 movementInput;
    21.     private Vector3 movementChange;
    22.     private Quaternion rotationInput;
    23.     private Quaternion rotationChange;
    24.     private Quaternion rotationOutput;
    25.  
    26.     private PlayerInput playerInput;
    27.  
    28.     public void OnMove(InputAction.CallbackContext context) {
    29.         print(context.control.x);
    30.  
    31.     }
    32.     public void OnJump(InputAction.CallbackContext context) {
    33.  
    34.     }
    35.     public void OnActivate(InputAction.CallbackContext context) {
    36.         print(context);
    37.     }
    38.     public void OnTarget(InputAction.CallbackContext context) {
    39.  
    40.     }
    41.     public void OnMenu(InputAction.CallbackContext context) {
    42.  
    43.     }
    44.     void Awake() {
    45.         playerBody = transform.GetChild(0).GetComponent<PlayerBody>();
    46.         playerSensor = transform.GetChild(1).GetComponent<PlayerSensor>();
    47.         playerInput = new PlayerInput();
    48.         playerInput.World.SetCallbacks(this);
    49.     }                  
    50.  
    51.  
    52.     void OnEnable() {
    53.         playerInput.Enable();
    54.     }
    55.  
    56.     void OnDisable(){
    57.         playerInput.Disable();
    58.     }
    59.  
    60.  
    61.     void Update(){
    62.         //PlayerInput();
    63.     }
    64.  
    65.     void FixedUpdate()
    66.     {
    67.         //if (isMoving) PlayerMove();
    68.     }
    69.  
    70.  
    71.     void CalculateRotation(){
    72.        
    73.         // DEPRECATED
    74.         // Reads the value in from our InputAction (WASD keys)
    75.         //movementInput = movement.ReadValue<Vector2>();
    76.         //movementChange.z = movementInput.y;
    77.    
    78.         // Ternary conditional to set isMoving flag based on user input measured by magnitude
    79.         isMoving = (movementChange.magnitude != 0) ? true : false;
    80.  
    81.         if(isMoving) {
    82.             // Converts Vector3 movementChange to Quaternion
    83.             rotationInput = transform.rotation;
    84.  
    85.             // Adds the Y Euler angle of playerCamera to rotationInput to create a new quaternion
    86.             // --This is necessary because you cannot do arithmetic on quaternions directly
    87.             rotationChange = Quaternion.Euler(new Vector3(  rotationInput.x,
    88.                                                             rotationInput.y + playerCamera.eulerAngles.y,
    89.                                                             rotationInput.z));
    90.            
    91.             // Interpolates between current rotation and the desired rotation
    92.             rotationOutput = Quaternion.Slerp(transform.rotation, rotationChange, .05f);
    93.         }
    94.     }
    95.  
    96.     void PlayerMove(){
    97.  
    98.         // Applies the calculations
    99.         transform.position += transform.forward * Time.fixedDeltaTime * movementSpeed;
    100.         transform.rotation = rotationOutput;
    101.     }
    102. }
     
  3. djweaver

    djweaver

    Joined:
    Jul 4, 2020
    Posts:
    105
    Here is updated code that provides some of my desired movement functionality... but again, there has to be a better way. I just don't know how (or what) to access from the callback context.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.InputSystem;
    5.  
    6. public class PlayerControl : MonoBehaviour, PlayerInput.IWorldActions
    7. {
    8.  
    9.     // V A R I A B L E S
    10.  
    11.     public Transform playerCamera; // Camera object (within the rig)
    12.     private PlayerBody playerBody; // Collider script of Body
    13.     private PlayerSensor playerSensor; // PlayerSensor script
    14.     private PlayerInput playerInput;
    15.     private InputAction movement;
    16.    
    17.     // Movement system variables
    18.     public bool isMoving;
    19.     public string direction;
    20.     public float movementSpeed = 2.0f;
    21.     private Vector2 movementInput;
    22.     private Quaternion rotationInput;
    23.     private Quaternion rotationChange;
    24.     private Quaternion rotationOutput;
    25.  
    26.     // I N P U T
    27.  
    28.     public void OnMove(InputAction.CallbackContext context) {
    29.         movementInput = context.ReadValue<Vector2>();
    30.         isMoving = true;
    31.         switch(movementInput.y){
    32.             case 1f:
    33.                 direction = "forward";
    34.                 break;
    35.             case 0f:
    36.                 isMoving = false;
    37.                 break;
    38.             case -1f:
    39.                 direction = "backward";
    40.                 break;
    41.         }
    42.     }
    43.  
    44.     public void OnJump(InputAction.CallbackContext context) {
    45.     }
    46.     public void OnActivate(InputAction.CallbackContext context) {
    47.     }
    48.     public void OnTarget(InputAction.CallbackContext context) {
    49.     }
    50.     public void OnMenu(InputAction.CallbackContext context) {
    51.     }
    52.  
    53.     // I N I T I A L I Z A T I O N
    54.  
    55.     void Awake() {
    56.         playerBody = transform.GetChild(0).GetComponent<PlayerBody>();
    57.         playerSensor = transform.GetChild(1).GetComponent<PlayerSensor>();
    58.         playerInput = new PlayerInput();
    59.         playerInput.World.SetCallbacks(this);
    60.     }                  
    61.  
    62.     void OnEnable() {
    63.         playerInput.Enable();
    64.     }
    65.  
    66.     void OnDisable(){
    67.         playerInput.Disable();
    68.     }
    69.  
    70.     // U P D A T E S
    71.  
    72.     void Update(){
    73.         //PlayerInput();
    74.     }
    75.  
    76.     void FixedUpdate()
    77.     {
    78.         if (isMoving) PlayerMove(direction);
    79.     }
    80.  
    81.     // M O V E M E N T
    82.  
    83.     void PlayerRotation() {
    84.  
    85.         // Takes our current rotation
    86.         rotationInput = transform.rotation;
    87.  
    88.         // Adds the Y Euler angle of playerCamera to rotationInput to create a new quaternion
    89.         // --this is necessary because you cannot do arithmetic on quaternions directly
    90.         rotationChange = Quaternion.Euler(new Vector3(  rotationInput.x,
    91.                                                         rotationInput.y + playerCamera.eulerAngles.y,
    92.                                                         rotationInput.z));
    93.        
    94.         // Interpolates between current rotation and the desired rotation
    95.         rotationOutput = Quaternion.Slerp(transform.rotation, rotationChange, .05f);
    96.     }
    97.  
    98.     void PlayerMove(string direction){
    99.         PlayerRotation();
    100.         // Applies the calculations
    101.         if(direction == "forward")  transform.position += transform.forward * Time.fixedDeltaTime * movementSpeed;
    102.         if(direction == "backward") transform.position -= transform.forward * Time.fixedDeltaTime * movementSpeed;
    103.         transform.rotation = rotationOutput;
    104.     }
    105. }
    106.  

    Right here I am only using the value of the Vector2 read from the context because frankly, thats all I know how to get.
    Code (CSharp):
    1.     // I N P U T
    2.  
    3.     public void OnMove(InputAction.CallbackContext context) {
    4.         movementInput = context.ReadValue<Vector2>();
    5.         isMoving = true;
    6.         switch(movementInput.y){
    7.             case 1f:
    8.                 direction = "forward";
    9.                 break;
    10.             case 0f:
    11.                 isMoving = false;
    12.                 break;
    13.             case -1f:
    14.                 direction = "backward";
    15.                 break;
    16.         }
    17.     }

    This solution seems hacky and dumb, and is hardly a solution at all considering I want to isolate the WASD keys to two axis. One for forward/backward, and the other for horizontal strafing, which would be movement relevant to the direction my player is facing. This would be dependent on the rotation of my camera, which is stored in the
    playerCamera
    transform.

    The character rotation and forward/backward movement functionality is already implemented here:
    Code (CSharp):
    1.     // M O V E M E N T
    2.  
    3.     void PlayerRotation() {
    4.  
    5.         // Takes our current rotation
    6.         rotationInput = transform.rotation;
    7.  
    8.         // Adds the Y Euler angle of playerCamera to rotationInput to create a new quaternion
    9.         // --this is necessary because you cannot do arithmetic on quaternions directly
    10.         rotationChange = Quaternion.Euler(new Vector3(  rotationInput.x,
    11.                                                         rotationInput.y + playerCamera.eulerAngles.y,
    12.                                                         rotationInput.z));
    13.      
    14.         // Interpolates between current rotation and the desired rotation
    15.         rotationOutput = Quaternion.Slerp(transform.rotation, rotationChange, .05f);
    16.     }
    17.  
    18.     void PlayerMove(string direction){
    19.         PlayerRotation();
    20.         // Applies the calculations
    21.         if(direction == "forward")  transform.position += transform.forward * Time.fixedDeltaTime * movementSpeed;
    22.         if(direction == "backward") transform.position -= transform.forward * Time.fixedDeltaTime * movementSpeed;
    23.         transform.rotation = rotationOutput;
    24.     }

    I want to be able to strafe, as well as add a ton of other functionality. The problem is I feel I am limited by not knowing how to access more information and properties from the callback context. I imagine there is a ton of refactoring I could do if only I knew what is inside the context.
     
  4. djweaver

    djweaver

    Joined:
    Jul 4, 2020
    Posts:
    105
    FlavioIT likes this.
  5. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,024
    djweaver likes this.
  6. robtown

    robtown

    Joined:
    Jul 9, 2013
    Posts:
    3
    "Right here I am only using the value of the Vector2 read from the context because frankly, thats all I know how to get."
    I guess consider yourself lucky... I can't even get InputAction.CallbackContext to work in my callbacks.

    If I change it to InputValue in my callback method, it works fine.

    Is there a secret to using InputAction.CallbackContext as the value passed in to your input callback?
     
  7. robtown

    robtown

    Joined:
    Jul 9, 2013
    Posts:
    3
  8. benryhenson

    benryhenson

    Joined:
    Dec 21, 2021
    Posts:
    4