转自:http://www.codeguru.com/csharp/csharp/cs_misc/designtechniques/article.php/c12527/

A-Star (A*) Implementation in C# (Path Finding, PathFinder)

Introduction

Some time ago, I had to make a project where I need to find the shorted path inside a matrix and I though "nothing better than use path finding for this."

There is lots of links and explanation about Path Finding, but Ididn't find a version written in C# that could meet my expectatations. So, I decided to make the A-star implementation in C#. This code was really useful for me and I bet it can be useful for many people too.

I won't explain the algorithm implementation too much, because just typing "pathfinding algorithm a-star" in Google brings 25,000 documents where you can find every single detail about it.

About the Application

A* is a generic algorithm and there are no perfect parameters to be set. The algorithm has many things that can be set, so the best way to know the best parameters that will fit in your project is to test the different combinations.

Note: Usually, a good A* implementation does not use a standard ArrayList or List for the open nodes. If a standard List is used, the algorithm will spend a huge amount of time searching for nodes in that list; instead, a priority queue should be used.

I borrow code from BenDi (http://www.codeproject.com/csharp/PriorityQueue.asp) for the priority queue implementation. I changed it a little bit and I changed the implementation to use generics instead ArrayList to make it run faster than before.

[PathFinder.png]

This project is really useful for two reasons:

  1. I followed the A* implementation and I tried to implement it to run with good performance, so the algorithm itself can be easily reused in any project.
  2. The front end gives a full chance to experiment with many variables where you can really watch and learn how it works. You also can change the heuristic, formula, or options to analyze the best setting for your project.

The call in the source code that does the entire job is the following:

public List<PathFinderNode> FindPath(Point start, Point end,byte[,] grid);

This method takes as parameters a start, end point, and the grid; it will return the path as a list of nodes with the coordinates. I made this call on a separate thread; this gives the chance to keep control of the application when PathFinder is working.

Algorithm Settings

Speed

This is the rendering speed. Reducing the speed changes the look of how the algorithm opens and closes the nodes in real time.

Diagonals

This hint will tell the algorithm whether it is allowed to process diagonals as a valid path. If this checkbox is not set, the algorithm will process just four directions instead of eight.

Heavy Diagonals

If this check box is set, the cost of the diagonals will be bigger. That will make the algorithm avoid using diagonals.

Punish Change Direction

If this check box is set, every time the algorithm changes direction it will have a bigger cost. The end result is that, if the path is found, it will be a smoother path without too many changes in directions and look more natural. The con is that it will take more time because it searches for extra nodes.

Heuristic

This is a constant that will affect the estimated distance from the current position to the goal destination. A heuristic function creates this estimate of how long it will take to reach the goal state because the better the estimate, the better a short path will be found.

Formula

This is the equation used to calculate the heuristic. Different formulas give different results. Some will be faster and others slower. The end may vary, and the formula to be used depends strongly on what the A-star algorithm will be used for.

Use Tie Breaker

Sometimes when A* is finding the path, it will find many possible choices with the same cost and basically all of them could reach the destination. A tie breaker setting is a hint to tell the algorithm that when it has multiple choices to research, instead keeping going, to change those costs a little bit and apply a second formula to determinate what could be the best "guess" to follow. Usually, this formula increments the heuristic from the current position to the goal by multipling by a constant factor.

Heuristic = Heuristic + Abs(CurrentX * GoalY - GoalX * CurrentY)* 0.001

Search Limit

This is the limit of closed nodes to be researched before returning a "Path not found." This is a useful parameter because sometimes the grid can be too big and you need to know a path only if the goal is near from the current position or it can't spend too much time calculating the path.

Grid Size

This parameter just affects the front end. It will change the grid size; reducing the grid size gives a chance to create a bigger test, but it will take longer to render.

Fast PathFinder

When unchecked, the implementation used is the algorithm as it usually appears in the books. When checked, it will use my own PathFinder implementation. It requires more memory. but it is about 300 to 1500 times faster or more, depending on the map complexity (See PathFinder Optimization below).

Show Progress

This allows seeing how the algorithm works in real time. If this box is checked, the completed time will be the calculation plus rendering time.

Completed Time

This is the time that the algorithm took to calculate the path. To know the real value, uncheck 'Show Progress'.

Path Finder Optimization

After I implemented the original algorithm, I got frustrated because of the amount of time it took to resolve paths, especially for bigger grids and also when there was no solution to the path. Basically. I noticed that the open and closing lists were killing the algorithm. The first optimization was to replace the open list by a sorted list and the close list by a hashtable. This made a good improvement in the calculation time, but still was not what I expected. Later, I replaced the open list from a sorted list to a priority queue; it made a change, but still was not a big difference.

The big problem was that when the grid was big (1000x1000), the number of open and close nodes in the list was huge and searching in those lists a took long time, whatever method I used. At first, I thought to use classes to keep the nodes' information, but that was going to make the garbage collection crazy between the nodes' memory allocation and releasing the memory for the nodes that were disposed. Instead of classes, I used structs and re-use them in the code. I got more improvements, but still nothing close to what StarCraft does to handle eight hundred units in real time.

My current application is like a Viso application where I need to find a path between objects. The objects are not moving, so I didn't need really a super-fast algorithm, but I needed something that can react in less than one second.

I needed to find a way to get nodes from the open list in O(1) or closer to that. I though the only way to get that was not having an open list at all. There is when I thought to use a calculation grid to store the nodes. If I knew the (X/Y) location, I could reach the node immediately O(1).

Because of this, I could get rid of the close list. I could mark a closed node directly in the calculation grid. Every node has a link to the parent node, so I did not need a close list at all. However, I could not get rid of the open list because I needed to keep getting the nodes with less total cost (F), and the second grid didn't help with that.

This time I kept using the open list (priority queue), but it was just to push and get the node with lowest cost. Priority queues are excellent to do that; they require no linear access at all.

The only cons are that the memory consumption was huge to keep a second grid, because every cell stores a node, and every node was 32 bytes long. Basically, for a map (1000x1000), I needed 32 Mb of RAM. Now I was accessing the second grid by coordinates (X/Y), so I didn't need those values in the node anymore. That reduced eight bytes, multiplied by 1,000,000. I saved 8 Mb of RAM.

Every node has a link to the parent nodes and those were int (32 bits). Because the grid can never be too big, I replaced them for ushort (16 bits). That saved another 2 bytes by node; that meant another 2 Mb of savings.

Also, I realize that the heuristic (H) is calculated for every node on the fly and it is not used any more for the algorithm, so I removed it from the node structure too. Heuristic was a int (4 bytes), so I saved another 4 Mb. Finally, I got a minimum node that took 13 bytes but, because of memory alignment, they took 16 bytes at run-time. I had to set the struct to use memory alignment for every byte.

[StructLayout(LayoutKind.Sequential, Pack=1)]

About the Author

started with programming about 19 years ago as a teenager, from my old Commodore moving to PC/Server environment Windows/UNIX SQLServer/Oracle doing gwBasic, QBasic, Turbo Pascal, Assembler, Turbo C, BC, Clipper, Fox, SQL, C/C++, Pro*C, VB3/5/6, Java, and today loving C#. Currently working on VOIP/SIP technology. Passion for most programming languages and my son Aidan.
参考文章
http://www.cnblogs.com/alamiye010/archive/2009/06/17/1505339.html

游戏开发基础:A*算法(转)相关推荐

  1. 手把手教你架构3d游戏引擎pdf_游戏开发中的算法

    游戏技术这条路,可深可浅.你可以满足于完成GamePlay玩法层面的东西,你也可以满足于架构和框架设计层面的东西,你也可以醉心于了解某一游戏引擎带来的掌控感.但是,我们不该止步于此,止步与目前所见或所 ...

  2. 斗牛怎么玩法算法_游戏开发中的算法

    游戏技术这条路,可深可浅.你可以满足于完成GamePlay玩法层面的东西,你也可以满足于架构和框架设计层面的东西,你也可以醉心于了解某一游戏引擎带来的掌控感.但是,我们不该止步于此,止步与目前所见或所 ...

  3. 虚幻引擎C++编程游戏开发基础

    流派:电子学习| MP4 |视频:h264,1280×720 |音频:AAC,44.1 KHz 语言:英语+中英文字幕(根据原英文字幕机译更准确)|大小解压后:23.8 GB |时长:44h 59m ...

  4. Android游戏开发基础part2--Canvas画布

    游戏开发基础part2--Canvas画布 又过了一周才继续做总结,四级结束了,应该可以多点时间学习游戏编程了. Canvas画布类是一个在游戏当中担当非常重要的角色,它可以绘制出不同的图形和图片,可 ...

  5. 【读书笔记《Android游戏编程之从零开始》】16.游戏开发基础(动画)

    1. Animation动画 在Android 中,系统提供了动画类 Animation ,其中又分为四种动画效果: ● AlphaAnimation:透明度渐变动画 ● ScaleAnimation ...

  6. os-cocos2d游戏开发基础-进度条-开发笔记

     os-cocos2d游戏开发基础-进度条-开发笔记(十)   ios-cocos2d游戏开发基础-游戏音效-开发笔记(九)       ios-cocos2d游戏开发基础-CCLayer和Touch ...

  7. Unity2D游戏开发基础教程1.2项目、资源和场景

    Unity2D游戏开发基础教程1.2项目.资源和场景 如果使用Unity制作游戏,就一定会接触到项目(Project.资源(Asset)和场景(Scene).本节将依次介绍它们. 1.2.1  项目 ...

  8. Unity2D游戏开发基础教程1.2 项目、资源和场景

    Unity2D游戏开发基础教程1.2 项目.资源和场景 如果使用Unity制作游戏,就一定会接触到项目(Project.资源(Asset)和场景(Scene).本节将依次介绍它们. 1.2.1  项目 ...

  9. Unity4.x 2D游戏开发基础教程第1章Unity及其组成的介绍

    Unity4.x 2D游戏开发基础教程第1章Unity及其组成的介绍 本书主要讲解的是,如何使用Unity开发2D游戏.但在开始讲解之前,最好先熟悉一下Unity这个工具.本章会首先介绍Unity的下 ...

  10. Unity 4.x 2D游戏开发基础教程大学霸第一更

    Unity 4.x 2D游戏开发基础教程 大学霸 第1章  Unity及其组成的介绍 本书主要讲解的是,如何使用Unity开发2D游戏.但在开始讲解之前,最好先熟悉一下Unity这个工具.本章会首先介 ...

最新文章

  1. 后台的代理nginx部署方法
  2. C++类中封装线程函数
  3. 浙江金融职业学院计算机一级,浙江金融职业学院全景-360度,720度,高清全景地图-expoon网展...
  4. c语言冒泡结构入门程序,C语言入门:冒泡排序
  5. 春节福利:《Oracle性能优化与诊断案例精选》电子版首次公开下载
  6. Appium之开发计算器自动化测试脚本Demo
  7. 北京Uber优步司机奖励政策(4月7日)
  8. 如何在命令行更改IP地址
  9. 金鹏GB28181平台对接
  10. php 有序数组,php 归拢两个有序数组
  11. 博微写狗.exe和博微电力工程造价深思4写狗
  12. Topaz Mask AI for mac(人工智能AI抠图软件) 最新版
  13. 台式计算机是32位还64位,小编教你怎么看电脑是32位还是64位
  14. 使用python爬取图片(爬取百度图片为例)
  15. C++之 最大公约数求法
  16. 明明白白学通C语言 二维码版 pdf
  17. 普通计算机怎么改闹铃的音乐,怎么设置闹钟铃声为自己喜欢的音乐
  18. java屏蔽游戏中骂人的话,替换为*,屏蔽敏感词汇
  19. 周易六十四卦——天风姤卦
  20. H5上拉加载以及在微信内置浏览器上拉加载失效问题记录

热门文章

  1. android电视工程模式,智能电视如何打开ADB?进入工程模式方法
  2. cdr怎样把一张图片随意变形_PS手记|移动工具的使用与画布的变形
  3. 南京晓庄学院计算机网络试卷,南京晓庄学院计算机网络8套卷(完整含答案).doc...
  4. python 步进电机_【Applied Motion Products】伺服电机|步进电机也可以python编程啦
  5. Oracle 常用运维命令整理
  6. java auth fail_com.jcraft.jsch.JSchException: Auth fail
  7. poj2449(k短路算法)
  8. Good Bye 2019 SZU cf集训C~D
  9. crash工具分析linux内核,如何使用crash工具分析Linux内核崩溃转储文件
  10. Luogu P4178 Tree (点分治 + 树状数组)