mirror of
https://github.com/Relintai/godot-steering-ai-framework.git
synced 2024-11-14 04:57:19 +01:00
Edit docstrings in src/Behaviors
This commit is contained in:
parent
4885707145
commit
bd41d5987c
@ -1,16 +1,17 @@
|
||||
# Calculates acceleration to take an agent to its target's location.
|
||||
# The calculation will attempt to arrive with zero remaining velocity.
|
||||
# Calculates acceleration to take an agent to its target's location. The
|
||||
# calculation attempts to arrive with zero remaining velocity.
|
||||
class_name GSTArrive
|
||||
extends GSTSteeringBehavior
|
||||
|
||||
|
||||
# The target whose location the agent will be steered to arrive at
|
||||
# Target agent to arrive to.
|
||||
var target: GSTAgentLocation
|
||||
# The distance from the target for the agent to be considered successfully arrived
|
||||
# Distance from the target for the agent to be considered successfully
|
||||
# arrived.
|
||||
var arrival_tolerance: float
|
||||
# The distance from the target for the agent to begin slowing down
|
||||
# Distance from the target for the agent to begin slowing down.
|
||||
var deceleration_radius: float
|
||||
# The amount of time to reach the target velocity
|
||||
# Represents the time it takes to change acceleration.
|
||||
var time_to_reach := 0.1
|
||||
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
# Behavior that steers the agent to avoid obstacles lying in its path as approximated by spheres.
|
||||
# Steers the agent to avoid obstacles in its path. Approximates obstacles as
|
||||
# spheres.
|
||||
class_name GSTAvoidCollisions
|
||||
extends GSTGroupBehavior
|
||||
|
||||
@ -20,22 +21,22 @@ func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAccele
|
||||
first_neighbor = null
|
||||
first_minimum_separation = 0
|
||||
first_distance = 0
|
||||
|
||||
|
||||
var neighbor_count := proximity.find_neighbors(_callback)
|
||||
|
||||
|
||||
if neighbor_count == 0 or not first_neighbor:
|
||||
acceleration.set_zero()
|
||||
else:
|
||||
if(
|
||||
first_minimum_separation <= 0 or
|
||||
first_minimum_separation <= 0 or
|
||||
first_distance < agent.bounding_radius + first_neighbor.bounding_radius):
|
||||
acceleration.linear = first_neighbor.position - agent.position
|
||||
else:
|
||||
acceleration.linear = first_relative_position + (first_relative_velocity * shortest_time)
|
||||
|
||||
|
||||
acceleration.linear = acceleration.linear.normalized() * -agent.linear_acceleration_max
|
||||
acceleration.angular = 0
|
||||
|
||||
|
||||
return acceleration
|
||||
|
||||
|
||||
@ -45,12 +46,12 @@ func report_neighbor(neighbor: GSTSteeringAgent) -> bool:
|
||||
var relative_position := neighbor.position - agent.position
|
||||
var relative_velocity := neighbor.linear_velocity - agent.linear_velocity
|
||||
var relative_speed_squared := relative_velocity.length_squared()
|
||||
|
||||
|
||||
if relative_speed_squared == 0:
|
||||
return false
|
||||
else:
|
||||
var time_to_collision = -relative_position.dot(relative_velocity) / relative_speed_squared
|
||||
|
||||
|
||||
if time_to_collision <= 0 or time_to_collision >= shortest_time:
|
||||
return false
|
||||
else:
|
||||
|
@ -1,10 +1,11 @@
|
||||
# Blends multiple steering behaviors into one, and returns acceleration combining all of them.
|
||||
#
|
||||
# Each behavior is associated with a weight - a modifier by which the result will be multiplied by,
|
||||
# then added to a total acceleration.
|
||||
#
|
||||
# Each behavior is stored internally as a `Dictionary` with a `behavior` key with a value of type
|
||||
# `GSTSteeringBehavior` and a `weight` key with a value of type float.
|
||||
# Blends multiple steering behaviors into one, and returns a weighted
|
||||
# acceleration from their calculations.
|
||||
#
|
||||
# Stores the behaviors internally as dictionaries of the form
|
||||
# {
|
||||
# behavior : GSTSteeringBehavior,
|
||||
# weight : float
|
||||
# }
|
||||
class_name GSTBlend
|
||||
extends GSTSteeringBehavior
|
||||
|
||||
@ -17,13 +18,14 @@ func _init(agent: GSTSteeringAgent).(agent) -> void:
|
||||
pass
|
||||
|
||||
|
||||
# Adds a behavior to the next index and gives it a `weight` by which its results will be multiplied
|
||||
# Appends a behavior to the internal array along with its `weight`.
|
||||
func add(behavior: GSTSteeringBehavior, weight: float) -> void:
|
||||
behavior.agent = agent
|
||||
_behaviors.append({behavior = behavior, weight = weight})
|
||||
|
||||
|
||||
# Returns the behavior at the specified `index`. Returns an empty `Dictionary` if none was found.
|
||||
# Returns the behavior at the specified `index`, or an empty `Dictionary` if
|
||||
# none was found.
|
||||
func get_behavior_at(index: int) -> Dictionary:
|
||||
if _behaviors.size() > index:
|
||||
return _behaviors[index]
|
||||
@ -33,18 +35,18 @@ func get_behavior_at(index: int) -> Dictionary:
|
||||
|
||||
func _calculate_steering(blended_accel: GSTTargetAcceleration) -> GSTTargetAcceleration:
|
||||
blended_accel.set_zero()
|
||||
|
||||
|
||||
for i in range(_behaviors.size()):
|
||||
var bw: Dictionary = _behaviors[i]
|
||||
bw.behavior.calculate_steering(_accel)
|
||||
|
||||
|
||||
blended_accel.add_scaled_accel(_accel, bw.weight)
|
||||
|
||||
|
||||
blended_accel.linear = GSTUtils.clampedv3(blended_accel.linear, agent.linear_acceleration_max)
|
||||
blended_accel.angular = clamp(
|
||||
blended_accel.angular,
|
||||
-agent.angular_acceleration_max,
|
||||
agent.angular_acceleration_max
|
||||
)
|
||||
|
||||
|
||||
return blended_accel
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Group behavior that produces linear acceleration that attempts to move the agent towards the
|
||||
# center of mass of the agents in the area defined by the Proximity.
|
||||
# Calculates an acceleration that attempts to move the agent towards the center
|
||||
# of mass of the agents in the area defined by the `GSTProximity`.
|
||||
class_name GSTCohesion
|
||||
extends GSTGroupBehavior
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
# Calculates acceleration to take an agent away from where a target agent will be.
|
||||
# Calculates acceleration to take an agent away from where a target agent is
|
||||
# moving.
|
||||
class_name GSTEvade
|
||||
extends GSTPursue
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Calculates angular acceleration to rotate a target to face its target's position.
|
||||
# The acceleration will attempt to arrive with zero remaining angular velocity.
|
||||
# Calculates angular acceleration to rotate a target to face its target's
|
||||
# position. The behavior attemps to arrive with zero remaining angular velocity.
|
||||
class_name GSTFace
|
||||
extends GSTMatchOrientation
|
||||
|
||||
@ -11,7 +11,7 @@ func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent, target) ->
|
||||
func _face(acceleration: GSTTargetAcceleration, target_position: Vector3) -> GSTTargetAcceleration:
|
||||
var to_target := target_position - agent.position
|
||||
var distance_squared := to_target.length_squared()
|
||||
|
||||
|
||||
if distance_squared < agent.zero_linear_speed_threshold:
|
||||
acceleration.set_zero()
|
||||
return acceleration
|
||||
|
@ -11,5 +11,5 @@ func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAccele
|
||||
acceleration.linear = (
|
||||
(agent.position - target.position).normalized() * agent.linear_acceleration_max)
|
||||
acceleration.angular = 0
|
||||
|
||||
|
||||
return acceleration
|
||||
|
@ -3,22 +3,22 @@ class_name GSTFollowPath
|
||||
extends GSTArrive
|
||||
|
||||
|
||||
# The path to follow and travel along
|
||||
# The path to follow and travel along.
|
||||
var path: GSTPath
|
||||
# The distance along the path to generate the next target position.
|
||||
var path_offset := 0.0
|
||||
|
||||
# Whether to use `GSTArrive` behavior on an open path.
|
||||
var arrive_enabled := true
|
||||
# The amount of time in the future to predict the owning agent's position along the path. Setting
|
||||
# it to 0 will force non-predictive path following.
|
||||
# The amount of time in the future to predict the owning agent's position along
|
||||
# the path. Setting it to 0.0 will force non-predictive path following.
|
||||
var prediction_time := 0.0
|
||||
|
||||
|
||||
func _init(
|
||||
agent: GSTSteeringAgent,
|
||||
path: GSTPath,
|
||||
path_offset := 0.0,
|
||||
agent: GSTSteeringAgent,
|
||||
path: GSTPath,
|
||||
path_offset := 0.0,
|
||||
prediction_time := 0.0).(agent, null) -> void:
|
||||
self.path = path
|
||||
self.path_offset = path_offset
|
||||
@ -29,12 +29,12 @@ func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAccele
|
||||
var location := (
|
||||
agent.position if prediction_time == 0
|
||||
else agent.position + (agent.linear_velocity * prediction_time))
|
||||
|
||||
|
||||
var distance := path.calculate_distance(location)
|
||||
var target_distance := distance + path_offset
|
||||
|
||||
|
||||
var target_position := path.calculate_target_position(target_distance)
|
||||
|
||||
|
||||
if arrive_enabled and path.open:
|
||||
if path_offset >= 0:
|
||||
if target_distance > path.length - deceleration_radius:
|
||||
@ -42,9 +42,9 @@ func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAccele
|
||||
else:
|
||||
if target_distance < deceleration_radius:
|
||||
return _arrive(acceleration, target_position)
|
||||
|
||||
|
||||
acceleration.linear = (target_position - agent.position).normalized()
|
||||
acceleration.linear *= agent.linear_acceleration_max
|
||||
acceleration.angular = 0
|
||||
|
||||
|
||||
return acceleration
|
||||
|
@ -1,4 +1,5 @@
|
||||
# Calculates an angular acceleration to match an agent's orientation to its direction of travel.
|
||||
# Calculates an angular acceleration to match an agent's orientation to its
|
||||
# direction of travel.
|
||||
class_name GSTLookWhereYouGo
|
||||
extends GSTMatchOrientation
|
||||
|
||||
|
@ -1,14 +1,16 @@
|
||||
# Calculates an angular acceleration to match an agent's orientation to its target's.
|
||||
# The calculation will attempt to arrive with zero remaining angular velocity.
|
||||
# Calculates an angular acceleration to match an agent's orientation to that of
|
||||
# its target. Attempts to make the agent arrive with zero remaining angular
|
||||
# velocity.
|
||||
class_name GSTMatchOrientation
|
||||
extends GSTSteeringBehavior
|
||||
|
||||
|
||||
# The target orientation for the behavior to try and match rotations to
|
||||
# The target orientation for the behavior to try and match rotations to.
|
||||
var target: GSTAgentLocation
|
||||
# The amount of distance in radians for the behavior to consider itself close enough to match
|
||||
# The amount of distance in radians for the behavior to consider itself close
|
||||
# enough to be matching the target agent's rotation.
|
||||
var alignment_tolerance: float
|
||||
# The amount of distance in radians from the goal to start slowing down
|
||||
# The amount of distance in radians from the goal to start slowing down.
|
||||
var deceleration_radius: float
|
||||
# The amount of time to reach the target velocity
|
||||
var time_to_reach: float = 0.1
|
||||
@ -27,20 +29,20 @@ func _match_orientation(acceleration: GSTTargetAcceleration, desired_orientation
|
||||
acceleration.set_zero()
|
||||
else:
|
||||
var desired_rotation := agent.angular_speed_max
|
||||
|
||||
|
||||
if rotation_size <= deceleration_radius:
|
||||
desired_rotation *= rotation_size / deceleration_radius
|
||||
|
||||
|
||||
desired_rotation *= rotation / rotation_size
|
||||
|
||||
|
||||
acceleration.angular = (desired_rotation - agent.angular_velocity) / time_to_reach
|
||||
|
||||
|
||||
var limited_acceleration := abs(acceleration.angular)
|
||||
if limited_acceleration > agent.angular_acceleration_max:
|
||||
acceleration.angular *= agent.angular_acceleration_max / limited_acceleration
|
||||
|
||||
|
||||
acceleration.linear = Vector3.ZERO
|
||||
|
||||
|
||||
return acceleration
|
||||
|
||||
|
||||
|
@ -1,13 +1,15 @@
|
||||
# Contains multiple behaviors and returns only the result of the first with non-zero acceleration.
|
||||
# Container for multiple behaviors that returns the result of the first child
|
||||
# behavior with non-zero acceleration.
|
||||
class_name GSTPriority
|
||||
extends GSTSteeringBehavior
|
||||
|
||||
|
||||
var _behaviors := []
|
||||
|
||||
# The index in the behavior array of the last behavior that was selected.
|
||||
# The index of the last behavior the container prioritized.
|
||||
var last_selected_index: int
|
||||
# The amount of acceleration for a behavior to be considered to have effectively zero acceleration
|
||||
# If a behavior's acceleration is lower than this threshold, the container
|
||||
# considers it has an acceleration of zero.
|
||||
var zero_threshold: float
|
||||
|
||||
|
||||
@ -15,13 +17,13 @@ func _init(agent: GSTSteeringAgent, zero_threshold := 0.001).(agent) -> void:
|
||||
self.zero_threshold = zero_threshold
|
||||
|
||||
|
||||
# Add a steering `behavior` to the pool of behaviors to consider
|
||||
# Appends a steering behavior as a child of this container.
|
||||
func add(behavior: GSTSteeringBehavior) -> void:
|
||||
_behaviors.append(behavior)
|
||||
|
||||
|
||||
# Returns the behavior at the position in the pool referred to by `index`.
|
||||
# Returns `null` if none were found.
|
||||
# Returns the behavior at the position in the pool referred to by `index`, or
|
||||
# `null` if no behavior was found.
|
||||
func get_behavior_at(index: int) -> GSTSteeringBehavior:
|
||||
if _behaviors.size() > index:
|
||||
return _behaviors[index]
|
||||
@ -31,20 +33,20 @@ func get_behavior_at(index: int) -> GSTSteeringBehavior:
|
||||
|
||||
func _calculate_steering(accel: GSTTargetAcceleration) -> GSTTargetAcceleration:
|
||||
var threshold_squared := zero_threshold * zero_threshold
|
||||
|
||||
|
||||
last_selected_index = -1
|
||||
|
||||
|
||||
var size := _behaviors.size()
|
||||
|
||||
|
||||
if size > 0:
|
||||
for i in range(size):
|
||||
last_selected_index = i
|
||||
var behavior: GSTSteeringBehavior = _behaviors[i]
|
||||
behavior.calculate_steering(accel)
|
||||
|
||||
|
||||
if accel.get_magnitude_squared() > threshold_squared:
|
||||
break
|
||||
else:
|
||||
accel.set_zero()
|
||||
|
||||
|
||||
return accel
|
||||
|
@ -1,12 +1,13 @@
|
||||
# Calculates acceleration to take an agent to intersect with where a target agent will be, instead
|
||||
# of where it currently is.
|
||||
# Calculates an acceleration to make an agent intercept another based on the
|
||||
# target agent's movement.
|
||||
class_name GSTPursue
|
||||
extends GSTSteeringBehavior
|
||||
|
||||
|
||||
# The target agent that the behavior is trying to intercept
|
||||
# The target agent that the behavior is trying to intercept.
|
||||
var target: GSTSteeringAgent
|
||||
# The maximum amount of time in the future for the behavior to predict the target's position
|
||||
# The maximum amount of time in the future the behavior predicts the target's
|
||||
# location.
|
||||
var predict_time_max: float
|
||||
|
||||
|
||||
@ -21,21 +22,21 @@ func _init(
|
||||
func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration:
|
||||
var target_position := target.position
|
||||
var distance_squared := (target_position - agent.position).length_squared()
|
||||
|
||||
|
||||
var speed_squared := agent.linear_velocity.length_squared()
|
||||
var predict_time := predict_time_max
|
||||
|
||||
|
||||
if speed_squared > 0:
|
||||
var predict_time_squared := distance_squared / speed_squared
|
||||
if predict_time_squared < predict_time_max * predict_time_max:
|
||||
predict_time = sqrt(predict_time_squared)
|
||||
|
||||
|
||||
acceleration.linear = ((
|
||||
target_position + (target.linear_velocity * predict_time))-agent.position).normalized()
|
||||
acceleration.linear *= _get_modified_acceleration()
|
||||
|
||||
|
||||
acceleration.angular = 0
|
||||
|
||||
|
||||
return acceleration
|
||||
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
# Calculates acceleration to take an agent to a target agent's position directly
|
||||
# Calculates an acceleration to take an agent to a target agent's position
|
||||
# directly.
|
||||
class_name GSTSeek
|
||||
extends GSTSteeringBehavior
|
||||
|
||||
|
||||
# The target that the behavior aims to move the agent to
|
||||
# The target that the behavior aims to move the agent to.
|
||||
var target: GSTAgentLocation
|
||||
|
||||
|
||||
@ -15,5 +16,5 @@ func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAccele
|
||||
acceleration.linear = (
|
||||
(target.position - agent.position).normalized() * agent.linear_acceleration_max)
|
||||
acceleration.angular = 0
|
||||
|
||||
|
||||
return acceleration
|
||||
|
@ -1,15 +1,16 @@
|
||||
# Group behavior that produces acceleration that repels the agent from the other neighbors that
|
||||
# are in the area defined by the given `GSTProximity`.
|
||||
#
|
||||
# The produced acceleration is an average of all agents under consideration, multiplied by a
|
||||
# strength decreasing by the inverse square law in relation to distance, and accumulated.
|
||||
# Calculates an acceleration that repels the agent from its neighbors in the
|
||||
# given `GSTProximity`.
|
||||
#
|
||||
# The acceleration is an average based on all neighbors, multiplied by a
|
||||
# strength decreasing by the inverse square law in relation to distance, and it
|
||||
# accumulates.
|
||||
class_name GSTSeparation
|
||||
extends GSTGroupBehavior
|
||||
|
||||
|
||||
# The coefficient to calculate how fast the separation strength decays with distance.
|
||||
var decay_coefficient := 1.0
|
||||
|
||||
# Container for the calculated acceleration.
|
||||
var acceleration: GSTTargetAcceleration
|
||||
|
||||
|
||||
@ -35,7 +36,7 @@ func report_neighbor(neighbor: GSTSteeringAgent) -> bool:
|
||||
var strength := decay_coefficient / distance_squared
|
||||
if strength > acceleration_max:
|
||||
strength = acceleration_max
|
||||
|
||||
|
||||
acceleration.linear += to_agent * (strength / sqrt(distance_squared))
|
||||
|
||||
return true
|
||||
|
@ -1,7 +1,6 @@
|
||||
# Represents a path made up of Vector3 waypoints, split into path segments for use by path
|
||||
# following behaviors.
|
||||
extends Reference
|
||||
class_name GSTPath
|
||||
# Represents a path made up of Vector3 waypoints, split into segments path
|
||||
# follow behaviors can use.
|
||||
extends Reference class_name GSTPath
|
||||
|
||||
|
||||
# If `false`, the path loops.
|
||||
@ -27,12 +26,12 @@ func create_path(waypoints: Array) -> void:
|
||||
if not waypoints or waypoints.size() < 2:
|
||||
printerr("Waypoints cannot be null and must contain at least two (2) waypoints.")
|
||||
return
|
||||
|
||||
|
||||
_segments = []
|
||||
length = 0
|
||||
var current: Vector3 = waypoints.front()
|
||||
var previous: Vector3
|
||||
|
||||
|
||||
for i in range(1, waypoints.size(), 1):
|
||||
previous = current
|
||||
if i < waypoints.size():
|
||||
@ -60,16 +59,16 @@ func calculate_distance(agent_current_position: Vector3) -> float:
|
||||
segment.end,
|
||||
agent_current_position
|
||||
)
|
||||
|
||||
|
||||
if distance_squared < smallest_distance_squared:
|
||||
_nearest_point_on_path = _nearest_point_on_segment
|
||||
smallest_distance_squared = distance_squared
|
||||
nearest_segment = segment
|
||||
|
||||
|
||||
var length_on_path := (
|
||||
nearest_segment.cumulative_length -
|
||||
nearest_segment.cumulative_length -
|
||||
_nearest_point_on_path.distance_to(nearest_segment.end))
|
||||
|
||||
|
||||
return length_on_path
|
||||
|
||||
|
||||
@ -82,19 +81,19 @@ func calculate_target_position(target_distance: float) -> Vector3:
|
||||
target_distance = length + fmod(target_distance, length)
|
||||
elif target_distance > length:
|
||||
target_distance = fmod(target_distance, length)
|
||||
|
||||
|
||||
var desired_segment: GSTSegment
|
||||
for i in range(_segments.size()):
|
||||
var segment: GSTSegment = _segments[i]
|
||||
if segment.cumulative_length >= target_distance:
|
||||
desired_segment = segment
|
||||
break
|
||||
|
||||
|
||||
if not desired_segment:
|
||||
desired_segment = _segments.back()
|
||||
|
||||
|
||||
var distance := desired_segment.cumulative_length - target_distance
|
||||
|
||||
|
||||
return (
|
||||
(desired_segment.begin - desired_segment.end) *
|
||||
(distance / desired_segment.length) + desired_segment.end)
|
||||
@ -117,7 +116,7 @@ func _calculate_point_segment_distance_squared(start: Vector3, end: Vector3, pos
|
||||
if start_end_length_squared != 0:
|
||||
var t = (position - start).dot(start_end) / start_end_length_squared
|
||||
_nearest_point_on_segment += start_end * clamp(t, 0, 1)
|
||||
|
||||
|
||||
return _nearest_point_on_segment.distance_squared_to(position)
|
||||
|
||||
|
||||
@ -126,8 +125,8 @@ class GSTSegment:
|
||||
var end: Vector3
|
||||
var length: float
|
||||
var cumulative_length: float
|
||||
|
||||
|
||||
|
||||
|
||||
func _init(begin: Vector3, end: Vector3) -> void:
|
||||
self.begin = begin
|
||||
self.end = end
|
||||
|
@ -23,34 +23,34 @@ func _init(agent: GSTSteeringAgent, agents: Array, radius: float).(agent, agents
|
||||
func find_neighbors(callback: FuncRef) -> int:
|
||||
var agent_count := agents.size()
|
||||
var neighbor_count := 0
|
||||
|
||||
|
||||
var current_frame := _scene_tree.get_frame() if _scene_tree else -_last_frame
|
||||
if current_frame != _last_frame:
|
||||
_last_frame = current_frame
|
||||
|
||||
|
||||
var owner_position := agent.position
|
||||
|
||||
|
||||
for i in range(agent_count):
|
||||
var current_agent := agents[i] as GSTSteeringAgent
|
||||
|
||||
|
||||
if current_agent != agent:
|
||||
var distance_squared := owner_position.distance_squared_to(current_agent.position)
|
||||
|
||||
|
||||
var range_to := radius + current_agent.bounding_radius
|
||||
|
||||
|
||||
if distance_squared < range_to * range_to:
|
||||
if callback.call_func(current_agent):
|
||||
current_agent.tagged = true
|
||||
neighbor_count += 1
|
||||
continue
|
||||
|
||||
|
||||
current_agent.tagged = false
|
||||
else:
|
||||
for i in range(agent_count):
|
||||
var current_agent = agents[i] as GSTSteeringAgent
|
||||
|
||||
|
||||
if current_agent != agent and current_agent.tagged:
|
||||
if callback.call_func(current_agent):
|
||||
neighbor_count += 1
|
||||
|
||||
|
||||
return neighbor_count
|
||||
|
Loading…
Reference in New Issue
Block a user