Content Pipeline Navmeshes and SharedResource

posted in Lyost's Journal
Published November 21, 2011
Advertisement
While working on a basic statemachine AI for my tank game, I found that my A* pathfinding on a navmesh wasn't working. I had already verified that the A* implementation worked in a tester program, which created the navmesh at run-time. However in the game, the content pipeline is used for loading a navmesh from an XML file. The A* implementation was using Object.ReferenceEquals to determine whether the destination region was reached, and was relying on each region's neighbor list working on the same instances of regions. As it turns out that due to having each region's neighbor list have [ContentSerializer(SharedResource = true)] attribute and parameter on the property, neighbors were not the same instances throughout the navmesh and therefore the destination detection would not work, as well as the closed list not working properly.

My navmesh is specified in an XML file enumerating the regions and their connecting edges. For the sake of this particular game, the regions of the navmesh are axis aligned boxes where connected regions must share a full edge. Because of the axis aligned boxes part, my class for storing the regions is named "Rect". I originally tried to declare its neighbor list property as:

[ContentSerializer]
public Rect[] Neighbors { get; private set; }
That produced a compiler error for a cyclic reference. This is because of when region 0 is a neighbor of region 1, region 1 is in region 0's neighbor list and vice versa. From a quick search, the normal way to deal with this is to set "SharedResource = true" parameter for the "ContentSerializer" attribute:

[ContentSerializer (SharedResource = true)]
public Rect[] Neighbors { get; private set; }
What I hadn't realized until debugging my A* implementation was that setting "SharedResource = true" made it so the region 1 instance in region 0's neighbor list was not the same instance as in the list of all regions in the navmesh. The particular test I used to determine this was:

if (Object.ReferenceEquals(m_regions[0],m_regions[1].Neighbors[0]))
{
int foo = 3;
}
if (Object.ReferenceEquals(m_regions[0],m_regions[1].Neighbors[1]))
{
int foo = 3;
}
With breakpoints set at both of the "int foo = 3;" lines, and neither breakpoint was hit. It should also probably be noted that in my navmesh for this level each region is connected only to two other regions which is why only the two if statements above where needed for this test. After debugging this, I found http://social.msdn.m...4-652207885ad8/ which (while old) confirms that setting SharedResource to true does result in different instances.

My solution for dealing with this was to store an ID number for each region and have the neighbor list that the XML importer populates be a list of those IDs. At run-time after the navmesh is loaded, each region now has a CompleteLoad function called which takes the list of all regions. This function takes care of converting the IDs to the actual instance, which allows my A* implementation to function properly.
Previous Entry Mesh's Matrix
Next Entry XNA Game Complete
0 likes 0 comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement