Instancing tiles

The first thing we need in our game is a grid of hexagons to be used as tiled map for the ships movements. In my previous post I created a MainMap class, and here I'll put the code for the dynamic creation of our grid.
Maybe you'll wonder why I didn't simply create an Actor instance for every tile in the map: the reason is that an Actor class is a bit heavy to handle for the Unreal Engine, so having hundreds of Actors in the scene only to render a static map isn't a good practice; especially when we have a nice and clean way to do it: components.

An Actor can have many components, or sub-objects. They can be meshes, but also other types of sub-classes that handle a particular task for the main object (movement, aiming, etc.)


 This is the code to create a component from C++:


With the CreateDefaultSubobject() method we can create a new empty component (tile) for our Actor.
In order to make it visible, we have to assign it a StaticMesh.
In my previous post I wrote about extending th class to Blueprint so that I could reference the Hexagon mesh directly from the Unreal Editor, without having it hard-coded. Unfortunatly, at the moment I haven't yet managed to make it work, so I'm going to use the path of the mesh.

In the constructor method of our MainMap class (and only there, you'll get an error if you try to do it ouside of it), we can use the FObjectFinder static method of the ConstructorHelpers class to create a new StaticMesh reference (tileVisualAsset):


In this line, I used a string with the actual path of the Hexagon mesh inside of our project to reference it.
If the StaticMesh is correctly referenced, I can assign it to our tile component, along with its position and scale in the world.

This is a working solution, but I'll get back at this later and see why it doesn't work in BP.

If you compile the class and launch the preview game, you'll see that a Hexagon is spawned at 0,0.



Now that we have the code to create the Hexagon Static Mesh, it's just a matter of putting it in an array and spawn multiple instances of it.
The problem is that it's not a square grid, but an hexagon one; so how to create it? The simple answer: this is a 2D array, just with every even column  shifted upwards:
2D array with X and Y indexes


The same array, just with shifted position for even columns.



All we need to do is to find the right distances between 2 hexagons and we're done (distances are obviously based on the dimensions of the tile, I found them out by trial & error):



The grid is done! Every tile will be seen as a different sub-object, because inside the loop I gave them a different name (based in the iterating variables) to avoid a "duplicate sub-object" error. This means that the Engine can tell us what object we clicked on, its position, etc.



But we'll take a look at that next time.

Commenti

  1. Hi, what are the xCoord and yCoord, I assumed it would be an FVector2D but that gives compilation errors. It would be great to see all the code, especially the bits you don't explain. Thanks.

    RispondiElimina
    Risposte
    1. Hi! xCoord and yCoord are simply 2 bidimensional arrays of float where I store the coordinates of each tile. They're declared in my MainMap.h file like this:

      static const int jDim = 10;
      static const int kDim = 10;
      float xCoord[jDim][kDim];
      float yCoord[jDim][kDim];

      I declared a dimension of 10x10 tiles, and created the arrays accordingly. I didn't show this part because I haven't used them yet, and maybe I won't even need them, I don't know :)

      They can also be stored as FVector2D of course: in this case, it would be a single bidimensional array declared like this:

      FVector2D coord[jDim][kDim];

      and the relative code should be changed:

      if (y % 2 == 0) {
      tile->SetRelativeLocation(FVector(x * 180, y * 156, 0));
      coord[x][y] = FVector2D(x * 180, y * 156);
      }
      else
      {
      tile->SetRelativeLocation(FVector(x * 180 + 90, y * 156, 0));
      coord[x][y] = FVector2D(x * 180 + 90, y * 156);
      }

      Elimina

Posta un commento