Support Forum

Dynamic Grid Obstacle question

I’d like to have a two types of seekers, and two types of dynamic grid obstacles. Seeker A will only avoid Obstacle A. Seeker B will only avoid Obstacle B. The player will change the locations of Obstacle A and Obstacle B very frequently.

Is it possible to achieve this affect? If so, how would I do it?

When using a grid graph, is it possible to designate certain regions as unwalkable only to Seeker A, and other nodes as unwalkable only to Seeker B?

If I was to produce two grid graphs - one that only acknowledges Obstacle A, and one that only acknowledges Obstacle B - how would I tell Seeker A to only look at Graph A, and tell Seeker B to only look at Graph B?

It appears that a “Graph Update Scene” object can generate restricted areas that Seekers will not traverse. However, is this capable of dynamically changing at runtime? Is there a more simple solution than using the Graph Update Scene object?

Hi

Yes this is possible using tags: http://arongranberg.com/astar/docs/tags.php
If you are using the DynamicGridObstacle script you should be able to open it up and edit it to modify the tag instead of the walkability.
Something like
guo.updatePhysics = false; guo.modifyTag = true; guo.setTag = someTag;

There is an example scene called “Penalties” which contains a demo using tags.

I see! I had contemplated trying to edit the script myself, but I generally try to avoid modifying plugin scripts if I know that the developer of the plugin is routinely updating the plugin.

It would be fantastic if a future version of the plug-in supported the ability for the user to toggle between “tag” and “walkability” in the DynamicGridObstacle script. Until then, I guess I could try modifying the script myself. I hope I don’t break anything!

Yes, that is usually a good thing. But you could always just make a copy of the script.
That script is not in the core of the project so nothing else depends on it.

I seem to have hit a roadblock. I’ve modified the “DoUpdateGraphs” function of the DynamicGridObstacle script so that it defines a certain area with a specified tag. However, when I move the obstacle and the “DoUpdateGraphs” function fires again, it doesn’t define the previous area as walkable. Moving the obstacle around creates new unwalkable areas, but doesn’t restore the old areas to being walkable again.

I don’t want to harass you with amateurish questions, so I spent a good deal of time trying to solve it myself, but I just couldn’t figure it out, so now I’ve got to ask you for help again. What steps must I follow in order to restore the previous area to its original tag and make it walkable again?

Hi

That is a bit tricky.
Well, it is pretty simple for most cases.
First you need to issue a graph update request to clear the tag (set tag to 0) on the previous position of the obstacle, then after that you will need to issue a new graph update request to set the tag at the new position.

The only downside is that this can cause small issues if obstacles are almost overlapping (and large issues if they are actually overlapping, since one obstacle will completely override the other).

Okay, I’ve made some progress. Using the following code, I have obstacles that use the bounds of their colliders to define certain areas of the grid with a specific tag. When the object is dragged and dropped, I call DoUpdateGraphs().

`using UnityEngine;
using System.Collections;
using Pathfinding;

public class DynamicGridObstacleTag : MonoBehaviour
{
	Bounds currentBounds;
	Bounds prevBounds;

	Collider col;

	public int tag = 0; //Defined in editor

	void Start ()
	{
		col = collider;
		prevBounds = col.bounds;
		currentBounds = col.bounds;
	}

	public void DoUpdateGraphs ()
	{
		GraphUpdateObject prevGuo = new GraphUpdateObject (prevBounds);

		prevGuo.updatePhysics = false;
		prevGuo.modifyTag = true;
		prevGuo.setTag = 0;

		AstarPath.active.UpdateGraphs (prevGuo);

		currentBounds = col.bounds;

		GraphUpdateObject currentGuo = new GraphUpdateObject (currentBounds);
		
		currentGuo.updatePhysics = false;
		currentGuo.modifyTag = true;
		currentGuo.setTag = tag;

		AstarPath.active.UpdateGraphs (currentGuo);

		prevBounds = currentBounds;
	}
}`

However, there is a problem. As you stated, if an obstacle overlaps another obstacle, then its area is over-written and tagged with the improper tag. In my app, it’s absolutely essential to have obstacles overlapping, so I need a solution for this problem.

Obstacle A should only block Seeker A, and Obstacle B should only block Seeker B. If Obstacle A and Obstacle B are overlapping, the overlapping area should be walkable by neither Seeker A nor Seeker B.

What would be the best solution, to make only the overlapping area walkable by neither Seeker?

I still haven’t been able to devise a solution to the problem. Could it ever be possible to have two obstacles create overlapping zones that are recognized as walkable / unwalkable by different Seekers? Or is that a function that this plugin cannot support?

Hi

The only possibility to do that is to create a custom GraphUpdateObject.

public MyGUO : GraphUpdateObject { /** True if adding the tag, false if removing the tag */ public bool add = true; public override void Apply ( GraphNode node ) { if ( add ) { node.Tag |= 1U << setTag; } else { node.Tag &= ~(1U << setTag); } } }

Then you would treat the tags as a bitmask (see http://en.wikipedia.org/wiki/Mask_(computing) ).

The limitation is that you can only have 32 tags.

I added your code to astarclasses.cs, and now scripts that have “using Pathfinding” can acknowledge “MyGUO”. That was the correct thing to do, right? However, I’m having trouble figuring out the exact way to use MyGUO.

In the script I posted above, I have this line of code:

`GraphUpdateObject prevGuo = new GraphUpdateObject (prevBounds);`

Simply replacing “GraphUpdateObject” with “MyGUO” isn’t going to work, since MyGUO doesn’t take a ‘Bounds’ argument. I hate to ask you to spoonfeed me, but where is MyGUO supposed to be utilized?

I also have a question about an alternate solution to this problem. If there are two obstacles in the game, Obstacle A and Obstacle B, and both of them are overlapping with one another, can the overlapping area be designated with a specific tag?

For example, when Obstacle A runs this code:

AstarPath.active.UpdateGraphs (currentGuo);

Can UpdateGraphs check to see if the bounds of currentGuo contain nodes that are tagged as “Obstacle B”? If so, perhaps UpdateGraphs could re-tag those nodes as “Obstacle C”, to designate it as a zone where Obstacle A and Obstacle B are overlapping.

I hate to keep asking for help like this, but I really appreciate all of your help and patience so far.

Hi

Right, I forgot the constructor.

Add this code to the class, that will make it inherit the constructor.
public MyGUO ( Bounds bounds ) : base (bounds) {}

Also… I remembered one thing, I forgot that the tag is no longer stored as a separate field, but it is stored in a bitpacked value. So it will only have support for up to 5 obstacles. Is this a problem for your game?

Well, since it’s a bitmask, what you will end up with is something like this.

The tag per default is
00000
if written in base 2 (i.e showing all bits)

After adding tag 0, you will have
00001

After adding tag 3 to the same node, you will have
01001

After adding tag 2 to the same node, you will have
01011

After removing tag 0 from the same node, you will have
01010

So each bit will specify if a particular obstacle is occupying that node.
Since each of these bit-patterns will be treated as a separate tag (e.g 01010 = tag 10), you can configure each of these patterns individually with penalties and things like that.

Wow! That was a perfect solution. It worked like a charm. I’m so glad there was an easy way to solve the problem!

The game is feature-complete, and designed specifically around the idea of two types of obstacles, so the limit of 5 obstacles won’t present a problem.

Once again, thank you so much for your patience and assistance!

Hello, I apologize for grave digging an old topic, but my question is closely related to previous discussion.

I am trying to solve a completely same problem, but realized that now with burst compiler and jobs, overriding the Apply method is not enough. I realized I should override ApplyJob, but how can I get the current node tag value to perform bitmask operation as the real execution is happening in JobGraphUpdate.Execute() and it can’t be override (which is impossible to modify when using package manager)?

I am using GridGraph, 2D with 2D physics on XY plane, plugin version 4.3.51

So, what is the right way to put multiple tags on a single node these days? Or is there now a better way to create obstacles just for specific agents?