0
\$\begingroup\$

I have a tetris-like 2D game with tiles, each made up of a sprite, a Rigidbody2D and a BoxCollider2D.

The tiles fall from the top, and the player can move them left and right by pressing keys on the keypad.

The tiles' bodies are kinematic.

I have logic in a GameManager class that handles the player's input.

E.g. when the player presses the right-arrow-key, the tile should move right, if it can. If there already is a tile occupying the space to the right of the current tile, the tile should not move.

This is where I am having trouble.

Here is the code that handles input and checks if the space the tile wants to move into is open.

void HandleInput()
{

    if (Input.GetKeyDown(KeyCode.RightArrow))
    {


        rightSpacePosition = new Vector2(activeTile.transform.position.x + fBlockSize, activeTile.transform.position.y);
        var intersectingBox2D = Physics2D.OverlapBoxAll(rightSpacePosition, new Vector2(0.5f * fBlockSize, 0.5f * fBlockSize), 0);
        if (intersectingBox2D.Length == 0)
        {
            activeTile.targetX = GridObject.GridToWorldPosition(activeTile.gridPosition.x + 1, 0).x;
            activeTile.gridPosition = new GridPosition(activeTile.gridPosition.x + 1, activeTile.gridPosition.y);
        }


    }
    else if (Input.GetKeyDown(KeyCode.LeftArrow))
    {
        leftSpacePosition = new Vector2(activeTile.transform.position.x - fBlockSize, activeTile.transform.position.y);
        var intersectingBox2D = Physics2D.OverlapBoxAll(leftSpacePosition, new Vector2(0.5f * fBlockSize, 0.5f * fBlockSize), 0);
        if (intersectingBox2D.Length == 0)
        {
            activeTile.targetX = GridObject.GridToWorldPosition(activeTile.gridPosition.x - 1, 0).x;
            activeTile.gridPosition = new GridPosition(activeTile.gridPosition.x - 1, activeTile.gridPosition.y);
        }
    }
}

As you can see, I am using Physics2D.OverlapBoxAll to find out if there is already a tile at the position the tile wants to move to. The weird thing (and this is hard to describe) is that when the expected overlap is small (i.e. the OverlapBox and the collider of another tile barely overlap), unity seems to think there is no overlap. I've attached a gif here, with Gizmos for the tiles' colliders in yellow and Gizmos for the overlap box queries in red.

Animated example
(Higher quality video of above gif here)

Box 3 (the one that is moving at the beginning of the gif) is the one that is interesting here. It is moving downward, as intended, until, at some point, its lower y-component is less than the upper y-component of the tile to its left. In other words, at this point, the other tile's collider (yellow) lies well within the OverlapBox (red), so any pressing on the left arrow key should have no result (see code above). However, as demonstrated in the gif, this is not the case. The tile does move to the left, and is now overlapping the tile below it, which is not at all desired.

If I had waited a fraction of a second longer when pressing the left arrow key, the code would have worked as intended. I.e. the OverlapBox method would have correctly identified the collider blocking the way, and no lateral movement would have occured. So, in effect, Unity seems to have trouble recognizing that there is a collider in the box region.

Is there anything I can do about this?

\$\endgroup\$
4
  • 1
    \$\begingroup\$ First suspect is timing. The physics transforms and visible game object transforms are not always synchronized (this is expensive, so you have to ask for it specifically using Physics2D.SyncTransforms if you want collision checks to recognize transform changes that happened in the same update step as the code that's querying). Next is mismatches between fixed and variable time step if this function is called outside FixedUpdate. That would let the shape be drawn one step further along than its physics rep, so it performs a move that's valid in its physics position but not in its drawn one. \$\endgroup\$
    – DMGregory
    Jul 24, 2023 at 1:18
  • 1
    \$\begingroup\$ However, if you're intending to have these blocks snap to grid alignment, you shouldn't use physics queries for this at all, and just keep a 2D array of occupied/unoccupied flags. This will be simpler, more robust against weird edge cases, and it will be faster to check or update. \$\endgroup\$
    – DMGregory
    Jul 24, 2023 at 1:20
  • \$\begingroup\$ thanks @DMGregory. I tried Physics2D.SyncTransforms but that didn't fix it. All the code is being called in FixedUpdate. I have also been exploring 2D-Array-based ideas, but am unsure how I could reconcile this with smoothness of motion \$\endgroup\$
    – ChrisC
    Jul 25, 2023 at 0:28
  • \$\begingroup\$ That's a question worth asking if you want help with it. It only makes sense if the intention is that blocks only ever come to rest in grid-aligned positions though. If that's not the way you want the mechanic to work then we can discuss alternatives. \$\endgroup\$
    – DMGregory
    Jul 25, 2023 at 0:34

0

You must log in to answer this question.

Browse other questions tagged .