在多个网格A*寻路

来源:互联网 发布:app下不了软件 编辑:程序博客网 时间:2024/05/11 04:12

本文选自StackOverflow(简称:SOF)精选问答汇总系列文章之一,本系列文章将为读者分享国外最优质的精彩问与答,供读者学习和了解国外最新技术。本文将为读者讲解Unity中在多个网格A*寻路。

问题:

Caius Eugene

我正尝试着在一个cube周围执行A*寻路,这个cube是由6个网格组成的,为了保持简单,我用了四个函数:GetXPlus, GetXMinus, GetYPlus, GetYMinus。每个函数检查下一个砖块是否在最近的网格空间之内,如果不是就切换到相应的网格。

我遇到的问题是:当试图从当前网格翻转到其他方式的网格获得砖块时,返回的砖块是在相对的一侧。是否有方法让我避免为每个单个原有网格和方向写特定逻辑?

为了阐明我的问题,下图源自网格(紫色),使用GetXPlus函数:


目前执行的snippit (每格64*64):

1
2
3
4
5
6
7
8
9
10
11
12
13
public Tile GetXPlus( int currentX, int currentY )
{
    var newX = currentX + 1;
    var tile = GetTile( newX , currentY );
 
    if( newX > 64 )//Get adjacent XPlus Grid
    {
        currentGrid = SetCurrentGrid( XPlusGridIndex );
        tile = GetTile( newX - 64, currentY );
    }
 
    return tile;
}

背景

这个实现源自于另一个问题的回答:

http://gamedev.stackexchange.com/questions/53866/pathfinding-on-a-uneven-planetary-surface

答案:

Corniel Nobel

我建议你可以比先前的答案走的更远。创建一个cube代表所有的砖块,你要缓存每个砖块周围的东西。砖块之间的关系是固定的,这能给你节省不少时间。

之后亦可以用double[,,] 或者int[,,,] 跟踪你处理的砖块,并在此基础上添加邻近物到Queue<Tile>.

如果需要你也可以执行GetDirection(Tile tile)。那个函数只需要在方向dictionary上搜寻。

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
public class Cube { private Tile[,,] tiles;
    public Cube(int size)
    {
        tiles = newTile[size, size, 6];
 
        // initialize.
        for(var side = 0; side < 6; side++)
        {
            for(var x = 0; x < size; x++)
            {
                for(var y = 0; y < size; y++)
                {
                    tiles[x, y, side] = newTile(x, y, side);
                }
            }
        }
 
        // set directions & neighbors
        for(var side = 0; side < 6; side++)
        {
            for(var x = 0; x < size; x++)
            {
                for(var y = 0; y < size; y++)
                {
                    // todo: implement.
                }
            }
        }
    }
 
    public Tile this[int x, int y, int side]
    {
        get
        {
            returntiles[x, y, side];
        }
    }
}
 
public class Tile
{
    private Dictionary<DirectionType, Tile> directions = new Dictionary<DirectionType, Tile>();
 
    private Tile[] neighbors = newTile[4];
 
    public Tile(int x, int y, int side)
    {
        this.X = x;
        this.Y = y;
        this.Side = side;
    }
 
    public int X { get; private set; }
    public int Y { get; private set; }
    public int Side { get; private set; }
 
    public Tile this[DirectionType dir]
    {
        get
        {
            returndirections[dir];
        }
    }
 
 
 
    public Tile[] Neighbors { get { returnneighbors; } }
}
 
public enum DirectionType
{
    // delta: +1, 0
    e,
    // delta: 0, +1
    n,
    // delta: -1, 0
    w,
    // delta: 0, -1
    s,
    // delta: 0, 0
    X
}

Tilo

你可以使用函数映射,从X Y Z坐标以及砖块组成的3D空间到另一个。

执行个命令:

1
2
3
4
5
6
7
enum TileBorder
{
    Left   = 0,
    Top    = 1,
    Right  = 2,
    Bottom = 3
}

你可以在Tile class数组里存储这些改变:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Tile
{
    public Tile[] Neighbors { get; set; }
    public Func<int, int, int>[] XTransitions { get; set; }
    public Func<int, int, int>[] YTransitions { get; set; }
 
    public void GetXPlus(int x, int y, out int newX, out int newY, out Tile newTile)
    {
        x++;
        if (x <= 64)
        {
            newX = x;
            newY = y;
            newTile = this;
        }
        else
        {
            newX = XTransitions[(int)TileBorder.Right](x, y);
            newY = YTransitions[(int)TileBorder.Right](x, y);
            newTile = Neighbors[(int)TileBorder.Right];
        }
    }
    // ...
}

接下来你只需要在建立结构的时候注意一下就可以了。例如:这是你设置绿色砖块的方法,假设坐标包含1到64.

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
Tile pink   = newTile();
Tile green  = newTile();
Tile orange = newTile();
Tile purple = newTile();
Tile blue   = newTile();
 
green.Neighbors = newTile[]
{
    /* left */  orange,
    /* top */   pink,
    /* right */ blue,
    /* bottom */purple
};
 
green.XTransitions = newFunc<int, int, int>[]
{
    /* left */  (x, y) => 1,
    /* top */   (x, y) => x,
    /* right */ (x, y) => 64,
    /* bottom */(x, y) => x
};
 
green.YTransitions = newFunc<int, int, int>[]
{
    /* left */  (x, y) => 65 - y,
    /* top */   (x, y) => 64,
    /* right */ (x, y) => 65 - y,
    /* bottom */(x, y) => 1
};

注意砖块转变函数只是一个查找,为了充分灵活你也可以使用下面这些类型的函数:

X轴:Func<int, int, Tile, int> 
Y轴:Func<int, int, Tile, int> 
Z轴:Func<int, int, Tile, Tile>

0 0