In my top-down game I allow players to place objects. Now I got to the part where I want to place roads, water, fences, basically things that need to “connect” seemlessly to each other while the player places/removed them. This is usually done using bitmasking.
Bitmasking requires me to build my own grid, and each element in that grid should know what it contains. So far so good, but I need to place several thing in my game that span across several elements in such a grid (A house might cover 10x12 grid-indices). So due to this I never created a grid and simply used unity colliders together with Mathf.Round to create a snapping effect for the player placing objects:
mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
transform.position = new Vector2(Mathf.Round(mousePos.x - 0.5f), Mathf.Round(mousePos.y - 0.5f)); //offset since pivot is bottom left.
My question is, since I don’t use a grid, could I do bitmasking using raycast? Or would this be really performance heavy? i.e every time I place/remove for example a piece of road-tile, that tile checks 1 unit out in all 4 directions to see what is there by getting the object attached to the collider. Do you see any issues with this approach?
If I’m not making sense I can draw some things up to explain what I mean.
EDIT:
In the process of building a solution with my own logic using raycasts. I figure it shouldnt be that heavy on performance because its only called when I place/remove a tile. I’ll update this post with my results.
Okay so, some cool progress. I managed to get it working using raycast and it seems fine on performance. When I place a tile I cheack the 8 surrounding tiles, and then I also go to those 8 tiles and update those to fit the new formation.
If I have one complaint it would be the amount or repetetive code I had to write, and maybe I over-simplified things, but does anyone have any clue if this could be done without 48 if-statements? (48 different combinations of tiles/directions when using 8-bit). I can’t really find sample code for it, and my way works, but feel pretty sure that someone smarter than me can figure out a way to reduce these if-statements. Maybe that is what bitmasking does in the sample I linked in my OP, but couldn’t really understand it.
The start of my 48 if-statements:
if(southWest && southEast && northWest && northEast && west && south && east && north)
{
_spriteRenderer.sprite = _tiles[47];
}
else if (!southWest && southEast && northWest && northEast && west && south && east && north)
{
_spriteRenderer.sprite = _tiles[46];
}
//...
[Flags]
public enum Directions
{
East = 1 << 0, // = 1
West = 1 << 1, // = 2
North = 1 << 2, // = 4
South = 1 << 3, // = 8
// ...
}
Use them like this:
var directions = (east ? Directions.East : 0) | (west ? Directions.West : 0) | (north ? Directions.North : 0) | (south ? Directions.South : 0); //...
// Now directions contains number 0 - 15 for all 16 possible combinations (256 after you add remaining 4 directions)
_spriteRenderer.sprite = _tiles[directions];
Thanks, you code works, i.e if I print directions it prints all the directions the tile has a neighbor. But I don’t really understand the code, so having a hard time making it fit my solution. For example,
The above code wont work, can’t convert Directions to int. Which makes sense. Probably missing a few steps there, maybe you thought those steps were obvious so you left them out, would be great if you could explain some of it Basically, how can I use the enum Direction to set the correct sprite? It needs to represent an int somehow.
Yup… Wast just coming here to edit my post. Then I guess I just need to map the values to the corresponding index in the array somehow, like (direction)255=(index)47. Thanks!
Yeah, as methos5k mentioned, just cast Directions to int like this:
_spriteRenderer.sprite = _tiles[(int)directions];
Directions flags are defined as power of two numbers. 1 for East, 2 for West, 4 for North and so on. Actual flags for each tile is computed as sum of all his neighbours. So if there are for example tiles at the east and at the north, total directions value will be 1 + 4 = 5. Now you just have to assign _tiles[5] (or more readable _tiles[(int)(Directions.East | Directions.North)]) to appropriate sprite and you are done.
Hmm, not really though? Because ‘directions’ will give me values between 0-255, so I cant use that value as the index, I will have to map the values I get in directions to an int between 0-47, that I then can use in the array. See here under “Tile order”
for example, If I place a tile that is surrounded on all 8 directions, then ‘directions’ will return ‘255’
There’s even a spot on that link that shows the values they saved in a list. If yours is like that, you should use it (or something similar if they differ)