【发布时间】:2021-05-27 12:17:39
【问题描述】:
我已经在这个问题上工作了几天,尝试创建一个方形网格,使用 Unity Tilemaps 似乎是最有效的方法,并且已经内置了很多。
我想突出显示玩家周围的图块,以便他看到合法的动作是什么。 为此,我在底图(地面/草)之上使用了第二个 Tilemap。
第二个Tilemap,highlightsMap由不可见的Tiles组成,当Physics.SphereOverlap或Physics2D.CircleAll出现时会变成高亮的Tiles
为了检测每个 Tile,我在一个空对象上添加了一个盒子碰撞器,并在 Tilemap 网格的顶部制作了一个由这些碰撞器组成的网格,这样:
Box Collider at Position (2,4,0) 正好在Tile at Position(2,4,0) 之上
这应该是最直接的处理方式,因为您可以使用Tilemap.SetTile(Vector3Int Pos, Tile tile)更改磁贴
然而问题很奇怪。碰撞器具有正确的位置值,以便能够通过该位置数据准确地引用它们下方的图块。如上所述,我已经仔细检查过,对撞机空的位置与其下方的瓷砖完全相同,不需要转换。
问题是瓷砖没有像预期的那样在玩家周围突出显示,而是玩家旁边的一些被突出显示而其他人没有,我使用的 Physics.OverlapSphere 仅适用于 3D 碰撞器,这就是我添加它们的原因作为一切之上的另一个网格。
不幸的是,使用 Physics2D.CircleAll 并没有检测到图块本身(Sprite 或 Grid)上的任何 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, 4, 0
Vector3Int newColPos = new Vector3Int(xC, yC, 0); // 2, 4, 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, Quaternion.identity, transform);
}
gridArray[i] = newPos;
i++;
}
}
highlightMap.SetTiles(gridArray, tiles);
highlightMap.SetTile(new Vector3Int(2,4,0), highlightTile); // 2,4,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.y,
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 forward 和 z+ is up/dephth(瓷砖地图未使用)。
我拥有的空 Collider 预制件是一个空的 GO,位置为 0,0,0。它还有一个空的GO Child,里面有Box Collider Component,这个child的transform值是0.5,0.5,0.5,这样Collider就在每个tile的顶部居中。
【问题讨论】:
-
小心:Afaik
Tilemap.SetTile(Vector3Int Pos, Tile tile)参数Pos指的是 grid 位置 .. 这可能与实际的 world Vector3 位置不同(transform.position) 对撞机...你检查它们是否真的在正确的地方? -
是的,请确保您使用一个物理引擎;) Physics 和 Physics2D 是两个完全独立的引擎,并且没有任何关联!如果你使用 Physics.OverlapSphere 你将需要 3D
Colliders ..如果你想要Physics2D.OverlapCircle你将需要 2DCollider2Ds (在 2D 中 Z 轴基本上不存在)......你的截图看起来像你宁愿在 3D 中工作 -
是的,100% 它们在正确的位置,当我在 pos (2,4,0) 突出显示 Tile 然后遍历层次结构中的 emptyCollider 数组时,emptyCollider 在位置 ( 2,4,0) 正好在突出显示的 Tile(2,4,0) 之上,所以它应该是这样,但我认为添加这些 3d 对撞机是一团糟,是否没有内置的方法来检查附近的瓷砖?我只是获取玩家所在的 Tile 并从中添加/减去以突出显示该中心周围的 Tiles,但这也是一团糟并且不允许可扩展性,这就是我想使用 Sphere/Circle 的原因。跨度>
标签: c# unity3d grid collision tile