Skip to content

Commit

Permalink
Merge pull request #94 from nezvers/obstackle_navigation
Browse files Browse the repository at this point in the history
Ai cornering
  • Loading branch information
nezvers authored Oct 13, 2024
2 parents ce8df21 + 8a1032b commit 91af5ed
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 45 deletions.
85 changes: 52 additions & 33 deletions addons/nezvers_library/nodes/Navigation/TileNavigationGetter.gd
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
class_name TileNavigationGetter
extends Line2D


@export var astargrid_resource:AstarGridResource
## How close to be to a point to look up next one
@export var reached_distance:float = 6.0

var last_path:PackedVector2Array
var navigation_path:PackedVector2Array
var tile_path:Array[Vector2i]
var index:int = 0
var closest_point:Vector2
var is_finished:bool
var finish_reached:bool : set = set_finish_reached
var point_reached:bool

func set_finish_reached(value:bool)->void:
finish_reached = value

func _ready()->void:
top_level = true
Expand All @@ -17,49 +23,62 @@ func _ready()->void:
func get_target_path(from:Vector2, to:Vector2)->PackedVector2Array:
var _from_tile:Vector2i = astargrid_resource.tilemap_layer.local_to_map(from)
var _to_tile:Vector2i = astargrid_resource.tilemap_layer.local_to_map(to)
last_path = astargrid_resource.value.get_point_path(_from_tile, _to_tile)
index = 0
first_point_choice(from)
navigation_path = astargrid_resource.value.get_point_path(_from_tile, _to_tile)
tile_path = astargrid_resource.value.get_id_path(_from_tile, _to_tile)

if navigation_path.size() < 2:
index = 0
else:
index = 1
assert(index < navigation_path.size())

is_finished = false
finish_reached = false
if visible:
points = last_path
return last_path
points = navigation_path
return navigation_path

## TODO: Don't use top_level to be able use position
##
func get_next_path_position(from:Vector2)->Vector2:
if last_path.is_empty():
if navigation_path.is_empty():
return closest_point

## TODO: add corner avoidance steering
closest_point = last_path[index]
closest_point = navigation_path[index]
var _closest_dist:float = (closest_point - from).length_squared()
var _treshold:float = reached_distance * reached_distance
var i:int = index +1
while i < last_path.size():
var _current_point = last_path[i]
var _current_dist = (_current_point - from).length_squared()
if _closest_dist < _current_dist:
break
closest_point = _current_point
_closest_dist = _current_dist
index = i
i += 1 # <- don't forget, or else...
var i:int = index
#if i < navigation_path.size() - 1:
#i += 1
#assert(i < navigation_path.size())
#while i < navigation_path.size():
#var _current_point = navigation_path[i]
#var _current_dist = (_current_point - from).length_squared()
#if _closest_dist < _current_dist:
#i -= 1
#assert(i < navigation_path.size())
#break
#closest_point = _current_point
#_closest_dist = _current_dist
#i += 1 # <- don't forget, or else...
#i = min(i , navigation_path.size() - 1)

if _closest_dist < _treshold && index < last_path.size() - 1:
index += 1
closest_point = last_path[index]
else:
is_finished = true
if _closest_dist < _treshold && i < navigation_path.size() - 1:
i += 1
assert(i < navigation_path.size())
closest_point = navigation_path[i]

if i != index:
point_reached = true
if index == navigation_path.size() - 1:
finish_reached = true
elif !finish_reached:
point_reached = false

index = i
assert(i < navigation_path.size())
return closest_point

## Solution to not go backwards for a first point
func first_point_choice(_position:Vector2)->void:
if last_path.size() < 2:
return
var _dot_product:float = (last_path[0] - _position).normalized().dot((last_path[1] - _position).normalized())
if _dot_product > 0.0:
return
index = 1

func _draw()->void:
pass
2 changes: 1 addition & 1 deletion addons/top_down/scenes/obstacles/hole_obstacle.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ collision_mask = 6
script = ExtResource("1_soon6")

[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="AreaTransmitter2D"]
polygon = PackedVector2Array(0, -5, -12, 0, 0, 5, 12, 0)
polygon = PackedVector2Array(0, -5, -11, 0, 0, 5, 11, 0)

[node name="HoleTransmitter" type="Node" parent="AreaTransmitter2D" node_paths=PackedStringArray("area_transmitter")]
script = ExtResource("2_otvmq")
Expand Down
46 changes: 35 additions & 11 deletions addons/top_down/scripts/actor/bots/TargetDirection.gd
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,19 @@ extends Node
@export var tile_navigation:TileNavigationGetter
## Value used to change recalculation cooldown
@export var retarget_distance:float = 16.0
@export var straight_path_distance:float = 16.0 * 5.0
@export var debug:bool


## From bot to target
var local_direction:Vector2
var target_direction:Vector2
## Track targets position
var last_target_position:Vector2
## Time last navigation update happened
var last_update_time:float
var navigation_cooldown:float = 1.0


## Used to control navigation around corners
var allow_straight_path:bool = false

func _ready()->void:
target_finder.target_update.connect(on_target_update)
Expand All @@ -30,13 +31,13 @@ func on_target_update()->void:
if target_finder.target_count < 1:
set_direction(Vector2.ZERO)
return
local_direction = target_finder.closest.global_position - bot_input.global_position
var local_dir_len:float = local_direction.length_squared()
var attack_dist_squared:float = bot_input.attack_distance * bot_input.attack_distance
target_direction = target_finder.closest.global_position - bot_input.global_position
#var local_dir_len:float = target_direction.length_squared()
#var attack_dist_squared:float = bot_input.attack_distance * bot_input.attack_distance


if line_of_sight():
set_direction(local_direction)
if test_line_of_sight():
set_direction(target_direction)
return

navigation_update()
Expand All @@ -45,10 +46,33 @@ func on_target_update()->void:
set_direction(direction)

## Raycast checks if anything from environment is in the way
func line_of_sight()->bool:
raycast.target_position = local_direction
func test_line_of_sight()->bool:
raycast.target_position = target_direction
raycast.force_raycast_update()
return !raycast.is_colliding()

var _is_line_of_sight:bool = !raycast.is_colliding()
if !_is_line_of_sight:
allow_straight_path = false

if tile_navigation.navigation_path.is_empty():
return _is_line_of_sight
if tile_navigation.finish_reached:
return _is_line_of_sight
if !(tile_navigation.index < tile_navigation.navigation_path.size() - 1):
return _is_line_of_sight

#if target_direction.length_squared() > (straight_path_distance * straight_path_distance):
#return allow_straight_path

if _is_line_of_sight && !allow_straight_path && tile_navigation.point_reached:
# use tile Vector2i positions for dot product to have straight angles
var _target_tile_direction:Vector2 = (target_direction / tile_navigation.astargrid_resource.value.cell_size).round()
var _point_direction:Vector2 = tile_navigation.tile_path[tile_navigation.index + 1] - tile_navigation.tile_path[tile_navigation.index]
var _dot_product:float = _target_tile_direction.normalized().dot(_point_direction.normalized())
if _dot_product > 0.5:
allow_straight_path = true

return allow_straight_path

func navigation_update()->void:
var time: = Time.get_ticks_msec() * 0.001
Expand Down

0 comments on commit 91af5ed

Please sign in to comment.