Search Unity

Rule Tiles won't change depending on adjacent tiles but from a different tilemap component.

Discussion in '2D' started by GleaveGames, Nov 25, 2020.

  1. GleaveGames

    GleaveGames

    Joined:
    Oct 31, 2019
    Posts:
    6
    I'm working on a rogue like where I instantiate different rooms, all with destructible terrain. Each room has a different tilemap component with the walls for that room. Unfortunately there are these really obvious lines between each room where the rule tiles don't think there are any of that tile when the room ends, but there is and I want the rooms to connect seemlessly with the terrain. Any help would be greatly appreciated. I'm using the new unity 2D extras component.
     
  2. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,511
    Here are several ideas to help you fix the problem.

    1. You could modify the RuleTile script to get other tilemap components shared by the same grid, but this may make it slow and allocating: tilemap.layoutGrid.GetComponentsInChildren<Tilemap>(..). You could then check against every tilemap for what exists at a cell position on each. To improve this idea, perhaps you have a list of Tilemaps which may have walls on them that you maintain somewhere and check against that to speed things up.

    2. You could have a special RuleTile that, if a wall, looks up wall data from an tilemap-independent data store. This would require some data structure (e.g. HashSet<Vector3Int>) which you add / remove current wall locations. The walls use that as the basis for their rule.

    3. Instead of instantiating different rooms, you merge them onto the same tilemap. From a tilemap prefab, you could copy the tiles from it as a template. These copied tiles are merged with onto a common tilemap. Caveat: if you're using composite colliders, it's possible huge tilemaps (if your maps are large and your walls have colliders) can cause performance problems when they rebuild themselves. Some people have had the need to break them up into several tilemaps b/c rebuilding the composites can be expensive. I mention this because you say your terrain is destructible so this may apply to your situation.
     
    GleaveGames likes this.
  3. GleaveGames

    GleaveGames

    Joined:
    Oct 31, 2019
    Posts:
    6
    I'm a little confused by the custom rule tile script. I think it will probably be the answer for this problem, as you said in your answer 1. Do I add the rule tile script to the same object as the tilemap? Just a bit confused as to where I would put the script once I've written it.
     
  4. GleaveGames

    GleaveGames

    Joined:
    Oct 31, 2019
    Posts:
    6
    Also @Lo-renzo thank you so much for the reply! Greatly appreciate your help :)
     
  5. GleaveGames

    GleaveGames

    Joined:
    Oct 31, 2019
    Posts:
    6
    @Lo-renzo I'm understanding now what you mean by editing the ruletile script. i'm going to take a stab at that now, I'm just a little confused about where the functions in the script are being called from, as what I think I will have to do is change the method to take an array of tilemaps and loop through them, or as you say, create a larger tilemap that has all the data and do it that way. I suppose if I do that I won't have to edit the rule tile script at all. Maybe I should look into that first.
     
  6. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,511
    To make a custom RuleTile script, you would want to create a new class, MultiTilemapRuleTile (or some cleaner name!) to create a child class of RuleTile. This may require going into the original RuleTile script and marking some methods "protected virtual" so you may access them from the child class.

    Now that I'm looking at the newest version of RuleTile, it's gotten way more complicated (my custom versions of it were from an earlier, simpler iteration) so this might not be an easy task at all. (Or Idea #2 or #3 looks better than #1.)

    If you need #1. Here's what I would attempt: from ITilemap (this is a pseudo-interface despite its naming) you can call GetComponent. If you add a component to each one of your wall Tilemaps which stores a runtime list of other wall Tilemaps, you then have access to a list a wall tilemaps. In GetTileData() the RuleTile decides "what sprite and rotation do I need based on what's in the nearby cells in this tilemap?" You need this decision to change to "in these tilemaps." Again this looks pretty complicated :(

    Maybe someone else can chime in with a simpler suggestion.
     
  7. GleaveGames

    GleaveGames

    Joined:
    Oct 31, 2019
    Posts:
    6
    @Lo-renzo , thanks again for you help. I've actually just got it working using that number 3 method you suggested earlier. what I've done is just loop through all the tilemaps at runtime and create and array of ints just saying where the walls on that layer of tilemaps are, removing them as I go. Then once I have an array of all of the wall positions, I use settile to replace them all but all on one tilemap. I can then do this with all of the different types of tiles and it should all fit together nicely. There's only about 1400 total tiles in each scene so I don't think that it will be a problem doing it this way. Thanks for all your suggestions though.
     
  8. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,511
    Glad it worked out! At 1400, SetTiles or SetTilesBlock may be worth it if this happens at runtime. It's a more performant API and from my testing starts being worth it at >6 tiles.