0
\$\begingroup\$

I want to number tiles and when gameobject moves, the gameobject should know which tiles it's in. I dont want to use collider. How can I do that ?

This is my game area. For example tile numbers should increase left to right. and when gameobject starts to move tile to tile, it should know which tile it's in. For example if gameobject in tile in this image, it should know that it's in sixth tile

enter image description here

I made and 2D array but I couldn't reference this array with tiles. Idk how to do.

 void Make2dArray(int _row, int _column)
{
    array2D = new int[_row, _column];

    for (int i = 0; i < _row; i++)
    {
        for (int j = 0; j < _column; j++)
        {

            array2D[i, j] = tileIndex;
            tileIndex++;
        }
    }
}
\$\endgroup\$
3
  • \$\begingroup\$ What have you tried so far? Why didn't it work to your liking? \$\endgroup\$
    – Vaillancourt
    Jul 4 '21 at 20:57
  • \$\begingroup\$ I have tried to index tile with for loop by using 2D array but I my tiles don't know this array because I couldn't reference this array. This 2D array just state 2D array in space @Vaillancourt \$\endgroup\$ Jul 4 '21 at 21:01
  • \$\begingroup\$ Don't tell me, edit the question instead, folks tend to ignore the comments. \$\endgroup\$
    – Vaillancourt
    Jul 4 '21 at 21:05
2
\$\begingroup\$

It's important to recognize you now have an additional coordinate system. You already have world coordinates (the game objects in Unity) but you also have "grid coordinates". Your top left tile is 0,0. The one to the right of it is 1,0. The one below is 0,1.

Consider the world point 200,300. If your tiles are 100x00, world point 200,300 corresponds to grid coordinate 2,3. The math to turn, say, world point 250.6,320.5 into a grid coordinate is slightly more involved than just dropping the decimal. There may be better options here's the math with the modulo operator (%) to ensure you're working on tile boundaries. (Eg, you want 400 instead of world point 487.392.)

(int)(250.6) = 250
(int)(320.5) = 320
250 % 100 = 50
320 % 100 = 20
250 - 50 = 200
320 - 20 = 300
[200,300] / 100 = 2,3

With that above math, from any world point you can get any tile coordinate.

You can then turn any tile coordinate into a tile index, assuming you know how many tiles in each row. Given tile coordinate 2,3:

TilesPerRow = 12
((3 * 12) + 2) = 38

You don't actually need to associate a number with a tile. You just need to know each tile's X and Y coordinate. Of course, you certainly could pre-calculate these indices and store them, along with each tile's X and Y as a property in Unity, but you can turn any "world coordinate" into a "grid coordinate", and then into a tile index, as long as your tiles either start at 0,0, or the middle tile is always 0,0 and you store the number of tiles across/down somewhere. (Using a starting tile index other than 0,0 left as an exercise up to the reader but it pretty much just involves subtraction, to act as if that top left tile is at world coordinate 0,0).

So, with your box game object, its coordinate can tell you what tile it's in. Or multiple tiles, if it's larger than a single tile, if you treat it as a rectangle.

All that said, it sounds like you're fairly new to both Unity and programming in general. If you prefer to stick with your original solution, that 2D array needs to be on a globally accessible object. It could be a static variable on a component script that is attached to your tile objects. If none of that makes sense, perhaps following a few more Unity tutorials is in order.

\$\endgroup\$
1
\$\begingroup\$

It seems to me like the main problem is that you have the variable array2D on one gameObject, but you need different gameObjects to access that array.

When you have only ever have one tile grid in your game, then you can put it into a static variable. Static variables are variables which are not parts of each instances of a class but are global variables which are parts of the class itself:

public class GameArea : MonoBehaviour {

     public static int[] tiles;     

     void Make2dArray(int _row, int _column) {
         tiles = new int[_row, _column];
         /*...*/
     }
}

Now all other classes can access that array using GameArea.tiles. No need for a reference.

OK, but when exactly do you call the method Make2dArray? Well, some object needs to call it. But when? In its Start method? What if there are other scripts which need to access the tiles in their Start method and they happen to run before that initialization script? They would run into a NullReferenceException.

Yes, there are ways to manage script execution order. But keeping that list in mind all the time can get really annoying, especially in complex projects. I actually never bother with that list. Because with properly structured code architecture, it's perfectly possible to write code which works regardless of execution order.

Here is one elegant way to initialize it before it is first accessed, regardless of who accesses it and how: Make that variable private, but add a public property to access it. That property first checks if the array is null, and when that's the case it initializes it:

public class GameArea : MonoBehaviour {

     public int rows;
     public int columns;

     private static int _tiles;

     public static int[] Tiles {
          get {
              if (_tiles == null) {
                    Make2dArray()
              }
              return _tiles;
          }
     };     

     void Make2dArray() {
         tiles = new int[row, column];
         /*...*/
     }
}

I also turned the number of rows and columns into public variables, so you can set them in the inspector of the gameObject carrying this MonoBehaviour.


This should get you working for now. But a good next step could be to turn this whole MonoBehaviour into a proper Singleton. That allows you to delegate further functionality to the script. For example, you can move the logic for translating world-coordinates to tile-coordinates into that MonoBehaviour. When the object isn't always centered around the world origin, then you would require access to the transform for that. Which isn't static, so you can't access it in a static method. But by using a static method to get the one and only instance of that MonoBehaviour on a game object, you can get around that.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .