SortedSet.Min不包含在SortedSet中。

问题描述 投票:0回答:1

我目前正在尝试在Unity和C#中使用一个脚本进行寻路。我正在使用一个SortedSet来获取游戏地图上离目标瓷砖最近的瓷砖。在某些情况下,SortedSet会返回一个不属于集合成员的值作为最小值! 对于这样一个比较特殊的问题,很难贴出一个最小可复制的例子,所以我把使用的脚本贴在下面。

using System.Collections.Generic;
using UnityEngine;

public class Tile : MonoBehaviour
{
//--------------------PATHFINDING-------------------------

//Neighboring tiles stored in a list. Assigned by tile assignment script
public List<Tile> neighbors;

//The tile which leads to this tile when pathfinding. Found during pathfinding.
public Tile previousPathTile { get; private set; }

//The cost of moving across this tile, based on terrain type
public float traversalCost { get; set; }

//The cost of moving through this tile, including the previous tiles already
//on the path. Found during pathfinding.
public float previousTraversalCost { get; private set; }

//The estimated cost from this tile to the end tile. Found during pathfinding.
public float heuristicCost { get; private set; }

//Finds path from current tile to the destination tile
public List<Tile> pathFind( Tile endTile)
{
    //The path which is returned by this function
    List<Tile> path = new List<Tile>();

    //The tiles which have been encountered but not explored
    SortedSet<Tile> unexploredTiles = new SortedSet<Tile>(new TileSortOrder());

    //The tile which is currently being explored
    Tile currentTile;

    //Make sure that we're not adding infinity to our traversal cost from the start!
    this.previousTraversalCost = 0.0f;

    //How much the heuristic cost should guide the search algorithm. Should be set so that the maximum
    //multiplier will not force a terrain switch.
    float steeringPower = 12.0f;

    //Add the starting tile to the unexploredTiles set of tiles
    unexploredTiles.Add(this);

    //Used to break out of infinite loop on SortedSet error!
    int tmp = 0;

    //Run the pathfinding algorithm
    while (unexploredTiles.Count > 0 && tmp < 250)
    {
        ++tmp;

        //---------------- ERROR OCCURS HERE ---------------------------
        UnityEngine.Debug.Log(unexploredTiles.Min);
        currentTile = unexploredTiles.Min;
        if(!unexploredTiles.Contains(unexploredTiles.Min))
        { UnityEngine.Debug.Log("ERROR: unexploredTiles does not contain its own min! " + currentTile + " " + unexploredTiles.Min); }

        //Attempting to remove here results in an error code return by the function.
        unexploredTiles.Remove(currentTile);
        //----------------------------------------------------------------

        //If we are on the final tile
        if(GameObject.ReferenceEquals(currentTile, endTile))
        {
            //Rebuild the path from end to start, then reverse.
            while (currentTile != null)
            {
                path.Add(currentTile);
                currentTile = currentTile.previousPathTile;
            }
            path.Reverse();

            return path;
        }

        int neighborsSize = currentTile.neighbors.Count;
        for (int i = 0; i < neighborsSize; ++i)
        {
            //The tile which we are checking the pathfinding cost for
            Tile nextTile = currentTile.neighbors[i];

            //Get the distance from the next tile to the destination tile only if it hasn't been obtained already.
            if(nextTile.heuristicCost < 0.0f)
            {
                nextTile.heuristicCost = (endTile.gameObject.transform.position - nextTile.gameObject.transform.position).magnitude * steeringPower;
            }

            //Get the actual traversal cost to the next tile.
            float nextTilePreviousTraversalCostFromThisTile = currentTile.previousTraversalCost + currentTile.traversalCost;

            //If the cost from this tile to the next tile is less than the previous lowest cost
            if ( nextTilePreviousTraversalCostFromThisTile < nextTile.previousTraversalCost )
            {
                nextTile.previousPathTile = currentTile;
                nextTile.previousTraversalCost = nextTilePreviousTraversalCostFromThisTile;
                unexploredTiles.Add(nextTile);
            }
        }
    }
    return path;
}

}

这里是用来比较两个Tiles的IComparer。

public class TileSortOrder : IComparer<Tile>
{
    public int Compare(Tile firstTile, Tile secondTile)
    {
        UnityEngine.Debug.Log("Comparing: " + firstTile.gameObject.name + " and: " + secondTile.gameObject.name + (GameObject.ReferenceEquals(firstTile, secondTile) ? "They were equal." : "They were not equal.") );
        if( GameObject.ReferenceEquals(firstTile, secondTile) )
        {
            return 0;
        }
        else
        {
            float tentativeTraversalCostFirst = firstTile.previousTraversalCost + firstTile.heuristicCost;
            float tentativeTraversalCostSecond = secondTile.previousTraversalCost + secondTile.heuristicCost;
            return tentativeTraversalCostFirst < tentativeTraversalCostSecond ? -1 : 1;
        }
    }
}

这里是当SortedSet.Contains()检查失败时产生的一些示例输出。

ERROR: unexploredTiles does not contain its own min! tile1247 (Tile) tile1247 (Tile)
UnityEngine.Debug:Log(Object)
Tile:pathFind(Tile) (at Assets/Scripts/Tiles/Tile.cs:211)
InputRouting:runPathPlan() (at Assets/Scripts/InputRouting.cs:312)
InputRouting:Update() (at Assets/Scripts/InputRouting.cs:291)

如果你能提供任何帮助,我将不胜感激。我很困惑,为什么提供的SortedSet.Min值不能成为集合的成员,我不知道是不是我犯了一个愚蠢的错误。谢谢!谢谢 :-)

c# unity3d
1个回答
2
投票

sortedSet文档

不支持更改现有项目的排序值,可能会导致意外行为。

比较器使用以前的TraversalCost,这在代码中是更新的。与其更新traversalCost,不如删除节点并插入一个新节点。

© www.soinside.com 2019 - 2024. All rights reserved.