For loop 如何使用*(Astart)寻路系统连接点?在戈多

For loop 如何使用*(Astart)寻路系统连接点?在戈多,for-loop,path-finding,a-star,godot,code-cleanup,For Loop,Path Finding,A Star,Godot,Code Cleanup,我正试着做一些和平常不一样的事情 我有一个3D gridmap节点设置,我正在尝试使用* 我不是在瓷砖之间创建障碍物,而是在瓷砖之间创建墙,这样瓷砖仍然可以行走,只是不能穿过墙。我已经想清楚了 但我不知道如何编码如何连接点以一种简单的方式,而不是连接点之间有墙 我使用一个RaycastCast节点来检测墙,以及它穿过每个网格时的位置 但我无法通过嵌套循环找到要连接的相邻点 这就是我试图做的(显然,get_nexist_point()没有按我想要的方式工作)。 如果我只使用矢量3坐标就能得到一个点

我正试着做一些和平常不一样的事情

我有一个3D gridmap节点设置,我正在尝试使用* 我不是在瓷砖之间创建障碍物,而是在瓷砖之间创建墙,这样瓷砖仍然可以行走,只是不能穿过墙。我已经想清楚了

但我不知道如何编码如何连接点以一种简单的方式,而不是连接点之间有墙

我使用一个RaycastCast节点来检测墙,以及它穿过每个网格时的位置

但我无法通过嵌套循环找到要连接的相邻点

这就是我试图做的(显然,get_nexist_point()没有按我想要的方式工作)。 如果我只使用矢量3坐标就能得到一个点,我想我可以让它工作

额外:如果你们能告诉我清理代码的方法,特别是在“FORs”语法上,因为我不知道我在做什么

任何其他干净的代码建议都会令人惊讶,并且非常受欢迎

在最后有一个视觉画(图像)的逻辑的想法


onready var rc = $RayCast
onready var aS = AStar.new()
var floor_size = Vector3(12,0,12)
var origin = Vector3(-5.5, 0.5, -2.5)
var FRONT = Vector3(1,0,0)
var RIGHT = Vector3(0,0,1)
var BACK = Vector3(-1,0,0)
var LEFT = Vector3(-1,0,0)


func set_walkable():
    var value = 0
    var value2 = 0
    var i = 0
    for _length in range (origin.x, origin.x + floor_size.x + 1):
        value += 1 
        value2 = 0
        for _width in range(origin.z, origin.z + floor_size.z):
            i += 1
            value2 += 1
            aS.add_point(i,  Vector3(origin.x + value -1 , 0.5, origin.z + value2 -1) , 1.0)
    value = 0       
    for _u in range(origin.x, origin.x + floor_size.x + 1):
        value += 1 
        value2 = 0
        for _v in range(origin.z, origin.z + floor_size.z):
            value2 += 1
            var from = aS.get_closest_point(Vector3(origin.x + value ,0.5,  origin.z + value2) ) # Current
            rc.translation = Vector3(origin.x + value -1 ,0.5,  origin.z + value2 -1)
            draw_points()
            print(rc.translation)
            rc.cast_to = FRONT
            var to = aS.get_closest_point(rc.translation) # Front
            if from != -1 and !rc.is_colliding():
                aS.connect_points(from, to)
                draw_connections(Vector3(rc.translation.x + 0.5,rc.translation.y,rc.translation.z))
            rc.cast_to = BACK
            to = aS.get_closest_point(rc.translation) # back
            if from != -1 and !rc.is_colliding():
                aS.connect_points(from, to)
                draw_connections(Vector3(rc.translation.x + -0.5,rc.translation.y,rc.translation.z))
            rc.cast_to = RIGHT
            to = aS.get_closest_point(rc.translation) # right
            if from != -1 and !rc.is_colliding():
                aS.connect_points(from, to)
                draw_connections(Vector3(rc.translation.x,rc.translation.y,rc.translation.z + 0.5))
            rc.cast_to = LEFT
            to = aS.get_closest_point(rc.translation) # left
            if from != -1 and !rc.is_colliding():
                aS.connect_points(from, to)
                draw_connections(Vector3(rc.translation.x + 0.5,rc.translation.y,rc.translation.z + -0.5))


func draw_points(): # Make points visible
    var cube = MeshInstance.new() 
    cube.mesh = CubeMesh.new()
    cube.translation = rc.translation
    cube.scale = Vector3(0.25,0.25,0.25)
    add_child(cube)
    print("Cubo adicionado")

func draw_connections(position): # Make connections visible
    var line = MeshInstance.new()
    line.mesh = PlaneMesh.new()
    line.scale = Vector3(0.03,0.03,0.03)
    line.translation = position
    add_child(line)
    print("Cubo adicionado")

在坐标和点ID之间转换 让我们在坐标和点ID之间建立映射。考虑到我们有
地板尺寸
,这很容易:

func vector_to_id(vector:Vector3, size:Vector3) -> int:
    return int(int3(vector).dot(dimension_size(size)))

func id_to_vector(id:int, size:Vector3) -> Vector3:
    var s:Vector3 = dimension_size(size)
    var z:int = int(id / s.z)
    var y:int = int((id % int(s.z)) / s.y)
    var x:int = id % int(s.y)
    return Vector3(x, y, z)

func int3(vector:Vector3) -> Vector3:
    return Vector3(int(vector.x), int(vector.y), int(vector.z))

func dimension_size(size:Vector3) -> Vector3:
    return Vector3(1, int(size.x + 1), int(size.x + 1) * int(size.y + 1))
可能的优化:

  • 存储
    尺寸大小(地板大小)
    并直接使用
  • 如果传递给
    vector\u to\u id
    的值保证为整数,则跳过调用
    int3
我们需要一个函数来获得总点数:

func total_size(size:Vector3) -> int:
    return int(size.x + 1) * int(size.y + 1) * int(size.z + 1)

解释

让我们从一维开始。我们只有一个坐标。所以我们有一个假设的
Vector1
,它有一个
x
属性。我们只是把事情排成一行

那么映射就很简单了:要从坐标转换到id,我们需要
id=int(vector.x)
,如果我们想要坐标,我们只需要
vector=Vector1(id)


现在,让我们转到2D。我们有
Vector2
x
y
。谢天谢地,我们有一个大小(当大小未知时,有一些方法可以进行映射,但是有一个大小很方便)

因此,我们将做一个二维网格,具有一定的宽度和高度。
y
坐标告诉我们所在的行,
x
告诉我们该行的位置

然后,如果我们有一些id,我们需要计算出需要到达那里的行数,以及我们在该行中的位置。计算出行很容易,我们除以网格的宽度。行中的位置是提醒。一个警告:我们是从0开始测量的(因此0的宽度实际上意味着每行1个元素)

我们有:

func id_to_vector(id:int, size:Vector2) -> Vector2:
    var y:int = int(id / (size.x + 1))
    var x:int = id % int(size.x + 1)
    return Vector2(x, y)
换个方向怎么样?我们将
y
乘以行的长度(宽度),然后加上
x

func vector_to_id(vector:Vector2, size:Vector2) -> int:
    return int(vector.x) + int(vector.y) * int(size.x + 1)
注意:

  • 我们不需要
    size.y
  • 这两个函数都需要
    size.x+1
  • 向量到id
    看起来非常类似于点积
因此,让我们创建一个新函数,该函数返回我们将用于生成点积的向量:

func dimension_size(size:Vector2) -> Vector2:
    return Vector2(1, int(size.x + 1))
并使用它:

func vector_to_id(vector:Vector2, size:Vector2) -> int:
    return int(vector.dot(dimensional_size(size)))

func id_to_vector(id:int, size:Vector2) -> Vector2:
    var s = dimensional_size(size)
    var y:int = int(id / int(s.y))
    var x:int = id % int(s.y)
    return Vector2(x, y)
注意如果不能保证
vector
中只有
vector\u to\u id
中的整数,则点积中的小数部分会导致错误的结果。这就是为什么我有一个函数使它只有整数


是3D的时候了。我们有
Vector3
x
y
z
。我们正在制作一个3D网格。现在,
z
将告诉我们该层,每个层都是一个二维网格

让我们回顾一下尺寸,我们有:

func dimension_size(size:Vector2) -> Vector2:
    return Vector2(1, int(size.x + 1))
这是元素的大小(
1
),行的大小(
size.x+1
),我们需要添加层的大小。也就是说,二维网格的大小,即宽度乘以高度

func dimension_size(size:Vector3) -> Vector3:
    return Vector3(1, int(size.x + 1), int(size.x + 1) * int(size.y + 1))
我们如何从id中获取
z
?我们除以网格的大小(所以我们知道我们在什么网格上)。然后从该分区的提示中,我们可以找到
y

func vector_to_id(vector:Vector3, size:Vector3) -> int:
    return int(vector.dot(dimensional_size(size)))

func id_to_vector(id:int, size:Vector3) -> Vector3:
    var s = dimensional_size(size)
    var z:int = int(id / int(s.z))
    var y:int = int(int(id % int(s.z)) / int(s.y))
    var x:int = id % int(s.y)
    return Vector2(x, y, z)
事实上,从技术上讲,所有这些坐标都是以相同的形式计算的:

func id_to_vector(id:int, size:Vector3) -> Vector3:
    var s = dimensional_size(size)
    var tot = total_size(size)
    var z:int = int(int(id % int(tot)) / int(s.z))
    var y:int = int(int(id % int(s.z)) / int(s.y))
    var x:int = int(int(id % int(s.y)) / int(s.x))
    return Vector2(x, y, z)
除此之外,无需使用总大小的提醒,因为
id
应始终小于该值。而且不需要除以
s.x
,因为单个元素的大小总是
1
。我还删除了一些多余的int类型转换

总尺寸是多少?当然,
尺寸的下一个元素是:

func dimension_size(size:Vector3) -> Vector3:
    return Vector3(1, int(size.x + 1), int(size.x + 1) * int(size.y + 1))

func total_size(size:Vector3) -> int:
    return int(size.x + 1) * int(size.y + 1) * int(size.z + 1)

检查连通性 还有一种检查连通性的方法:

func check_connected(start:Vector3, end:Vector3) -> bool:
    rc.transform.origin = start;
    rc.cast_to = end;
    rc.force_update_transform();
    rc.force_raycast_update();
    return !raycast.is_colliding():
for id in total_size(floor_size):
    var vector = id_to_vector(id, floor_size)
    aS.add_point(id, vector)
    for offset in offsets:
        var adjacent = vector + offset
        var adjacent_id = vector_to_id(adjacent, floor_size)
        aS.add_point(adjacent_id, adjacent)
        if check_connected(vector, adjacent):
            pass
for id in total_size(floor_size):
    var vector = id_to_vector(id, floor_size)
    aS.add_point(id, vector)
    for offset in offsets:
        var adjacent = vector + offset
        var adjacent_id = vector_to_id(adjacent, floor_size)
        aS.add_point(adjacent_id, adjacent)
        if check_connected(vector, adjacent):
            connect_points(id, adjacent_id)
您对
前面
右边
后面
左边
的想法是正确的,但将它们放在一个数组中:

var offsets = [Vector3(1,0,0), Vector3(0,0,1), Vector3(-1,0,0), Vector3(-1,0,0)]
注意我正在调用
force\u update\u transform
force\u raycast\u update
,因为它们在同一帧上执行多个光线投射检查


填充
AStar
好了,设置足够了,我们现在可以迭代:

for id in total_size(floor_size):
    pass
在每次迭代中,我们需要得到向量:

for id in total_size(floor_size):
    var vector = id_to_vector(id, floor_size)
可能的优化:直接迭代向量坐标以避免调用
id\u to\u vector

我们可以将向量添加到AStar

for id in total_size(floor_size):
    var vector = id_to_vector(id, floor_size)
    aS.add_point(id, vector)
接下来我们需要相邻向量:

for id in total_size(floor_size):
    var vector = id_to_vector(id, floor_size)
    aS.add_point(id, vector)
    for offset in offsets:
        var adjacent = vector + offset
让我们也将它们添加到AStar中:

for id in total_size(floor_size):
    var vector = id_to_vector(id, floor_size)
    aS.add_point(id, vector)
    for offset in offsets:
        var adjacent = vector + offset
        var adjacent_id = vector_to_id(adjacent, floor_size)
        aS.add_point(adjacent_id, adjacent)
可能的优化:

  • 如果
    有_点
    返回true,则不要添加
  • 如果相邻向量的id较低,则不要对其进行处理
  • 修改偏移量,以便只检查尚未添加的相邻位置(从而防止前两种情况)
让我们检查一下连通性:

func check_connected(start:Vector3, end:Vector3) -> bool:
    rc.transform.origin = start;
    rc.cast_to = end;
    rc.force_update_transform();
    rc.force_raycast_update();
    return !raycast.is_colliding():
for id in total_size(floor_size):
    var vector = id_to_vector(id, floor_size)
    aS.add_point(id, vector)
    for offset in offsets:
        var adjacent = vector + offset
        var adjacent_id = vector_to_id(adjacent, floor_size)
        aS.add_point(adjacent_id, adjacent)
        if check_connected(vector, adjacent):
            pass
for id in total_size(floor_size):
    var vector = id_to_vector(id, floor_size)
    aS.add_point(id, vector)
    for offset in offsets:
        var adjacent = vector + offset
        var adjacent_id = vector_to_id(adjacent, floor_size)
        aS.add_point(adjacent_id, adjacent)
        if check_connected(vector, adjacent):
            connect_points(id, adjacent_id)
并告诉
AStar
有关连接的信息