No longer updated: new and updated blog (including old content) at http://roy-t.nl

Archive for http://roy-t.nl, please update your bookmarks

Posts Tagged ‘XNA’

New Version A* pathfinding in 3D

Posted by Roy Triesscheijn on Tuesday 7 July, 2009

Note: since the 1st of December 2009, this blog was moved to www.roy-t.nl, all content here should be considered archived, new content, updates, comments, etc… will no longer be released here. A fresh copy of this article exists at the new website, here you can post comments and ask questions which I will try to answer asap.

Sincerely,

Roy Triesscheijn

Intro and thanks.

Ok so let’s quickly forget the debacle around the first release of this code sample, I wan’t to delete the entire post about that one but I would’nt  have know that I made an error (until much later on) if it wasn’t for some people spotting it instantly! So I would first like to thank some of my visitors who spotted the errors:

-Oscar for spotting possible performance problems.

-Ryan for suggesting possible HashSet’s (altough I didn’t use them in the end, see below why).

I would also like to thank posters from http://www.tweakers.net  who helped me get this version of A* so fast, especially (on post order):

-Phyxion & Mammon for their one line version of Equals()

-Nick The Heazk for spotting that I totally forgot the Heuristic part for scoring (doh, I swear I had it in my draft)

-pedorus &  jip_86 for suggesting to use a Binary(Min)Heap

-Marcj & NotPingu for pointing out a 3D version of Pythagoras

-Soultaker for letting me think more about efficiency of containers (O(?) of add, extract and contains))

-.oisyn & pedorus for suggesting to combine a binary heap and a HashSet (altough I didn’t use it in the end, see why below)

-PrisonerOfPain for suggesting to use binary flags instead of extra HashSet’s (that’s why I didn’t use them).

Why is this version faster?

A lot was changed from the previous version, let’s start with the openList, checking if an item is in the openList costs O(n) iterations and checking which item has the lowest score costs O(n) and removing an item costs O(log(n)). So I’ve replaced the openList with a BinaryHeap for checking the lowest score and removing/adding. These operations cost O(1), O(log(n)). That’s allot faster already.

As for checking if an item is in an openList (or closedList) all I did was add a boolean flag to the BreadCrumb class (onOpenList and onClosedList).  Checking this flagg is O(1) so that really makes checks allot faster.

Also all I needed the closedList for was checking if items where already in there, so with the boolean flag I could completely remove the closedList.

Another new feature is that we immediatly return from the FindPath function when we find the finish, this also saves some operations.

I also made sure that I don’t  create to much new objects but re-use them after they where first indexed (this was  also the cause for a small ‘score’ bug) and I’ve re-aranged some ifs.

For the algorithm itself I now use DistanceSquared for the (forgotten) Heuristic part of the scoring which is allot better than ManHattan distance which is slightly biased. I’ve also changed the cost (G) to move from the current node to the next node to incorporate these squared cost  (so instead of 1,  1.4 and 1.7 I can now use 1,2,3 for these scores. I also don’t have to multiply all these numbers by 10 since 1, 2 and 3 are integers.

A final additon is the class Point3D which allows us to use only Integers instead of floats (which are slower for a cpu).

All in all this made this code about 200x faster (yes really!). But that is not completely fair since the first code was broken. If you count from after I fixed the heuristic part of the code the code is ‘only’ about 30x faster.

Benchmark results.

And before we get to the exciting part (the code!).  Let’s first show some benchmarks.

Situation:

World: 10x10x10

Start: 0,0,0

End: 9,5,8

Nodes blocked: 300

Time:

Total (100 iterations) : 134ms

Average:  1.34ms

Lowest:   < 1ms

Highest:  17ms

Note: as you can see because we did this test 100 times there is quite allot off difference between the lowest and highest time we needed to calculate this route, that’s because sometimes the cpu stops executing this program, and starts handleing an irq or doing something else, that’s why it’s important to always take a big number of benches to be representative. We can see from the average that this code is extremely fast.

Efficiency:

A* is an extremely efficient algorithm, consider we would’ve liked to brute-force this problem instead of using A*. That would’ve cost us 10^10^10 = 1,e+100 iterations. However with an (this) A* implementation we only needed 119 iterations (in which we checked 3094 nodes).

So, on to the code!

The code.

Well since I’ve divided every thing in much neater classes it’s a bit of a problem adding showing off all these as code-listings as I usually do. So I will only show the most important method here, the rest of the classes, and an example  you can download at the bottom of this article or by clicking here

        /// <summary>
        /// Method that switfly finds the best path from start to end. Doesn't reverse outcome
        /// </summary>
        /// <returns>The end breadcrump where each .next is a step back)</returns>
        private static BreadCrumb FindPathReversed(World world, Point3D start, Point3D end)
        {
            MinHeap<BreadCrumb> openList = new MinHeap<BreadCrumb>(256);
            BreadCrumb[, ,] brWorld = new BreadCrumb[world.Right, world.Top, world.Back];
            BreadCrumb node;
            Point3D tmp;
            int cost;
            int diff;

            BreadCrumb current = new BreadCrumb(start);
            current.cost = 0;

            BreadCrumb finish = new BreadCrumb(end);
            brWorld[current.position.X, current.position.Y, current.position.Z] = current;
            openList.Add(current);

            while (openList.Count > 0)
            {
                //Find best item and switch it to the 'closedList'
                current = openList.ExtractFirst();
                current.onClosedList = true;

                //Find neighbours
                for (int i = 0; i < surrounding.Length; i++)
                {
                    tmp = current.position + surrounding[i];
                    if (world.PositionIsFree(tmp))
                    {
                        //Check if we've already examined a neighbour, if not create a new node for it.
                        if (brWorld[tmp.X, tmp.Y, tmp.Z] == null)
                        {
                            node = new BreadCrumb(tmp);
                            brWorld[tmp.X, tmp.Y, tmp.Z] = node;
                        }
                        else
                        {
                            node = brWorld[tmp.X, tmp.Y, tmp.Z];
                        }

                        //If the node is not on the 'closedList' check it's new score, keep the best
                        if (!node.onClosedList)
                        {
                            diff = 0;
                            if (current.position.X != node.position.X)
                            {
                                diff += 1;
                            }
                            if (current.position.Y != node.position.Y)
                            {
                                diff += 1;
                            }
                            if (current.position.Z != node.position.Z)
                            {
                                diff += 1;
                            }
                            cost = current.cost + diff + node.position.GetDistanceSquared(end);

                            if (cost < node.cost)
                            {
                                node.cost = cost;
                                node.next = current;
                            }

                            //If the node wasn't on the openList yet, add it
                            if (!node.onOpenList)
                            {
                                //Check to see if we're done
                                if (node.Equals(finish))
                                {
                                    node.next = current;
                                    return node;
                                }
                                node.onOpenList = true;
                                openList.Add(node);
                            }
                        }
                    }
                }
            }
            return null; //no path found
        }

(note the class also has a normal FindPath() method that switches start and end for you).

Download.

In case you missed the download link in the middle of the text, download the entire example:  here

kick it on GameDevKicks.com

Posted in General Gamedesign, XNA | Tagged: , , , , , , , , , , | 23 Comments »

Upcomming A* pathfinding in 2D and 3D code updated

Posted by Roy Triesscheijn on Monday 29 June, 2009

So allot of people have commented on my A* tutorial I posted here a while ago, but they’ve also pointed out a few flaws in the design so I’ve been working on a new version.

The new version also incorperates 2D AND 3D worlds so you can use this class for both, I’ve also optimized a bunch, made everything allot more clear replaced those dodgy ints with nice structs and fixed an unseen bug.

I hope to be able to get it online tomorrow, there’s just to much to polish atm to post it right now, but I’ll keep you guys updated!

Posted in General Gamedesign, XNA | Tagged: , , , , , , | Leave a Comment »

Implementing A* path finding in C# (and XNA): source-code (can we cut the corner?)

Posted by Roy Triesscheijn on Tuesday 24 February, 2009

Note: since the 1st of December 2009, this blog was moved to www.roy-t.nl, all content here should be considered archived, new content, updates, comments, etc… will no longer be released here. A fresh copy of this article exists at the new website, here you can post comments and ask questions which I will try to answer asap. I also wrote a new version of my A* implementation here: http://roy-t.nl/index.php/2009/07/07/new-version-a-pathfinding-in-3d/ which is greatly superior and faster than this version.

Sincerely,

Roy Triesscheijn

Update: there is a new fully 2D and 3D version of this article now available that fixes many issues some of you where having, and having a much faster and more readable codebase, get it here!

Please excuse my grammar in my last post, I was quite tired and well, let’s not talk about it anymore 🙂 .

Anyway, as I’ve said I’ve been working on an A* path finding algorithm in C# for one of my XNA projects. I’ve cleaned up the garbage and refactored the algorithm into one nice .cs file (2classes)

Today I will give a short explanation of the A* path finding algorithm and my implementation of it, specifically the extra point about cutting corners. You can download the source code at the end of this article. The source-code can be used in any C# project, and doesn’t use specific XNA classes. (All it really uses are Point’s, generic Lists and a couple of ints and bools).

Note: For more in depth information check out the following links

http://www.policyalmanac.org/games/aStarTutorial.htm

http://en.wikipedia.org/wiki/A*_search_algorithm

http://en.wikipedia.org/wiki/Dijkstra’s_algorithm (A* is an extension on Dijkstra’s algorithm. (You could view Dijkstra’s algorithm as A* where H is always 0, more about H later))

Note 2: I will use the terms square and node interchangeable in this article because in my A* implementation my nodes are square, however you can use A* for any kind of shapes for the node, and my code is easily adjustable to accommodate that.

A* generally works the following way  (source: Patrick Lester from policyalmanac.org )

1) Add the starting square (or node) to the open list.

2) Repeat the following:

a) Look for the lowest F cost square on the open list. We refer to this as the current square.

b) Switch it to the closed list.

c) For each of the 8 squares adjacent to this current square …

– If it is not walkable or if it is on the closed list, ignore it. Otherwise do the following.

– If it isn’t on the open list, add it to the open list. Make the current square the parent of this square. Record the F, G, and H costs of the square.

– If it is on the open list already, check to see if this path to that square is better, using G cost as the measure. A lower G cost means that this is a better path. If so, change the parent of the square to the current square, and recalculate the G and F scores of the square. If you are keeping your open list sorted by F score, you may need to resort the list to account for the change.

d) Stop when you:

Add the target square to the closed list, in which case the path has been found (see note below), or

Fail to find the target square, and the open list is empty. In this case, there is no path.

3) Save the path. Working backwards from the target square, go from each square to its parent square until you reach the starting square. That is your path.

The costs F which is  G+H might not be evident at first. But is calculated the following way:

G is the movement cost from the start point to that square, and H is the estimated cost from there to the end square.

G is calculated as  TargetSquare.G =  parent.G + 10  or + 14 if the square is diagonal from the parent. (That’s because the square root of 2 is 1.4 and we try to keep the numbers integers here)

H is calculated (in my implementation) as the Manhattan distance from the target to the end.  Which is something like (Math.Abs(G.x – H.x) + Math.Abs(G.y – H.y) ) * 10.

The algorithm keeps checking of squares that are on the open list can be reached cheaper from the current square.

Corner Cutting.

Now about the corner cutting: my implementation adds one new situation before the first point of 2.C.

-If the node is diagonal from the current node check if we can cut the corners of the 2 others nodes we will cross. If so this square is walkable, else it isn’t.

A picture might explain better why this is important:

Art

square A is our current square and we are considering if we can walk 2 square B. Square B’s walkable attribute is set to true, so we might think that we can continue to (now point 2) in c, adding it to the open list etc… However if the object that is going to walk the path is going to get to B, a part of it will be at with red indicated areas of squares C and D.  Imagine square D represents a house, that exactly fills the square, this way our object is going to traverse trough a house! However if squares C and D represents a well, centred in a square filled with grass, we can easily cut the corner to get to B.

The rest of my algorithm isn’t any different than general A*. The code is well commented and all the pitfalls are avoided as much as possible. However why the code works might not be evident if you haven’t studied A* first. I suggest you check the link to policyalmanac.org at the top of this article for a very detailed explanation of A*

Speed.

A* is a very fast algorithm, I’ve tested it on a grid with 64 nodes and the general search time was under 1ms.

Download.

You can download the source code via this link: (My Skydrive)

Don’t be afraid to post your optimizations, notes, questions or other comments here!

kick it on GameDevKicks.com

Posted in General Gamedesign, XNA | Tagged: , , , , , , , , , , , | 32 Comments »

Implementing A* into XNA

Posted by Roy Triesscheijn on Sunday 22 February, 2009

Edit: the full article + source-code is now available here.

Most of the day I’ve been toying around with the implementation details of A*.  A* is both easy and hard at the same time, small errors in the function that calculates the cost of each node can really break the algorithm (and especially an ‘<’ instead of an ‘>’ and a faulty initialisation can break it, of which I’m, after a good old debugger session, am now painfully aware.

I’m not ready to post my code yet (it still has a nasty quirk, diagonal tiles are somehow very rarely considered even if you try to go from 0,0 to 5,5 without obstacles where a diagonal path (1,1  2,2 3,3 4,4) would be the fastest.  I think I’ve found the piece of code where it goes wrong though)  But I’ll soon do once I eliminated all the bugs and optimized/refactored the code.

Meanwhile have a look at http://www.policyalmanac.org/games/aStarTutorial.htm it’s a very good beginners tutorial (not tailored to any language) be sure to read it front-to-end before implementing it .

Posted in Blog, General Gamedesign | Tagged: , , , , | Leave a Comment »

Update

Posted by Roy Triesscheijn on Monday 9 February, 2009

Well, as you’ve all noticed, it’s been a while since I’ve posted here!

I’m currently not to busy with XNA or any other programming work for that matter. I’m trying to focus on my study (Computer Science at the RuG, Groningen, the Netherlandes). Unfortunately all the courses I’m getting at the moment is programming correctness (utilizing logic and math to prove code is correct) and abstract math, needles to say I’m not coding anything worth posting about. And I’ve yet got to see the first XNA game that used programming correctness (PCOR) to verify that there are no bugs! (Ha that would be a first!).

I am toying around with PHP though, I know you are going to ask why, and yes I know it’s ugly but still it’s quite a learning experience programming in a loose-typed language. I’m also intrigued by all the markup (CSS) and database (MySQL) integration that I’m currently utilizing in PHP.

My small project is trying to create the most simplest CMS possible:

-User creation and logging in.

-Posting new items

-Commenting on items.

(Might hack a forum togheter from these components just for fun).

I’m trying to broaden my not-so-broad perspective of programming languages, the only real languages I’ve been working with for more than a few hours are (in chronological order):  Visual Basic 6, C#, Java, VHDL (made my cry), 68Kasm (I hated that!),  and now PHP. I hope i can add C++ and Delphi to that in the near future (and maybe even Haskell or F#).

Oh well, I’ll make sure to post and release the source-code of my crazy-cms,  it might contain something usefull for people starting with PHP. 🙂

I hope It won’t take me this long again to post another item, I want to update you guys on a small project I might be working on in the near future that could be off help to programming/game enthusaist near Groningen. I’ll keep you guys posted!

Posted in Blog | Tagged: , , , | 1 Comment »

Youtube

Posted by Roy Triesscheijn on Tuesday 25 November, 2008

I today uploaded my first youtube video *yay*.

Was just trying to test some stuf, and some dudes at the #XNA channel would like to see it. It took me almost an hour to get all the proper tools and codecs to make a normal size video (the original was 500MB of RAW avi)

However here it is, nothing fancy but it’s just a show of of the driving mechanics for my little racing game.

edit: oops didn’t know there was a wordpress shortcode to embed youtube video’s

Posted in XNA | Tagged: , | Leave a Comment »

Creating Animated Textured Models for XNA – Part2: trueSpace Online at Ziggyware

Posted by Roy Triesscheijn on Tuesday 11 November, 2008

Ah,

Ziggy was a swift beast this time, you can view my most recent article at

Ziggyware (direct link)

In this article it’s trueSpace’s turn to show what an excellent modelling tool it is. All relevant parts for building and exporting a basic UV-textured model will be covered, including sample source code and the finished trueSpace project. This tutorial will help give your game a bit of body right from the start. By Roy Triesscheijn

Posted in XNA | Tagged: , , , , , | Leave a Comment »

Creating Animated Textured Models for XNA part 2: that was fast!

Posted by Roy Triesscheijn on Monday 10 November, 2008

Well only half a day ago I posted a progress report for this part of the modelling for XNA tutorial series. And well here I am again! I’ve finished the entire article and found out even more about UV-texture-editing in trueSpace. Damn that UV-Editor has some powerfull tools!

I hope Michael from Ziggyware.com will be able to put part 2 online fast. As the Blender article it is a long one. (15pages in word, and over 30 images explaining what to do and where to find the buttons and toolbars 😉 ).

I’m sure you’ll all like it!

I’ll write a new post as soon as Michael puts it up!

Posted in XNA | Tagged: , , , , , | Leave a Comment »

Creating Animated Textured Models for XNA part 2 : progress report

Posted by Roy Triesscheijn on Monday 10 November, 2008

So,

Haven’t been hearing much from me on part 2, I know I promissed to get it done soon, (hell I said to finish it two weeks ago). But I’ve been haveing some problems with trueSpace. In the end it wouldn’t even start and crashed instantly at the splash screen.

So after some agony I’ve reinstalled trueSpace7.6 and gave it another go. It’s to bad that some of the more advanced features of trueSpace are poorly documented. (I still havent found the mark seam button that the manual speaks off).

Also some tools are not available in the standard Workspace view so I have to switch to the ‘older’ model view to get it done.

However I’ve finally been able to recreate a nice textured cube with good texture coords and been able to get a good uv-map for combined meshes.

I’ll hope to finish up on the tutorial in two days and have it submitted to ZiggyWare so Ziggy– can put it online.

Posted in XNA | Tagged: , , | Leave a Comment »

Standard 1x1x1 textured fbx cube for testing in XNA

Posted by Roy Triesscheijn on Wednesday 29 October, 2008

I often hear people asking for a standard cube or model to test in XNA, well here it is. You can download the fbx model and tga texture from the rapidshare link. It’s a standard cube with dimensions 1x1x1 made in Blender, it is UV-textured, and exported using the modified .fbx export script for XNA, it works perfectly in my code and imports without errors so it should be alright.

rapidshare link

Btw if it’s not online anymore, leave a message here or try downloading it directly from the apache server running at my computer ( here ) (that link only works if my computer is on).

Posted in XNA | Tagged: , , , , | 4 Comments »