GameObject moving 1.015 units instead of 1.

I’m a beginner so please bear with me. Also, I tried looking up how a post should be structured here (like in StackOverflow for example) but didn’t find anything, so if something should be changed let me know.

QUESTION:
I’m trying to make a tetris game so movement of the blocks should be restricted to whole units, if not, there would be problems aligning each time a new block is added. In my script, when RightArrow is pressed down, the shape should move one unit to the right. Instead it moves 1.015 (the same for any direction and axis). So what do I have to do so that movement is always exactly 1 unit at a time in the x and y axis?

Here’s my ShapeControl script:

public class ShapeControl : MonoBehaviour
{
    [SerializeField] private bool inPlayArea;
    [SerializeField] private Rigidbody2D myRigidBody;
    [SerializeField] private Vector2 shapePosition;
    public Transform PlayAreaChecker;
    public LayerMask Layer;
    private int delay = 0;

    void FixedUpdate()
    {
        // ignore this
        //inPlayArea = Physics2D.OverlapCircle(PlayAreaChecker.position, 0.1f, Layer);

        if (Input.GetKeyDown(KeyCode.RightArrow))
        {
            shapePosition.x = myRigidBody.position.x + 1;
            shapePosition.y = myRigidBody.position.y;
            myRigidBody.MovePosition(shapePosition);
        }
        if (Input.GetKeyDown(KeyCode.LeftArrow))
        {
            shapePosition.x = myRigidBody.position.x - 1;
            shapePosition.y = myRigidBody.position.y;
            myRigidBody.MovePosition(shapePosition);
        }
     
        OnTriggerEnter2D(GetComponent<Collider2D>());
    }

    //whenever a shape is in the 'play area', it continuously drops 1 unit with a delay.
    void OnTriggerEnter2D(Collider2D other)
    {
        delay++;
        if (delay == 50)
        {
            shapePosition.y = myRigidBody.position.y - 1;
            myRigidBody.MovePosition(shapePosition);
            delay = 0;
        }
    }
}

QUESTION 2:
(not sure if this is allowed) Also, in my project, the FixedUpdate happens multiple times a second so the physics update does too. Therefore it should be responsive: everytime I press RightArrow or LeftArrow, the shape should move. This isn’t the case in practice, however. Movement is instead very unresponsive, I have to press RightArrow a few times for it to move, and that number is irregular (eg: I press 5 times, it moves along 1. Then, I press 10 times: moves along 1.)

Physics (Rigidbody) is not necessary for a tetris game. Just move the pieces and snap them to the grid yourself.

Here’s an example:

Download the project and run the scene by the same name.

The above should address both of your questions.

Hmm, I thought that the blocks would need a RigidBody component to detect collisions with other blocks. And setting up colliders seems easier than to have the same behaviour using only logic and Transform. Am I wrong?

If you can do that, good luck to you. I would personally just check it on a grid basis, since you already must know about the grid to decide “hey this row is full” as well as go grab the proper blocks and move them down.

Ok, so my next question: using your method, how would you know a row of the grid is full. I guess I’m confused because I don’t know what your ‘grid’ would look like and therefore how you would check your grid. In my case I have a script that instantiates square sprites to make a 10x20 grid. I’ve shown it below to make it easier:

void GenerateGrid()
    {
        for(int x = 0; x < _width; x++)
        {
            for(int y = 0; y < _height; y++)
            {
                var SpawnedTile = Instantiate(_tilePrefab, new Vector3(x, y), Quaternion.identity);
                SpawnedTile.name = $"Tile {x} {y}";
                // Below is just to give a checkerboard appearance (unimportant)
                if ((x + y) % 2 == 0) isOffset = false;
                else isOffset = true;
                // function that sets colour depending on offset (unimportant)
                SpawnedTile.Init(isOffset);
            }
        }
          // adjust camera to center of grid (unimportant)
        _camera.transform.position = new Vector3((float)_width / 2 - 0.5f, (float)_height / 2 - 0.5f, -10);
    }

Grid would be a 2D array of “something.”

You would iterate across and check lines for completion, after a drop.

This guy does it:

https://www.youtube.com/watch?v=T5P8ohdxDjo

He chooses to store the Transform of each sub-chunk after it lands in place.

Okay, thanks for your time. I will refrain from watching the video for now as I don’t want to see how to do the entire project since it’s what i’m trying to do. I will restart the project and use logic and Transform. Keep an eye in the forums as most likely I will face more problems haha.
Thanks again.