GetNearest with TraversalProvider?

I want to make AstarPath.active.GetNearest( transform.position, NNConstraint.None ) to use

ABPath path = ABPath.Construct( from, to ); if( traversalProvider != null ) { path.traversalProvider = traversalProvider; } AstarPath.StartPath( path );

as I am trying to use the grid/hex graph to find the closest available node.

I tried something of the sort but doesn’t work:

In BlockManager:

public bool IsNodeBlocked( GraphNode node )
		{
			return m_BlockedDictionary.ContainsKey( node ) && m_BlockedDictionary[ node ].Count > 0;
		}

public class BlockedConstraint : NNConstraint
	{
		public override bool Suitable( GraphNode node )
		{
			return base.Suitable( node ) && !BlockManager.Instance.IsNodeBlocked( node );
		}

		/// <summary>Returns a constraint which does not filter the results</summary>
		public static NNConstraint Blocked
		{
			get
			{
				return new BlockedConstraint();
			}
		}
	}
			GraphNode node = AstarPath.active.GetNearest( transform.position, BlockedConstraint.Blocked ).node;

Hi

Your code should work. That’s exactly how I’d implement it. Assuming your blocked dictionary is filled out correctly.

1 Like

hmm I instantiate all characters in runtime at the same time, could there be a race condition between the pathfinding searching and the check?

The path search doesn’t modify the traversal provider, so I don’t think so.

My code does right after the search this way:

        public void Init( List<GridElement> friends = null )
		{
			GraphNode node = AstarPath.active.GetNearest( transform.position, BlockedConstraint.Blocked ).node;
			transform.position = ( Vector3 )node.position;


			// Set the traversal provider to block all nodes that are blocked by a SingleNodeBlocker
			// except the SingleNodeBlocker owned by this AI (we don't want to be blocked by ourself)
			m_TraversalProvider = new BlockManager.TraversalProvider( BlockManager.BlockMode.AllExceptSelector, friends );


			Block( node );
		}

I guess GetNearest is instant, not multithreaded so it shouldn’t have a race condition

I tried this and it’s positioning some of them ontop of eachother.

            if( Input.GetKeyDown( KeyCode.Alpha1 ) )
			{
				for( int i = 0; i < 100; i++ )
				{
					GridElement element = GameObject.CreatePrimitive( PrimitiveType.Cube ).GetOrAddComponent<GridElement>();
					element.GetComponent<Renderer>().material.color = Color.red;
					element.transform.position = new Vector3().Random( -15, 15 );
					element.transform.position = new Vector3( element.transform.position.x, 0, element.transform.position.z );
					element.Init();
				}
			}

EDIT1: OK I think this is the cause:

        public void InternalBlock( GraphNode node, GridElement blocker )
		{
			AstarPath.active.AddWorkItem( new AstarWorkItem( () =>
			{
				List<GridElement> blockersInNode;
				if( !m_BlockedDictionary.TryGetValue( node, out blockersInNode ) )
				{
					blockersInNode = m_BlockedDictionary[ node ] = ListPool<GridElement>.Claim();
				}

				blockersInNode.Add( blocker );
			} ) );
		}

EDIT2: I tried not to flood the channel :frowning:

Ah. Yeah that will be it.

You can force the work item to complete immediately by using AstarPath.active.FlushWorkItems().

1 Like

I removed the threading process, isn’t it just a dictionary process? I haven’t read what ListPool.Claim(); does which was my only worry removing this

What do you mean by this?

        public void InternalBlock( GraphNode node, GridElement blocker )
		{
			//AstarPath.active.AddWorkItem( new AstarWorkItem( () =>
			{
				List<GridElement> blockersInNode;
				if( !m_BlockedDictionary.TryGetValue( node, out blockersInNode ) )
				{
					blockersInNode = m_BlockedDictionary[ node ] = ListPool<GridElement>.Claim();
				}

				blockersInNode.Add( blocker );
			} //) );
		}

sorry my english drifted as I was writting this sentence :smiley: I meant that I removed the threading process as I thought it’s ok to not have this multithreaded as removing an element from a dictionary isnt that slow, is it?