2D Tilemap Extras 2.0 released for Unity 2021.1

Yes, but that’s an older version. I was wondering why is the latest version not available.

There are some changes in the 2.x versions for Unity 2021 (Reorderable list) that make it not compatible with the previous LTS versions unfortunately.

Hi,

I’m not sure if this is the right place for my question but there doesn’t seem to exist a Tilemap thread.

I have seams on my tilemap, how do we fix that? And why do I have these seams? The only way that works for me right now is setting the x and y Grid cell size to 0.99. The other solutions do not work.

How would I go about creating a pseudo-random tile that doesn’t repeat the same sprite as its neighbors?

I previously wrote some hacky solution to this by overriding GetTileData in a custom class that inherits from RuleTile, but I don’t think this was correct, and it’s currently not working for me. I’m on version 1.7.

I figured this page would be relevant, but it doesn’t really explain how to get info from the tile or its neighbors (eg position, current sprite). And it doesn’t explain the “neighbor” argument for RuleMatch.

[quote=“_eternal, post:24, topic: 840315, username:_eternal”]
How would I go about creating a pseudo-random tile that doesn’t repeat the same sprite as its neighbors?
[/quote]Xorshift. Replace line in the RuleTile so it uses your own GetRandom(x, y) method. You could xorshift x and y independently then add, multiply them, throw in some primes - whatever you find gives you a good random distribution.

If I recall correctly, RuleTile uses PerlinNoise which really isn’t a good choice for random distributions where neighbors aren’t biased together.

I haven’t looked at the latest RuleTile version but I doubt there’s a good inheritance hook for it, so simply replace with your own method.

Interesting, thanks. Sorry, can you elaborate on how to use xorshift?

I tried to override GetTileData, and I replaced the Random case in the switch statement with this just to test it out:

case TilingRule.OutputSprite.Random:
    float randomValue = Random.Range(0f, rule.m_Sprites.Length - 1);
    int index = Mathf.FloorToInt(randomValue);
    tileData.sprite = rule.m_Sprites[index];
    if (rule.m_RandomTransform != TilingRule.Transform.Fixed)
        transform = ApplyRandomTransform(rule.m_RandomTransform, transform, rule.m_PerlinScale, position);
    break;

The override works, so that’s good. But the randomization is still placing neighbors beside each other.

For comparison, this was the original logic in the source code (you were right that it uses Perlin Noise).

case TilingRule.OutputSprite.Random:
    int index = Mathf.Clamp(Mathf.FloorToInt(GetPerlinValue(position, rule.m_PerlinScale, 100000f) * rule.m_Sprites.Length), 0, rule.m_Sprites.Length - 1f);
    tileData.sprite = rule.m_Sprites[index];
    if (rule.m_RandomTransform != TilingRule.Transform.Fixed)
        transform = ApplyRandomTransform(rule.m_RandomTransform, transform, rule.m_PerlinScale, position);
    break;

And this is GetPerlinValue, though I couldn’t really tell you what it does or why you’d pass in 100000f.

/// <summary>
/// Returns a Perlin Noise value based on the given inputs.
/// </summary>
/// <param name="position">Position of the Tile on the Tilemap.</param>
/// <param name="scale">The Perlin Scale factor of the Tile.</param>
/// <param name="offset">Offset of the Tile on the Tilemap.</param>
/// <returns>A Perlin Noise value based on the given inputs.</returns>
public static float GetPerlinValue(Vector3Int position, float scale, float offset)
{
    return Mathf.PerlinNoise((position.x + offset) * scale, (position.y + offset) * scale);
}

You don’t want to use Random.Range because it won’t produce consistent results.

The reason they use Perlin Noise is you can give the function an input (x, y) and you’ll always get the same output. This is good in this situation where you don’t want every time the tile refreshes it produces a different sprite or different mirroring. That would be inconsistent and bad.

However, Perlin Noise sometimes fails to produce different neighbors even if you try to adjust the scale very carefully. YouTube some Perlin Noise visualizations to get it. But the jist is that (x,y) that are near one another remain correlated.

I recommend Xorshift because it’s a way - like Perlin Noise - to get consistent output from an input.

All we’re doing is taking the bits of an input (x) and bit-shifting them around to produce a pseudo-random. You ultimately want a single output from both x and y, so you can experiment to see what produces good results for you: for example, perhaps adding x + 123 and y + 47 then xorshifting them ea individually, then adding the two results to produce a single integer works for your case. Try some stuff out.

You can see the formula and variants for xorshift on the Wikipedia page.

On the posted code, you’d ultimately replace this

int index = Mathf.Clamp(Mathf.FloorToInt(GetPerlinValue(position, rule.m_PerlinScale, 100000f) * rule.m_Sprites.Length), 0, rule.m_Sprites.Length - 1f);

to thisint index = Mathf.Abs(XorshiftPosition(position)) % rule.m_Sprites.Length;
or something like that. You then have a random # from your position input that is randomly distributed across the indices of your sprite array.

1 Like

Thank you for this! This is really helpful.

Yeah, this explains why the random rule tiles would always change when I mouse over them with the tile. GetTileData was probably being called when I did that, and Random.Range was generating a new random seed and therefore a (basically) true random number each time.

It looks like this is working now. I still have a hardcoded solution that checks for duplicate neighbors and picks a new random sprite via Xorshift if necessary. But I also tried making a rule tile with just Xorshift random and without manually checking neighbors, and it seems to work really well. So that’s a huge improvement. Thanks again!

For what it’s worth, this is what I did for the latter solution.

case TilingRule.OutputSprite.Random:
    int pseudoRandom = Helper.XORShift(position.x, position.y);
    pseudoRandom = Mathf.Abs(pseudoRandom);
    int index = pseudoRandom % rule.m_Sprites.Length;
    tileData.sprite = rule.m_Sprites[index];

    if (rule.m_RandomTransform != TilingRule.Transform.Fixed)
        transform = ApplyRandomTransform(rule.m_RandomTransform, transform, rule.m_PerlinScale, position);
                      
     break;
//this is in Helper.cs
public static int XORShift(int x, int y)
{
    int t = y ^ (y << 11);
    return x ^ (x >> 19) ^ t ^ (t >> 8);
}

Are these seams between Tiles whose Sprites come from a shared Texture? We would recommend that the Sprites from the Tiles be atlased together using the Sprite Atlas with padding between the Sprites. This would help with the seams when in Play mode/in the player. Making use of the 2D Pixel Perfect package can help with this as well (2D Pixel Perfect | Universal RP | 11.0.0).

1 Like

No, not shared textures. And now that you mention it, they were atlased already, with the default padding. I removed the atlases because the secondary textures disappear in play mode when these atlases are around (see here and below: https://forum.unity.com/threads/sprite-atlases.1119226/#post-7220938 ).

I put the grid back to it’s original size 1, 1, 1, and the seam have disappeared. :slight_smile:

Does anyone have some experience using the ruletile and custom ruletile script setup? I want to prevent tiles from changing, either at runtime or when a certain bool I set is true during runtime, but work as usual when I am using the editor. I can’t seem to find an override in the “customruletile” that will allow me to do this.

I basically want to allow the player to destroy tiles by “setting” them without running the ruleset, but when a player is building (or when I am in the editor) I want to USE the ruleset. Tiles change visuals when I want them to, and don’t change when I set them to something else when otherwise stated. (IE if I remove tiles green tiles to dig into the earth, I want it to stay gone and dig into earth and not magically change to green topsoil surroundings).

Psuedo world destruction if you will.

If there currently exists no way for me to turn on and off the functionality for autotiling in this manner, that is a feature I would greatly request be added @rustum

I don’t see a thread related to the 2D Tilemap Editor package.

I have tried to use this with a 3D game but it was very buggy, problems I encountered are:

  • It builds on the same tile over and over
  • While using the brush, it has no respect to the grid, randomly acts like it is a rectangular grid while in case it is a hex grid.
  • Tiles offset are very off in hex mode and I can’t even fix this

Here you can see all those issues:

Would it be possible to try setting the Anchor value in the GameObjectBrush to (0, 0, 0) instead of (0.5, 0.5, 0.5)? The Anchor offset does not really make sense for hexagonal grids outside of the z-axis (for height).

If you could also share the cell content for the GameObjectBrush, that would be helpful to debug this issue as well. Thanks!

1 Like

Yes the issue was the Anchor value, I didn’t touch it beucase it was the default value, after I set it to (0, 0, 0) everything worked flawlessly. Since you asked, here is the content for the GameObjectBrush. Thank you!

There was a menu to create brush assets, but now I cannot find it anywhere. Is it a bug?

Could you share which brush you want to create an asset for, and which version of the Tilemap Extras package you are using? Some brushes which you have used previously may not be available in the Tilemap Extras package downloaded from the Unity Package Manager.

I’m using Unity 2020.3.20 and install this package from Package Manager. The package is 2D Tilemap Extras 1.8.1-preview. I was trying to create the random brush, gameobject brush. Currently I have to write a custom MenuItem to create the brush assets.

Hi I’m not using 2021 but I have what is hopefully general UI feedback, using Unity 2020 LTS

  1. How do I zoom in and out of the Tile Palette? I tried the usual Unity shortcut of Alt-RMB+cursor but it only pans the view. Is zooming the view possible?
  2. Can I change the Tile Palette window background colour? This is a very handy feature in Tiled for tiles that might be the same colour as the interface UI. For example bright green is a useful background colour for seeing small tiles with transparency. (much like the alpha option in Sprite Editor)

The intention for those brushes is not to have individual assets for them, but to have the user pick the items from the Tile Palette itself.

I guess that it does not suit your use case. Would it be possible to share them to us? I guess that setting up the random sets used for the Random Brush could be a hassle, so that can be changed to do so.