Update code reference

Proof and edit docstrings in all the base types and proximity types
Remove docstring for the _init builtin callback
This commit is contained in:
Nathan Lovato 2020-01-27 17:31:10 -06:00
parent 2d8bdaebd7
commit 6276fc0413
23 changed files with 114 additions and 142 deletions

View File

@ -14,7 +14,6 @@ var deceleration_radius: float
var time_to_reach := 0.1 var time_to_reach := 0.1
# Initializes the behavior
func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent) -> void: func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent) -> void:
self.target = target self.target = target
@ -22,22 +21,22 @@ func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent) -> void:
func _arrive(acceleration: GSTTargetAcceleration, target_position: Vector3) -> GSTTargetAcceleration: func _arrive(acceleration: GSTTargetAcceleration, target_position: Vector3) -> GSTTargetAcceleration:
var to_target := target_position - agent.position var to_target := target_position - agent.position
var distance := to_target.length() var distance := to_target.length()
if distance <= arrival_tolerance: if distance <= arrival_tolerance:
acceleration.set_zero() acceleration.set_zero()
else: else:
var desired_speed := agent.linear_speed_max var desired_speed := agent.linear_speed_max
if distance <= deceleration_radius: if distance <= deceleration_radius:
desired_speed *= distance / deceleration_radius desired_speed *= distance / deceleration_radius
var desired_velocity := to_target * desired_speed/distance var desired_velocity := to_target * desired_speed/distance
desired_velocity = (desired_velocity - agent.linear_velocity) * 1.0 / time_to_reach desired_velocity = (desired_velocity - agent.linear_velocity) * 1.0 / time_to_reach
acceleration.linear = GSTUtils.clampedv3(desired_velocity, agent.linear_acceleration_max) acceleration.linear = GSTUtils.clampedv3(desired_velocity, agent.linear_acceleration_max)
acceleration.angular = 0 acceleration.angular = 0
return acceleration return acceleration

View File

@ -11,7 +11,6 @@ var first_relative_position: Vector3
var first_relative_velocity: Vector3 var first_relative_velocity: Vector3
# Intializes the behavior
func _init(agent: GSTSteeringAgent, proximity: GSTProximity).(agent, proximity) -> void: func _init(agent: GSTSteeringAgent, proximity: GSTProximity).(agent, proximity) -> void:
pass pass

View File

@ -13,7 +13,6 @@ var _behaviors := []
var _accel := GSTTargetAcceleration.new() var _accel := GSTTargetAcceleration.new()
# Initializes the behavior
func _init(agent: GSTSteeringAgent).(agent) -> void: func _init(agent: GSTSteeringAgent).(agent) -> void:
pass pass

View File

@ -7,7 +7,6 @@ extends GSTGroupBehavior
var center_of_mass: Vector3 var center_of_mass: Vector3
# Initializes the behavior
func _init(agent: GSTSteeringAgent, proximity: GSTProximity).(agent, proximity) -> void: func _init(agent: GSTSteeringAgent, proximity: GSTProximity).(agent, proximity) -> void:
pass pass

View File

@ -3,7 +3,6 @@ extends GSTPursue
# 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 will be.
# Initializes the behavior
func _init( func _init(
agent: GSTSteeringAgent, agent: GSTSteeringAgent,
target: GSTSteeringAgent, target: GSTSteeringAgent,

View File

@ -4,7 +4,6 @@ extends GSTMatchOrientation
# The acceleration will attempt to arrive with zero remaining angular velocity. # The acceleration will attempt to arrive with zero remaining angular velocity.
# Initializes the behavior
func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent, target) -> void: func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent, target) -> void:
pass pass

View File

@ -3,7 +3,6 @@ extends GSTSeek
# Calculates acceleration to take an agent directly away from a target agent. # Calculates acceleration to take an agent directly away from a target agent.
# Initializes the behavior
func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent, target) -> void: func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent, target) -> void:
pass pass

View File

@ -15,7 +15,6 @@ var arrive_enabled := true
var prediction_time := 0.0 var prediction_time := 0.0
# Initializes the behavior
func _init( func _init(
agent: GSTSteeringAgent, agent: GSTSteeringAgent,
path: GSTPath, path: GSTPath,

View File

@ -3,7 +3,6 @@ extends GSTMatchOrientation
# 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.
# Initializes the behavior
func _init(agent: GSTSteeringAgent).(agent, null) -> void: func _init(agent: GSTSteeringAgent).(agent, null) -> void:
pass pass

View File

@ -14,7 +14,6 @@ var deceleration_radius: float
var time_to_reach: float = 0.1 var time_to_reach: float = 0.1
# Initializes the behavior
func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent) -> void: func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent) -> void:
self.target = target self.target = target

View File

@ -11,7 +11,6 @@ var last_selected_index: int
var zero_threshold: float var zero_threshold: float
# Initializes the behavior
func _init(agent: GSTSteeringAgent, zero_threshold := 0.001).(agent) -> void: func _init(agent: GSTSteeringAgent, zero_threshold := 0.001).(agent) -> void:
self.zero_threshold = zero_threshold self.zero_threshold = zero_threshold

View File

@ -10,7 +10,6 @@ var target: GSTSteeringAgent
var predict_time_max: float var predict_time_max: float
# Initializes the behavior
func _init( func _init(
agent: GSTSteeringAgent, agent: GSTSteeringAgent,
target: GSTSteeringAgent, target: GSTSteeringAgent,

View File

@ -7,7 +7,6 @@ extends GSTSteeringBehavior
var target: GSTAgentLocation var target: GSTAgentLocation
# Initializes the behavior
func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent) -> void: func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent) -> void:
self.target = target self.target = target

View File

@ -13,7 +13,6 @@ var decay_coefficient := 1.0
var acceleration: GSTTargetAcceleration var acceleration: GSTTargetAcceleration
# Initializes the behavior
func _init(agent: GSTSteeringAgent, proximity: GSTProximity).(agent, proximity) -> void: func _init(agent: GSTSteeringAgent, proximity: GSTProximity).(agent, proximity) -> void:
pass pass

View File

@ -1,5 +1,5 @@
class_name GSTAgentLocation class_name GSTAgentLocation
# Data type to represent an agent with a location and an orientation only. # Represents an agent with only a location and an orientation.
# The agent's position in space. # The agent's position in space.

View File

@ -1,19 +1,19 @@
extends GSTSteeringBehavior extends GSTSteeringBehavior
class_name GSTGroupBehavior class_name GSTGroupBehavior
# Extended behavior that features a Proximity group for group-based behaviors. # Base type for group-based steering behaviors.
# The group area definition that will be used to find the owning agent's neighbors # Container to find neighbors of the agent and apply a group behavior.
var proximity: GSTProximity var proximity: GSTProximity
var _callback := funcref(self, "report_neighbor") var _callback := funcref(self, "report_neighbor")
# Initializes the behavior
func _init(agent: GSTSteeringAgent, proximity: GSTProximity).(agent) -> void: func _init(agent: GSTSteeringAgent, proximity: GSTProximity).(agent) -> void:
self.proximity = proximity self.proximity = proximity
# Internal callback for the behavior to define whether or not a member is relevant # Internal callback for the behavior to define whether or not a member is
# relevant
func report_neighbor(neighbor: GSTSteeringAgent) -> bool: func report_neighbor(neighbor: GSTSteeringAgent) -> bool:
return false return false

View File

@ -1,136 +1,110 @@
extends Reference extends Reference class_name GSTPath
class_name GSTPath # Represents a path made up of Vector3 waypoints, split into segments path
# Represents a path made up of Vector3 waypoints, split into path segments for use by path # follow behaviors can use.
# following behaviors.
# Whether the path is a loop, or has its start and end disconnected and open ended # If `false`, the path loops.
var open: bool var open: bool
# The length of the full path # Total length of the path.
var length: float var length: float
var _segments: Array var _segments: Array
var _nearest_point_on_segment: Vector3 var _nearest_point_on_path: Vector3
var _nearest_point_on_segment: Vector3
var _nearest_point_on_path: Vector3
# Initializes and creates a path with the provided waypoints
func _init(waypoints: Array, open := false) -> void: func _init(waypoints: Array, open := false) -> void:
self.open = open self.open = open create_path(waypoints) _nearest_point_on_segment =
create_path(waypoints) waypoints[0] _nearest_point_on_path = waypoints[0]
_nearest_point_on_segment = waypoints[0]
_nearest_point_on_path = waypoints[0]
# Creates a path with the provided waypoints # Creates a path from a list of waypoints.
func create_path(waypoints: Array) -> void: func create_path(waypoints: Array) -> void:
if not waypoints or waypoints.size() < 2: if not waypoints or waypoints.size() < 2:
printerr("Waypoints cannot be null and must contain at least two (2) waypoints.") printerr("Waypoints cannot be null and must contain at least two (2)
return waypoints.") return
_segments = [] _segments = [] length = 0 var current: Vector3 = waypoints.front() var
length = 0 previous: Vector3
var current: Vector3 = waypoints.front()
var previous: Vector3
for i in range(1, waypoints.size(), 1): for i in range(1, waypoints.size(), 1):
previous = current previous = current if i < waypoints.size():
if i < waypoints.size(): current = waypoints[i] elif open:
current = waypoints[i] break else:
elif open: current = waypoints[0] var segment := GSTSegment.new(previous,
break current) length += segment.length segment.cumulative_length = length
else:
current = waypoints[0]
var segment := GSTSegment.new(previous, current)
length += segment.length
segment.cumulative_length = length
_segments.append(segment) _segments.append(segment)
# Returns the distance from the provided `agent_current_position` to the next point waypoint. # Returns the distance from `agent_current_position` to the next waypoint.
func calculate_distance(agent_current_position: Vector3) -> float: func calculate_distance(agent_current_position: Vector3) -> float:
if _segments.size() == 0: if _segments.size() == 0:
return 0.0 return 0.0 var smallest_distance_squared: float = INF var
var smallest_distance_squared: float = INF nearest_segment: GSTSegment for i in range(_segments.size()):
var nearest_segment: GSTSegment var segment: GSTSegment = _segments[i] var distance_squared :=
for i in range(_segments.size()): _calculate_point_segment_distance_squared(
var segment: GSTSegment = _segments[i] segment.begin, segment.end, agent_current_position
var distance_squared := _calculate_point_segment_distance_squared(
segment.begin,
segment.end,
agent_current_position
) )
if distance_squared < smallest_distance_squared: if distance_squared < smallest_distance_squared:
_nearest_point_on_path = _nearest_point_on_segment _nearest_point_on_path = _nearest_point_on_segment
smallest_distance_squared = distance_squared smallest_distance_squared = distance_squared nearest_segment =
nearest_segment = segment segment
var length_on_path := ( var length_on_path := (
nearest_segment.cumulative_length - nearest_segment.cumulative_length -
_nearest_point_on_path.distance_to(nearest_segment.end)) _nearest_point_on_path.distance_to(nearest_segment.end))
return length_on_path return length_on_path
# Calculates the target position on the path based on the provided `target_distance` from the # Calculates a target position from the path's starting point based on the `target_distance`.
# path's starting point.
func calculate_target_position(target_distance: float) -> Vector3: func calculate_target_position(target_distance: float) -> Vector3:
if open: if open:
target_distance = clamp(target_distance, 0, length) target_distance = clamp(target_distance, 0, length) else:
else:
if target_distance < 0: if target_distance < 0:
target_distance = length + fmod(target_distance, length) target_distance = length + fmod(target_distance, length) elif
elif target_distance > length: target_distance > length:
target_distance = fmod(target_distance, length) target_distance = fmod(target_distance, length)
var desired_segment: GSTSegment var desired_segment: GSTSegment for i in range(_segments.size()):
for i in range(_segments.size()): var segment: GSTSegment = _segments[i] if segment.cumulative_length >=
var segment: GSTSegment = _segments[i] target_distance:
if segment.cumulative_length >= target_distance: desired_segment = segment break
desired_segment = segment
break
if not desired_segment: if not desired_segment:
desired_segment = _segments.back() desired_segment = _segments.back()
var distance := desired_segment.cumulative_length - target_distance var distance := desired_segment.cumulative_length - target_distance
return ( return (
(desired_segment.begin - desired_segment.end) * (desired_segment.begin - desired_segment.end) * (distance /
(distance / desired_segment.length) + desired_segment.end) desired_segment.length) + desired_segment.end)
# Returns the position of the beginning point of the path # Returns the position of the first point on the path.
func get_start_point() -> Vector3: func get_start_point() -> Vector3:
return _segments.front().begin return _segments.front().begin
# Returns the position of the last point of the path # Returns the position of the last point on the path.
func get_end_point() -> Vector3: func get_end_point() -> Vector3:
return _segments.back().end return _segments.back().end
func _calculate_point_segment_distance_squared(start: Vector3, end: Vector3, position: Vector3) -> float: func _calculate_point_segment_distance_squared(start: Vector3, end: Vector3,
_nearest_point_on_segment = start position: Vector3) -> float:
var start_end := end - start _nearest_point_on_segment = start var start_end := end - start var
var start_end_length_squared := start_end.length_squared() start_end_length_squared := start_end.length_squared() if
if start_end_length_squared != 0: start_end_length_squared != 0:
var t = (position - start).dot(start_end) / start_end_length_squared var t = (position - start).dot(start_end) / start_end_length_squared
_nearest_point_on_segment += start_end * clamp(t, 0, 1) _nearest_point_on_segment += start_end * clamp(t, 0, 1)
return _nearest_point_on_segment.distance_squared_to(position) return _nearest_point_on_segment.distance_squared_to(position)
class GSTSegment: class GSTSegment:
var begin: Vector3 var begin: Vector3 var end: Vector3 var length: float var cumulative_length:
var end: Vector3 float
var length: float
var cumulative_length: float
func _init(begin: Vector3, end: Vector3) -> void: func _init(begin: Vector3, end: Vector3) -> void:
self.begin = begin self.begin = begin self.end = end length = begin.distance_to(end)
self.end = end
length = begin.distance_to(end)

View File

@ -1,24 +1,28 @@
extends GSTAgentLocation extends GSTAgentLocation
class_name GSTSteeringAgent class_name GSTSteeringAgent
# An extended `GSTAgentLocation` that adds velocity, speed, and size data. It is the character's # Adds velocity, speed, and size data to `GSTAgentLocation`.
# responsibility to keep this information up to date for the steering toolkit to work correctly. #
# It is the character's responsibility to keep this information up to date for
# the steering toolkit to work correctly.
# The amount of velocity to be considered effectively not moving. # The amount of velocity to be considered effectively not moving.
var zero_linear_speed_threshold := 0.01 var zero_linear_speed_threshold := 0.01
# The maximum amount of speed the agent can move at. # The maximum speed at which the agent can move.
var linear_speed_max := 0.0 var linear_speed_max := 0.0
# The maximum amount of acceleration that any behavior can apply to an agent. # The maximum amount of acceleration that any behavior can apply to the agent.
var linear_acceleration_max := 0.0 var linear_acceleration_max := 0.0
# The maximum amount of angular speed the agent can rotate at. # The maximum amount of angular speed at which the agent can rotate.
var angular_speed_max := 0.0 var angular_speed_max := 0.0
# The maximum amount of angular acceleration that any behavior can apply to an agent. # The maximum amount of angular acceleration that any behavior can apply to an
# agent.
var angular_acceleration_max := 0.0 var angular_acceleration_max := 0.0
# The current speed in a given direction the agent is traveling at. # Current velocity of the agent.
var linear_velocity := Vector3.ZERO var linear_velocity := Vector3.ZERO
# The current angular speed the agent is traveling at. # Current angular velocity of the agent.
var angular_velocity := 0.0 var angular_velocity := 0.0
# The radius of the sphere that approximates the agent's size in space. # The radius of the sphere that approximates the agent's size in space.
var bounding_radius := 0.0 var bounding_radius := 0.0
# Used internally by group behaviors and proximities to mark an agent as already considered. # Used internally by group behaviors and proximities to mark the agent as already
# considered.
var tagged := false var tagged := false

View File

@ -1,24 +1,25 @@
class_name GSTSteeringBehavior class_name GSTSteeringBehavior
# The base class for all steering behaviors to extend. A steering behavior calculates the linear # Base class for all steering behaviors.
# and/or angular acceleration to be applied to its owning agent #
# # Steering behaviors calculate the linear and the angular acceleration to be
# The entry point for all behaviors is the `calculate_steering` function. Everything else is # to the agent that owns them.
# self-contained within the behavior. #
# The `calculate_steering` function is the entry point for all behaviors.
# Individual steering behaviors encapsulate the steering logic.
# Whether this behavior is enabled. All disabled behaviors return zero amounts of acceleration. # If `false`, all calculations return zero amounts of acceleration.
# Defaults to true
var enabled := true var enabled := true
# The agent on which all steering calculations are to be made. # The AI agent on which the steering behavior bases its calculations.
var agent: GSTSteeringAgent var agent: GSTSteeringAgent
# Initializes the behavior
func _init(agent: GSTSteeringAgent) -> void: func _init(agent: GSTSteeringAgent) -> void:
self.agent = agent self.agent = agent
# Returns the `acceleration` parameter modified with the behavior's desired amount of acceleration # Returns the `acceleration` modified with the behavior's desired amount of
# acceleration.
func calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration: func calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration:
if enabled: if enabled:
return _calculate_steering(acceleration) return _calculate_steering(acceleration)

View File

@ -1,14 +1,15 @@
class_name GSTTargetAcceleration class_name GSTTargetAcceleration
# A desired linear and angular amount of acceleration requested by the steering system. # A desired linear and angular amount of acceleration requested by the steering
# system.
# The linear amount of acceleration # Linear acceleration
var linear := Vector3.ZERO var linear := Vector3.ZERO
# The angular amount of acceleration # Angular acceleration
var angular := 0.0 var angular := 0.0
# Sets the linear and angular components to 0 # Sets the linear and angular components to 0.
func set_zero() -> void: func set_zero() -> void:
linear.x = 0.0 linear.x = 0.0
linear.y = 0.0 linear.y = 0.0
@ -22,11 +23,11 @@ func add_scaled_accel(accel: GSTTargetAcceleration, scalar: float) -> void:
angular += accel.angular * scalar angular += accel.angular * scalar
# Returns the squared magnitude of the linear and angular components # Returns the squared magnitude of the linear and angular components.
func get_magnitude_squared() -> float: func get_magnitude_squared() -> float:
return linear.length_squared() + angular * angular return linear.length_squared() + angular * angular
# Returns the magnitude of the linear and angular components # Returns the magnitude of the linear and angular components.
func get_magnitude() -> float: func get_magnitude() -> float:
return sqrt(get_magnitude_squared()) return sqrt(get_magnitude_squared())

View File

@ -1,8 +1,8 @@
class_name GSTUtils class_name GSTUtils
# Useful math and vector manipulation functions to complement Godot's own. # Math and vector utility functions.
# Returns the provided `vector` with its length capped to `limit`. # Returns the `vector` with its length capped to `limit`.
static func clampedv3(vector: Vector3, limit: float) -> Vector3: static func clampedv3(vector: Vector3, limit: float) -> Vector3:
var length_squared := vector.length_squared() var length_squared := vector.length_squared()
var limit_squared := limit * limit var limit_squared := limit * limit
@ -11,7 +11,9 @@ static func clampedv3(vector: Vector3, limit: float) -> Vector3:
return vector return vector
# Returns the provided vector as an angle in radians. This assumes orientation for 2D # Returns an angle in radians between the positive X axis and the `vector`.
# agents or 3D agents that are upright and rotate around the Y axis. #
# This assumes orientation for 2D agents or 3D agents that are upright and
# rotate around the Y axis.
static func vector_to_angle(vector: Vector3) -> float: static func vector_to_angle(vector: Vector3) -> float:
return atan2(vector.x, -vector.y) return atan2(vector.x, -vector.y)

View File

@ -1,12 +1,17 @@
extends GSTProximity extends GSTProximity
class_name GSTInfiniteProximity class_name GSTInfiniteProximity
# Determines any agent that is in the specified list as being neighbors with the owner agent. # Determines any agent that is in the specified list as being neighbors with the
# owner agent.
func _init(agent: GSTSteeringAgent, agents: Array).(agent, agents) -> void: func _init(agent: GSTSteeringAgent, agents: Array).(agent, agents) -> void:
pass pass
# Returns a number of neighbors based on a `callback` function.
#
# `find_neighbors` calls `callback` for each agent in the `agents` array and
# adds one to the count it if `callback` returns true.
func find_neighbors(callback: FuncRef) -> int: func find_neighbors(callback: FuncRef) -> int:
var neighbor_count := 0 var neighbor_count := 0
var agent_count := agents.size() var agent_count := agents.size()
@ -16,5 +21,5 @@ func find_neighbors(callback: FuncRef) -> int:
if current_agent != agent: if current_agent != agent:
if callback.call_func(current_agent): if callback.call_func(current_agent):
neighbor_count += 1 neighbor_count += 1
return neighbor_count return neighbor_count

View File

@ -1,7 +1,6 @@
extends Reference extends Reference
class_name GSTProximity class_name GSTProximity
# Defines a way to determine any agent that is in the specified list as being neighbors with the # Base container type that stores data to find the neighbors of an agent.
# owner agent.
var agent: GSTSteeringAgent var agent: GSTSteeringAgent