微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Unity Tilemaps,用于突出显示瓷砖/单元格的单瓷砖碰撞检测,奇怪的行为

如何解决Unity Tilemaps,用于突出显示瓷砖/单元格的单瓷砖碰撞检测,奇怪的行为

我已经在这个问题上工作了几天,试图创建一个方形的瓷砖网格,使用 Unity Tilemaps 似乎是最有效的方法,而且它已经内置了很多。

我想突出显示玩家周围的瓷砖,以便他看到合法的动作是什么。 为此,我在底图(地面/草地)之上使用了第二个 Tilemap。

第二个Tilemap,highlightsMap由不可见的Tiles组成,当出现Physics.SphereOverlapPhysics2D.CircleAll时会变成高亮的Tiles

为了检测每个 Tile,我在一个空对象上添加一个盒子碰撞器,并在 Tilemap 网格的顶部制作了这些碰撞器的网格,以便:

Box Collider at Position (2,4,0) 正好在 Tile at Position(2,0)

之上

这应该是最直接的处理方式,因为您可以使用 Tilemap.SetTile(Vector3Int Pos,Tile tile)

更改 Tile

然而这个问题很奇怪。碰撞器具有正确的位置值,以便能够仅通过该位置数据来引用它们正下方的图块。如上所述,我已经仔细检查了这一点,碰撞器空物与它们下方的瓷砖具有完全相同的位置,不需要转换。

问题是瓷砖没有像预期的那样在玩家周围突出显示,而是突出显示了玩家旁边的一些而其他人没有,我使用的 Physics.OverlapSphere 仅适用于 3D Colliders,这就是我添加它们的原因作为一切之上的另一个网格。

不幸的是,使用 Physics2D.CircleAll 并没有检测到瓦片本身(精灵或网格)上的任何 2D 碰撞器,不确定这是否打算像那样工作。

碰撞网格脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;

public class scr_ColliderGrid : MonoBehavIoUr
{
    public GameObject eCollider;
public Tile invisibleTile;
public Tile highlightTile;
public Tilemap highlightMap;
public int xSize,ySize;

private Vector3Int[] gridArray;                 // Tilemaps use Vector3Int BUT only use (X,Y,0)   !!!!!!!
private int xC = 0,yC = 0,i = 0;

private Tile[] tiles;

private Vector3Int prevIoUs;

private void Start()
{
    gridArray = new Vector3Int[xSize * ySize];
    tiles = new Tile[xSize * ySize];

    GenerateCollisionGrid();
}

private void GenerateCollisionGrid()
{
    for (xC = 0; xC < xSize; xC++)
    {
        for (yC = 0; yC < ySize; yC++)
        {
            Vector3Int newPos = new Vector3Int(xC,yC,0);       // 2,0
            Vector3Int newColPos = new Vector3Int(xC,0);    // 2,0     //This used to be different values,but Now they are exactly the same.
            if (invisibleTile != null)
            {
                Tile tile = Instantiate(invisibleTile,newPos,Quaternion.identity,transform);
                tiles[i] = tile;

                GameObject col = Instantiate(eCollider,newColPos,transform);
            }
            gridArray[i] = newPos;
            i++;
        }
    }

    highlightMap.SetTiles(gridArray,tiles);
    highlightMap.SetTile(new Vector3Int(2,0),highlightTile);   // 2,0  //Test to see if positions are the same. (collider and tiles)
}

玩家高亮合法移动脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;

public class scr_TankMoves : MonoBehavIoUr
{
public Tile highlightTile;
public TileBase[] highlightTiles;
public Tilemap highlightMap;
public int maxMoveTiles;
public bool highlight;

private Vector3Int prevIoUs,prevIoUsLeft,prevIoUsRight,prevIoUsForward,prevIoUsAft,prevIoUsvect;
private Vector3Int[] prevIoUsvectors;

void Start()
{

}
private void Update()
{
    if (Input.GetKeyDown(KeyCode.W))
    {
        transform.localPosition = new Vector3(transform.localPosition.x,transform.localPosition.y + 1,transform.localPosition.z );
    }
    if (Input.GetKeyDown(KeyCode.S))
    {
        transform.localPosition = new Vector3(transform.localPosition.x,transform.localPosition.y - 1,transform.localPosition.z );
    }
    if (Input.GetKeyDown(KeyCode.D))
    {
        transform.localPosition = new Vector3(transform.localPosition.x + 1,transform.localPosition.y,transform.localPosition.z);
    }
    if (Input.GetKeyDown(KeyCode.A))
    {
        transform.localPosition = new Vector3(transform.localPosition.x - 1,transform.localPosition.z);
    }
}
void LateUpdate()
{
    if (highlight)
        HighlightMoves();
    else EraseHighlights();
}
private void HighlightMoves()
{
    prevIoUsvectors = new Vector3Int[1];
    highlightMap.SetTiles(prevIoUsvectors,null);

    int tMax = 0;
    
    Collider[] legalTiles = Physics.OverlapSphere(transform.position,maxMoveTiles/2);
    prevIoUsvectors = new Vector3Int[legalTiles.Length];
    foreach (Collider col in legalTiles)
    {
        //Vector3 conversionVector = new Vector3(col.transform.localPosition.x,col.transform.localPosition.y,col.transform.localPosition.z);
        Vector3Int tileVector = Vector3Int.FloorToInt(col.transform.position);
        prevIoUsvectors[tMax] = tileVector;
        tMax++;
    }
    highlightMap.SetTiles(prevIoUsvectors,highlightTiles);
}
private void EraseHighlights()
{
    //highlightMap.SetTile(prevIoUsForward,null);
    //highlightMap.SetTile(prevIoUsAft,null);
    //highlightMap.SetTile(prevIoUs,null);
    //highlightMap.SetTile(prevIoUsRight,null);
    //highlightMap.SetTile(prevIoUsLeft,null);

    highlightMap.SetTiles(prevIoUsvectors,null);
}

private void OnDrawGizmos()
{
    Gizmos.DrawWireSphere(transform.position,maxMoveTiles/2);
    }
}


    }

如果您在 Unity 中打开一个新的 3D 项目并使用 Tilemap 设置网格,在我的代码示例中称为 highlightMap,您应该能够使用 2 个脚本准确地重新创建它。

一切都是面向 2D 的,这意味着 x+ is Right y+ is forwardz+ is up/dephth(瓷砖地图未使用)。

我拥有的空对撞机预制件是一个空的 GO,位置为 0,0。它有另一个空的 GO Child,它有 Box Collider Component,这个 child 的变换值是 0.5,0.5,0.5,所以 Collider 在每个 tile 的顶部居中。

这是在 0 次移动之后,所以只需按下 Play:

enter image description here

这是在向前移动 1 次之后,(y+1):

enter image description here

解决方法

您也可以像使用 GridLayout.WorldToCell 一样使用 Wikipedia: Binomial coefficient,例如

Tilemap yourTileMap;

// see https://docs.unity3d.com/ScriptReference/Tilemaps.Tilemap-layoutGrid.html
var grid = yourTileMap.layoutGrid;
// The "Grid" implements "GridLayout"
// see https://docs.unity3d.com/ScriptReference/Grid.html
var currentCellPos = grid.WorldToCell(transform.position);
var currentCell = yourTileMap.GetTile(currentCellPos);

然后,如果您需要获得多个瓷砖,我可能会采用“懒惰/愚蠢”的方式,然后做一些类似的事情

var currentCellPos = grid.WorldToCell(transform.position);
var currentCell = yourTileMap.GetTile(currentCellPos);

var leftCellPos = grid.WorldToCell(transform.position - transform.right * someRange);
var leftCell = yourTileMap.GetTile(leftCellPos);

var rightCellPos = grid.WorldToCell(transform.position + transform.right * someRange);
var rightCell = yourTileMap.GetTile(rightCellPos);

var frontCellPos = grid.WorldToCell(transform.position + transform.forward * someRange);
var frontCell = yourTileMap.GetTile(frontCellPos);

var backCellPos = grid.WorldToCell(transform.position - transform.forward * someRange);
var backCell = yourTileMap.GetTile(backCellPos);
,
  highlightTiles[tMax] = Instantiate(highlightTile,col.transform.parent.position,Quaternion.identity,transform);

我不知道为什么,但显然我没有将瓦片本身实例化为瓦片阵列,所以每次我将它们“放置”在网格上时,它实际上是放置一个空阵列。 现在它固定了!只需要找到一个好的方法来在移动和设置后擦除所有内容!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。