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.
  2. Dismiss Notice

Question Cleaning up checking for adjacent tile

Discussion in 'Scripting' started by Corva-Nocta, Jul 13, 2023.

  1. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    Hey all, got an easy one here but I've been working on this project all day so the simple stuff is getting difficult haha. I just need to find if a player is on an adjacent tile to a target. I've got a tilemap and the player navigates to a tile that is closest to a target. Then I do a simple check:

    Code (csharp):
    1. if ((tilemap.WorldToCell(transform.position) - tilemap.WorldToCell(target.position)) == new Vector3Int(1,1,0)
    2. || (tilemap.WorldToCell(transform.position) - tilemap.WorldToCell(target.position)) == new Vector3Int(1, 0, 0)
    3. || (tilemap.WorldToCell(transform.position) - tilemap.WorldToCell(target.position)) == new Vector3Int(0, 1, 0))
    4.             {
    5.                 Debug.Log("We are adjacent!");
    6.             }
    Code is simple and works, but feels like it can be cleaned up and made far simpler. Is that true? Can this code be cleaned up to be easier to read, or is it fine as is? Is there a way to turn the difference between two Vector3Int values to a single number (like 1 if adjacent, or 3 if 3 tiles away)
     
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,769
    This is the kind of thing you clean up via a reusable method. Though with anything tile-based, you should have an underlying 1d or 2d array to record what is where in the grid, so you can simply check via some simple maths, rather than using fragile positions.
     
  3. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    I should definitely make this a reusable method, it will be called all the time so that is definitely something I will look into!

    Is an array necessary if I'm using the tilemap system that is built into Unity?
     
  4. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,769
    Unity's Tilemap I would consider to be for visuals only. I wouldn't tie my underlying gameplay logic and data to it, but it can reflect the current state of said data through visuals.

    If you maintain your own grid you have full control over what happens to it and how it works.
     
  5. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    1,315
    This can indeed be cleaned up. the simplest target is the repeated calls to
    tilemap.WorldToCell()
    .
    target.position
    and
    transform.position
    don't change in between calls to the method, so these values can be cached as a variable:

    Code (CSharp):
    1. var tilePosition = tilemap.WorldToCell(transform.position);
    2. var targetPosition = tilemap.WorldToCell(target.position);
    3.  
    4. if (tilePosition - targetPosition == new Vector3Int(1,1,0))
    5. || (tilePosition - targetPosition == new Vector3Int(1, 0, 0))
    6. || (tilePosition - targetPosition == new Vector3Int(0, 1, 0))
    7.             {
    8.                 Debug.Log("We are adjacent!");
    9.             }
    Next, you are also duplicating the subtraction, which is unnecessary for the same reason:

    Code (CSharp):
    1. var tilePosition = tilemap.WorldToCell(transform.position);
    2. var targetPosition = tilemap.WorldToCell(target.position);
    3. var deltaPosition = tilePosition - targetPosition;
    4.  
    5. if (deltaPosition == new Vector3Int(1,1,0))
    6. || (deltaPosition == new Vector3Int(1, 0, 0))
    7. || (deltaPosition == new Vector3Int(0, 1, 0))
    8.             {
    9.                 Debug.Log("We are adjacent!");
    10.             }
    However, let's not stop here. Think deeper about what this method is trying to do. Another way to word this problem is that you are detecting when one point is a certain distance away from another point. You already have the distance encoded within the deltaPosition, so let's use that. If this were normal world coordinates then we could use
    deltaPosition.magnitude
    to measure whether the distance is under some threshold.

    In a tilemap frame of reference, all positions are on an integer grid, so we want a more "integer"-esque way of determining distance. We can do this by checking the Manhattan distance. This results in the final cleaned up logic:

    Code (CSharp):
    1. var tilePosition = tilemap.WorldToCell(transform.position);
    2. var targetPosition = tilemap.WorldToCell(target.position);
    3. var deltaPosition = tilePosition - targetPosition;
    4.  
    5. if( Mathf.Abs( deltaPosition.x ) <= 1 && Mathf.Abs( deltaPosition.y ) <= 1 ) {
    6.   Debug.Log( "We are adjacent!" );
    7. }
    Note: This will detect corners as well.
     
    Corva-Nocta likes this.
  6. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    That makes sense. Though I'm not sure I'm quite ready to do my own grid system just yet!

    If I want to make the function reusable, should I go with a static method? Or would something like a singleton with the function be more efficient?
     
  7. Corva-Nocta

    Corva-Nocta

    Joined:
    Feb 7, 2013
    Posts:
    801
    Wow! This is awesome! And the walk through makes a ton of sense! Thanks for the info, I'll be adding this in and giving it a go! (Also love that it does corners too!)