mirror of
https://github.com/Relintai/godot-steering-ai-framework.git
synced 2024-11-14 04:57:19 +01:00
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:
parent
2d8bdaebd7
commit
6276fc0413
@ -14,7 +14,6 @@ var deceleration_radius: float
|
||||
var time_to_reach := 0.1
|
||||
|
||||
|
||||
# Initializes the behavior
|
||||
func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent) -> void:
|
||||
self.target = target
|
||||
|
||||
@ -22,22 +21,22 @@ func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent) -> void:
|
||||
func _arrive(acceleration: GSTTargetAcceleration, target_position: Vector3) -> GSTTargetAcceleration:
|
||||
var to_target := target_position - agent.position
|
||||
var distance := to_target.length()
|
||||
|
||||
|
||||
if distance <= arrival_tolerance:
|
||||
acceleration.set_zero()
|
||||
else:
|
||||
var desired_speed := agent.linear_speed_max
|
||||
|
||||
|
||||
if distance <= deceleration_radius:
|
||||
desired_speed *= distance / deceleration_radius
|
||||
|
||||
|
||||
var desired_velocity := to_target * desired_speed/distance
|
||||
|
||||
|
||||
desired_velocity = (desired_velocity - agent.linear_velocity) * 1.0 / time_to_reach
|
||||
|
||||
|
||||
acceleration.linear = GSTUtils.clampedv3(desired_velocity, agent.linear_acceleration_max)
|
||||
acceleration.angular = 0
|
||||
|
||||
|
||||
return acceleration
|
||||
|
||||
|
||||
|
@ -11,7 +11,6 @@ var first_relative_position: Vector3
|
||||
var first_relative_velocity: Vector3
|
||||
|
||||
|
||||
# Intializes the behavior
|
||||
func _init(agent: GSTSteeringAgent, proximity: GSTProximity).(agent, proximity) -> void:
|
||||
pass
|
||||
|
||||
|
@ -13,7 +13,6 @@ var _behaviors := []
|
||||
var _accel := GSTTargetAcceleration.new()
|
||||
|
||||
|
||||
# Initializes the behavior
|
||||
func _init(agent: GSTSteeringAgent).(agent) -> void:
|
||||
pass
|
||||
|
||||
|
@ -7,7 +7,6 @@ extends GSTGroupBehavior
|
||||
var center_of_mass: Vector3
|
||||
|
||||
|
||||
# Initializes the behavior
|
||||
func _init(agent: GSTSteeringAgent, proximity: GSTProximity).(agent, proximity) -> void:
|
||||
pass
|
||||
|
||||
|
@ -3,7 +3,6 @@ extends GSTPursue
|
||||
# Calculates acceleration to take an agent away from where a target agent will be.
|
||||
|
||||
|
||||
# Initializes the behavior
|
||||
func _init(
|
||||
agent: GSTSteeringAgent,
|
||||
target: GSTSteeringAgent,
|
||||
|
@ -4,7 +4,6 @@ extends GSTMatchOrientation
|
||||
# The acceleration will attempt to arrive with zero remaining angular velocity.
|
||||
|
||||
|
||||
# Initializes the behavior
|
||||
func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent, target) -> void:
|
||||
pass
|
||||
|
||||
|
@ -3,7 +3,6 @@ extends GSTSeek
|
||||
# Calculates acceleration to take an agent directly away from a target agent.
|
||||
|
||||
|
||||
# Initializes the behavior
|
||||
func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent, target) -> void:
|
||||
pass
|
||||
|
||||
|
@ -15,7 +15,6 @@ var arrive_enabled := true
|
||||
var prediction_time := 0.0
|
||||
|
||||
|
||||
# Initializes the behavior
|
||||
func _init(
|
||||
agent: GSTSteeringAgent,
|
||||
path: GSTPath,
|
||||
|
@ -3,7 +3,6 @@ extends GSTMatchOrientation
|
||||
# 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:
|
||||
pass
|
||||
|
||||
|
@ -14,7 +14,6 @@ var deceleration_radius: float
|
||||
var time_to_reach: float = 0.1
|
||||
|
||||
|
||||
# Initializes the behavior
|
||||
func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent) -> void:
|
||||
self.target = target
|
||||
|
||||
|
@ -11,7 +11,6 @@ var last_selected_index: int
|
||||
var zero_threshold: float
|
||||
|
||||
|
||||
# Initializes the behavior
|
||||
func _init(agent: GSTSteeringAgent, zero_threshold := 0.001).(agent) -> void:
|
||||
self.zero_threshold = zero_threshold
|
||||
|
||||
|
@ -10,7 +10,6 @@ var target: GSTSteeringAgent
|
||||
var predict_time_max: float
|
||||
|
||||
|
||||
# Initializes the behavior
|
||||
func _init(
|
||||
agent: GSTSteeringAgent,
|
||||
target: GSTSteeringAgent,
|
||||
|
@ -7,7 +7,6 @@ extends GSTSteeringBehavior
|
||||
var target: GSTAgentLocation
|
||||
|
||||
|
||||
# Initializes the behavior
|
||||
func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent) -> void:
|
||||
self.target = target
|
||||
|
||||
|
@ -13,7 +13,6 @@ var decay_coefficient := 1.0
|
||||
var acceleration: GSTTargetAcceleration
|
||||
|
||||
|
||||
# Initializes the behavior
|
||||
func _init(agent: GSTSteeringAgent, proximity: GSTProximity).(agent, proximity) -> void:
|
||||
pass
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
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.
|
||||
|
@ -1,19 +1,19 @@
|
||||
extends GSTSteeringBehavior
|
||||
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 _callback := funcref(self, "report_neighbor")
|
||||
|
||||
|
||||
# Initializes the behavior
|
||||
func _init(agent: GSTSteeringAgent, proximity: GSTProximity).(agent) -> void:
|
||||
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:
|
||||
return false
|
||||
|
@ -1,136 +1,110 @@
|
||||
extends Reference
|
||||
class_name GSTPath
|
||||
# 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.
|
||||
|
||||
|
||||
# Whether the path is a loop, or has its start and end disconnected and open ended
|
||||
# If `false`, the path loops.
|
||||
var open: bool
|
||||
# The length of the full path
|
||||
# Total length of the path.
|
||||
var length: float
|
||||
|
||||
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:
|
||||
self.open = open
|
||||
create_path(waypoints)
|
||||
_nearest_point_on_segment = waypoints[0]
|
||||
_nearest_point_on_path = waypoints[0]
|
||||
self.open = open create_path(waypoints) _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:
|
||||
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
|
||||
|
||||
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():
|
||||
current = waypoints[i]
|
||||
elif open:
|
||||
break
|
||||
else:
|
||||
current = waypoints[0]
|
||||
var segment := GSTSegment.new(previous, current)
|
||||
length += segment.length
|
||||
segment.cumulative_length = length
|
||||
previous = current if i < waypoints.size():
|
||||
current = waypoints[i] elif open:
|
||||
break else:
|
||||
current = waypoints[0] var segment := GSTSegment.new(previous,
|
||||
current) length += segment.length segment.cumulative_length = length
|
||||
_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:
|
||||
if _segments.size() == 0:
|
||||
return 0.0
|
||||
var smallest_distance_squared: float = INF
|
||||
var nearest_segment: GSTSegment
|
||||
for i in range(_segments.size()):
|
||||
var segment: GSTSegment = _segments[i]
|
||||
var distance_squared := _calculate_point_segment_distance_squared(
|
||||
segment.begin,
|
||||
segment.end,
|
||||
agent_current_position
|
||||
return 0.0 var smallest_distance_squared: float = INF var
|
||||
nearest_segment: GSTSegment for i in range(_segments.size()):
|
||||
var segment: GSTSegment = _segments[i] var distance_squared :=
|
||||
_calculate_point_segment_distance_squared(
|
||||
segment.begin, 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
|
||||
|
||||
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
|
||||
|
||||
|
||||
# Calculates the target position on the path based on the provided `target_distance` from the
|
||||
# path's starting point.
|
||||
# Calculates a target position from the path's starting point based on the `target_distance`.
|
||||
func calculate_target_position(target_distance: float) -> Vector3:
|
||||
if open:
|
||||
target_distance = clamp(target_distance, 0, length)
|
||||
else:
|
||||
target_distance = clamp(target_distance, 0, length) else:
|
||||
if target_distance < 0:
|
||||
target_distance = length + fmod(target_distance, length)
|
||||
elif target_distance > length:
|
||||
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
|
||||
|
||||
|
||||
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)
|
||||
(desired_segment.begin - desired_segment.end) * (distance /
|
||||
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:
|
||||
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:
|
||||
return _segments.back().end
|
||||
|
||||
|
||||
func _calculate_point_segment_distance_squared(start: Vector3, end: Vector3, position: Vector3) -> float:
|
||||
_nearest_point_on_segment = start
|
||||
var start_end := end - start
|
||||
var start_end_length_squared := start_end.length_squared()
|
||||
if start_end_length_squared != 0:
|
||||
func _calculate_point_segment_distance_squared(start: Vector3, end: Vector3,
|
||||
position: Vector3) -> float:
|
||||
_nearest_point_on_segment = start var start_end := end - start var
|
||||
start_end_length_squared := start_end.length_squared() 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)
|
||||
|
||||
|
||||
class GSTSegment:
|
||||
var begin: Vector3
|
||||
var end: Vector3
|
||||
var length: float
|
||||
var cumulative_length: float
|
||||
|
||||
|
||||
var begin: Vector3 var end: Vector3 var length: float var cumulative_length:
|
||||
float
|
||||
|
||||
func _init(begin: Vector3, end: Vector3) -> void:
|
||||
self.begin = begin
|
||||
self.end = end
|
||||
length = begin.distance_to(end)
|
||||
self.begin = begin self.end = end length = begin.distance_to(end)
|
||||
|
@ -1,24 +1,28 @@
|
||||
extends GSTAgentLocation
|
||||
class_name GSTSteeringAgent
|
||||
# An extended `GSTAgentLocation` that adds velocity, speed, and size data. It is the character's
|
||||
# responsibility to keep this information up to date for the steering toolkit to work correctly.
|
||||
# Adds velocity, speed, and size data to `GSTAgentLocation`.
|
||||
#
|
||||
# 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.
|
||||
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
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
# The current speed in a given direction the agent is traveling at.
|
||||
# Current velocity of the agent.
|
||||
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
|
||||
# The radius of the sphere that approximates the agent's size in space.
|
||||
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
|
||||
|
@ -1,24 +1,25 @@
|
||||
class_name GSTSteeringBehavior
|
||||
# The base class for all steering behaviors to extend. A steering behavior calculates the linear
|
||||
# and/or angular acceleration to be applied to its owning agent
|
||||
#
|
||||
# The entry point for all behaviors is the `calculate_steering` function. Everything else is
|
||||
# self-contained within the behavior.
|
||||
# Base class for all steering behaviors.
|
||||
#
|
||||
# Steering behaviors calculate the linear and the angular acceleration to be
|
||||
# to the agent that owns them.
|
||||
#
|
||||
# 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.
|
||||
# Defaults to true
|
||||
# If `false`, all calculations return zero amounts of acceleration.
|
||||
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
|
||||
|
||||
|
||||
# Initializes the behavior
|
||||
func _init(agent: GSTSteeringAgent) -> void:
|
||||
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:
|
||||
if enabled:
|
||||
return _calculate_steering(acceleration)
|
||||
|
@ -1,14 +1,15 @@
|
||||
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
|
||||
# The angular amount of acceleration
|
||||
# Angular acceleration
|
||||
var angular := 0.0
|
||||
|
||||
|
||||
# Sets the linear and angular components to 0
|
||||
# Sets the linear and angular components to 0.
|
||||
func set_zero() -> void:
|
||||
linear.x = 0.0
|
||||
linear.y = 0.0
|
||||
@ -22,11 +23,11 @@ func add_scaled_accel(accel: GSTTargetAcceleration, scalar: float) -> void:
|
||||
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:
|
||||
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:
|
||||
return sqrt(get_magnitude_squared())
|
||||
|
@ -1,8 +1,8 @@
|
||||
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:
|
||||
var length_squared := vector.length_squared()
|
||||
var limit_squared := limit * limit
|
||||
@ -11,7 +11,9 @@ static func clampedv3(vector: Vector3, limit: float) -> Vector3:
|
||||
return vector
|
||||
|
||||
|
||||
# Returns the provided vector as an angle in radians. This assumes orientation for 2D
|
||||
# agents or 3D agents that are upright and rotate around the Y axis.
|
||||
# Returns an angle in radians between the positive X axis and the `vector`.
|
||||
#
|
||||
# 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:
|
||||
return atan2(vector.x, -vector.y)
|
||||
|
@ -1,12 +1,17 @@
|
||||
extends GSTProximity
|
||||
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:
|
||||
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:
|
||||
var neighbor_count := 0
|
||||
var agent_count := agents.size()
|
||||
@ -16,5 +21,5 @@ func find_neighbors(callback: FuncRef) -> int:
|
||||
if current_agent != agent:
|
||||
if callback.call_func(current_agent):
|
||||
neighbor_count += 1
|
||||
|
||||
|
||||
return neighbor_count
|
||||
|
@ -1,7 +1,6 @@
|
||||
extends Reference
|
||||
class_name GSTProximity
|
||||
# Defines a way to determine any agent that is in the specified list as being neighbors with the
|
||||
# owner agent.
|
||||
# Base container type that stores data to find the neighbors of an agent.
|
||||
|
||||
|
||||
var agent: GSTSteeringAgent
|
||||
|
Loading…
Reference in New Issue
Block a user