2020-01-29 17:04:04 +01:00
|
|
|
# Steers the agent to avoid obstacles in its path. Approximates obstacles as
|
|
|
|
# spheres.
|
2020-04-03 02:31:59 +02:00
|
|
|
# @category - Group behaviors
|
2020-02-11 18:33:25 +01:00
|
|
|
class_name GSAIAvoidCollisions
|
|
|
|
extends GSAIGroupBehavior
|
2020-01-09 18:25:48 +01:00
|
|
|
|
2020-02-11 18:33:25 +01:00
|
|
|
var _first_neighbor: GSAISteeringAgent
|
2023-01-13 13:09:18 +01:00
|
|
|
var _shortest_time : float = 0.0
|
|
|
|
var _first_minimum_separation : float = 0.0
|
|
|
|
var _first_distance : float = 0.0
|
|
|
|
var _first_relative_position : Vector3
|
|
|
|
var _first_relative_velocity : Vector3
|
2020-01-09 18:25:48 +01:00
|
|
|
|
|
|
|
|
2020-02-11 18:33:25 +01:00
|
|
|
func _calculate_steering(acceleration: GSAITargetAcceleration) -> void:
|
2020-01-30 19:06:35 +01:00
|
|
|
_shortest_time = INF
|
|
|
|
_first_neighbor = null
|
|
|
|
_first_minimum_separation = 0
|
|
|
|
_first_distance = 0
|
2020-01-29 17:04:04 +01:00
|
|
|
|
2023-01-13 20:08:32 +01:00
|
|
|
var neighbor_count : int = proximity.find_neighbors(_callback)
|
2020-01-29 17:04:04 +01:00
|
|
|
|
2020-01-30 19:06:35 +01:00
|
|
|
if neighbor_count == 0 or not _first_neighbor:
|
2020-01-09 18:25:48 +01:00
|
|
|
acceleration.set_zero()
|
|
|
|
else:
|
2023-01-13 13:09:18 +01:00
|
|
|
if (_first_minimum_separation <= 0 || _first_distance < agent.bounding_radius + _first_neighbor.bounding_radius):
|
2020-01-30 19:06:35 +01:00
|
|
|
acceleration.linear = _first_neighbor.position - agent.position
|
2020-01-09 18:25:48 +01:00
|
|
|
else:
|
2023-01-13 13:09:18 +01:00
|
|
|
acceleration.linear = (_first_relative_position+ (_first_relative_velocity * _shortest_time))
|
2020-01-29 17:04:04 +01:00
|
|
|
|
2020-02-14 17:35:18 +01:00
|
|
|
acceleration.linear = (acceleration.linear.normalized() * -agent.linear_acceleration_max)
|
2020-01-21 18:49:46 +01:00
|
|
|
acceleration.angular = 0
|
2020-01-29 17:04:04 +01:00
|
|
|
|
2020-01-09 18:25:48 +01:00
|
|
|
|
2020-01-29 05:56:10 +01:00
|
|
|
# Callback for the proximity to call when finding neighbors. Keeps track of every `neighbor`
|
|
|
|
# that was found but only keeps the one the owning agent will most likely collide with.
|
2020-04-03 02:31:59 +02:00
|
|
|
# @tags - virtual
|
2020-02-11 18:33:25 +01:00
|
|
|
func _report_neighbor(neighbor: GSAISteeringAgent) -> bool:
|
2023-01-13 13:09:18 +01:00
|
|
|
var relative_position : Vector3 = neighbor.position - agent.position
|
|
|
|
var relative_velocity : Vector3 = neighbor.linear_velocity - agent.linear_velocity
|
|
|
|
var relative_speed_squared : float = relative_velocity.length_squared()
|
2020-01-29 17:04:04 +01:00
|
|
|
|
2020-01-09 18:25:48 +01:00
|
|
|
if relative_speed_squared == 0:
|
|
|
|
return false
|
|
|
|
else:
|
2023-01-13 13:09:18 +01:00
|
|
|
var time_to_collision : float = -relative_position.dot(relative_velocity) / relative_speed_squared
|
2020-01-29 17:04:04 +01:00
|
|
|
|
2023-01-13 13:09:18 +01:00
|
|
|
if time_to_collision <= 0 || time_to_collision >= _shortest_time:
|
2020-01-09 18:25:48 +01:00
|
|
|
return false
|
|
|
|
else:
|
|
|
|
var distance = relative_position.length()
|
2023-01-13 13:09:18 +01:00
|
|
|
var minimum_separation: float = (distance - sqrt(relative_speed_squared) * time_to_collision)
|
|
|
|
|
2020-01-09 18:25:48 +01:00
|
|
|
if minimum_separation > agent.bounding_radius + neighbor.bounding_radius:
|
|
|
|
return false
|
|
|
|
else:
|
2020-01-30 19:06:35 +01:00
|
|
|
_shortest_time = time_to_collision
|
|
|
|
_first_neighbor = neighbor
|
|
|
|
_first_minimum_separation = minimum_separation
|
|
|
|
_first_distance = distance
|
|
|
|
_first_relative_position = relative_position
|
|
|
|
_first_relative_velocity = relative_velocity
|
2020-01-09 18:25:48 +01:00
|
|
|
return true
|