-
Notifications
You must be signed in to change notification settings - Fork 340
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rule Override Tile #67
Comments
I haven't used the RuleOverrideTile yet, but RuleTiles in general only look for copies of the same tile. It sounds like you are using two tiles that implement the same ruleset. Let's call them tile A and B. A has walls when Up and Down neighbors are matched, B has a window when they are matched. Tilemap looks like this: The thing is, as far as B is concerned, it doesn't have neighbors, because there are no tiles of B around it. So you'll get the Sprite for no matching neighbors on B, and "edges" from the neighboring A tiles. Does that make sense? Rule Override Tile is designed to reuse rulesets on different tiles, not for alternate sprites within a ruleset. For our project, we added what we call "Siblings" to the rule tile. It's a list of Tiles it considers as a match. A and B would be siblings, and you'd get the desired effect. |
You're right, that is what I'm doing, and what you say makes sense. Your solution sounds like what I need.. Would you be willing to share the code? |
Nice! I wasn't sure if it'd be useful to others so it's good to hear about
your use case.
Another option is to paint tile B on another layer or at a different z
depth, on top of an A tile. But I don't like that option myself as 3d
Tilemaps are harder to paint with.
Unfortunately our code diverged too much to directly share but I can modify
it I think. I'm at lunch, so I'll do it when I get back in 30 mins or so.
|
Here's a quick modification to RuleTile to do what I'm saying. You should be cautious about diverging from this repository too much, as it can make it hard to update. And this is actually pretty tricky to make work with Override tiles as it's a bit unclear how they should behave, so it only works for the base rule tile right now. This required changes to both the RuleTile and RuleTileEditor scripts. |
I have added a quick and hopefully correct example of Rule Override Tile and Custom Rule that may help with this at 2d-techdemos: I will check out RuleTileWithSiblings as well! |
@Krummelz For your case, this is an example of inheriting the RuleTile implementation: [CreateAssetMenu]
public class MyTile : RuleTile {
public bool isWall;
public override bool RuleMatch(int neighbor, TileBase other) {
if (neighbor == RuleTile.TilingRule.Neighbor.This)
if (other is MyTile)
if (this.isWall && (other as MyTile).isWall)
return true;
return base.RuleMatch(neighbor, other);
}
} |
@ChuanXin-Unity Thank you for this example, this is look good! I found that comparing the methods of RuleTile and RuleOverrideTile is a bit complicated. I tried to add the m_OverrideSelf field to RuleOverrideTile to handle different connection situations. I am not sure if this is better because it may become more difficult to understand. Can you look at it? PR: #70 |
Here's my script! It works like a charm. Based on @johnsoncodehk's script: using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
[CreateAssetMenu(fileName = "New Sibling Rule Tile", menuName = "Tiles/Sibling Rule Tile")]
public class SiblingRuleTile : RuleTile
{
public List<TileBase> siblings;
public override bool RuleMatch(int neighbor, TileBase other)
{
if (siblings.Contains(other))
{
return true;
}
return base.RuleMatch(neighbor, other);
}
} I hope this gets added into 2d-extras, it is a much needed feature! |
I ran into exactly the same problem. Your example scripts have helped me a lot! I found that @ElnuDev 's implementation is close, but had a few bugs when you're using both positive and negative neighbor rules. Here's my code, based on yours, fixing this behavior:
|
Hey, I know this post is old but I had some questions (I used the example script in the wiki):
|
What you currently see is the default option in the switch, where a label with selected rule is printed. You can change it to an icon you have created by adding a new case with
|
@ChuanXin-Unity If I draw the custom tile everything is normal but if I draw the custom tile and then draw a normal tile (sibling tile to the custom one) it won't update until I hover my cursor to its position. |
@longtran2904 RuleTile refresh can only be trigger by RuleTiles (RuleTile, OverrideRuleTile, CustomRuleTile...), "trigger by any tile" need Tilemap to add support. |
@johnsoncodehk Most of the time, I would use RuleTile but in some special cases that the rules didn't apply, I had to use the normal tile (which messed up the rule tile so I created a custom sibling tile for it). So I had a custom rule tile and a normal tile. Are there any other ways? |
@longtran2904 If you want to use normal tile, you need to inherit the normal tile class and override RefreshTile() to update RuleTile. Compared to this method, it is much simpler to switch to RuleTile. |
@johnsoncodehk Does this problem only appear visually and when I in play mode or instantiate the tilemap from a prefab it will be disappeared? If it's true then I can live with it. |
All tiles will be refreshed once when entering playback mode. Therefore, if you do not change the Tilemap at runtime, this problem will not occur. |
@johnsoncodehk Thank you, I think I will just leave it there. |
@ChuanXin-Unity Maybe we can consider refresh affected tiles by Tilemap, or create RuleTilemap for this problem? |
@johnsoncodehk Hey, when my game starts, it spawns some tilemaps (which have rule tiles) and then copies it into a shared tilemap so sometimes the tiles don't get updated again. How to call RefreshTile() for all the tiles through code? |
@longtran2904 You can use Tilemap.RefreshAllTiles, But if the tilemap size is relatively large, you need to consider performance. |
@johnsoncodehk Thank you! It worked. My game is composed of different rooms (which have different tilemaps) and I copy it at the start of the level only so it will be fine (max: 50,000 tiles). |
@johnsoncodehk How the bool RuleMatch(int neighbor, TileBase tile) work? How the parameter neighbor gets passed? I want a rule which has a sibling tile in it and do I need to make another case for the switch (Neighbor.Sibling) or Neighbor.This is ok? |
@longtran2904 |
@longtran2904 If the neighbor is a sibling then will the int neighbor equal to 1 or 3? If it is 3 then how the case Neighbor.This work (This == 1)? (I used the example script sibling 1 in the 2d-extras wiki) |
@longtran2904 |
@johnsoncodehk I knew that, but when the RuleMatch gets called if the tile gets checked is a sibling then the int neighbor parameter is 1 or 3? |
@longtran2904 The role of RuleMatch is not to judge the neighbor type. It is to check whether the rules in Tiling Rules match in order. RuleMatch(This, GetOtherTile(0, 1));
RuleMatch(NotThis, GetOtherTile(-1, 0));
RuleMatch(NotThis, GetOtherTile(1, 0));
RuleMatch(NotThis, GetOtherTile(0, -1)); If all return true, the sprite of A will be displayed. RuleMatch(This, GetOtherTile(0, 1));
RuleMatch(NotThis, GetOtherTile(1, 1));
RuleMatch(NotThis, GetOtherTile(-1, 0));
RuleMatch(This, GetOtherTile(1, 0));
RuleMatch(NotThis, GetOtherTile(0, -1)); If all return true, the sprite of B will be displayed. |
Oh, I understand now. Thanks for replying! |
For this issue, perhaps the Tilemap could have a default refresh radius parameter that users can specify if TileBase.RefreshTile has not been overridden instead of just the current cell. This is only useful if there is a mix of different types of Tiles with different Refresh ranges. Alternatively, the base RefreshTile of the normal Tile needs to have its RefreshTile range increased to include all of the neighbours, same as the Rule Tile used. |
@ChuanXin-Unity If it is implemented by normal tiles, AnimatedTile/PipelineTile/TerrainTile... and so on all need to be changed, which is not conducive to the user to create custom normal tiles, and the user may not know that in order to support the use with RuleTile, you need to override RefreshTile to add related logic . Therefore, I recommend implementing it by Tilemap. The advantage of setting with radius is that it is easy to understand. It is feasible to convert the neighbor positions of RuleTile to radius and provide it to Tilemap, but performance may be a problem. |
Yes, performance will be an issue if the radius is set unnecessarily. Having special cases such as the one as you set above also makes it unfeasible. The issue then would be how to track individual cases like this for refreshing, since the placement of a normal Tile can could trigger updates for Rule Tiles anywhere with extended neighbours. |
@ChuanXin-Unity Fortunately RuleTile has already dealt with this problem and the way it works is:
Since the calculation method is based on Tilemap, it is easy to migrate to Tilemap. |
Thanks for pointing this out! It could be possible that the Tilemap has its own callback method for refreshing Tiles without the RefreshTile override that implements this for all types of Tiles (or some other way if needed) instead of the default radius. We would definitely check this out! |
Let's say I have a set of rules to paint walls with, in a top-down game. Now, I want to add windows to the walls at specific points. The windows would be one extra tile, and should take the place of a straight wall segment, where I paint it. I cannot add a window tile to the existing rules, because the rules for a straight segment, and a straight segment with a window, would be the same. So you would always get only one or the other.
I tried using the rule override tiles, overriding a straight segment with a windowed segment. When I now paint this on the same layer, to replace a straight wall segment, I expect a window to appear, and the wall tiles from the base rule should connect as they normally would, except the existing tiles don't connect to the new overridden tile. The rules don't work across both the base rules, and the overridden rules. It seems this is only useful for is creating another set of rules with the same tiles. The end result is that you have to use your override tiles somewhere else on your tile map.
Is there some way of doing this? There's no sample project that makes use of the Rule Override Tile, so I can't really tell, and from my experiments, it doesn't do what the name implies.
The text was updated successfully, but these errors were encountered: