在 Unity 中渲染等距交错瓦片贴图时缺少瓦片

Missing tiles when rendering an isometric Staggered tilemap in Unity

提问人:Nick785 提问时间:9/21/2023 最后编辑:Nick785 更新时间:9/21/2023 访问量:24

问:

我正在尝试在Unity中的等距交错瓦片地图上显示图块,但缺少一些图块。我认为问题可能出在我放置瓷砖的位置或一些浮点精度问题上。

主要问题:

我从JSON文件中读取图块,并尝试将它们放在Unity Tilemap上。但是,有些瓷砖就是不显示。我已经仔细检查了我的数学,甚至尝试了一些小的调整,但我仍然缺少瓷砖。

这是我正在使用的代码:

MapLoader.cs - 负责从文件路径加载地图数据。

using System.IO;
using UnityEngine;

public static class MapLoader
{
    public static MapDataStructure.MapData LoadMapFromPath(string path)
    {
        if (!IsValidPath(path)) return null;
        return DeserializeMap(File.ReadAllText(path));
    }

    private static bool IsValidPath(string path)
    {
        if (File.Exists(path)) return true;
        Debug.LogError($"Cannot find or access map file at: {path}");
        return false;
    }

    private static MapDataStructure.MapData DeserializeMap(string jsonData)
    {
        return JsonUtility.FromJson<MapDataStructure.MapData>(jsonData);
    }
}

TilePlacer.cs - 包含用于确定要放置的图块及其世界位置的逻辑。

using UnityEngine;
using UnityEngine.Tilemaps;

public class TilePlacer
{
    private readonly Tilemap _tilemap;
    private readonly Tile[] _tileAssets;

    public TilePlacer(Tilemap tilemap, Tile[] tileAssets)
    {
        _tilemap = tilemap;
        _tileAssets = tileAssets;
    }

    public void PlaceTileAtCoordinates(int[] tileData, int x, int y, MapDataStructure.MapData mapData)
    {
        int tileIndex = GetTileIndex(tileData, x, y, mapData);

        if (IsValidTileIndex(tileIndex))
        {
            PlaceTile(tileIndex, x, y, mapData);
        }
        else
        {
            Debug.LogWarning($"Invalid tile index {tileIndex} at position {y},{x}");
        }
    }

    private int GetTileIndex(int[] tileData, int x, int y, MapDataStructure.MapData mapData)
    {
        return tileData[y * mapData.width + x] - 1;
    }

    private bool IsValidTileIndex(int tileIndex)
    {
        return tileIndex >= 0 && tileIndex < _tileAssets.Length;
    }

    private void PlaceTile(int tileIndex, int x, int y, MapDataStructure.MapData mapData)
    {
        Vector3 tileWorldPosition = ComputeTileWorldPosition(x, y, mapData);
        Vector3Int cellPosition = _tilemap.WorldToCell(tileWorldPosition);
        _tilemap.SetTile(cellPosition, _tileAssets[tileIndex]);
    }

    private Vector3 ComputeTileWorldPosition(int x, int y, MapDataStructure.MapData mapData)
    {
        float worldX = x * mapData.tileWidth;
        float worldY = y * mapData.tileHeight / 2;

        // Adjust x for odd rows
        if ((y & 1) == 1)
        {
            worldX += mapData.tileWidth / 2;
        }

        return new Vector3(worldX, worldY, 0);
    }
}

TilemapRenderer.cs - 管理将图块渲染到瓦片图的过程。

using System.IO;
using UnityEngine;
using UnityEngine.Tilemaps;

public class TilemapRenderer : MonoBehaviour
{
    [SerializeField]
    private string mapFileName = "WorldMap.json";

    [SerializeField]
    private Tile[] tileAssets;

    private Tilemap tilemap;
    private TilePlacer tilePlacer;

    private const int DEFAULT_LAYER_INDEX = 0;

    private void Start()
    {
        tilemap = GetComponent<Tilemap>();
        tilePlacer = new TilePlacer(tilemap, tileAssets);
        LoadAndRenderMap();
    }

    private void LoadAndRenderMap()
    {
        string filePath = BuildFilePath();
        MapDataStructure.MapData mapData = MapLoader.LoadMapFromPath(filePath);

        if (mapData != null)
        {
            RenderTilesFromLayer(mapData, DEFAULT_LAYER_INDEX);
        }
        else
        {
            Debug.LogError("Failed to deserialize map data from the file.");
        }
    }

    private string BuildFilePath()
    {
        return Path.Combine(Application.streamingAssetsPath, mapFileName);
    }

    private void RenderTilesFromLayer(MapDataStructure.MapData mapData, int layerIndex)
    {
        if (mapData.layers == null || layerIndex >= mapData.layers.Length)
        {
            Debug.LogError("Invalid map layer.");
            return;
        }

        int[] tileData = mapData.layers[layerIndex].data;
        for (int y = 0; y < mapData.height; y++)
        {
            for (int x = 0; x < mapData.width; x++)
            {
                tilePlacer.PlaceTileAtCoordinates(tileData, x, y, mapData);
            }
        }
    }
}

代码的重要部分:

TilePlacer.cs 中的 ComputeTileWorldPosition 函数根据给定图块的坐标 x 和 y 计算其世界位置。 计算世界位置后,函数_tilemap。WorldToCell 用于将此世界位置转换为单元格位置。

截图:

https://imgur.com/a/WVFLuF0

我尝试过什么:

如果我在放置每个图块的位置添加一个小的偏移量(如 0.1),或者如果我将网格的位置更改为 -0.5,它似乎可以修复它。但感觉我只是在修补问题,而不是真正解决它。

下面是调整后的 ComputeTileWorldPosition 函数:

private Vector3 ComputeTileWorldPosition(int x, int y, MapDataStructure.MapData mapData)
    {
        float worldX = x * mapData.tileWidth;
        float worldY = y * mapData.tileHeight / 2;

        // Adjust x for odd rows
        if ((y & 1) == 1)
        {
            worldX += mapData.tileWidth / 2;
        }

        worldX += 0.1f;
        worldY += 0.1f;

        return new Vector3(worldX, worldY, 0);
    }

以前有没有人遇到过这个问题,或者看到我可能做错了什么?任何帮助都会很棒!谢谢!

C# unity-游戏引擎 数学 等距

评论

0赞 Mike 'Pomax' Kamermans 9/21/2023
虽然与编程相关,但最好在 gamedev.stackexchange.com

答: 暂无答案