For loop 如何使用*(Astart)寻路系统连接点?在戈多
我正试着做一些和平常不一样的事情 我有一个3D gridmap节点设置,我正在尝试使用* 我不是在瓷砖之间创建障碍物,而是在瓷砖之间创建墙,这样瓷砖仍然可以行走,只是不能穿过墙。我已经想清楚了 但我不知道如何编码如何连接点以一种简单的方式,而不是连接点之间有墙 我使用一个RaycastCast节点来检测墙,以及它穿过每个网格时的位置 但我无法通过嵌套循环找到要连接的相邻点 这就是我试图做的(显然,get_nexist_point()没有按我想要的方式工作)。 如果我只使用矢量3坐标就能得到一个点,我想我可以让它工作 额外:如果你们能告诉我清理代码的方法,特别是在“FORs”语法上,因为我不知道我在做什么 任何其他干净的代码建议都会令人惊讶,并且非常受欢迎 在最后有一个视觉画(图像)的逻辑的想法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坐标就能得到一个点
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
有关连接的信息