在 Unity (2D) 中连接具有不同纹理的规则图块

Posted

技术标签:

【中文标题】在 Unity (2D) 中连接具有不同纹理的规则图块【英文标题】:Connecting Rule-Tiles with different textures in Unity (2D) 【发布时间】:2018-12-02 07:14:08 【问题描述】:

我正在 Unity 中创建 2D 平台游戏,并且正在使用“2D Extras”插件中的规则拼贴。我目前正试图让两个规则块相互连接,即使它们具有不同的纹理。在这里您可以看到Ruletiles which I want to connect 的示例。我想连接浅色和深色的草砖。它们位于两个单独的规则文件中。

我该如何管理?

【问题讨论】:

This unity asset(高级规则图块)已经存在很长时间了。它完全符合您的要求,并且与 2d 资产中的常规规则拼贴一样易于使用,不像硬编码每个拼贴以能够检测黑草等,这使您可以建立多种类型的关系在任何瓷砖类型之间。 【参考方案1】:

有几种方法可以解决此问题,主要取决于您希望如何在视觉上连接相关图块。我一般处理这个问题的方法是改变规则,以便区分:

相同的瓷砖类型(这个) 另一种图块类型(不是这个) 一个空磁贴(空)

我认为实现相当简单,可以通过在以下位置编辑原始 ruletile.cs 来完成:

public enum Neighbor  DontCare, This, NotThis, Empty 

最重要的是:

 // When this returns true, that means that the rule does not match
    // IE this is testing if any of the rules are broken
    // If the rule matches that means that the sprite associated to the rule will be the new main sprite
    // These are the rules which are being checked if they are broken
    // This -    should only be triggered for the same tile type,
    //           which is not the case when the tile is not this
    // NotThis - should only be triggered for another tile, which is not empty
    //           IE broken when it is this or null(empty)
    // Empty -   should only be triggered when there is no tile
    //           IE broken when it is this or not null(empty)
    private bool RuleBroken(TilingRule rule, int index, TileBase tile)
    
        return (rule.m_Neighbors[index] == TilingRule.Neighbor.This && tile != this)
            || (rule.m_Neighbors[index] == TilingRule.Neighbor.NotThis && (tile == this || tile == null))
            || (rule.m_Neighbors[index] == TilingRule.Neighbor.Empty && (tile == this || tile != null))
            ;
    

剩下的就是对编辑器文件进行更改,以便您实际上可以在 4 种而不是 3 种枚举状态之间切换,然后在网格中绘制一个选择的图形。

如果你想使用我修改后的版本,你可以找到ruletile.cs and ruletileeditor.cs in this gist。

请注意,使用此实现,您的规则图块将需要更多规则来描述每个图块。

【讨论】:

感谢您的回答。我检查了您的代码并且理解您的方法,但我不确定您如何询问邻居是否为空。这是如何工作的?如果您对此感到满意,我将使用您的代码,但我也想理解它。 是的,请随意使用。 :) 我也花了一段时间才明白第一次到底发生了什么。我一般理解这个类的方式是,每次刷新网格中的规则块时,它都会通过循环每个平铺规则来检查它需要什么,以返回第一个实际匹配您的规则的规则。换句话说,第一个没有违反规则的。这也意味着编辑器中平铺规则的顺序可能很重要。被编辑的brokenrule函数用于查找规则不匹配的情况。 brokenrule 函数本身会检查其 tilingruleset(编辑器 tilingrule)中的每个邻居是否有对应的邻居。如果瓦片(它是实际的邻居)违反了规则,那么它返回 true 并且规则被破坏,使函数寻找下一个瓦片。有关实际违反规则的信息,请参见 cmets。希望对您有所帮助。【参考方案2】:

我遇到了同样的问题,但我看到包代码已更新,因此我将相同的解决方案应用于包的最新版本(适用于 Unity 2019.2.0f1)。我把它放在这里以防万一有人需要它:https://github.com/Scorpin/RuleTiles-differentiating-between-another-tile-and-empty

添加代码的最相关部分

RuleTile.cs 中添加了新的邻居类型,在第 57 行(Neighbor 类):

public const int Empty = 3;

以及如何管理它(RuleMatch 的更基本的实现):

在 413 处更改为:

case TilingRule.Neighbor.NotThis: return (tile != m_Self && tile != null);

然后添加:

case TilingRule.Neighbor.Empty: return tile == null;

RuleTileEditor.cs中,在第28行添加图标:

private const string s_OtherTile = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAABNmlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjarY6xSsNQFEDPi6LiUCsEcXB4kygotupgxqQtRRCs1SHJ1qShSmkSXl7VfoSjWwcXd7/AyVFwUPwC/0Bx6uAQIYODCJ7p3MPlcsGo2HWnYZRhEGvVbjrS9Xw5+8QMUwDQCbPUbrUOAOIkjvjB5ysC4HnTrjsN/sZ8mCoNTIDtbpSFICpA/0KnGsQYMIN+qkHcAaY6addAPAClXu4vQCnI/Q0oKdfzQXwAZs/1fDDmADPIfQUwdXSpAWpJOlJnvVMtq5ZlSbubBJE8HmU6GmRyPw4TlSaqo6MukP8HwGK+2G46cq1qWXvr/DOu58vc3o8QgFh6LFpBOFTn3yqMnd/n4sZ4GQ5vYXpStN0ruNmAheuirVahvAX34y/Axk/96FpPYgAAACBjSFJNAAB6JQAAgIMAAPn/AACA6AAAUggAARVYAAA6lwAAF2/XWh+QAAAAdElEQVR42qyTOxKAIAxEWcbCK1B5/2NZcQW7ZwMNMCROTMM3S/YBAlIkjt3iJT29f8P5SUASdRgDGvdlK7m0trZ5U2BMBrQTySkYEwNA/ZSV56li6xpXltwWrGQ3g7KxE4boYrCDGa7ABXH1An+zoOh3fgcAkVNC6ZGUg/8AAAAASUVORK5CYII=";

在第 47 行添加到纹理数组(并在第 37 行将数组的项数更改为 11):

s_Arrows[10] = Base64ToTexture(s_OtherTile);

最后,将“NotThis”GUI 移动到数组中的第 10 项,因此我们可以添加“Empty”并在第 198 行为其使用第 9 号图标,如下所示:

case RuleTile.TilingRule.Neighbor.NotThis:
     GUI.DrawTexture(rect, arrows[10]);
     break;
case RuleTile.TilingRule.Neighbor.Empty:
     GUI.DrawTexture(rect, arrows[9]);
     break;

仅此而已:)

非常感谢您的解决方案 Alexander :)

【讨论】:

您能否在答案中包含该链接中的相关部分? 嗯,这里和那里都有一些小的变化,但我会尽量以最清晰的方式表达:)【参考方案3】:

2d Tilemap Extras 的贡献者包括选择性覆盖规则图块。

可以在此处找到示例:

https://docs.unity3d.com/Packages/com.unity.2d.tilemap.extras@1.6/manual/CustomRulesForRuleTile.html

尤其是 Siblings Tiles 1。

这将创建一个新的规则图块,其功能与规则图块相同,只是它还包括也在可展开列表中的规则图块。

我不想通过我的一百万个半规则图块并将所有规则从绿色箭头“This”更改为#3“Sibling”,所以我只是用它来覆盖“This”以包含“兄弟姐妹”。

public class SiblingTile : RuleTile<SiblingTile> 
    public List<TileBase> Siblings = new List<TileBase>();
    
    public override bool RuleMatch(int neighbor, TileBase tile) 
        // Direct override of rule tile's "this" check with an inclusion of those in Siblings list.
        switch (neighbor) 
            case TilingRuleOutput.Neighbor.This: 
                return tile == this || Siblings.Contains(tile);
        
        return base.RuleMatch(neighbor, tile);
    

真的很好很简单。

【讨论】:

【参考方案4】:

我使用了 Kmsxkuse 的解决方案,但我不得不对其进行一些修改,因为它不适合我。

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
using static UnityEngine.RuleTile.TilingRuleOutput;

namespace Assets.Scripts.Tiles

    [CreateAssetMenu]
    public class PathHighlightTile : IsometricRuleTile<Neighbor>
    
        public List<TileBase> Siblings = new List<TileBase>();

        public override bool RuleMatch(int neighbor, TileBase other)
        
            switch (neighbor)
            
                case Neighbor.This:
                    
                        return other == this || Siblings.Contains(other);
                    
                case Neighbor.NotThis:
                    
                        return other != this && !Siblings.Contains(other);
                    
            

            return base.RuleMatch(neighbor, other);
        
    

【讨论】:

以上是关于在 Unity (2D) 中连接具有不同纹理的规则图块的主要内容,如果未能解决你的问题,请参考以下文章

Unity_二维纹理 Texture 2D_3_按平台覆盖

Unity 2D精灵

如何在 Unity 中从 3D 对象中获取 2D 视图/纹理

Unity_二维纹理 Texture 2D_2_高级纹理

Unity Shader Graph中的Worldspace 2d纹理置换

着色器图弄乱了纹理(Unity 2D)