micropather实现A*算法
来源:互联网 发布:常州协同工作软件 编辑:程序博客网 时间:2024/06/04 08:57
MicroPather is a path finder and A* solver (astar or a-star) written in platform independent C++ that can be easily integrated into existing code. MicroPather focuses on being a path finding engine for video games but is a generic A* solver.
There is plenty of pathing code out there, but most if it seems to focus on teaching somewhat how to write an A* solver, rather than being utility code for pathing. MicroPather is firmly aimed at providing functionality, not at being a tutorial.
MicroPather's primary goal is to be easy to use:
- An easy API
- No requirements on the host program to change its data structures or objects
- No library or 'make' - just add 1 .cpp and 1 .h file to your project.
Enjoy, and thanks for checking out MicroPather!
官方网站可以下载其sdk和demo。
demo1的代码如下:
dungeon.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
#define USE_PATHER
#include <ctype.h>
#include <stdio.h>
#include <memory.h>
#include <math.h>
#include <vector>
#include <iostream>
#ifdef USE_PATHER
#include "micropather.h"
using
namespace
micropather;
#endif
const
int
MAPX = 30;
const
int
MAPY = 10;
const
char
gMap[MAPX*MAPY+1] =
//"012345678901234567890123456789"
" | | |"
" | |----+ | +"
"---+ +---DD-+ +--+--+ "
" | +-- +"
" +----+ +---+ "
"---+ + D D | "
" | | +----+ +----+ +--+"
" D | | | "
" | +-------+ +-+ |--+ "
"---+ | +"
;
class
Dungeon
#ifdef USE_PATHER
:
public
Graph
#endif
{
private
:
Dungeon(
const
Dungeon& );
void
operator=(
const
Dungeon& );
// 寻路的起始点位置
int
playerX, playerY;
// 寻路的最终路径
std::vector<
void
*> path;
// 门是否打开
bool
doorsOpen;
//
bool
showConsidered;
MicroPather* pather;
public
:
Dungeon() : playerX( 0 ), playerY( 0 ), doorsOpen(
false
), showConsidered(
false
), pather( 0 )
{
// this : The "map" that implements the Graph callbacks.
// 20 : How many states should be internally allocated at a time.
// This can be hard to get correct. The higher the value,
// the more memory MicroPather will use.
pather =
new
MicroPather(
this
, 20 );
// Use a very small memory block to stress the pather
}
virtual
~Dungeon()
{
delete
pather;
}
int
X() {
return
playerX; }
int
Y() {
return
playerY; }
// 校验和,用于debug
unsigned Checksum() {
return
pather->Checksum(); }
void
ClearPath()
{
#ifdef USE_PATHER
path.resize( 0 );
#endif
}
//
void
ToggleTouched()
{
showConsidered = !showConsidered;
// Reset() Should be called whenever the cost between states or
// the connection between states changes.
// Also frees overhead memory used by MicroPather,
// and calling will free excess memory.
pather->Reset();
}
// 打开或者关闭Door
void
ToggleDoor()
{
doorsOpen = !doorsOpen;
#ifdef USE_PATHER
pather->Reset();
#endif
}
// 目标点(nx, ny)是否可到达(" "或者"D")
int
Passable(
int
nx,
int
ny )
{
if
( nx >= 0 && nx < MAPX
&& ny >= 0 && ny < MAPY )
{
int
index = ny * MAPX + nx;
char
c = gMap[index];
if
( c ==
' '
)
return
1;
else
if
( c ==
'D'
)
return
2;
}
return
0;
}
// 计算起始位置到(nx,ny)的路径及其代价
int
SetPos(
int
nx,
int
ny )
{
int
result = 0;
if
( Passable( nx, ny ) == 1 )
{
#ifdef USE_PATHER
float
totalCost;
if
( showConsidered )
pather->Reset();
/*
int micropather::MicroPather::Solve
( void * startState,
void * endState,
std::vector< void * > * path,
float * totalCost
)
Solve for the path from start to end.
Parameters:
startState: Input, the starting state for the path.
endState: Input, the ending state for the path.
path: Output, a vector of states that define the path. Empty if not found.
totalCost: Output, the cost of the path, if found.
Returns:
Success or failure, expressed as SOLVED, NO_SOLUTION, or START_END_SAME.
*/
result = pather->Solve( XYToNode( playerX, playerY ), XYToNode( nx, ny ), &path, &totalCost );
if
( result == MicroPather::SOLVED )
{
// 将玩家位置设置为(nx, ny)
playerX = nx;
playerY = ny;
}
printf
(
"Pather returned %d\n"
, result );
#else
playerX = nx;
playerY = ny;
#endif
}
return
result;
}
void
Print()
{
char
buf[ MAPX + 1 ];
std::vector<
void
*> stateVec;
if
( showConsidered )
pather->StatesInPool(&stateVec);
printf
(
" doors %s\n"
, doorsOpen ?
"open"
:
"closed"
);
printf
(
" 0 10 20\n"
);
printf
(
" 012345678901234567890123456789\n"
);
for
(
int
j=0; j<MAPY; ++j )
{
// 按行复制, 并输出
memcpy
(buf, &gMap[MAPX * j], MAPX + 1);
buf[MAPX] = 0;
#ifdef USE_PATHER
unsigned k;
// Wildly inefficient demo code.
for
( k=0; k<path.size(); ++k )
{
int
x, y;
NodeToXY( path[k], &x, &y );
if
( y == j )
buf[x] =
'0'
+ k % 10;
}
if
( showConsidered )
{
for
( k=0; k<stateVec.size(); ++k )
{
int
x, y;
NodeToXY( stateVec[k], &x, &y );
if
( y == j )
buf[x] =
'x'
;
}
}
#endif
// Insert the player
if
( j == playerY )
buf[playerX] =
'i'
;
printf
(
"%d%s\n"
, j % 10, buf );
}
}
#ifdef USE_PATHER
void
NodeToXY(
void
* node,
int
* x,
int
* y )
{
int
index = (
int
)node;
*y = index / MAPX;
*x = index - *y * MAPX;
}
void
* XYToNode(
int
x,
int
y )
{
return
(
void
*) ( y*MAPX + x );
}
// 最小代价
virtual
float
LeastCostEstimate(
void
* nodeStart,
void
* nodeEnd )
{
int
xStart, yStart, xEnd, yEnd;
NodeToXY( nodeStart, &xStart, &yStart );
NodeToXY( nodeEnd, &xEnd, &yEnd );
/* Compute the minimum path cost using distance measurement. It is possible
to compute the exact minimum path using the fact that you can move only
on a straight line or on a diagonal, and this will yield a better result.
*/
int
dx = xStart - xEnd;
int
dy = yStart - yEnd;
return
(
float
)
sqrt
( (
double
)(dx*dx) + (
double
)(dy*dy) );
}
// Return the exact cost from the given state to all its neighboring states.
// This may be called multiple times, or cached by the solver.
virtual
void
AdjacentCost(
void
* node, std::vector< StateCost > *neighbors )
{
int
x, y;
// 在X,Y轴上8个方向 E SE S SW W NW N NE
const
int
dx[8] = { 1, 1, 0, -1, -1, -1, 0, 1 };
const
int
dy[8] = { 0, 1, 1, 1, 0, -1, -1, -1 };
// X,Y轴上8个方向的代价
const
float
cost[8] = { 1.0f, 1.41f, 1.0f, 1.41f, 1.0f, 1.41f, 1.0f, 1.41f };
NodeToXY( node, &x, &y );
// 得到与该点相邻的8个方向的点的坐标;计算是否可通过;将代价push到vector中
for
(
int
i=0; i<8; ++i )
{
int
nx = x + dx[i];
int
ny = y + dy[i];
int
pass = Passable( nx, ny );
if
( pass > 0 )
{
if
( pass == 1 || doorsOpen )
{
// Normal floor
StateCost nodeCost =
{
// (nx, ny)点的索引号
XYToNode( nx, ny ),
// node到该点的代价
cost[i]
};
neighbors->push_back( nodeCost );
}
else
{
// 若不可pass则代价为FLT_MAX
StateCost nodeCost = { XYToNode( nx, ny ), FLT_MAX };
neighbors->push_back( nodeCost );
}
}
}
}
virtual
void
PrintStateInfo(
void
* node )
{
int
x, y;
NodeToXY( node, &x, &y );
printf
(
"(%d,%d)"
, x, y );
}
#endif
};
int
main(
int
/*argc*/
,
const
char
**
/*argv*/
)
{
{
Dungeon test;
const
int
NUM_TEST = 5;
int
tx[NUM_TEST] = { 24, 25, 10, 6, 0 };
// x of test
int
ty[NUM_TEST] = { 9, 9, 5, 5, 0 };
// y of test
int
door[NUM_TEST] = { 0, 0, 0, 1, 0 };
// toggle door? (before move)
unsigned check[NUM_TEST] = { 139640, 884, 0, 129313, 2914 };
for
(
int
i=0; i<NUM_TEST; ++i )
{
// (25,9)到(10, 5)时, (10, 5)正好被不通路包围的中心,这个不通路有2扇门,
// 此时2扇门没打开,所以(25,9)到(10, 5)不通!
// (10,5)到(6,5)之间正好有一扇门,若门关闭则此路不通,门打开则可以通
if
( door[i] )
test.ToggleDoor();
int
_result = test.SetPos( tx[i], ty[i] );
if
( _result == MicroPather::SOLVED )
{
// Return the "checksum" of the last path returned by Solve().
// Useful for debugging, and a quick way to see if 2 paths are the same.
unsigned checkNum = test.Checksum();
if
( checkNum == check[i] )
printf
(
"Test %d to (%d,%d) ok\n"
, i, tx[i], ty[i] );
else
printf
(
"Test %d to (%d,%d) BAD CHECKSUM\n"
, i, tx[i], ty[i] );
}
else
if
(_result == MicroPather::NO_SOLUTION)
{
printf
(
"Test %d to (%d,%d) no solution\n"
, i, tx[i], ty[i] );
}
else
if
(_result == MicroPather::START_END_SAME)
{
printf
(
"Test %d to (%d,%d) start end same\n"
, i, tx[i], ty[i] );
}
}
}
Dungeon dungeon;
bool
done =
false
;
char
buf[ 256 ];
while
( !done )
{
dungeon.Print();
printf
(
"\n# # to move, q to quit, r to redraw, d to toggle doors, t for touched\n"
);
std::cin.getline( buf, 256 );
if
( *buf )
{
if
( buf[0] ==
'q'
)
done =
true
;
else
if
( buf[0] ==
'd'
)
{
dungeon.ToggleDoor();
dungeon.ClearPath();
}
else
if
( buf[0] ==
't'
)
dungeon.ToggleTouched();
else
if
( buf[0] ==
'r'
)
dungeon.ClearPath();
else
if
(
isdigit
( buf[0] ) )
{
int
x, y;
sscanf
( buf,
"%d %d"
, &x, &y );
// sleazy, I know
dungeon.SetPos( x, y );
}
}
else
dungeon.ClearPath();
}
return
0;
}
- micropather实现A*算法
- A*算法实现
- A* 算法实现
- A*算法实现
- A*算法C实现
- A*算法的实现
- C#实现A*算法
- A*算法实现特例
- c++ 实现A* 算法
- A*算法实现
- A*算法 JAVA实现
- A*算法实现
- A*算法 c++实现
- Unity A*算法实现
- A*算法lua实现
- A*(A星)算法python实现
- 基本A*算法python实现
- 基本A*算法python实现
- C#操作Excel的学习
- 读《道德经》第四章
- 苹果软件系列产品
- Message,MessageQueue,Looper,Handler的理解
- Linux AIO
- micropather实现A*算法
- ASP.NET 用户控件的使用
- ADF 11.1.1.5.0未认证Win 7 64位系统
- AD 转换的软件滤波方法
- 《深入 python3 》中文版
- 仪器编程VISA
- 74ls192/74ls193中文资料介绍-引脚图-真值表-工作原理
- Direct3D 11设备介绍
- 居思安:搜索引擎中文网站收录地址录口