🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Pathfinding, need feedback

Started by
109 comments, last by Calin 4 years, 1 month ago

Ok, I`ll keep my code to myself.

My project`s facebook page is “DreamLand Page”

Advertisement

@Calin You can even work in a team without showing your teammates your code. Modern programming languages allow for that. Somebody from the other end of the world could write part of the code and comment it in Indian and somebody else write his part of the code and comment it in french. Modern programming languages allow for that.

But you will hardly manage to work in a team, because you lack the most basic communication skills.
Not the end of the world.
It is just that you need to go solo.

I am programming completely solo since always. I did lead two teams with success, but with the third i had bad luck, got a**h***s for teammates and failed.

I was coding in the last 4 days a piece of code completely alone. And had nobody to help me. I put in google what i needed to learn and not a single result. Completely alone on my own.

Soon, I will have to learn NNs, and will be on my own alone again. Having to learn it all ALONE. Completely ALONE! It is one thing to know how something works, and another thing to actually code it yourself. It will be hard and i will be alone.

It happens or happened to everybody. Sometimes you are on your own.

(Are you good at electronics or some other than programming thing? Maybe you are pushing in the wrong direction. You could be creative with 3D printers and make mechanized toys.)

NikiTo said:
But you will hardly manage to work in a team

I have a team though we aren`t working as a team yet.

My project`s facebook page is “DreamLand Page”

Slowest path finding algorithm i've ever seen

It`s not that slow. The load increases exponentially but for a 10 tile path length you get about three times that tile checks so 30 times iterated 30 times gives 900. In RTS games 90% of the time units have paths of under 30 tiles. A typical RTS has less than 50 moving units.

I`m not saying it`s it fast compared to other path finding algorithms I`m saying its more or less reasonable.

My project`s facebook page is “DreamLand Page”

Calin said:
It`s not that slow. The load increases exponentially but for a 10 tile path length you get about three times that tile checks so 30 times iterated 30 times gives 900. In RTS games 90% of the time units have paths of under 30 tiles.

Who says the average RTS games has a path length of 30?

But does not matter. You make a good point. Example: We have a large map of 100.000 nodes. In this case it is too slow to initialize all of the nodes to be not visited yet, have a cost of infinity, etc.

What people do in this case is to use something like a hash table to resolve indirection from node index to a smaller set of active nodes. (STL has std::unordered_map for this purpose: https://www.geeksforgeeks.org/unordered_map-in-cpp-stl/​ )
This is in practice not really related to the path finding algorithm which stays the same (talking about Dijkstra or A*). It is just a decision we make for many algorithms that face this exact same problem depending on problem size.
The downside is: It is usually hard to know how much memory we need for the active nodes. STL containers like std::vector or map etc. manage this for us under hood by allocating more memory if necessary. For non realtime application that's fine.

But for games it can be too slow. This is why game devs often implement their own containers, or overload allocation with some memory manager that pre allocates pools, etc. All of this is a lot of work, and so simple things become tedious for us realtime programmers.

However, computers became fast and its often ok to use STL with some care.
Replacing your loops with std::unordered map would be a nice exercise for you. (Assuming your algorithm allows this - otherwise it is really bad)
Or you implement your own hash tables, and later queues to make it faster again. Surely no waste of time either. Depends on what you want to learn in which order.

Just don't think your algorithm is acceptable because you can construct cases where it is fast enough. A single long path would destroy your performance. People would indeed fire you if you would show a solution like this at work.

Calin said:

I still have to code the scenario when no link can be made between start and finish.

You might also need paths from one source to multiple goals.

This should be no extra work at all.

A general path finding algorithm creates all paths (remember my image with the star shape of paths).

So, to enable all those options, the user code could call to advance one path segment, and then it checks if one goal, any goal, or all goals have been found. If the user code is happy it just stops with calling to find the next segment.
In case nothing has been found, the function to find next segment has to notify the user code, e.g. by returning -1 instead a node index, or NULL instead a pointer.

(May not work for A*, which is optimized to find just a single path)

Who says the average RTS games has a path length of 30

No one, just common sense. In games like Starcraft/Warcraft all the action takes place inside bases.

Thanks for advice and insight JoeJ.

This is how I establish the weight

TrunkListCount++;
    TrunkList[TrunkListCount].x = NodeCoord(x, z + 1, 4).x;
    TrunkList[TrunkListCount].z = NodeCoord(x, z + 1, 5).z;
    TrunkList[TrunkListCount].index = TrunkListCount;
    TrunkList[TrunkListCount].Parent = BestNode.index;
    int ParentCount = FindParentTrack(BestNode.index, Startx, Startz);
    int Distancex = TrunkList[TrunkListCount].x - Endx;
    int Distancez = TrunkList[TrunkListCount].z - Endz;
    int distance = sqrtf(Distancex * Distancex + Distancez * Distancez);

    TrunkList[TrunkListCount].weight = ParentCount + distance;

here is debug view you can read

My project`s facebook page is “DreamLand Page”

Your visualization is not very helpful. Show the path(s) to see if it's correct:

Showing all paths gives good understanding of how the algorithm is a process of growing paths in multiple directions until the goal has been found. (A* is more efficient here, but does not work on the surface of a mesh like this)

The visualization code is a good example of the interface i talked above, so my ‘grower’ is path finding class and this is the 'user code':

			PathGrower grower;
			grower.Init (source, edgeLengths, conn, true);

			for (;;)
			{
				int curVertex = grower.Next(); // find one more path segment
				if (curVertex == -1) break;
				
				vec p0 = hm.GetVertexPos(curVertex);
				RenderPoint(p0, 0,0,0);

				if (curVertex == goal) // vis path from goal and done
				{
					for (;;)
					{
						int prevVertex = grower.GetPrevPrimitive(curVertex);
						if (prevVertex == -1) break;
						
						vec p1 = hm.GetVertexPos(prevVertex);
						RenderArrow(p0, (p1-p0), 0.05f, 1,0,0);
						curVertex = prevVertex;
						p0 = p1;
					}
					break;
				}
				else // vis segment we have just added to the paths
				{
					int prevVertex = grower.GetPrevPrimitive(curVertex);
					if (prevVertex != -1)
					{
						vec p1 = hm.GetVertexPos(prevVertex);
						RenderArrow(p0, (p1-p0), 0.05f, 1,1,1);
					}
				}
			}

It is a common optimization to use two growers at both the start and goal. Then we iterate both in each step until they meet at a single vertex. This is then the midpoint of the shortest path between the two and we are done, but processed only maybe ⅓ of nodes.

This is helpful in cases where A* is no option.

@JoeJ You could remove the visualization code, so Calin can visually compare your code with his code. Replace “for(;;)” with "while(true)" which is more friendly to beginners. And “prevVertex" should be ”previewVertex" instead. Because “prevVertex” could be misunderstand as “previousVertex” in a path finding algorithm.

And finally, your deadliest sin - "if (prevVertex == -1)" should be “if (-1 == prevVertex)” instead.
(just kidding for the last one in case it is not clear)

(Shouldn't “int curVertex = grower.Next();” be “int curVertInd = grower.NextAndPush();” instead?. A method “next()” makes me think of a Timer. Maybe better “step()” or “grow()”.)

This topic is closed to new replies.

Advertisement