Where can I get help beyond courses?

Hi, I finished 2D course + watched some parts of 3d courses and other publicly available code then started to work on my project.

But I am having trouble with new Input system.

I have a grid system with a cell size of 1.0f. My goal is to implement a “cursor” to navigate the grid on keyboard or the controller.
The new input system is set to invoke UnityEvents.

When I take the input vector I round it to integer so that I can calculate the proper position in the grid.

var value = context.ReadValue<Vector2>();
_inputVector = Vector2Int.RoundToInt(value);

I had a problem that movement was too fast and I did not know how to slow it down because I am not using any rigid body and physics system. In the end I was able to slow it down byt adding a coroutine to wait for 0.05s before each move.

Now my problem is that often the input is registered twice and the cursor skips one square.

I’d welcome any tips how to prevent that and make the movement more precies.
Thank you

image

im not an expert in the new input system but i think you are probably approaching this the wrong way. if your goal is to get a handle controller/keyboard input, id probably store the grid location as a _currentCursorLocation. then in the input actions map (for example) button south and down arrow on the keyboard to move your _currentCurrentLocation -1y on your grid. it looks to me like you are almost writing this as if it was “aiming” at a cell rather than selecting one. I cant tell for sure.

also the fact that you are getting multiple inputs per press makes me think you might be using InputAction.started and you probably want InputAction.performed . started will count the input as long as its pressed which happens many times a second. performed only counts the first time, and wont count it again until you press the button again.

@Fitz0Fury Calculating the next cell is not a problem.
The main problem is the frequency of updates I receive from devices.

If I simply do this, I have 2 problems:

  1. Stick causes way too many perform action for each digree it moves (think like 20+ actions for forward and backward movement)
  1. Keyboard movement is only caught once. So it requires me pressing repeatedly.

I want to achieve press & hold for keyboard. And make 1 press on the stick to really perfom a single action.

See the log - performed triggered 16 times while all I did was to move it from the center to one side and then released.

public void ReceiveMovementEvents(InputAction.CallbackContext context)
    {
        Debug.Log($"Received movement event: {context.phase} | {context.ReadValue<Vector2>()}");
        if (context.performed)
        {
            var value = context.ReadValue<Vector2>();
            _inputVector = Vector2Int.RoundToInt(value);
            var newGridPosition = GetNewGridPosition(Vector2Int.RoundToInt(value));
            SetGridPosition(newGridPosition);
        }
        else if (context.canceled)
        {
            _inputVector = Vector2.zero;
        }
    }

Later I added delay to slow down the movement, but still very often counts more than once. eg. it triggers 2 or 3 times for one travers of the stick.

private IEnumerator MoveDelay(GridPosition gridPosition)
    {
        _isMoving = true;
        yield return new WaitForSeconds(moveDelay);
        SetGridPosition(gridPosition);
        _isMoving = false;
    }

    public void ReceiveMovementEvents(InputAction.CallbackContext context)
    {
        Debug.Log($"Received movement event: {context.phase} | {context.ReadValue<Vector2>()}");
        var value = context.ReadValue<Vector2>();
        _inputVector = Vector2Int.RoundToInt(value);
        if (context.performed && _inputVector!=Vector2Int.zero)
        {
            if (_isMoving) return;
            var newGridPosition = GetNewGridPosition(Vector2Int.RoundToInt(value));
            StartCoroutine(MoveDelay(newGridPosition));
        }
        else if (context.canceled)
        {
            _inputVector = Vector2.zero;
        }
    }

if that’s what you want to do i would recommend using screentoworldpoint instead of actually passaging the read value directly in. though i would say that forcing a cursor on players that are trying to use controller buttons isn’t exactly ideal. it just makes it seem like you made a game for PC and then ported it to controller without wanting to set up a controller map for them.

ScreentoWorldPoint solution would look something like this. i used in a little card game prototype last year, you can adjust that speed value… and it should probably be serialized instead of public. its really just an example to get you on the right track. basically it will move in relation to the screen. it fires a ray and if the ray is overlapping with one of your grid slots it will update the cursor to select that. this wont 1:1 replace your current script but it should help wit the syntax of swapping to screentowrodpoint.

using UnityEngine;

using UnityEngine.InputSystem;

public class CursorController : MonoBehaviour

{

public Camera cam; // Assign your camera in the inspector

public float speed = 1f; // Speed of cursor movement

private Vector2 _currentStickValue;

private InputAction _moveAction;

private void Awake()

{

    // Assuming you have an InputActionAsset named inputActions. 

    var inputActions = new InputActionAsset();

    // Assuming you have an action map named "ActionMap" and an action named "Move"

    _moveAction = inputActions.FindActionMap("ActionMap").FindAction("Move");

    if (_moveAction != null)

    {

        _moveAction.performed += context => _currentStickValue = context.ReadValue<Vector2>();

        _moveAction.canceled += context => _currentStickValue = Vector2.zero;

        _moveAction.Enable();

    }

}

private void Update()

{

    // Move the cursor based on the thumbstick value

    Vector3 newPosition = transform.position + new Vector3(_currentStickValue.x, _currentStickValue.y, 0) * speed * Time.deltaTime;

    Vector3 screenPosition = cam.WorldToScreenPoint(newPosition);

    // Perform a raycast from the screen position

    Ray ray = cam.ScreenPointToRay(screenPosition);

    RaycastHit hit;

    if (Physics.Raycast(ray, out hit))

    {

        // If the raycast hits something, move the cursor to the hit point

        transform.position = hit.point;

    }

}

private void OnDestroy()

{

    if (_moveAction != null)

    {

        _moveAction.Disable();

    }

}

}

@Fitz0Fury
I think I fixed it! I did not use ray casting (I might in the future).

But this conversation helped me to realize something I wanted to do in the beginning.

Simply get the direction in float vector and Lerp between the origin and the target.
But instead of updating transform.position on every step I just save the intermediate steps in a temporary variable. And once the movement has finished, update the transform.position with the final value. So it will look like a “snap”.

     void Update()
    {
        if (!_isMoving)
        {
            StartCoroutine(LerpMovement());
        }
    }

    IEnumerator LerpMovement()
    {
        _isMoving = true;
        float elapsedTime = 0;
        
        originalPosition = transform.position;
        targetPosition = originalPosition + _inputVector.normalized;
        var targetGridPosition = playerGrid.WorldToGridPosition(targetPosition);
        Vector3 finalPositin = new Vector3();

        if (playerGrid.IsPositionAccessible(targetGridPosition) && targetPosition != originalPosition)
        {
            targetPosition = playerGrid.GridToWorldPosition(targetGridPosition);
            while (elapsedTime < moveDelay)
            {
                var t = elapsedTime / moveDelay;
                finalPositin = Vector3.Lerp(originalPosition, targetPosition, t);
                transform.position = finalPositin; // commenting this makes it "snappy"
                elapsedTime += Time.deltaTime;
                yield return null;
            }

            var cellPosition = playerGrid.WorldToGridPosition(finalPositin);

            SetGridPosition(cellPosition);
        }

        _isMoving = false;
    }

Here’s the result. Although it may still have some unexpected bugs for now it does somewhat what I wanted.

I still need to have it in Update because I do not understand how to make “hold” keybord button.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms