4
\$\begingroup\$

I am looking for a way to select tiles within a bounding box for object placement within a scene/world, similar to Roller Coaster Tycoon and other simulation games.

theme parkitect object placement
(source: tumblr.com)

In the above screenshot of Theme Parkitect you can see that a 4x4 grid is used as the footprint for the object being placed. Given the bounding box and location of the mouse, how can I suitably determine the neighbouring tiles which fall into the bounding box?

I have implemented a graph like structure of tiles, corners and edges by following Amit's fantastic articles on Red Blob Games. As of such, I have a graph of all tiles and their neighbours as well as associated tile edges and corners. These tiles are laid out diagonally against the world axis so simply selecting all tiles within a rectangular region isn't as simple (or maybe it is?) as i'd expected. This layout can be changed if necessary however.

The main source of information used to steer my implementation has been from Amit's Thoughts on Grids and the graph structure implemented in his article about Procedural Map Generation

tilemap grid layout

As a bonus, I would like to implement a way to rotate the object being placed such that a footprint of 1x5 could be rotated to instead be 5x1. I would imagine that once the basics of multiple tile picking has been implemented this should be reasonably simple.

Unfortunately, Amit's articles don't seem to cover this topic and the approaches I have found and tried so far haven't quite yielded the correct results. Any help that fits in with the graph like structure for connected tiles, edges and corners would be greatly appreciated.

I have tried to implement the approach outlined in Raytracing on a Grid with a mixture of both Broad-Phase collision and A* Path Finding but neither of these two approaches cover selection of multiple surrounding tiles.

I am not concerned with the viability of tiles for placing objects at this point (i.e.: sloped edges of tiles or obstructions from other objects). The ideal solution for now would simply be to find the tiles included within the bounds.

My initial forays into this have resulted in incorrect results whereby the bounding rect doesn't include all neighbouring tiles (sometimes missing entire rows/columns) or returning neighbours outside of the bounds. I was pretty sure that I was close to a winning implementation but my vector math isn't strong enough to validate my findings.

\$\endgroup\$
  • 1
    \$\begingroup\$ Sharing your research helps everyone. What were the approaches you tried and how did their result differ from the desired results? Also, could you maybe post a direct link to the relevant article? You've linked to the frontpage of Red Blob Games, and the website has quite a lot of articles. This would help us to understand how you implemented your isometric engine which in turn would help us to propose a solution which fits your implementation. \$\endgroup\$ – Philipp Mar 21 '16 at 11:40
  • \$\begingroup\$ I have updated my question with additional references to the articles used as the basis for my implementation thus far :] \$\endgroup\$ – CaptainRedmuff Mar 21 '16 at 12:05
  • \$\begingroup\$ If i understand correctly you are looking to solve 2 problems? The first one trying to find the square the mouse is currently over and then selecting all grid locations covered by a template? When you solve the first problem the second one should be trivially easy as long as you can select your gridlocations by x-y-coordinates. Just don't try to select all the tiles at once, select one and place your building on that point, testing all locations covered by your template. edit: a question turned into half an awnser, I will work this out when i have more thime. \$\endgroup\$ – Niels Mar 22 '16 at 7:17
  • \$\begingroup\$ I have already managed to implement tile picking for a single tile. I want to expand upon this to include neighbouring tiles for those within a bounding box. If it makes any difference to the answer, I am using Unity's built in ray tracing and mesh colliders to determine the tile being picked. \$\endgroup\$ – CaptainRedmuff Mar 22 '16 at 8:59
1
\$\begingroup\$

enter image description here

if your data is in a one dimensional array you can convert from index to coords and back easily. making it easy to determine what is beside a coord

public int TileIndex(int x, int y)
{
    return y * Width + x;
}
public Vector2 TilePosition(int index)
{
    float y = index / Width;
    float x = index - Width * y;
    return new Vector2(x, y);
}

so to check the tile to the east of 2,2 you can get the tile at index 3,2

if (Empty(TileAt(TileIndex(x + 1, y)))
    MoveEast();
\$\endgroup\$
2
\$\begingroup\$

When you have your mouse-picking working all you need to do is overlap your map with the object you wish to place. This problem would be the same for an isometric grid as for a rectangular grid.

Take this exmaple map:

enter image description here

And this building:

enter image description here

On this map the green squares are meant to as grass, the brown squares as mountain and the blue squares as water. Although this is irrelevant to the actual solution

On the building the color of the squares determines the placemant restrictions, white can be placed anywhere, yellow can only be placed on green squares and orange can be placed on either green or brown squares.

After you've picked the square the mouse is over on the map you simply pick a square from your building-template, (this can be any square you want, top-left, best-effort middle or whatever provides the best experience to your players), let's use top-left for this example. and then check if all squares are compatible with the map.

This can be done by simply looping over the squares:

for each square in building_template do:
    determine offset from cursor on template
    pick tile from map with same offset
    check if placement is allowed

    if placement is not allowed, depending on your design either:
        return false immediately and draw the entire template in red.
        color that square from your template red and continue, keep track if any blocking squares were encountered

If we place the building on C4 for example We'd get the following result: enter image description here

Where B2 of the building is blocked because that square could only be placed on green tiles.

Note that you can have the matching algorithm take into account any conditions you want.

I hope this is the problem you were trying to solve.

\$\endgroup\$
  • \$\begingroup\$ This is an interesting answer but it doesn't quite cover how to determine which tiles are covered by the footprint of the object being placed. In your example, if you chose the top left corner of the object and find a tile on the map to place it, how do you then iterate over the remaining tiles, i.e.: all the tiles in the same row, and then those in the subsequent rows? \$\endgroup\$ – CaptainRedmuff Mar 22 '16 at 16:24
  • \$\begingroup\$ @CaptainRedmuff a simple loop would cover that. for(int blueprint_x = 0; blueprint_x < blueprint.width; blueprint_x++){for (int blueprint_y = 0; blueprint_y < blueprint.width; blueprint_y++){ if(getBlueprintTile(blueprint_x, blueprint_y).canBePlacedOn(map.getTile(pickedTile_x + blueprint_x, pickedTile_y + blueprint_y) ){//do stuff}else{//show that tile cant be placed}}} \$\endgroup\$ – Niels Mar 23 '16 at 7:01
  • \$\begingroup\$ @CaptainRedmuff I just realised the pseudocode for that was already in the awnser, so I assume I must be missing what you are actually asking. \$\endgroup\$ – Niels Mar 23 '16 at 7:08
  • \$\begingroup\$ i.imgur.com/djq7UI2.jpg \$\endgroup\$ – Rakka Rage Mar 23 '16 at 22:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.