From 57f3c4a24a247e8e0a14a31a85ac1b55d7f8d6d8 Mon Sep 17 00:00:00 2001 From: Francois Belair Date: Thu, 6 Feb 2020 14:46:21 -0500 Subject: [PATCH 1/6] Make calculate_acceleration return void This makes the code more in line with GDQuest gdscript guidelines about not both transforming state and returning a value. --- project/demos/Arrive/Arriver.gd | 2 +- project/demos/AvoidCollisions/Avoider.gd | 2 +- project/demos/Face/Turret.gd | 2 +- project/demos/FollowPath/PathFollower.gd | 2 +- project/demos/GroupBehaviors/Member.gd | 2 +- project/demos/PursueSeek/Pursuer.gd | 4 ++-- project/demos/SeekFlee/Seeker.gd | 4 ++-- project/src/Behaviors/GSTArrive.gd | 8 +++----- project/src/Behaviors/GSTAvoidCollisions.gd | 4 +--- project/src/Behaviors/GSTBlend.gd | 4 +--- project/src/Behaviors/GSTCohesion.gd | 3 +-- project/src/Behaviors/GSTFace.gd | 9 ++++----- project/src/Behaviors/GSTFlee.gd | 4 +--- project/src/Behaviors/GSTFollowPath.gd | 10 +++++----- project/src/Behaviors/GSTLookWhereYouGo.gd | 5 ++--- project/src/Behaviors/GSTMatchOrientation.gd | 8 +++----- project/src/Behaviors/GSTPriority.gd | 4 +--- project/src/Behaviors/GSTPursue.gd | 4 +--- project/src/Behaviors/GSTSeek.gd | 4 +--- project/src/Behaviors/GSTSeparation.gd | 3 +-- project/src/GSTSteeringBehavior.gd | 11 ++++------- 21 files changed, 38 insertions(+), 61 deletions(-) diff --git a/project/demos/Arrive/Arriver.gd b/project/demos/Arrive/Arriver.gd index 9a71df8..dedce81 100644 --- a/project/demos/Arrive/Arriver.gd +++ b/project/demos/Arrive/Arriver.gd @@ -12,7 +12,7 @@ var _drag := 0.1 func _physics_process(delta: float) -> void: _update_agent() - _accel = arrive.calculate_steering(_accel) + arrive.calculate_steering(_accel) _velocity += Vector2(_accel.linear.x, _accel.linear.y) _velocity = _velocity.linear_interpolate(Vector2.ZERO, _drag).clamped(agent.linear_speed_max) _velocity = move_and_slide(_velocity) diff --git a/project/demos/AvoidCollisions/Avoider.gd b/project/demos/AvoidCollisions/Avoider.gd index ad87840..7027e13 100644 --- a/project/demos/AvoidCollisions/Avoider.gd +++ b/project/demos/AvoidCollisions/Avoider.gd @@ -28,7 +28,7 @@ func _draw() -> void: func _physics_process(delta: float) -> void: _update_agent() - _accel = priority.calculate_steering(_accel) + priority.calculate_steering(_accel) _velocity += Vector2(_accel.linear.x, _accel.linear.y) _velocity = _velocity.linear_interpolate(Vector2.ZERO, _drag) _velocity = _velocity.clamped(agent.linear_speed_max) diff --git a/project/demos/Face/Turret.gd b/project/demos/Face/Turret.gd index 468bf54..38fa4fa 100644 --- a/project/demos/Face/Turret.gd +++ b/project/demos/Face/Turret.gd @@ -19,7 +19,7 @@ func _ready() -> void: func _physics_process(delta: float) -> void: - _accel = face.calculate_steering(_accel) + face.calculate_steering(_accel) agent.angular_velocity = clamp( agent.angular_velocity + _accel.angular, -agent.angular_speed_max, diff --git a/project/demos/FollowPath/PathFollower.gd b/project/demos/FollowPath/PathFollower.gd index c19c9a6..9445050 100644 --- a/project/demos/FollowPath/PathFollower.gd +++ b/project/demos/FollowPath/PathFollower.gd @@ -34,7 +34,7 @@ func setup( func _physics_process(delta: float) -> void: if _valid: _update_agent() - _accel = follow.calculate_steering(_accel) + follow.calculate_steering(_accel) _velocity += Vector2(_accel.linear.x, _accel.linear.y) _velocity = _velocity.linear_interpolate(Vector2.ZERO, _drag) _velocity = _velocity.clamped(agent.linear_speed_max) diff --git a/project/demos/GroupBehaviors/Member.gd b/project/demos/GroupBehaviors/Member.gd index 43eca39..f3285a1 100644 --- a/project/demos/GroupBehaviors/Member.gd +++ b/project/demos/GroupBehaviors/Member.gd @@ -46,7 +46,7 @@ func _physics_process(delta: float) -> void: agent.position.x = global_position.x agent.position.y = global_position.y if blend: - acceleration = blend.calculate_steering(acceleration) + blend.calculate_steering(acceleration) _velocity += Vector2(acceleration.linear.x, acceleration.linear.y) _velocity = _velocity.linear_interpolate(Vector2.ZERO, 0.1) _velocity = _velocity.clamped(agent.linear_speed_max) diff --git a/project/demos/PursueSeek/Pursuer.gd b/project/demos/PursueSeek/Pursuer.gd index 133fd57..86cf241 100644 --- a/project/demos/PursueSeek/Pursuer.gd +++ b/project/demos/PursueSeek/Pursuer.gd @@ -25,11 +25,11 @@ func _ready() -> void: func _physics_process(delta: float) -> void: _update_agent() - accel = _behavior.calculate_steering(accel) + _behavior.calculate_steering(accel) _direction_face.position = agent.position + accel.linear.normalized() - accel = _orient_behavior.calculate_steering(accel) + _orient_behavior.calculate_steering(accel) _angular_velocity += accel.angular _angular_velocity = clamp( diff --git a/project/demos/SeekFlee/Seeker.gd b/project/demos/SeekFlee/Seeker.gd index d27b381..5dd86d6 100644 --- a/project/demos/SeekFlee/Seeker.gd +++ b/project/demos/SeekFlee/Seeker.gd @@ -25,9 +25,9 @@ func _physics_process(delta: float) -> void: _update_agent() if use_seek: - accel = seek.calculate_steering(accel) + seek.calculate_steering(accel) else: - accel = flee.calculate_steering(accel) + flee.calculate_steering(accel) velocity = (velocity + Vector2(accel.linear.x, accel.linear.y)).clamped(agent.linear_speed_max) velocity = move_and_slide(velocity) diff --git a/project/src/Behaviors/GSTArrive.gd b/project/src/Behaviors/GSTArrive.gd index 8b4a8ce..17083be 100644 --- a/project/src/Behaviors/GSTArrive.gd +++ b/project/src/Behaviors/GSTArrive.gd @@ -19,7 +19,7 @@ func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent) -> void: self.target = target -func _arrive(acceleration: GSTTargetAcceleration, target_position: Vector3) -> GSTTargetAcceleration: +func _arrive(acceleration: GSTTargetAcceleration, target_position: Vector3) -> void: var to_target := target_position - agent.position var distance := to_target.length() @@ -38,8 +38,6 @@ func _arrive(acceleration: GSTTargetAcceleration, target_position: Vector3) -> G acceleration.linear = GSTUtils.clampedv3(desired_velocity, agent.linear_acceleration_max) acceleration.angular = 0 - return acceleration - -func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration: - return _arrive(acceleration, target.position) +func _calculate_steering(acceleration: GSTTargetAcceleration) -> void: + _arrive(acceleration, target.position) diff --git a/project/src/Behaviors/GSTAvoidCollisions.gd b/project/src/Behaviors/GSTAvoidCollisions.gd index d00afc0..711b744 100644 --- a/project/src/Behaviors/GSTAvoidCollisions.gd +++ b/project/src/Behaviors/GSTAvoidCollisions.gd @@ -16,7 +16,7 @@ func _init(agent: GSTSteeringAgent, proximity: GSTProximity).(agent, proximity) pass -func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration: +func _calculate_steering(acceleration: GSTTargetAcceleration) -> void: _shortest_time = INF _first_neighbor = null _first_minimum_separation = 0 @@ -37,8 +37,6 @@ func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAccele acceleration.linear = acceleration.linear.normalized() * -agent.linear_acceleration_max acceleration.angular = 0 - return acceleration - # 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. diff --git a/project/src/Behaviors/GSTBlend.gd b/project/src/Behaviors/GSTBlend.gd index 57daff3..db20eab 100644 --- a/project/src/Behaviors/GSTBlend.gd +++ b/project/src/Behaviors/GSTBlend.gd @@ -33,7 +33,7 @@ func get_behavior_at(index: int) -> Dictionary: return {} -func _calculate_steering(blended_accel: GSTTargetAcceleration) -> GSTTargetAcceleration: +func _calculate_steering(blended_accel: GSTTargetAcceleration) -> void: blended_accel.set_zero() for i in range(_behaviors.size()): @@ -48,5 +48,3 @@ func _calculate_steering(blended_accel: GSTTargetAcceleration) -> GSTTargetAccel -agent.angular_acceleration_max, agent.angular_acceleration_max ) - - return blended_accel diff --git a/project/src/Behaviors/GSTCohesion.gd b/project/src/Behaviors/GSTCohesion.gd index 062cc43..eb2c816 100644 --- a/project/src/Behaviors/GSTCohesion.gd +++ b/project/src/Behaviors/GSTCohesion.gd @@ -11,14 +11,13 @@ func _init(agent: GSTSteeringAgent, proximity: GSTProximity).(agent, proximity) pass -func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration: +func _calculate_steering(acceleration: GSTTargetAcceleration) -> void: acceleration.set_zero() _center_of_mass = Vector3.ZERO var neighbor_count = proximity._find_neighbors(_callback) if neighbor_count > 0: _center_of_mass *= 1.0 / neighbor_count acceleration.linear = (_center_of_mass - agent.position).normalized() * agent.linear_acceleration_max - return acceleration # Callback for the proximity to call when finding neighbors. Adds `neighbor`'s position diff --git a/project/src/Behaviors/GSTFace.gd b/project/src/Behaviors/GSTFace.gd index 81338a5..8a97e0b 100644 --- a/project/src/Behaviors/GSTFace.gd +++ b/project/src/Behaviors/GSTFace.gd @@ -8,17 +8,16 @@ func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent, target) -> pass -func _face(acceleration: GSTTargetAcceleration, target_position: Vector3) -> GSTTargetAcceleration: +func _face(acceleration: GSTTargetAcceleration, target_position: Vector3) -> void: 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 else: var orientation = GSTUtils.vector3_to_angle(to_target) - return _match_orientation(acceleration, orientation) + _match_orientation(acceleration, orientation) -func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration: - return _face(acceleration, target.position) +func _calculate_steering(acceleration: GSTTargetAcceleration) -> void: + _face(acceleration, target.position) diff --git a/project/src/Behaviors/GSTFlee.gd b/project/src/Behaviors/GSTFlee.gd index e5aa961..86c071b 100644 --- a/project/src/Behaviors/GSTFlee.gd +++ b/project/src/Behaviors/GSTFlee.gd @@ -7,9 +7,7 @@ func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent, target) -> pass -func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration: +func _calculate_steering(acceleration: GSTTargetAcceleration) -> void: acceleration.linear = ( (agent.position - target.position).normalized() * agent.linear_acceleration_max) acceleration.angular = 0 - - return acceleration diff --git a/project/src/Behaviors/GSTFollowPath.gd b/project/src/Behaviors/GSTFollowPath.gd index 9d634c9..384d2d2 100644 --- a/project/src/Behaviors/GSTFollowPath.gd +++ b/project/src/Behaviors/GSTFollowPath.gd @@ -25,7 +25,7 @@ func _init( self.prediction_time = prediction_time -func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration: +func _calculate_steering(acceleration: GSTTargetAcceleration) -> void: var location := ( agent.position if prediction_time == 0 else agent.position + (agent.linear_velocity * prediction_time)) @@ -38,13 +38,13 @@ func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAccele if is_arrive_enabled and path.is_open: if path_offset >= 0: if target_distance > path.length - deceleration_radius: - return _arrive(acceleration, target_position) + _arrive(acceleration, target_position) + return else: if target_distance < deceleration_radius: - return _arrive(acceleration, target_position) + _arrive(acceleration, target_position) + return acceleration.linear = (target_position - agent.position).normalized() acceleration.linear *= agent.linear_acceleration_max acceleration.angular = 0 - - return acceleration diff --git a/project/src/Behaviors/GSTLookWhereYouGo.gd b/project/src/Behaviors/GSTLookWhereYouGo.gd index 7229e11..9e254f3 100644 --- a/project/src/Behaviors/GSTLookWhereYouGo.gd +++ b/project/src/Behaviors/GSTLookWhereYouGo.gd @@ -8,10 +8,9 @@ func _init(agent: GSTSteeringAgent).(agent, null) -> void: pass -func _calculate_steering(accel: GSTTargetAcceleration) -> GSTTargetAcceleration: +func _calculate_steering(accel: GSTTargetAcceleration) -> void: if agent.linear_velocity.length_squared() < agent.zero_linear_speed_threshold: accel.set_zero() - return accel else: var orientation := GSTUtils.vector3_to_angle(agent.linear_velocity) - return _match_orientation(accel, orientation) + _match_orientation(accel, orientation) diff --git a/project/src/Behaviors/GSTMatchOrientation.gd b/project/src/Behaviors/GSTMatchOrientation.gd index d132280..a682d70 100644 --- a/project/src/Behaviors/GSTMatchOrientation.gd +++ b/project/src/Behaviors/GSTMatchOrientation.gd @@ -20,7 +20,7 @@ func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent) -> void: self.target = target -func _match_orientation(acceleration: GSTTargetAcceleration, desired_orientation: float) -> GSTTargetAcceleration: +func _match_orientation(acceleration: GSTTargetAcceleration, desired_orientation: float) -> void: var rotation := wrapf(desired_orientation - agent.orientation, -PI, PI) var rotation_size := abs(rotation) @@ -43,8 +43,6 @@ func _match_orientation(acceleration: GSTTargetAcceleration, desired_orientation acceleration.linear = Vector3.ZERO - return acceleration - -func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration: - return _match_orientation(acceleration, target.orientation) +func _calculate_steering(acceleration: GSTTargetAcceleration) -> void: + _match_orientation(acceleration, target.orientation) diff --git a/project/src/Behaviors/GSTPriority.gd b/project/src/Behaviors/GSTPriority.gd index 184b1f1..f352461 100644 --- a/project/src/Behaviors/GSTPriority.gd +++ b/project/src/Behaviors/GSTPriority.gd @@ -31,7 +31,7 @@ func get_behavior_at(index: int) -> GSTSteeringBehavior: return null -func _calculate_steering(accel: GSTTargetAcceleration) -> GSTTargetAcceleration: +func _calculate_steering(accel: GSTTargetAcceleration) -> void: var threshold_squared := zero_threshold * zero_threshold last_selected_index = -1 @@ -48,5 +48,3 @@ func _calculate_steering(accel: GSTTargetAcceleration) -> GSTTargetAcceleration: break else: accel.set_zero() - - return accel diff --git a/project/src/Behaviors/GSTPursue.gd b/project/src/Behaviors/GSTPursue.gd index f9935ba..301bdd7 100644 --- a/project/src/Behaviors/GSTPursue.gd +++ b/project/src/Behaviors/GSTPursue.gd @@ -19,7 +19,7 @@ func _init( self.predict_time_max = predict_time_max -func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration: +func _calculate_steering(acceleration: GSTTargetAcceleration) -> void: var target_position := target.position var distance_squared := (target_position - agent.position).length_squared() @@ -37,8 +37,6 @@ func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAccele acceleration.angular = 0 - return acceleration - func _get_modified_acceleration() -> float: return agent.linear_acceleration_max diff --git a/project/src/Behaviors/GSTSeek.gd b/project/src/Behaviors/GSTSeek.gd index 4371f3f..61229e4 100644 --- a/project/src/Behaviors/GSTSeek.gd +++ b/project/src/Behaviors/GSTSeek.gd @@ -12,9 +12,7 @@ func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent) -> void: self.target = target -func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration: +func _calculate_steering(acceleration: GSTTargetAcceleration) -> void: acceleration.linear = ( (target.position - agent.position).normalized() * agent.linear_acceleration_max) acceleration.angular = 0 - - return acceleration diff --git a/project/src/Behaviors/GSTSeparation.gd b/project/src/Behaviors/GSTSeparation.gd index 0a3252e..87bec2a 100644 --- a/project/src/Behaviors/GSTSeparation.gd +++ b/project/src/Behaviors/GSTSeparation.gd @@ -18,11 +18,10 @@ func _init(agent: GSTSteeringAgent, proximity: GSTProximity).(agent, proximity) pass -func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration: +func _calculate_steering(acceleration: GSTTargetAcceleration) -> void: acceleration.set_zero() self._acceleration = acceleration proximity._find_neighbors(_callback) - return acceleration # Callback for the proximity to call when finding neighbors. Determines the amount of diff --git a/project/src/GSTSteeringBehavior.gd b/project/src/GSTSteeringBehavior.gd index c89a92f..b503d15 100644 --- a/project/src/GSTSteeringBehavior.gd +++ b/project/src/GSTSteeringBehavior.gd @@ -18,16 +18,13 @@ func _init(agent: GSTSteeringAgent) -> void: self.agent = agent -# Returns the `acceleration` modified with the behavior's desired amount of -# acceleration. -func calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration: +# Sets the `acceleration` with the behavior's desired amount of acceleration. +func calculate_steering(acceleration: GSTTargetAcceleration) -> void: if is_enabled: - return _calculate_steering(acceleration) + _calculate_steering(acceleration) else: acceleration.set_zero() - return acceleration -func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration: +func _calculate_steering(acceleration: GSTTargetAcceleration) -> void: acceleration.set_zero() - return acceleration From 85784791ecb5863561bc9908d3a53bdae9b8e16d Mon Sep 17 00:00:00 2001 From: Francois Belair Date: Thu, 6 Feb 2020 14:54:12 -0500 Subject: [PATCH 2/6] Add and have most demos use specialized agents The agents auto-update themselves and can calculate their velocities. This keeps the user from having to create an update_agent function. It can also save the user from having to keep track of and update velocities at all by using the provided `apply_steering` method. Closes #15, closes #16 --- project/demos/Arrive/Arriver.gd | 14 +- project/demos/AvoidCollisions/Avoider.gd | 26 +- project/demos/Face/Turret.gd | 14 +- project/demos/FollowPath/PathFollower.gd | 21 +- project/demos/GroupBehaviors/Member.gd | 10 +- project/demos/GroupBehaviors/Member.tscn | 1 + project/demos/PursueSeek/Pursuer.gd | 65 +- project/demos/SeekFlee/Seeker.gd | 14 +- project/project.godot | 18 + project/reference.json | 2238 ---------------------- project/src/Agents/GSTNode2DAgent.gd | 165 ++ project/src/Agents/GSTNodeAgent.gd | 79 + project/src/Agents/GSTSpatialAgent.gd | 166 ++ project/src/GSTUtils.gd | 10 + 14 files changed, 497 insertions(+), 2344 deletions(-) delete mode 100644 project/reference.json create mode 100644 project/src/Agents/GSTNode2DAgent.gd create mode 100644 project/src/Agents/GSTNodeAgent.gd create mode 100644 project/src/Agents/GSTSpatialAgent.gd diff --git a/project/demos/Arrive/Arriver.gd b/project/demos/Arrive/Arriver.gd index dedce81..e065805 100644 --- a/project/demos/Arrive/Arriver.gd +++ b/project/demos/Arrive/Arriver.gd @@ -1,7 +1,7 @@ extends KinematicBody2D -var agent := GSTSteeringAgent.new() +var agent := GSTNode2DAgent.new(self) var target := GSTAgentLocation.new() var arrive := GSTArrive.new(agent, target) var _accel := GSTTargetAcceleration.new() @@ -11,11 +11,8 @@ var _drag := 0.1 func _physics_process(delta: float) -> void: - _update_agent() arrive.calculate_steering(_accel) - _velocity += Vector2(_accel.linear.x, _accel.linear.y) - _velocity = _velocity.linear_interpolate(Vector2.ZERO, _drag).clamped(agent.linear_speed_max) - _velocity = move_and_slide(_velocity) + agent._apply_steering(_accel, delta) func setup( @@ -26,12 +23,7 @@ func setup( ) -> void: agent.linear_speed_max = linear_speed_max agent.linear_acceleration_max = linear_acceleration_max - agent.position = Vector3(global_position.x, global_position.y, 0) + agent.linear_drag_percentage = _drag arrive.deceleration_radius = deceleration_radius arrive.arrival_tolerance = arrival_tolerance target.position = agent.position - - -func _update_agent() -> void: - agent.position = Vector3(global_position.x, global_position.y, 0) - agent.linear_velocity = Vector3(_velocity.x, _velocity.y, 0) diff --git a/project/demos/AvoidCollisions/Avoider.gd b/project/demos/AvoidCollisions/Avoider.gd index 7027e13..3464351 100644 --- a/project/demos/AvoidCollisions/Avoider.gd +++ b/project/demos/AvoidCollisions/Avoider.gd @@ -13,7 +13,7 @@ var _drag := 0.1 var _color := Color(0.4, 1.0, 0.89, 0.3) onready var collision := $CollisionShape2D -onready var agent := GSTSteeringAgent.new() +onready var agent := GSTNode2DAgent.new(self) onready var proximity := GSTRadiusProximity.new(agent, [], 140) onready var avoid := GSTAvoidCollisions.new(agent, proximity) onready var target := GSTAgentLocation.new() @@ -27,12 +27,11 @@ func _draw() -> void: func _physics_process(delta: float) -> void: - _update_agent() + target.position.x = agent.position.x + _direction.x*_radius + target.position.y = agent.position.y + _direction.y*_radius + priority.calculate_steering(_accel) - _velocity += Vector2(_accel.linear.x, _accel.linear.y) - _velocity = _velocity.linear_interpolate(Vector2.ZERO, _drag) - _velocity = _velocity.clamped(agent.linear_speed_max) - _velocity = move_and_slide(_velocity) + agent._apply_steering(_accel, delta) func setup( @@ -46,15 +45,19 @@ func setup( ) -> void: rng.randomize() _direction = Vector2(rng.randf_range(-1, 1), rng.randf_range(-1, 1)).normalized() - _update_agent() + agent.linear_speed_max = linear_speed_max agent.linear_acceleration_max = linear_accel_max + proximity.radius = proximity_radius _boundary_bottom = boundary_bottom _boundary_right = boundary_right + _radius = collision.shape.radius agent.bounding_radius = _radius + agent.linear_drag_percentage = _drag + self.draw_proximity = draw_proximity priority.add(avoid) @@ -84,12 +87,3 @@ func set_random_nonoverlapping_position(others: Array, distance_from_boundary_mi done = false if done: break - - -func _update_agent() -> void: - agent.position.x = global_position.x - agent.position.y = global_position.y - agent.linear_velocity.x = _velocity.x - agent.linear_velocity.y = _velocity.y - target.position.x = agent.position.x + _direction.x*_radius - target.position.y = agent.position.y + _direction.y*_radius diff --git a/project/demos/Face/Turret.gd b/project/demos/Face/Turret.gd index 38fa4fa..6992a22 100644 --- a/project/demos/Face/Turret.gd +++ b/project/demos/Face/Turret.gd @@ -2,7 +2,7 @@ extends KinematicBody2D var face: GSTFace -var agent := GSTSteeringAgent.new() +var agent := GSTNode2DAgent.new(self) var _accel := GSTTargetAcceleration.new() var _angular_drag := 0.1 @@ -20,14 +20,7 @@ func _ready() -> void: func _physics_process(delta: float) -> void: face.calculate_steering(_accel) - agent.angular_velocity = clamp( - agent.angular_velocity + _accel.angular, - -agent.angular_speed_max, - agent.angular_speed_max - ) - agent.angular_velocity = lerp(agent.angular_velocity, 0, _angular_drag) - agent.orientation += agent.angular_velocity * delta - rotation = agent.orientation + agent._apply_steering(_accel, delta) func _draw() -> void: @@ -48,5 +41,4 @@ func setup( agent.angular_acceleration_max = angular_accel_max agent.angular_speed_max = angular_speed_max - agent.position = Vector3(global_position.x, global_position.y, 0) - + agent.angular_drag_percentage = _angular_drag diff --git a/project/demos/FollowPath/PathFollower.gd b/project/demos/FollowPath/PathFollower.gd index 9445050..cea97dd 100644 --- a/project/demos/FollowPath/PathFollower.gd +++ b/project/demos/FollowPath/PathFollower.gd @@ -6,7 +6,7 @@ var _accel := GSTTargetAcceleration.new() var _valid := false var _drag := 0.1 -onready var agent := GSTSteeringAgent.new() +onready var agent := GSTNode2DAgent.new(self) onready var path := GSTPath.new([ Vector3(global_position.x, global_position.y, 0), Vector3(global_position.x, global_position.y, 0) @@ -25,27 +25,18 @@ func setup( owner.drawer.connect("path_established", self, "_on_Drawer_path_established") follow.path_offset = path_offset follow.prediction_time = predict_time - agent.linear_acceleration_max = accel_max - agent.linear_speed_max = speed_max follow.deceleration_radius = decel_radius follow.arrival_tolerance = arrival_tolerance + + agent.linear_acceleration_max = accel_max + agent.linear_speed_max = speed_max + agent.linear_drag_percentage = _drag func _physics_process(delta: float) -> void: if _valid: - _update_agent() follow.calculate_steering(_accel) - _velocity += Vector2(_accel.linear.x, _accel.linear.y) - _velocity = _velocity.linear_interpolate(Vector2.ZERO, _drag) - _velocity = _velocity.clamped(agent.linear_speed_max) - _velocity = move_and_slide(_velocity) - - -func _update_agent() -> void: - agent.position.x = global_position.x - agent.position.y = global_position.y - agent.linear_velocity.x = _velocity.x - agent.linear_velocity.y = _velocity.y + agent._apply_steering(_accel, delta) func _on_Drawer_path_established(points: Array) -> void: diff --git a/project/demos/GroupBehaviors/Member.gd b/project/demos/GroupBehaviors/Member.gd index f3285a1..1658dd5 100644 --- a/project/demos/GroupBehaviors/Member.gd +++ b/project/demos/GroupBehaviors/Member.gd @@ -4,7 +4,7 @@ extends KinematicBody2D var separation: GSTSeparation var cohesion: GSTCohesion var proximity: GSTRadiusProximity -var agent := GSTSteeringAgent.new() +var agent := GSTNode2DAgent.new(self) var blend := GSTBlend.new(agent) var acceleration := GSTTargetAcceleration.new() var draw_proximity := false @@ -28,6 +28,7 @@ func setup( agent.linear_acceleration_max = linear_accel_max agent.linear_speed_max = linear_speed_max + agent.linear_drag_percentage = 0.1 proximity = GSTRadiusProximity.new(agent, [], proximity_radius) separation = GSTSeparation.new(agent, proximity) @@ -43,14 +44,9 @@ func _draw() -> void: func _physics_process(delta: float) -> void: - agent.position.x = global_position.x - agent.position.y = global_position.y if blend: blend.calculate_steering(acceleration) - _velocity += Vector2(acceleration.linear.x, acceleration.linear.y) - _velocity = _velocity.linear_interpolate(Vector2.ZERO, 0.1) - _velocity = _velocity.clamped(agent.linear_speed_max) - move_and_slide(_velocity) + agent._apply_steering(acceleration, delta) func set_neighbors(neighbor: Array) -> void: diff --git a/project/demos/GroupBehaviors/Member.tscn b/project/demos/GroupBehaviors/Member.tscn index 0baef77..c85ab3f 100644 --- a/project/demos/GroupBehaviors/Member.tscn +++ b/project/demos/GroupBehaviors/Member.tscn @@ -12,5 +12,6 @@ script = ExtResource( 1 ) [node name="CollisionShape2D" type="CollisionShape2D" parent="."] shape = SubResource( 1 ) script = ExtResource( 3 ) +inner_color = Color( 0, 0, 0, 1 ) outer_color = Color( 0.301961, 0.65098, 1, 1 ) stroke = 4.0 diff --git a/project/demos/PursueSeek/Pursuer.gd b/project/demos/PursueSeek/Pursuer.gd index 86cf241..37e245b 100644 --- a/project/demos/PursueSeek/Pursuer.gd +++ b/project/demos/PursueSeek/Pursuer.gd @@ -4,71 +4,68 @@ extends KinematicBody2D export var use_seek: bool = false -var _orient_behavior: GSTSteeringBehavior -var _behavior: GSTSteeringBehavior +var _blend: GSTBlend -var _linear_velocity := Vector2() var _linear_drag_coefficient := 0.025 -var _angular_velocity := 0.0 var _angular_drag := 0.1 var _direction_face := GSTAgentLocation.new() -onready var agent := GSTSteeringAgent.new() +onready var agent := GSTNode2DAgent.new(self) onready var accel := GSTTargetAcceleration.new() onready var player_agent: GSTSteeringAgent = owner.find_node("Player", true, false).agent func _ready() -> void: + agent.calculate_velocities = false set_physics_process(false) func _physics_process(delta: float) -> void: - _update_agent() - - _behavior.calculate_steering(accel) - _direction_face.position = agent.position + accel.linear.normalized() - _orient_behavior.calculate_steering(accel) - _angular_velocity += accel.angular - - _angular_velocity = clamp( - lerp(_angular_velocity, 0, _angular_drag), + _blend.calculate_steering(accel) + + agent.angular_velocity = clamp( + agent.angular_velocity + accel.angular, -agent.angular_speed_max, agent.angular_speed_max ) + agent.angular_velocity = lerp(agent.angular_velocity, 0, _angular_drag) + + rotation += agent.angular_velocity * delta - rotation += _angular_velocity * delta + var linear_velocity := ( + GSTUtils.to_vector2(agent.linear_velocity) + + (GSTUtils.angle_to_vector2(rotation) * -agent.linear_acceleration_max) + ) + linear_velocity = linear_velocity.clamped(agent.linear_speed_max) + linear_velocity = linear_velocity.linear_interpolate( + Vector2.ZERO, + _linear_drag_coefficient + ) - _linear_velocity += GSTUtils.angle_to_vector2(rotation) * -agent.linear_acceleration_max - _linear_velocity = _linear_velocity.clamped(agent.linear_speed_max) - _linear_velocity = _linear_velocity.linear_interpolate(Vector2.ZERO, _linear_drag_coefficient) - _linear_velocity = move_and_slide(_linear_velocity) + linear_velocity = move_and_slide(linear_velocity) + agent.linear_velocity = GSTUtils.to_vector3(linear_velocity) func setup(predict_time: float, linear_speed_max: float, linear_accel_max: float) -> void: + var behavior: GSTSteeringBehavior if use_seek: - _behavior = GSTSeek.new(agent, player_agent) + behavior = GSTSeek.new(agent, player_agent) else: - _behavior = GSTPursue.new(agent, player_agent, predict_time) + behavior = GSTPursue.new(agent, player_agent, predict_time) - _orient_behavior = GSTFace.new(agent, _direction_face) - _orient_behavior.alignment_tolerance = deg2rad(5) - _orient_behavior.deceleration_radius = deg2rad(5) + var orient_behavior := GSTFace.new(agent, _direction_face) + orient_behavior.alignment_tolerance = deg2rad(5) + orient_behavior.deceleration_radius = deg2rad(5) + + _blend = GSTBlend.new(agent) + _blend.add(behavior, 1) + _blend.add(orient_behavior, 1) agent.angular_acceleration_max = deg2rad(40) agent.angular_speed_max = deg2rad(90) agent.linear_acceleration_max = linear_accel_max agent.linear_speed_max = linear_speed_max - _update_agent() set_physics_process(true) - - -func _update_agent() -> void: - agent.position.x = global_position.x - agent.position.y = global_position.y - agent.orientation = rotation - agent.linear_velocity.x = _linear_velocity.x - agent.linear_velocity.y = _linear_velocity.y - agent.angular_velocity = _angular_velocity diff --git a/project/demos/SeekFlee/Seeker.gd b/project/demos/SeekFlee/Seeker.gd index 5dd86d6..da01af9 100644 --- a/project/demos/SeekFlee/Seeker.gd +++ b/project/demos/SeekFlee/Seeker.gd @@ -1,5 +1,4 @@ extends KinematicBody2D -# AI agent that uses the Seek behavior to hone in on the player's location as directly as possible. var player_agent: GSTAgentLocation @@ -8,7 +7,7 @@ var start_speed: float var start_accel: float var use_seek := true -onready var agent := GSTSteeringAgent.new() +onready var agent := GSTNode2DAgent.new(self) onready var accel := GSTTargetAcceleration.new() onready var seek := GSTSeek.new(agent, player_agent) onready var flee := GSTFlee.new(agent, player_agent) @@ -23,18 +22,9 @@ func _physics_process(delta: float) -> void: if not player_agent: return - _update_agent() if use_seek: seek.calculate_steering(accel) else: flee.calculate_steering(accel) - velocity = (velocity + Vector2(accel.linear.x, accel.linear.y)).clamped(agent.linear_speed_max) - velocity = move_and_slide(velocity) - - -func _update_agent() -> void: - agent.position.x = global_position.x - agent.position.y = global_position.y - agent.linear_velocity.x = velocity.x - agent.linear_velocity.y = velocity.y + agent._apply_steering(accel, delta) diff --git a/project/project.godot b/project/project.godot index d615c5b..f555a0d 100644 --- a/project/project.godot +++ b/project/project.godot @@ -74,6 +74,16 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://src/Behaviors/GSTMatchOrientation.gd" }, { +"base": "GSTNodeAgent", +"class": "GSTNode2DAgent", +"language": "GDScript", +"path": "res://src/Agents/GSTNode2DAgent.gd" +}, { +"base": "GSTSteeringAgent", +"class": "GSTNodeAgent", +"language": "GDScript", +"path": "res://src/Agents/GSTNodeAgent.gd" +}, { "base": "Reference", "class": "GSTPath", "language": "GDScript", @@ -109,6 +119,11 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://src/Behaviors/GSTSeparation.gd" }, { +"base": "GSTNodeAgent", +"class": "GSTSpatialAgent", +"language": "GDScript", +"path": "res://src/Agents/GSTSpatialAgent.gd" +}, { "base": "GSTAgentLocation", "class": "GSTSteeringAgent", "language": "GDScript", @@ -143,6 +158,8 @@ _global_script_class_icons={ "GSTInfiniteProximity": "", "GSTLookWhereYouGo": "", "GSTMatchOrientation": "", +"GSTNode2DAgent": "", +"GSTNodeAgent": "", "GSTPath": "", "GSTPriority": "", "GSTProximity": "", @@ -150,6 +167,7 @@ _global_script_class_icons={ "GSTRadiusProximity": "", "GSTSeek": "", "GSTSeparation": "", +"GSTSpatialAgent": "", "GSTSteeringAgent": "", "GSTSteeringBehavior": "", "GSTTargetAcceleration": "", diff --git a/project/reference.json b/project/reference.json deleted file mode 100644 index 1e9c8ba..0000000 --- a/project/reference.json +++ /dev/null @@ -1,2238 +0,0 @@ -[ - { - "name": "GSTArrive", - "path": "res://src/Behaviors/GSTArrive.gd", - "extends_class": [ - "GSTSteeringBehavior" - ], - "extends_file": "", - "icon": "", - "signature": "class GSTArrive", - "description": " Calculates acceleration to take an agent to its target's location. The\n calculation attempts to arrive with zero remaining velocity.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - { - "name": "target", - "data_type": "GSTAgentLocation", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var target: GSTAgentLocation", - "description": " Target agent to arrive to.\n" - }, - { - "name": "arrival_tolerance", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var arrival_tolerance: float", - "description": " Distance from the target for the agent to be considered successfully\n arrived.\n" - }, - { - "name": "deceleration_radius", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var deceleration_radius: float", - "description": " Distance from the target for the agent to begin slowing down.\n" - }, - { - "name": "time_to_reach", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var time_to_reach: float", - "description": " Represents the time it takes to change acceleration.\n" - } - ], - "signals": [ - - ], - "methods": [ - { - "name": "_init", - "return_type": "null", - "rpc_mode": 0, - "signature": "func _init(agent: GSTSteeringAgent, target: GSTAgentLocation) -> null", - "description": "", - "arguments": [ - { - "name": "agent", - "type": "GSTSteeringAgent" - }, - { - "name": "target", - "type": "GSTAgentLocation" - } - ] - }, - { - "name": "_arrive", - "return_type": "GSTTargetAcceleration", - "rpc_mode": 0, - "signature": "func _arrive(acceleration: GSTTargetAcceleration, target_position: Vector3) -> GSTTargetAcceleration", - "description": "", - "arguments": [ - { - "name": "acceleration", - "type": "GSTTargetAcceleration" - }, - { - "name": "target_position", - "type": "Vector3" - } - ] - }, - { - "name": "_calculate_steering", - "return_type": "GSTTargetAcceleration", - "rpc_mode": 0, - "signature": "func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration", - "description": "", - "arguments": [ - { - "name": "acceleration", - "type": "GSTTargetAcceleration" - } - ] - } - ], - "static_functions": [ - - ] - }, - { - "name": "GSTAvoidCollisions", - "path": "res://src/Behaviors/GSTAvoidCollisions.gd", - "extends_class": [ - "GSTGroupBehavior" - ], - "extends_file": "", - "icon": "", - "signature": "class GSTAvoidCollisions", - "description": " Steers the agent to avoid obstacles in its path. Approximates obstacles as\n spheres.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - { - "name": "_first_neighbor", - "data_type": "GSTSteeringAgent", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var _first_neighbor: GSTSteeringAgent", - "description": "" - }, - { - "name": "_shortest_time", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var _shortest_time: float", - "description": "" - }, - { - "name": "_first_minimum_separation", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var _first_minimum_separation: float", - "description": "" - }, - { - "name": "_first_distance", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var _first_distance: float", - "description": "" - }, - { - "name": "_first_relative_position", - "data_type": "Vector3", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var _first_relative_position: Vector3", - "description": "" - }, - { - "name": "_first_relative_velocity", - "data_type": "Vector3", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var _first_relative_velocity: Vector3", - "description": "" - } - ], - "signals": [ - - ], - "methods": [ - { - "name": "_init", - "return_type": "null", - "rpc_mode": 0, - "signature": "func _init(agent: GSTSteeringAgent, proximity: GSTProximity) -> null", - "description": "", - "arguments": [ - { - "name": "agent", - "type": "GSTSteeringAgent" - }, - { - "name": "proximity", - "type": "GSTProximity" - } - ] - }, - { - "name": "_calculate_steering", - "return_type": "GSTTargetAcceleration", - "rpc_mode": 0, - "signature": "func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration", - "description": "", - "arguments": [ - { - "name": "acceleration", - "type": "GSTTargetAcceleration" - } - ] - }, - { - "name": "_report_neighbor", - "return_type": "bool", - "rpc_mode": 0, - "signature": "func _report_neighbor(neighbor: GSTSteeringAgent) -> bool", - "description": " Callback for the proximity to call when finding neighbors. Keeps track of every `neighbor`\n that was found but only keeps the one the owning agent will most likely collide with.\n tags: virtual\n", - "arguments": [ - { - "name": "neighbor", - "type": "GSTSteeringAgent" - } - ] - } - ], - "static_functions": [ - - ] - }, - { - "name": "GSTBlend", - "path": "res://src/Behaviors/GSTBlend.gd", - "extends_class": [ - "GSTSteeringBehavior" - ], - "extends_file": "", - "icon": "", - "signature": "class GSTBlend", - "description": " Blends multiple steering behaviors into one, and returns a weighted\n acceleration from their calculations.\n\n Stores the behaviors internally as dictionaries of the form\n {\n \tbehavior : GSTSteeringBehavior,\n \tweight : float\n }\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - { - "name": "_behaviors", - "data_type": "Array", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var _behaviors: Array", - "description": "" - }, - { - "name": "_accel", - "data_type": "GSTTargetAcceleration", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var _accel: GSTTargetAcceleration", - "description": "" - } - ], - "signals": [ - - ], - "methods": [ - { - "name": "_init", - "return_type": "null", - "rpc_mode": 0, - "signature": "func _init(agent: GSTSteeringAgent) -> null", - "description": "", - "arguments": [ - { - "name": "agent", - "type": "GSTSteeringAgent" - } - ] - }, - { - "name": "add", - "return_type": "null", - "rpc_mode": 0, - "signature": "func add(behavior: GSTSteeringBehavior, weight: float) -> null", - "description": " Appends a behavior to the internal array along with its `weight`.\n", - "arguments": [ - { - "name": "behavior", - "type": "GSTSteeringBehavior" - }, - { - "name": "weight", - "type": "float" - } - ] - }, - { - "name": "get_behavior_at", - "return_type": "Dictionary", - "rpc_mode": 0, - "signature": "func get_behavior_at(index: int) -> Dictionary", - "description": " Returns the behavior at the specified `index`, or an empty `Dictionary` if\n none was found.\n", - "arguments": [ - { - "name": "index", - "type": "int" - } - ] - }, - { - "name": "_calculate_steering", - "return_type": "GSTTargetAcceleration", - "rpc_mode": 0, - "signature": "func _calculate_steering(blended_accel: GSTTargetAcceleration) -> GSTTargetAcceleration", - "description": "", - "arguments": [ - { - "name": "blended_accel", - "type": "GSTTargetAcceleration" - } - ] - } - ], - "static_functions": [ - - ] - }, - { - "name": "GSTCohesion", - "path": "res://src/Behaviors/GSTCohesion.gd", - "extends_class": [ - "GSTGroupBehavior" - ], - "extends_file": "", - "icon": "", - "signature": "class GSTCohesion", - "description": " Calculates an acceleration that attempts to move the agent towards the center\n of mass of the agents in the area defined by the `GSTProximity`.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - { - "name": "_center_of_mass", - "data_type": "Vector3", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var _center_of_mass: Vector3", - "description": "" - } - ], - "signals": [ - - ], - "methods": [ - { - "name": "_init", - "return_type": "null", - "rpc_mode": 0, - "signature": "func _init(agent: GSTSteeringAgent, proximity: GSTProximity) -> null", - "description": "", - "arguments": [ - { - "name": "agent", - "type": "GSTSteeringAgent" - }, - { - "name": "proximity", - "type": "GSTProximity" - } - ] - }, - { - "name": "_calculate_steering", - "return_type": "GSTTargetAcceleration", - "rpc_mode": 0, - "signature": "func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration", - "description": "", - "arguments": [ - { - "name": "acceleration", - "type": "GSTTargetAcceleration" - } - ] - }, - { - "name": "_report_neighbor", - "return_type": "bool", - "rpc_mode": 0, - "signature": "func _report_neighbor(neighbor: GSTSteeringAgent) -> bool", - "description": " Callback for the proximity to call when finding neighbors. Adds `neighbor`'s position\n to the center of mass of the group.\n tags: virtual\n", - "arguments": [ - { - "name": "neighbor", - "type": "GSTSteeringAgent" - } - ] - } - ], - "static_functions": [ - - ] - }, - { - "name": "GSTEvade", - "path": "res://src/Behaviors/GSTEvade.gd", - "extends_class": [ - "GSTPursue" - ], - "extends_file": "", - "icon": "", - "signature": "class GSTEvade", - "description": " Calculates acceleration to take an agent away from where a target agent is\n moving.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - - ], - "signals": [ - - ], - "methods": [ - { - "name": "_init", - "return_type": "var", - "rpc_mode": 0, - "signature": "func _init(agent: GSTSteeringAgent, target: GSTSteeringAgent, predict_time_max: float = 1)", - "description": "", - "arguments": [ - { - "name": "agent", - "type": "GSTSteeringAgent" - }, - { - "name": "target", - "type": "GSTSteeringAgent" - }, - { - "name": "predict_time_max", - "type": "float", - "default_value": 1 - } - ] - }, - { - "name": "_get_modified_acceleration", - "return_type": "float", - "rpc_mode": 0, - "signature": "func _get_modified_acceleration() -> float", - "description": "", - "arguments": [ - - ] - } - ], - "static_functions": [ - - ] - }, - { - "name": "GSTFace", - "path": "res://src/Behaviors/GSTFace.gd", - "extends_class": [ - "GSTMatchOrientation" - ], - "extends_file": "", - "icon": "", - "signature": "class GSTFace", - "description": " Calculates angular acceleration to rotate a target to face its target's\n position. The behavior attemps to arrive with zero remaining angular velocity.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - - ], - "signals": [ - - ], - "methods": [ - { - "name": "_init", - "return_type": "null", - "rpc_mode": 0, - "signature": "func _init(agent: GSTSteeringAgent, target: GSTAgentLocation) -> null", - "description": "", - "arguments": [ - { - "name": "agent", - "type": "GSTSteeringAgent" - }, - { - "name": "target", - "type": "GSTAgentLocation" - } - ] - }, - { - "name": "_face", - "return_type": "GSTTargetAcceleration", - "rpc_mode": 0, - "signature": "func _face(acceleration: GSTTargetAcceleration, target_position: Vector3) -> GSTTargetAcceleration", - "description": "", - "arguments": [ - { - "name": "acceleration", - "type": "GSTTargetAcceleration" - }, - { - "name": "target_position", - "type": "Vector3" - } - ] - }, - { - "name": "_calculate_steering", - "return_type": "GSTTargetAcceleration", - "rpc_mode": 0, - "signature": "func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration", - "description": "", - "arguments": [ - { - "name": "acceleration", - "type": "GSTTargetAcceleration" - } - ] - } - ], - "static_functions": [ - - ] - }, - { - "name": "GSTFlee", - "path": "res://src/Behaviors/GSTFlee.gd", - "extends_class": [ - "GSTSeek" - ], - "extends_file": "", - "icon": "", - "signature": "class GSTFlee", - "description": " Calculates acceleration to take an agent directly away from a target agent.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - - ], - "signals": [ - - ], - "methods": [ - { - "name": "_init", - "return_type": "null", - "rpc_mode": 0, - "signature": "func _init(agent: GSTSteeringAgent, target: GSTAgentLocation) -> null", - "description": "", - "arguments": [ - { - "name": "agent", - "type": "GSTSteeringAgent" - }, - { - "name": "target", - "type": "GSTAgentLocation" - } - ] - }, - { - "name": "_calculate_steering", - "return_type": "GSTTargetAcceleration", - "rpc_mode": 0, - "signature": "func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration", - "description": "", - "arguments": [ - { - "name": "acceleration", - "type": "GSTTargetAcceleration" - } - ] - } - ], - "static_functions": [ - - ] - }, - { - "name": "GSTFollowPath", - "path": "res://src/Behaviors/GSTFollowPath.gd", - "extends_class": [ - "GSTArrive" - ], - "extends_file": "", - "icon": "", - "signature": "class GSTFollowPath", - "description": " Produces a linear acceleration that moves the agent along the specified path.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - { - "name": "path", - "data_type": "GSTPath", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var path: GSTPath", - "description": " The path to follow and travel along.\n" - }, - { - "name": "path_offset", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var path_offset: float", - "description": " The distance along the path to generate the next target position.\n" - }, - { - "name": "is_arrive_enabled", - "data_type": "bool", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var is_arrive_enabled: bool", - "description": " Whether to use `GSTArrive` behavior on an open path.\n" - }, - { - "name": "prediction_time", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var prediction_time: float", - "description": " The amount of time in the future to predict the owning agent's position along\n the path. Setting it to 0.0 will force non-predictive path following.\n" - } - ], - "signals": [ - - ], - "methods": [ - { - "name": "_init", - "return_type": "null", - "rpc_mode": 0, - "signature": "func _init(agent: GSTSteeringAgent, path: GSTPath, path_offset: float = 0, prediction_time: float = 0) -> null", - "description": "", - "arguments": [ - { - "name": "agent", - "type": "GSTSteeringAgent" - }, - { - "name": "path", - "type": "GSTPath" - }, - { - "name": "path_offset", - "type": "float", - "default_value": 0 - }, - { - "name": "prediction_time", - "type": "float", - "default_value": 0 - } - ] - }, - { - "name": "_calculate_steering", - "return_type": "GSTTargetAcceleration", - "rpc_mode": 0, - "signature": "func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration", - "description": "", - "arguments": [ - { - "name": "acceleration", - "type": "GSTTargetAcceleration" - } - ] - } - ], - "static_functions": [ - - ] - }, - { - "name": "GSTLookWhereYouGo", - "path": "res://src/Behaviors/GSTLookWhereYouGo.gd", - "extends_class": [ - "GSTMatchOrientation" - ], - "extends_file": "", - "icon": "", - "signature": "class GSTLookWhereYouGo", - "description": " Calculates an angular acceleration to match an agent's orientation to its\n direction of travel.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - - ], - "signals": [ - - ], - "methods": [ - { - "name": "_init", - "return_type": "null", - "rpc_mode": 0, - "signature": "func _init(agent: GSTSteeringAgent) -> null", - "description": "", - "arguments": [ - { - "name": "agent", - "type": "GSTSteeringAgent" - } - ] - }, - { - "name": "_calculate_steering", - "return_type": "GSTTargetAcceleration", - "rpc_mode": 0, - "signature": "func _calculate_steering(accel: GSTTargetAcceleration) -> GSTTargetAcceleration", - "description": "", - "arguments": [ - { - "name": "accel", - "type": "GSTTargetAcceleration" - } - ] - } - ], - "static_functions": [ - - ] - }, - { - "name": "GSTMatchOrientation", - "path": "res://src/Behaviors/GSTMatchOrientation.gd", - "extends_class": [ - "GSTSteeringBehavior" - ], - "extends_file": "", - "icon": "", - "signature": "class GSTMatchOrientation", - "description": " Calculates an angular acceleration to match an agent's orientation to that of\n its target. Attempts to make the agent arrive with zero remaining angular\n velocity.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - { - "name": "target", - "data_type": "GSTAgentLocation", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var target: GSTAgentLocation", - "description": " The target orientation for the behavior to try and match rotations to.\n" - }, - { - "name": "alignment_tolerance", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var alignment_tolerance: float", - "description": " The amount of distance in radians for the behavior to consider itself close\n enough to be matching the target agent's rotation.\n" - }, - { - "name": "deceleration_radius", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var deceleration_radius: float", - "description": " The amount of distance in radians from the goal to start slowing down.\n" - }, - { - "name": "time_to_reach", - "data_type": "float", - "default_value": 0.1, - "setter": "", - "getter": "", - "export": false, - "signature": "var time_to_reach: float = 0.1", - "description": " The amount of time to reach the target velocity\n" - } - ], - "signals": [ - - ], - "methods": [ - { - "name": "_init", - "return_type": "null", - "rpc_mode": 0, - "signature": "func _init(agent: GSTSteeringAgent, target: GSTAgentLocation) -> null", - "description": "", - "arguments": [ - { - "name": "agent", - "type": "GSTSteeringAgent" - }, - { - "name": "target", - "type": "GSTAgentLocation" - } - ] - }, - { - "name": "_match_orientation", - "return_type": "GSTTargetAcceleration", - "rpc_mode": 0, - "signature": "func _match_orientation(acceleration: GSTTargetAcceleration, desired_orientation: float) -> GSTTargetAcceleration", - "description": "", - "arguments": [ - { - "name": "acceleration", - "type": "GSTTargetAcceleration" - }, - { - "name": "desired_orientation", - "type": "float" - } - ] - }, - { - "name": "_calculate_steering", - "return_type": "GSTTargetAcceleration", - "rpc_mode": 0, - "signature": "func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration", - "description": "", - "arguments": [ - { - "name": "acceleration", - "type": "GSTTargetAcceleration" - } - ] - } - ], - "static_functions": [ - - ] - }, - { - "name": "GSTPriority", - "path": "res://src/Behaviors/GSTPriority.gd", - "extends_class": [ - "GSTSteeringBehavior" - ], - "extends_file": "", - "icon": "", - "signature": "class GSTPriority", - "description": " Container for multiple behaviors that returns the result of the first child\n behavior with non-zero acceleration.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - { - "name": "_behaviors", - "data_type": "Array", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var _behaviors: Array", - "description": "" - }, - { - "name": "last_selected_index", - "data_type": "int", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var last_selected_index: int", - "description": " The index of the last behavior the container prioritized.\n" - }, - { - "name": "zero_threshold", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var zero_threshold: float", - "description": " If a behavior's acceleration is lower than this threshold, the container\n considers it has an acceleration of zero.\n" - } - ], - "signals": [ - - ], - "methods": [ - { - "name": "_init", - "return_type": "null", - "rpc_mode": 0, - "signature": "func _init(agent: GSTSteeringAgent, zero_threshold: float = 0.001) -> null", - "description": "", - "arguments": [ - { - "name": "agent", - "type": "GSTSteeringAgent" - }, - { - "name": "zero_threshold", - "type": "float", - "default_value": 0.001 - } - ] - }, - { - "name": "add", - "return_type": "null", - "rpc_mode": 0, - "signature": "func add(behavior: GSTSteeringBehavior) -> null", - "description": " Appends a steering behavior as a child of this container.\n", - "arguments": [ - { - "name": "behavior", - "type": "GSTSteeringBehavior" - } - ] - }, - { - "name": "get_behavior_at", - "return_type": "GSTSteeringBehavior", - "rpc_mode": 0, - "signature": "func get_behavior_at(index: int) -> GSTSteeringBehavior", - "description": " Returns the behavior at the position in the pool referred to by `index`, or\n `null` if no behavior was found.\n", - "arguments": [ - { - "name": "index", - "type": "int" - } - ] - }, - { - "name": "_calculate_steering", - "return_type": "GSTTargetAcceleration", - "rpc_mode": 0, - "signature": "func _calculate_steering(accel: GSTTargetAcceleration) -> GSTTargetAcceleration", - "description": "", - "arguments": [ - { - "name": "accel", - "type": "GSTTargetAcceleration" - } - ] - } - ], - "static_functions": [ - - ] - }, - { - "name": "GSTPursue", - "path": "res://src/Behaviors/GSTPursue.gd", - "extends_class": [ - "GSTSteeringBehavior" - ], - "extends_file": "", - "icon": "", - "signature": "class GSTPursue", - "description": " Calculates an acceleration to make an agent intercept another based on the\n target agent's movement.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - { - "name": "target", - "data_type": "GSTSteeringAgent", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var target: GSTSteeringAgent", - "description": " The target agent that the behavior is trying to intercept.\n" - }, - { - "name": "predict_time_max", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var predict_time_max: float", - "description": " The maximum amount of time in the future the behavior predicts the target's\n location.\n" - } - ], - "signals": [ - - ], - "methods": [ - { - "name": "_init", - "return_type": "null", - "rpc_mode": 0, - "signature": "func _init(agent: GSTSteeringAgent, target: GSTSteeringAgent, predict_time_max: float = 1) -> null", - "description": "", - "arguments": [ - { - "name": "agent", - "type": "GSTSteeringAgent" - }, - { - "name": "target", - "type": "GSTSteeringAgent" - }, - { - "name": "predict_time_max", - "type": "float", - "default_value": 1 - } - ] - }, - { - "name": "_calculate_steering", - "return_type": "GSTTargetAcceleration", - "rpc_mode": 0, - "signature": "func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration", - "description": "", - "arguments": [ - { - "name": "acceleration", - "type": "GSTTargetAcceleration" - } - ] - }, - { - "name": "_get_modified_acceleration", - "return_type": "float", - "rpc_mode": 0, - "signature": "func _get_modified_acceleration() -> float", - "description": "", - "arguments": [ - - ] - } - ], - "static_functions": [ - - ] - }, - { - "name": "GSTSeek", - "path": "res://src/Behaviors/GSTSeek.gd", - "extends_class": [ - "GSTSteeringBehavior" - ], - "extends_file": "", - "icon": "", - "signature": "class GSTSeek", - "description": " Calculates an acceleration to take an agent to a target agent's position\n directly.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - { - "name": "target", - "data_type": "GSTAgentLocation", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var target: GSTAgentLocation", - "description": " The target that the behavior aims to move the agent to.\n" - } - ], - "signals": [ - - ], - "methods": [ - { - "name": "_init", - "return_type": "null", - "rpc_mode": 0, - "signature": "func _init(agent: GSTSteeringAgent, target: GSTAgentLocation) -> null", - "description": "", - "arguments": [ - { - "name": "agent", - "type": "GSTSteeringAgent" - }, - { - "name": "target", - "type": "GSTAgentLocation" - } - ] - }, - { - "name": "_calculate_steering", - "return_type": "GSTTargetAcceleration", - "rpc_mode": 0, - "signature": "func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration", - "description": "", - "arguments": [ - { - "name": "acceleration", - "type": "GSTTargetAcceleration" - } - ] - } - ], - "static_functions": [ - - ] - }, - { - "name": "GSTSeparation", - "path": "res://src/Behaviors/GSTSeparation.gd", - "extends_class": [ - "GSTGroupBehavior" - ], - "extends_file": "", - "icon": "", - "signature": "class GSTSeparation", - "description": " Calculates an acceleration that repels the agent from its neighbors in the\n given `GSTProximity`.\n\n The acceleration is an average based on all neighbors, multiplied by a\n strength decreasing by the inverse square law in relation to distance, and it\n accumulates.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - { - "name": "decay_coefficient", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var decay_coefficient: float", - "description": " The coefficient to calculate how fast the separation strength decays with distance.\n" - }, - { - "name": "_acceleration", - "data_type": "GSTTargetAcceleration", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var _acceleration: GSTTargetAcceleration", - "description": "" - } - ], - "signals": [ - - ], - "methods": [ - { - "name": "_init", - "return_type": "null", - "rpc_mode": 0, - "signature": "func _init(agent: GSTSteeringAgent, proximity: GSTProximity) -> null", - "description": "", - "arguments": [ - { - "name": "agent", - "type": "GSTSteeringAgent" - }, - { - "name": "proximity", - "type": "GSTProximity" - } - ] - }, - { - "name": "_calculate_steering", - "return_type": "GSTTargetAcceleration", - "rpc_mode": 0, - "signature": "func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration", - "description": "", - "arguments": [ - { - "name": "acceleration", - "type": "GSTTargetAcceleration" - } - ] - }, - { - "name": "_report_neighbor", - "return_type": "bool", - "rpc_mode": 0, - "signature": "func _report_neighbor(neighbor: GSTSteeringAgent) -> bool", - "description": " Callback for the proximity to call when finding neighbors. Determines the amount of\n acceleration that `neighbor` imposes based on its distance from the owner agent.\n tags: virtual\n", - "arguments": [ - { - "name": "neighbor", - "type": "GSTSteeringAgent" - } - ] - } - ], - "static_functions": [ - - ] - }, - { - "name": "GSTAgentLocation", - "path": "res://src/GSTAgentLocation.gd", - "extends_class": [ - - ], - "extends_file": "", - "icon": "", - "signature": "class GSTAgentLocation", - "description": " Represents an agent with only a location and an orientation.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - { - "name": "position", - "data_type": "Vector3", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var position: Vector3", - "description": " The agent's position in space.\n" - }, - { - "name": "orientation", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var orientation: float", - "description": " The agent's orientation on its Y axis rotation.\n" - } - ], - "signals": [ - - ], - "methods": [ - - ], - "static_functions": [ - - ] - }, - { - "name": "GSTGroupBehavior", - "path": "res://src/GSTGroupBehavior.gd", - "extends_class": [ - "GSTSteeringBehavior" - ], - "extends_file": "", - "icon": "", - "signature": "class GSTGroupBehavior", - "description": " Base type for group-based steering behaviors.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - { - "name": "proximity", - "data_type": "GSTProximity", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var proximity: GSTProximity", - "description": " Container to find neighbors of the agent and calculate group behavior.\n" - }, - { - "name": "_callback", - "data_type": "FuncRef", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var _callback: FuncRef", - "description": "" - } - ], - "signals": [ - - ], - "methods": [ - { - "name": "_init", - "return_type": "null", - "rpc_mode": 0, - "signature": "func _init(agent: GSTSteeringAgent, proximity: GSTProximity) -> null", - "description": "", - "arguments": [ - { - "name": "agent", - "type": "GSTSteeringAgent" - }, - { - "name": "proximity", - "type": "GSTProximity" - } - ] - }, - { - "name": "_report_neighbor", - "return_type": "bool", - "rpc_mode": 0, - "signature": "func _report_neighbor(neighbor: GSTSteeringAgent) -> bool", - "description": " Internal callback for the behavior to define whether or not a member is\n relevant\n tags: virtual\n", - "arguments": [ - { - "name": "neighbor", - "type": "GSTSteeringAgent" - } - ] - } - ], - "static_functions": [ - - ] - }, - { - "name": "GSTPath", - "path": "res://src/GSTPath.gd", - "extends_class": [ - "Reference" - ], - "extends_file": "", - "icon": "", - "signature": "class GSTPath", - "description": " Represents a path made up of Vector3 waypoints, split into segments path\n follow behaviors can use.\n", - "sub_classes": [ - { - "name": "GSTSegment", - "path": "res://src/GSTPath.gd", - "extends_class": [ - - ], - "extends_file": "", - "icon": "", - "signature": "class GSTSegment", - "description": "", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - { - "name": "begin", - "data_type": "Vector3", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var begin: Vector3", - "description": "" - }, - { - "name": "end", - "data_type": "Vector3", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var end: Vector3", - "description": "" - }, - { - "name": "length", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var length: float", - "description": "" - }, - { - "name": "cumulative_length", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var cumulative_length: float", - "description": "" - } - ], - "signals": [ - - ], - "methods": [ - { - "name": "_init", - "return_type": "null", - "rpc_mode": 0, - "signature": "func _init(begin: Vector3, end: Vector3) -> null", - "description": "", - "arguments": [ - { - "name": "begin", - "type": "Vector3" - }, - { - "name": "end", - "type": "Vector3" - } - ] - } - ], - "static_functions": [ - - ] - } - ], - "constants": [ - - ], - "members": [ - { - "name": "is_open", - "data_type": "bool", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var is_open: bool", - "description": " If `false`, the path loops.\n" - }, - { - "name": "length", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var length: float", - "description": " Total length of the path.\n" - }, - { - "name": "_segments", - "data_type": "Array", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var _segments: Array", - "description": "" - }, - { - "name": "_nearest_point_on_segment", - "data_type": "Vector3", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var _nearest_point_on_segment: Vector3", - "description": "" - }, - { - "name": "_nearest_point_on_path", - "data_type": "Vector3", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var _nearest_point_on_path: Vector3", - "description": "" - } - ], - "signals": [ - - ], - "methods": [ - { - "name": "_init", - "return_type": "null", - "rpc_mode": 0, - "signature": "func _init(waypoints: Array, is_open: bool = false) -> null", - "description": "", - "arguments": [ - { - "name": "waypoints", - "type": "Array" - }, - { - "name": "is_open", - "type": "bool", - "default_value": false - } - ] - }, - { - "name": "create_path", - "return_type": "null", - "rpc_mode": 0, - "signature": "func create_path(waypoints: Array) -> null", - "description": " Creates a path from a list of waypoints.\n", - "arguments": [ - { - "name": "waypoints", - "type": "Array" - } - ] - }, - { - "name": "calculate_distance", - "return_type": "float", - "rpc_mode": 0, - "signature": "func calculate_distance(agent_current_position: Vector3) -> float", - "description": " Returns the distance from `agent_current_position` to the next waypoint.\n", - "arguments": [ - { - "name": "agent_current_position", - "type": "Vector3" - } - ] - }, - { - "name": "calculate_target_position", - "return_type": "Vector3", - "rpc_mode": 0, - "signature": "func calculate_target_position(target_distance: float) -> Vector3", - "description": " Calculates a target position from the path's starting point based on the `target_distance`.\n", - "arguments": [ - { - "name": "target_distance", - "type": "float" - } - ] - }, - { - "name": "get_start_point", - "return_type": "Vector3", - "rpc_mode": 0, - "signature": "func get_start_point() -> Vector3", - "description": " Returns the position of the first point on the path.\n", - "arguments": [ - - ] - }, - { - "name": "get_end_point", - "return_type": "Vector3", - "rpc_mode": 0, - "signature": "func get_end_point() -> Vector3", - "description": " Returns the position of the last point on the path.\n", - "arguments": [ - - ] - }, - { - "name": "_calculate_point_segment_distance_squared", - "return_type": "float", - "rpc_mode": 0, - "signature": "func _calculate_point_segment_distance_squared(start: Vector3, end: Vector3, position: Vector3) -> float", - "description": "", - "arguments": [ - { - "name": "start", - "type": "Vector3" - }, - { - "name": "end", - "type": "Vector3" - }, - { - "name": "position", - "type": "Vector3" - } - ] - } - ], - "static_functions": [ - - ] - }, - { - "name": "GSTSteeringAgent", - "path": "res://src/GSTSteeringAgent.gd", - "extends_class": [ - "GSTAgentLocation" - ], - "extends_file": "", - "icon": "", - "signature": "class GSTSteeringAgent", - "description": " Adds velocity, speed, and size data to `GSTAgentLocation`.\n\n It is the character's responsibility to keep this information up to date for\n the steering toolkit to work correctly.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - { - "name": "zero_linear_speed_threshold", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var zero_linear_speed_threshold: float", - "description": " The amount of velocity to be considered effectively not moving.\n" - }, - { - "name": "linear_speed_max", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var linear_speed_max: float", - "description": " The maximum speed at which the agent can move.\n" - }, - { - "name": "linear_acceleration_max", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var linear_acceleration_max: float", - "description": " The maximum amount of acceleration that any behavior can apply to the agent.\n" - }, - { - "name": "angular_speed_max", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var angular_speed_max: float", - "description": " The maximum amount of angular speed at which the agent can rotate.\n" - }, - { - "name": "angular_acceleration_max", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var angular_acceleration_max: float", - "description": " The maximum amount of angular acceleration that any behavior can apply to an\n agent.\n" - }, - { - "name": "linear_velocity", - "data_type": "Vector3", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var linear_velocity: Vector3", - "description": " Current velocity of the agent.\n" - }, - { - "name": "angular_velocity", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var angular_velocity: float", - "description": " Current angular velocity of the agent.\n" - }, - { - "name": "bounding_radius", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var bounding_radius: float", - "description": " The radius of the sphere that approximates the agent's size in space.\n" - }, - { - "name": "is_tagged", - "data_type": "bool", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var is_tagged: bool", - "description": " Used internally by group behaviors and proximities to mark the agent as already\n considered.\n" - } - ], - "signals": [ - - ], - "methods": [ - - ], - "static_functions": [ - - ] - }, - { - "name": "GSTSteeringBehavior", - "path": "res://src/GSTSteeringBehavior.gd", - "extends_class": [ - - ], - "extends_file": "", - "icon": "", - "signature": "class GSTSteeringBehavior", - "description": " Base class for all steering behaviors.\n\n Steering behaviors calculate the linear and the angular acceleration to be\n to the agent that owns them.\n\n The `calculate_steering` function is the entry point for all behaviors.\n Individual steering behaviors encapsulate the steering logic.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - { - "name": "is_enabled", - "data_type": "bool", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var is_enabled: bool", - "description": " If `false`, all calculations return zero amounts of acceleration.\n" - }, - { - "name": "agent", - "data_type": "GSTSteeringAgent", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var agent: GSTSteeringAgent", - "description": " The AI agent on which the steering behavior bases its calculations.\n" - } - ], - "signals": [ - - ], - "methods": [ - { - "name": "_init", - "return_type": "null", - "rpc_mode": 0, - "signature": "func _init(agent: GSTSteeringAgent) -> null", - "description": "", - "arguments": [ - { - "name": "agent", - "type": "GSTSteeringAgent" - } - ] - }, - { - "name": "calculate_steering", - "return_type": "GSTTargetAcceleration", - "rpc_mode": 0, - "signature": "func calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration", - "description": " Returns the `acceleration` modified with the behavior's desired amount of\n acceleration.\n", - "arguments": [ - { - "name": "acceleration", - "type": "GSTTargetAcceleration" - } - ] - }, - { - "name": "_calculate_steering", - "return_type": "GSTTargetAcceleration", - "rpc_mode": 0, - "signature": "func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration", - "description": "", - "arguments": [ - { - "name": "acceleration", - "type": "GSTTargetAcceleration" - } - ] - } - ], - "static_functions": [ - - ] - }, - { - "name": "GSTTargetAcceleration", - "path": "res://src/GSTTargetAcceleration.gd", - "extends_class": [ - - ], - "extends_file": "", - "icon": "", - "signature": "class GSTTargetAcceleration", - "description": " A desired linear and angular amount of acceleration requested by the steering\n system.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - { - "name": "linear", - "data_type": "Vector3", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var linear: Vector3", - "description": " Linear acceleration\n" - }, - { - "name": "angular", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var angular: float", - "description": " Angular acceleration\n" - } - ], - "signals": [ - - ], - "methods": [ - { - "name": "set_zero", - "return_type": "null", - "rpc_mode": 0, - "signature": "func set_zero() -> null", - "description": " Sets the linear and angular components to 0.\n", - "arguments": [ - - ] - }, - { - "name": "add_scaled_accel", - "return_type": "null", - "rpc_mode": 0, - "signature": "func add_scaled_accel(accel: GSTTargetAcceleration, scalar: float) -> null", - "description": " Adds `accel`'s components, multiplied by `scalar`, to this one.\n", - "arguments": [ - { - "name": "accel", - "type": "GSTTargetAcceleration" - }, - { - "name": "scalar", - "type": "float" - } - ] - }, - { - "name": "get_magnitude_squared", - "return_type": "float", - "rpc_mode": 0, - "signature": "func get_magnitude_squared() -> float", - "description": " Returns the squared magnitude of the linear and angular components.\n", - "arguments": [ - - ] - }, - { - "name": "get_magnitude", - "return_type": "float", - "rpc_mode": 0, - "signature": "func get_magnitude() -> float", - "description": " Returns the magnitude of the linear and angular components.\n", - "arguments": [ - - ] - } - ], - "static_functions": [ - - ] - }, - { - "name": "GSTUtils", - "path": "res://src/GSTUtils.gd", - "extends_class": [ - - ], - "extends_file": "", - "icon": "", - "signature": "class GSTUtils", - "description": " Math and vector utility functions.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - - ], - "signals": [ - - ], - "methods": [ - - ], - "static_functions": [ - { - "name": "clampedv3", - "return_type": "Vector3", - "rpc_mode": 0, - "signature": "func clampedv3(vector: Vector3, limit: float) -> Vector3", - "description": " Returns the `vector` with its length capped to `limit`.\n", - "arguments": [ - { - "name": "vector", - "type": "Vector3" - }, - { - "name": "limit", - "type": "float" - } - ] - }, - { - "name": "vector3_to_angle", - "return_type": "float", - "rpc_mode": 0, - "signature": "func vector3_to_angle(vector: Vector3) -> float", - "description": " Returns an angle in radians between the positive X axis and the `vector`.\n\n This assumes orientation for 2D agents or 3D agents that are upright and\n rotate around the Y axis.\n", - "arguments": [ - { - "name": "vector", - "type": "Vector3" - } - ] - }, - { - "name": "angle_to_vector2", - "return_type": "Vector2", - "rpc_mode": 0, - "signature": "func angle_to_vector2(angle: float) -> Vector2", - "description": " Returns a directional vector from the given orientation angle.\n \n This assumes orientation for 2D agents or 3D agents that are upright and\n rotate around the Y axis.\n", - "arguments": [ - { - "name": "angle", - "type": "float" - } - ] - } - ] - }, - { - "name": "GSTInfiniteProximity", - "path": "res://src/Proximities/GSTInfiniteProximity.gd", - "extends_class": [ - "GSTProximity" - ], - "extends_file": "", - "icon": "", - "signature": "class GSTInfiniteProximity", - "description": " Determines any agent that is in the specified list as being neighbors with the\n owner agent, regardless of distance.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - - ], - "signals": [ - - ], - "methods": [ - { - "name": "_init", - "return_type": "null", - "rpc_mode": 0, - "signature": "func _init(agent: GSTSteeringAgent, agents: Array) -> null", - "description": "", - "arguments": [ - { - "name": "agent", - "type": "GSTSteeringAgent" - }, - { - "name": "agents", - "type": "Array" - } - ] - }, - { - "name": "_find_neighbors", - "return_type": "int", - "rpc_mode": 0, - "signature": "func _find_neighbors(callback: FuncRef) -> int", - "description": " Returns a number of neighbors based on a `callback` function.\n\n `_find_neighbors` calls `callback` for each agent in the `agents` array and\n adds one to the count if its `callback` returns true.\n tags: virtual\n", - "arguments": [ - { - "name": "callback", - "type": "FuncRef" - } - ] - } - ], - "static_functions": [ - - ] - }, - { - "name": "GSTProximity", - "path": "res://src/Proximities/GSTProximity.gd", - "extends_class": [ - "Reference" - ], - "extends_file": "", - "icon": "", - "signature": "class GSTProximity", - "description": " Base container type that stores data to find the neighbors of an agent.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - { - "name": "agent", - "data_type": "GSTSteeringAgent", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var agent: GSTSteeringAgent", - "description": " The owning agent whose neighbors are found in the group\n" - }, - { - "name": "agents", - "data_type": "Array", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var agents: Array", - "description": " The agents who are part of this group and could be potential neighbors\n" - } - ], - "signals": [ - - ], - "methods": [ - { - "name": "_init", - "return_type": "null", - "rpc_mode": 0, - "signature": "func _init(agent: GSTSteeringAgent, agents: Array) -> null", - "description": "", - "arguments": [ - { - "name": "agent", - "type": "GSTSteeringAgent" - }, - { - "name": "agents", - "type": "Array" - } - ] - }, - { - "name": "_find_neighbors", - "return_type": "int", - "rpc_mode": 0, - "signature": "func _find_neighbors(callback: FuncRef) -> int", - "description": " Returns a number of neighbors based on a `callback` function.\n\n `_find_neighbors` calls `callback` for each agent in the `agents` array and\n adds one to the count if its `callback` returns true.\n tags: virtual\n", - "arguments": [ - { - "name": "callback", - "type": "FuncRef" - } - ] - } - ], - "static_functions": [ - - ] - }, - { - "name": "GSTRadiusProximity", - "path": "res://src/Proximities/GSTRadiusProximity.gd", - "extends_class": [ - "GSTProximity" - ], - "extends_file": "", - "icon": "", - "signature": "class GSTRadiusProximity", - "description": " Determines any agent that is in the specified list as being neighbors with the owner agent if\n they lie within the specified radius.\n", - "sub_classes": [ - - ], - "constants": [ - - ], - "members": [ - { - "name": "radius", - "data_type": "float", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var radius: float", - "description": " The radius around the owning agent to find neighbors in\n" - }, - { - "name": "_last_frame", - "data_type": "int", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var _last_frame: int", - "description": "" - }, - { - "name": "_scene_tree", - "data_type": "SceneTree", - "default_value": null, - "setter": "", - "getter": "", - "export": false, - "signature": "var _scene_tree: SceneTree", - "description": "" - } - ], - "signals": [ - - ], - "methods": [ - { - "name": "_init", - "return_type": "null", - "rpc_mode": 0, - "signature": "func _init(agent: GSTSteeringAgent, agents: Array, radius: float) -> null", - "description": "", - "arguments": [ - { - "name": "agent", - "type": "GSTSteeringAgent" - }, - { - "name": "agents", - "type": "Array" - }, - { - "name": "radius", - "type": "float" - } - ] - }, - { - "name": "_find_neighbors", - "return_type": "int", - "rpc_mode": 0, - "signature": "func _find_neighbors(callback: FuncRef) -> int", - "description": " Returns a number of neighbors based on a `callback` function.\n\n `_find_neighbors` calls `callback` for each agent in the `agents` array that lie within\n the radius around the owning agent and adds one to the count if its `callback` returns true.\n tags: virtual\n", - "arguments": [ - { - "name": "callback", - "type": "FuncRef" - } - ] - } - ], - "static_functions": [ - - ] - } -] \ No newline at end of file diff --git a/project/src/Agents/GSTNode2DAgent.gd b/project/src/Agents/GSTNode2DAgent.gd new file mode 100644 index 0000000..dd4d0b9 --- /dev/null +++ b/project/src/Agents/GSTNode2DAgent.gd @@ -0,0 +1,165 @@ +# A specialized steering agent that updates itself every frame so the user does +# not have to. +extends GSTNodeAgent +class_name GSTNode2DAgent + + +# The Node2D to keep track of +var body: Node2D setget _set_body + +var _last_position: Vector2 + + +func _init(body: Node2D) -> void: + self.body = body + if body.is_inside_tree(): + body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") + else: + body.connect("ready", self, "_on_body_ready") + + +# Moves the agent's `body` by target `acceleration`. +# tags: virtual +func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: + _applied_steering = true + match _body_type: + BodyType.RIGID: + _apply_rigid_steering(acceleration) + BodyType.KINEMATIC: + match kinematic_movement_type: + MovementType.COLLIDE: + _apply_collide_steering(acceleration.linear, delta) + MovementType.SLIDE: + _apply_sliding_steering(acceleration.linear) + MovementType.POSITION: + _apply_normal_steering(acceleration.linear, delta) + BodyType.NODE: + _apply_normal_steering(acceleration.linear, delta) + if not _body_type == BodyType.RIGID: + _apply_orientation_steering(acceleration.angular, delta) + + +func _apply_rigid_steering(accel: GSTTargetAcceleration) -> void: + body.apply_central_impulse(GSTUtils.to_vector2(accel.linear)) + body.apply_torque_impulse(accel.angular) + if calculate_velocities: + linear_velocity = GSTUtils.to_vector3(body.linear_velocity) + angular_velocity = body.angular_velocity + + +func _apply_sliding_steering(accel: Vector3) -> void: + var velocity := GSTUtils.to_vector2(linear_velocity + accel).clamped(linear_speed_max) + if apply_linear_drag: + velocity = velocity.linear_interpolate(Vector2.ZERO, linear_drag_percentage) + velocity = body.move_and_slide(velocity) + if calculate_velocities: + linear_velocity = GSTUtils.to_vector3(velocity) + + +func _apply_collide_steering(accel: Vector3, delta: float) -> void: + var velocity := GSTUtils.clampedv3(linear_velocity + accel, linear_speed_max) + if apply_linear_drag: + velocity = velocity.linear_interpolate( + Vector3.ZERO, + linear_drag_percentage + ) + body.move_and_collide(GSTUtils.to_vector2(velocity) * delta) + if calculate_velocities: + linear_velocity = velocity + + +func _apply_normal_steering(accel: Vector3, delta: float) -> void: + var velocity := GSTUtils.clampedv3(linear_velocity + accel, linear_speed_max) + if apply_linear_drag: + velocity = velocity.linear_interpolate( + Vector3.ZERO, + linear_drag_percentage + ) + body.global_position += GSTUtils.to_vector2(velocity) * delta + if calculate_velocities: + linear_velocity = velocity + + +func _apply_orientation_steering(angular_acceleration: float, delta: float) -> void: + var velocity = angular_velocity + angular_acceleration + if apply_angular_drag: + velocity = lerp(velocity, 0, angular_drag_percentage) + body.rotation += velocity * delta + if calculate_velocities: + angular_velocity = velocity + + +func _set_use_physics(value: bool) -> void: + if use_physics and not value: + body.get_tree().disconnect("idle_frame", self, "_on_SceneTree_frame") + body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") + elif not use_physics and value: + body.get_tree().disconnect("physics_frame", self, "_on_SceneTree_frame") + body.get_tree().connect("idle_frame", self, "_on_SceneTree_frame") + use_physics = value + + +func _set_body(value: Node2D) -> void: + body = value + if body is RigidBody2D: + _body_type = BodyType.RIGID + elif body is KinematicBody2D: + _body_type = BodyType.KINEMATIC + else: + _body_type = BodyType.NODE + + if _body_type == BodyType.RIGID: + linear_velocity = GSTUtils.to_vector3(body.linear_velocity) + angular_velocity = body.angular_velocity + else: + _last_position = body.global_position + _last_orientation = body.rotation + + position = GSTUtils.to_vector3(_last_position) + orientation = _last_orientation + + +func _on_body_ready() -> void: + body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") + _set_body(body) + + +func _on_SceneTree_frame() -> void: + var current_position: Vector2 = body.global_position + var current_orientation: float = body.rotation + + position = GSTUtils.to_vector3(current_position) + orientation = current_orientation + + if calculate_velocities: + if _applied_steering: + _applied_steering = false + else: + match _body_type: + BodyType.RIGID: + linear_velocity = GSTUtils.to_vector3(body.linear_velocity) + angular_velocity = body.angular_velocity + _: + linear_velocity = GSTUtils.clampedv3( + GSTUtils.to_vector3(_last_position - current_position), + linear_speed_max + ) + if apply_linear_drag: + linear_velocity = linear_velocity.linear_interpolate( + Vector3.ZERO, + linear_drag_percentage + ) + angular_velocity = clamp( + _last_orientation - current_orientation, + -angular_speed_max, + angular_speed_max + ) + if apply_angular_drag: + angular_velocity = lerp( + angular_velocity, + 0, + angular_drag_percentage + ) + + _last_position = current_position + _last_orientation = current_orientation diff --git a/project/src/Agents/GSTNodeAgent.gd b/project/src/Agents/GSTNodeAgent.gd new file mode 100644 index 0000000..f69e06b --- /dev/null +++ b/project/src/Agents/GSTNodeAgent.gd @@ -0,0 +1,79 @@ +# A base class for a specialized steering agent that updates itself every frame +# so the user does not have to. +extends GSTSteeringAgent +class_name GSTNodeAgent + + +enum MovementType { SLIDE, COLLIDE, POSITION } + +enum BodyType { NODE, KINEMATIC, RIGID } + + +# If `true`, will update before `_physics_process` is called. If `false`, will +# update before `_process` is called. +# +# `KinematicBody`, `KinematicBody2D`, `RigidBody`, and `RigidBody2D` should +# always use `_physics_process`. +var use_physics := true setget _set_use_physics + +# If `true`, will calculate linear and angular velocities based on the previous +# frame. When `false`, the user must keep those values updated. +var calculate_velocities := true + +# If `true` and velocities and `calculate_velocities` is true, will interpolate +# the current linear velocity towards 0 by the `linear_drag_percentage` value. +# Does not apply to `RigidBody` and `RigidBody2D` nodes. +var apply_linear_drag := true + +# If `true` and velocities and `calculate_velocities` is true, will interpolate +# the current angular velocity towards 0 by the `angular_drag_percentage` value. +# Does not apply to `RigidBody` and `RigidBody2D` nodes. +var apply_angular_drag := true + +# The percentage between the current linear velocity and 0 to interpolate by if +# `calculate_velocities` and `apply_linear_drag` are true. +# Does not apply to `RigidBody` and `RigidBody2D` nodes. +var linear_drag_percentage := 0.0 + +# The percentage between the current angular velocity and 0 to interpolate by if +# `calculate_velocities` and `apply_angular_drag` are true. +# Does not apply to `RigidBody` and `RigidBody2D` nodes. +var angular_drag_percentage := 0.0 + +# Determines how linear movement occurs if the body is a `KinematicBody` or +# `KinematicBody2D`. +# +# SLIDE uses `move_and_slide` +# COLLIDE uses `move_and_collide` +# POSITION changes global position directly +var kinematic_movement_type: int = MovementType.SLIDE + +var _last_orientation: float +var _body_type: int +var _applied_steering := false + + +# Moves the agent's body by target `acceleration`. +# tags: virtual +func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: + pass + + +func _apply_sliding_steering(accel: Vector3) -> void: + pass + + +func _apply_collide_steering(accel: Vector3, delta: float) -> void: + pass + + +func _apply_normal_steering(accel: Vector3, delta: float) -> void: + pass + + +func _apply_orientation_steering(angular_acceleration: float, delta: float) -> void: + pass + + +func _set_use_physics(value: bool) -> void: + use_physics = value diff --git a/project/src/Agents/GSTSpatialAgent.gd b/project/src/Agents/GSTSpatialAgent.gd new file mode 100644 index 0000000..b145530 --- /dev/null +++ b/project/src/Agents/GSTSpatialAgent.gd @@ -0,0 +1,166 @@ +# A specialized steering agent that updates itself every frame so the user does +# not have to. +extends GSTNodeAgent +class_name GSTSpatialAgent + + +# The Spatial to keep track of +var body: Spatial setget _set_body + +var _last_position: Vector3 + + +func _init(body: Spatial) -> void: + self.body = body + if body.is_inside_tree(): + body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") + else: + body.connect("ready", self, "_on_body_ready") + + +# Moves the agent's `body` by target `acceleration`. +# tags: virtual +func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: + _applied_steering = true + match _body_type: + BodyType.RIGID: + _apply_rigid_steering(acceleration) + BodyType.KINEMATIC: + match kinematic_movement_type: + MovementType.COLLIDE: + _apply_collide_steering(acceleration.linear, delta) + MovementType.SLIDE: + _apply_sliding_steering(acceleration.linear) + MovementType.POSITION: + _apply_normal_steering(acceleration.linear, delta) + BodyType.NODE: + _apply_normal_steering(acceleration.linear, delta) + if not _body_type == BodyType.RIGID: + _apply_orientation_steering(acceleration.angular, delta) + + +func _apply_rigid_steering(accel: GSTTargetAcceleration) -> void: + body.apply_central_impulse(GSTUtils.to_Vector3(accel.linear)) + body.apply_torque_impulse(accel.angular) + if calculate_velocities: + linear_velocity = body.linear_velocity + angular_velocity = body.angular_velocity.y + + +func _apply_sliding_steering(accel: Vector3) -> void: + var velocity := GSTUtils.clampedv3(linear_velocity + accel, linear_speed_max) + if apply_linear_drag: + velocity = velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage) + velocity = body.move_and_slide(velocity) + if calculate_velocities: + linear_velocity = velocity + + +func _apply_collide_steering(accel: Vector3, delta: float) -> void: + var velocity := GSTUtils.clampedv3(linear_velocity + accel, linear_speed_max) + if apply_linear_drag: + velocity = velocity.linear_interpolate( + Vector3.ZERO, + linear_drag_percentage + ) + body.move_and_collide(velocity * delta) + if calculate_velocities: + linear_velocity = velocity + + +func _apply_normal_steering(accel: Vector3, delta: float) -> void: + var velocity := GSTUtils.clampedv3(linear_velocity + accel, linear_speed_max) + if apply_linear_drag: + velocity = velocity.linear_interpolate( + Vector3.ZERO, + linear_drag_percentage + ) + body.global_position += velocity * delta + if calculate_velocities: + linear_velocity = velocity + + +func _apply_orientation_steering(angular_acceleration: float, delta: float) -> void: + var velocity = angular_velocity + angular_acceleration + if apply_angular_drag: + velocity = lerp(velocity, 0, angular_drag_percentage) + body.rotation += velocity * delta + if calculate_velocities: + angular_velocity = velocity + + +func _set_use_physics(value: bool) -> void: + if use_physics and not value: + body.get_tree().disconnect("idle_frame", self, "_on_SceneTree_frame") + body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") + elif not use_physics and value: + body.get_tree().disconnect("physics_frame", self, "_on_SceneTree_frame") + body.get_tree().connect("idle_frame", self, "_on_SceneTree_frame") + use_physics = value + + +func _set_body(value: Spatial) -> void: + body = value + if body is RigidBody: + _body_type = BodyType.RIGID + elif body is KinematicBody: + _body_type = BodyType.KINEMATIC + else: + _body_type = BodyType.NODE + + if _body_type == BodyType.RIGID: + linear_velocity = body.linear_velocity + angular_velocity = body.angular_velocity + else: + _last_position = body.global_position + _last_orientation = body.rotation.y + + position = _last_position + orientation = _last_orientation + + +func _on_body_ready() -> void: + body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") + body.disconnect("ready", self, "_on_body_ready") + _set_body(body) + + +func _on_SceneTree_frame() -> void: + var current_position: Vector3 = body.global_position + var current_orientation: float = body.rotation.y + + position = current_position + orientation = current_orientation + + if calculate_velocities: + if _applied_steering: + _applied_steering = false + else: + match _body_type: + BodyType.RIGID: + linear_velocity = GSTUtils.to_vector3(body.linear_velocity) + angular_velocity = body.angular_velocity + _: + linear_velocity = GSTUtils.clampedv3( + _last_position - current_position, + linear_speed_max + ) + if apply_linear_drag: + linear_velocity = linear_velocity.linear_interpolate( + Vector3.ZERO, + linear_drag_percentage + ) + angular_velocity = clamp( + _last_orientation - current_orientation, + -angular_speed_max, + angular_speed_max + ) + if apply_angular_drag: + angular_velocity = lerp( + angular_velocity, + 0, + angular_drag_percentage + ) + + _last_position = current_position + _last_orientation = current_orientation diff --git a/project/src/GSTUtils.gd b/project/src/GSTUtils.gd index d3e1c89..bbe5e34 100644 --- a/project/src/GSTUtils.gd +++ b/project/src/GSTUtils.gd @@ -25,3 +25,13 @@ static func vector3_to_angle(vector: Vector3) -> float: # rotate around the Y axis. static func angle_to_vector2(angle: float) -> Vector2: return Vector2(sin(-angle), cos(angle)) + + +# Returns a vector2 with `vector`'s x and y components. +static func to_vector2(vector: Vector3) -> Vector2: + return Vector2(vector.x, vector.y) + + +# Returns a vector3 with `vector`'s x and y components and 0 in z. +static func to_vector3(vector: Vector2) -> Vector3: + return Vector3(vector.x, vector.y, 0) From 7311b75456b3f48320a9399731c34ec47d1ddad6 Mon Sep 17 00:00:00 2001 From: Francois Belair Date: Thu, 6 Feb 2020 14:54:12 -0500 Subject: [PATCH 3/6] Add and have most demos use specialized agents The agents auto-update themselves and can calculate their velocities. This keeps the user from having to create an update_agent function. It can also save the user from having to keep track of and update velocities at all by using the provided `apply_steering` method. Closes #15, closes #16 From 2ae06d3da34aa64a4d0673169c56c8ac2b1edcd3 Mon Sep 17 00:00:00 2001 From: Francois Belair Date: Thu, 6 Feb 2020 16:29:48 -0500 Subject: [PATCH 4/6] Split agent types into specialized classes --- project/demos/Arrive/Arriver.gd | 2 +- project/demos/AvoidCollisions/Avoider.gd | 2 +- project/demos/Face/Turret.gd | 2 +- project/demos/FollowPath/PathFollower.gd | 2 +- project/demos/GroupBehaviors/Member.gd | 2 +- project/demos/GroupBehaviors/Member.tscn | 1 - project/demos/PursueSeek/Pursuer.gd | 2 +- project/demos/SeekFlee/Seeker.gd | 2 +- project/project.godot | 44 +++-- ...e2DAgent.gd => GSTKinematicBody2DAgent.gd} | 125 ++++++------- project/src/Agents/GSTKinematicBodyAgent.gd | 138 +++++++++++++++ project/src/Agents/GSTNodeAgent.gd | 79 --------- project/src/Agents/GSTRigidBody2DAgent.gd | 59 +++++++ project/src/Agents/GSTRigidBodyAgent.gd | 59 +++++++ project/src/Agents/GSTSpatialAgent.gd | 166 ------------------ project/src/Agents/GSTSpecializedAgent.gd | 40 +++++ 16 files changed, 380 insertions(+), 345 deletions(-) rename project/src/Agents/{GSTNode2DAgent.gd => GSTKinematicBody2DAgent.gd} (50%) create mode 100644 project/src/Agents/GSTKinematicBodyAgent.gd delete mode 100644 project/src/Agents/GSTNodeAgent.gd create mode 100644 project/src/Agents/GSTRigidBody2DAgent.gd create mode 100644 project/src/Agents/GSTRigidBodyAgent.gd delete mode 100644 project/src/Agents/GSTSpatialAgent.gd create mode 100644 project/src/Agents/GSTSpecializedAgent.gd diff --git a/project/demos/Arrive/Arriver.gd b/project/demos/Arrive/Arriver.gd index e065805..0d3b81d 100644 --- a/project/demos/Arrive/Arriver.gd +++ b/project/demos/Arrive/Arriver.gd @@ -1,7 +1,7 @@ extends KinematicBody2D -var agent := GSTNode2DAgent.new(self) +var agent := GSTKinematicBody2DAgent.new(self) var target := GSTAgentLocation.new() var arrive := GSTArrive.new(agent, target) var _accel := GSTTargetAcceleration.new() diff --git a/project/demos/AvoidCollisions/Avoider.gd b/project/demos/AvoidCollisions/Avoider.gd index 3464351..dfb8281 100644 --- a/project/demos/AvoidCollisions/Avoider.gd +++ b/project/demos/AvoidCollisions/Avoider.gd @@ -13,7 +13,7 @@ var _drag := 0.1 var _color := Color(0.4, 1.0, 0.89, 0.3) onready var collision := $CollisionShape2D -onready var agent := GSTNode2DAgent.new(self) +onready var agent := GSTKinematicBody2DAgent.new(self) onready var proximity := GSTRadiusProximity.new(agent, [], 140) onready var avoid := GSTAvoidCollisions.new(agent, proximity) onready var target := GSTAgentLocation.new() diff --git a/project/demos/Face/Turret.gd b/project/demos/Face/Turret.gd index 6992a22..8326837 100644 --- a/project/demos/Face/Turret.gd +++ b/project/demos/Face/Turret.gd @@ -2,7 +2,7 @@ extends KinematicBody2D var face: GSTFace -var agent := GSTNode2DAgent.new(self) +var agent := GSTKinematicBody2DAgent.new(self) var _accel := GSTTargetAcceleration.new() var _angular_drag := 0.1 diff --git a/project/demos/FollowPath/PathFollower.gd b/project/demos/FollowPath/PathFollower.gd index cea97dd..d9b54cb 100644 --- a/project/demos/FollowPath/PathFollower.gd +++ b/project/demos/FollowPath/PathFollower.gd @@ -6,7 +6,7 @@ var _accel := GSTTargetAcceleration.new() var _valid := false var _drag := 0.1 -onready var agent := GSTNode2DAgent.new(self) +onready var agent := GSTKinematicBody2DAgent.new(self) onready var path := GSTPath.new([ Vector3(global_position.x, global_position.y, 0), Vector3(global_position.x, global_position.y, 0) diff --git a/project/demos/GroupBehaviors/Member.gd b/project/demos/GroupBehaviors/Member.gd index 1658dd5..183a681 100644 --- a/project/demos/GroupBehaviors/Member.gd +++ b/project/demos/GroupBehaviors/Member.gd @@ -4,7 +4,7 @@ extends KinematicBody2D var separation: GSTSeparation var cohesion: GSTCohesion var proximity: GSTRadiusProximity -var agent := GSTNode2DAgent.new(self) +var agent := GSTKinematicBody2DAgent.new(self) var blend := GSTBlend.new(agent) var acceleration := GSTTargetAcceleration.new() var draw_proximity := false diff --git a/project/demos/GroupBehaviors/Member.tscn b/project/demos/GroupBehaviors/Member.tscn index c85ab3f..0baef77 100644 --- a/project/demos/GroupBehaviors/Member.tscn +++ b/project/demos/GroupBehaviors/Member.tscn @@ -12,6 +12,5 @@ script = ExtResource( 1 ) [node name="CollisionShape2D" type="CollisionShape2D" parent="."] shape = SubResource( 1 ) script = ExtResource( 3 ) -inner_color = Color( 0, 0, 0, 1 ) outer_color = Color( 0.301961, 0.65098, 1, 1 ) stroke = 4.0 diff --git a/project/demos/PursueSeek/Pursuer.gd b/project/demos/PursueSeek/Pursuer.gd index 37e245b..cfe4884 100644 --- a/project/demos/PursueSeek/Pursuer.gd +++ b/project/demos/PursueSeek/Pursuer.gd @@ -10,7 +10,7 @@ var _linear_drag_coefficient := 0.025 var _angular_drag := 0.1 var _direction_face := GSTAgentLocation.new() -onready var agent := GSTNode2DAgent.new(self) +onready var agent := GSTKinematicBody2DAgent.new(self) onready var accel := GSTTargetAcceleration.new() onready var player_agent: GSTSteeringAgent = owner.find_node("Player", true, false).agent diff --git a/project/demos/SeekFlee/Seeker.gd b/project/demos/SeekFlee/Seeker.gd index da01af9..a18d111 100644 --- a/project/demos/SeekFlee/Seeker.gd +++ b/project/demos/SeekFlee/Seeker.gd @@ -7,7 +7,7 @@ var start_speed: float var start_accel: float var use_seek := true -onready var agent := GSTNode2DAgent.new(self) +onready var agent := GSTKinematicBody2DAgent.new(self) onready var accel := GSTTargetAcceleration.new() onready var seek := GSTSeek.new(agent, player_agent) onready var flee := GSTFlee.new(agent, player_agent) diff --git a/project/project.godot b/project/project.godot index f555a0d..11a6b05 100644 --- a/project/project.godot +++ b/project/project.godot @@ -64,6 +64,16 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://src/Proximities/GSTInfiniteProximity.gd" }, { +"base": "GSTSpecializedAgent", +"class": "GSTKinematicBody2DAgent", +"language": "GDScript", +"path": "res://src/Agents/GSTKinematicBody2DAgent.gd" +}, { +"base": "GSTSpecializedAgent", +"class": "GSTKinematicBodyAgent", +"language": "GDScript", +"path": "res://src/Agents/GSTKinematicBodyAgent.gd" +}, { "base": "GSTMatchOrientation", "class": "GSTLookWhereYouGo", "language": "GDScript", @@ -74,16 +84,6 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://src/Behaviors/GSTMatchOrientation.gd" }, { -"base": "GSTNodeAgent", -"class": "GSTNode2DAgent", -"language": "GDScript", -"path": "res://src/Agents/GSTNode2DAgent.gd" -}, { -"base": "GSTSteeringAgent", -"class": "GSTNodeAgent", -"language": "GDScript", -"path": "res://src/Agents/GSTNodeAgent.gd" -}, { "base": "Reference", "class": "GSTPath", "language": "GDScript", @@ -109,6 +109,16 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://src/Proximities/GSTRadiusProximity.gd" }, { +"base": "GSTSpecializedAgent", +"class": "GSTRigidBody2DAgent", +"language": "GDScript", +"path": "res://src/Agents/GSTRigidBody2DAgent.gd" +}, { +"base": "GSTSpecializedAgent", +"class": "GSTRigidBodyAgent", +"language": "GDScript", +"path": "res://src/Agents/GSTRigidBodyAgent.gd" +}, { "base": "GSTSteeringBehavior", "class": "GSTSeek", "language": "GDScript", @@ -119,10 +129,10 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://src/Behaviors/GSTSeparation.gd" }, { -"base": "GSTNodeAgent", -"class": "GSTSpatialAgent", +"base": "GSTSteeringAgent", +"class": "GSTSpecializedAgent", "language": "GDScript", -"path": "res://src/Agents/GSTSpatialAgent.gd" +"path": "res://src/Agents/GSTSpecializedAgent.gd" }, { "base": "GSTAgentLocation", "class": "GSTSteeringAgent", @@ -156,18 +166,20 @@ _global_script_class_icons={ "GSTFollowPath": "", "GSTGroupBehavior": "", "GSTInfiniteProximity": "", +"GSTKinematicBody2DAgent": "", +"GSTKinematicBodyAgent": "", "GSTLookWhereYouGo": "", "GSTMatchOrientation": "", -"GSTNode2DAgent": "", -"GSTNodeAgent": "", "GSTPath": "", "GSTPriority": "", "GSTProximity": "", "GSTPursue": "", "GSTRadiusProximity": "", +"GSTRigidBody2DAgent": "", +"GSTRigidBodyAgent": "", "GSTSeek": "", "GSTSeparation": "", -"GSTSpatialAgent": "", +"GSTSpecializedAgent": "", "GSTSteeringAgent": "", "GSTSteeringBehavior": "", "GSTTargetAcceleration": "", diff --git a/project/src/Agents/GSTNode2DAgent.gd b/project/src/Agents/GSTKinematicBody2DAgent.gd similarity index 50% rename from project/src/Agents/GSTNode2DAgent.gd rename to project/src/Agents/GSTKinematicBody2DAgent.gd index dd4d0b9..1f18176 100644 --- a/project/src/Agents/GSTNode2DAgent.gd +++ b/project/src/Agents/GSTKinematicBody2DAgent.gd @@ -1,16 +1,26 @@ # A specialized steering agent that updates itself every frame so the user does -# not have to. -extends GSTNodeAgent -class_name GSTNode2DAgent +# not have to using a KinematicBody2D +extends GSTSpecializedAgent +class_name GSTKinematicBody2DAgent -# The Node2D to keep track of -var body: Node2D setget _set_body +enum KinematicMovementType { SLIDE, COLLIDE, POSITION } + + +# The KinematicBody2D to keep track of +var body: KinematicBody2D setget _set_body + +# The type of movement the body executes +# +# SLIDE uses use move_and_slide +# COLLIDE uses move_and_collide +# POSITION changes the global_position directly +var kinematic_movement_type: int = KinematicMovementType.SLIDE var _last_position: Vector2 -func _init(body: Node2D) -> void: +func _init(body: KinematicBody2D) -> void: self.body = body if body.is_inside_tree(): body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") @@ -22,29 +32,15 @@ func _init(body: Node2D) -> void: # tags: virtual func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: _applied_steering = true - match _body_type: - BodyType.RIGID: - _apply_rigid_steering(acceleration) - BodyType.KINEMATIC: - match kinematic_movement_type: - MovementType.COLLIDE: - _apply_collide_steering(acceleration.linear, delta) - MovementType.SLIDE: - _apply_sliding_steering(acceleration.linear) - MovementType.POSITION: - _apply_normal_steering(acceleration.linear, delta) - BodyType.NODE: + match kinematic_movement_type: + KinematicMovementType.COLLIDE: + _apply_collide_steering(acceleration.linear, delta) + KinematicMovementType.SLIDE: + _apply_sliding_steering(acceleration.linear) + _: _apply_normal_steering(acceleration.linear, delta) - if not _body_type == BodyType.RIGID: - _apply_orientation_steering(acceleration.angular, delta) - - -func _apply_rigid_steering(accel: GSTTargetAcceleration) -> void: - body.apply_central_impulse(GSTUtils.to_vector2(accel.linear)) - body.apply_torque_impulse(accel.angular) - if calculate_velocities: - linear_velocity = GSTUtils.to_vector3(body.linear_velocity) - angular_velocity = body.angular_velocity + + _apply_orientation_steering(acceleration.angular, delta) func _apply_sliding_steering(accel: Vector3) -> void: @@ -89,31 +85,11 @@ func _apply_orientation_steering(angular_acceleration: float, delta: float) -> v angular_velocity = velocity -func _set_use_physics(value: bool) -> void: - if use_physics and not value: - body.get_tree().disconnect("idle_frame", self, "_on_SceneTree_frame") - body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") - elif not use_physics and value: - body.get_tree().disconnect("physics_frame", self, "_on_SceneTree_frame") - body.get_tree().connect("idle_frame", self, "_on_SceneTree_frame") - use_physics = value - - -func _set_body(value: Node2D) -> void: +func _set_body(value: KinematicBody2D) -> void: body = value - if body is RigidBody2D: - _body_type = BodyType.RIGID - elif body is KinematicBody2D: - _body_type = BodyType.KINEMATIC - else: - _body_type = BodyType.NODE - if _body_type == BodyType.RIGID: - linear_velocity = GSTUtils.to_vector3(body.linear_velocity) - angular_velocity = body.angular_velocity - else: - _last_position = body.global_position - _last_orientation = body.rotation + _last_position = body.global_position + _last_orientation = body.rotation position = GSTUtils.to_vector3(_last_position) orientation = _last_orientation @@ -135,31 +111,28 @@ func _on_SceneTree_frame() -> void: if _applied_steering: _applied_steering = false else: - match _body_type: - BodyType.RIGID: - linear_velocity = GSTUtils.to_vector3(body.linear_velocity) - angular_velocity = body.angular_velocity - _: - linear_velocity = GSTUtils.clampedv3( - GSTUtils.to_vector3(_last_position - current_position), - linear_speed_max - ) - if apply_linear_drag: - linear_velocity = linear_velocity.linear_interpolate( - Vector3.ZERO, - linear_drag_percentage - ) - angular_velocity = clamp( - _last_orientation - current_orientation, - -angular_speed_max, - angular_speed_max - ) - if apply_angular_drag: - angular_velocity = lerp( - angular_velocity, - 0, - angular_drag_percentage - ) + linear_velocity = GSTUtils.clampedv3( + GSTUtils.to_vector3(_last_position - current_position), + linear_speed_max + ) + if apply_linear_drag: + linear_velocity = linear_velocity.linear_interpolate( + Vector3.ZERO, + linear_drag_percentage + ) + + angular_velocity = clamp( + _last_orientation - current_orientation, + -angular_speed_max, + angular_speed_max + ) + + if apply_angular_drag: + angular_velocity = lerp( + angular_velocity, + 0, + angular_drag_percentage + ) _last_position = current_position _last_orientation = current_orientation diff --git a/project/src/Agents/GSTKinematicBodyAgent.gd b/project/src/Agents/GSTKinematicBodyAgent.gd new file mode 100644 index 0000000..690c147 --- /dev/null +++ b/project/src/Agents/GSTKinematicBodyAgent.gd @@ -0,0 +1,138 @@ +# A specialized steering agent that updates itself every frame so the user does +# not have to using a KinematicBody +extends GSTSpecializedAgent +class_name GSTKinematicBodyAgent + + +enum KinematicMovementType { SLIDE, COLLIDE, POSITION } + + +# The KinematicBody to keep track of +var body: KinematicBody setget _set_body + +# The type of movement the body executes +# +# SLIDE uses use move_and_slide +# COLLIDE uses move_and_collide +# POSITION changes the global_position directly +var kinematic_movement_type: int = KinematicMovementType.SLIDE + +var _last_position: Vector3 + + +func _init(body: KinematicBody) -> void: + self.body = body + if body.is_inside_tree(): + body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") + else: + body.connect("ready", self, "_on_body_ready") + + +# Moves the agent's `body` by target `acceleration`. +# tags: virtual +func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: + _applied_steering = true + match kinematic_movement_type: + KinematicMovementType.COLLIDE: + _apply_collide_steering(acceleration.linear, delta) + KinematicMovementType.SLIDE: + _apply_sliding_steering(acceleration.linear) + _: + _apply_normal_steering(acceleration.linear, delta) + + _apply_orientation_steering(acceleration.angular, delta) + + +func _apply_sliding_steering(accel: Vector3) -> void: + var velocity := GSTUtils.clampedv3(linear_velocity + accel, linear_speed_max) + if apply_linear_drag: + velocity = velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage) + velocity = body.move_and_slide(velocity) + if calculate_velocities: + linear_velocity = velocity + + +func _apply_collide_steering(accel: Vector3, delta: float) -> void: + var velocity := GSTUtils.clampedv3(linear_velocity + accel, linear_speed_max) + if apply_linear_drag: + velocity = velocity.linear_interpolate( + Vector3.ZERO, + linear_drag_percentage + ) + body.move_and_collide(velocity * delta) + if calculate_velocities: + linear_velocity = velocity + + +func _apply_normal_steering(accel: Vector3, delta: float) -> void: + var velocity := GSTUtils.clampedv3(linear_velocity + accel, linear_speed_max) + if apply_linear_drag: + velocity = velocity.linear_interpolate( + Vector3.ZERO, + linear_drag_percentage + ) + body.global_position += velocity * delta + if calculate_velocities: + linear_velocity = velocity + + +func _apply_orientation_steering(angular_acceleration: float, delta: float) -> void: + var velocity = angular_velocity + angular_acceleration + if apply_angular_drag: + velocity = lerp(velocity, 0, angular_drag_percentage) + body.rotation.y += velocity * delta + if calculate_velocities: + angular_velocity = velocity + + +func _set_body(value: KinematicBody) -> void: + body = value + + _last_position = body.global_position + _last_orientation = body.rotation.y + + position = _last_position + orientation = _last_orientation + + +func _on_body_ready() -> void: + body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") + _set_body(body) + + +func _on_SceneTree_frame() -> void: + var current_position: Vector3 = body.global_position + var current_orientation: float = body.rotation.y + + position = current_position + orientation = current_orientation + + if calculate_velocities: + if _applied_steering: + _applied_steering = false + else: + linear_velocity = GSTUtils.clampedv3( + _last_position - current_position, + linear_speed_max + ) + if apply_linear_drag: + linear_velocity = linear_velocity.linear_interpolate( + Vector3.ZERO, + linear_drag_percentage + ) + + angular_velocity = clamp( + _last_orientation - current_orientation, + -angular_speed_max, + angular_speed_max + ) + + if apply_angular_drag: + angular_velocity = lerp( + angular_velocity, + 0, + angular_drag_percentage + ) + + _last_position = current_position + _last_orientation = current_orientation diff --git a/project/src/Agents/GSTNodeAgent.gd b/project/src/Agents/GSTNodeAgent.gd deleted file mode 100644 index f69e06b..0000000 --- a/project/src/Agents/GSTNodeAgent.gd +++ /dev/null @@ -1,79 +0,0 @@ -# A base class for a specialized steering agent that updates itself every frame -# so the user does not have to. -extends GSTSteeringAgent -class_name GSTNodeAgent - - -enum MovementType { SLIDE, COLLIDE, POSITION } - -enum BodyType { NODE, KINEMATIC, RIGID } - - -# If `true`, will update before `_physics_process` is called. If `false`, will -# update before `_process` is called. -# -# `KinematicBody`, `KinematicBody2D`, `RigidBody`, and `RigidBody2D` should -# always use `_physics_process`. -var use_physics := true setget _set_use_physics - -# If `true`, will calculate linear and angular velocities based on the previous -# frame. When `false`, the user must keep those values updated. -var calculate_velocities := true - -# If `true` and velocities and `calculate_velocities` is true, will interpolate -# the current linear velocity towards 0 by the `linear_drag_percentage` value. -# Does not apply to `RigidBody` and `RigidBody2D` nodes. -var apply_linear_drag := true - -# If `true` and velocities and `calculate_velocities` is true, will interpolate -# the current angular velocity towards 0 by the `angular_drag_percentage` value. -# Does not apply to `RigidBody` and `RigidBody2D` nodes. -var apply_angular_drag := true - -# The percentage between the current linear velocity and 0 to interpolate by if -# `calculate_velocities` and `apply_linear_drag` are true. -# Does not apply to `RigidBody` and `RigidBody2D` nodes. -var linear_drag_percentage := 0.0 - -# The percentage between the current angular velocity and 0 to interpolate by if -# `calculate_velocities` and `apply_angular_drag` are true. -# Does not apply to `RigidBody` and `RigidBody2D` nodes. -var angular_drag_percentage := 0.0 - -# Determines how linear movement occurs if the body is a `KinematicBody` or -# `KinematicBody2D`. -# -# SLIDE uses `move_and_slide` -# COLLIDE uses `move_and_collide` -# POSITION changes global position directly -var kinematic_movement_type: int = MovementType.SLIDE - -var _last_orientation: float -var _body_type: int -var _applied_steering := false - - -# Moves the agent's body by target `acceleration`. -# tags: virtual -func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: - pass - - -func _apply_sliding_steering(accel: Vector3) -> void: - pass - - -func _apply_collide_steering(accel: Vector3, delta: float) -> void: - pass - - -func _apply_normal_steering(accel: Vector3, delta: float) -> void: - pass - - -func _apply_orientation_steering(angular_acceleration: float, delta: float) -> void: - pass - - -func _set_use_physics(value: bool) -> void: - use_physics = value diff --git a/project/src/Agents/GSTRigidBody2DAgent.gd b/project/src/Agents/GSTRigidBody2DAgent.gd new file mode 100644 index 0000000..2222259 --- /dev/null +++ b/project/src/Agents/GSTRigidBody2DAgent.gd @@ -0,0 +1,59 @@ +# A specialized steering agent that updates itself every frame so the user does +# not have to using a RigidBody2D +extends GSTSpecializedAgent +class_name GSTRigidBody2DAgent + + +# The RigidBody2D to keep track of +var body: RigidBody2D setget _set_body + +var _last_position: Vector2 + + +func _init(body: RigidBody2D) -> void: + self.body = body + if body.is_inside_tree(): + body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") + else: + body.connect("ready", self, "_on_body_ready") + + +# Moves the agent's `body` by target `acceleration`. +# tags: virtual +func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: + _applied_steering = true + body.apply_central_impulse(GSTUtils.to_vector2(acceleration.linear)) + body.apply_torque_impulse(acceleration.angular) + if calculate_velocities: + linear_velocity = GSTUtils.to_vector3(body.linear_velocity) + angular_velocity = body.angular_velocity + + +func _set_body(value: RigidBody2D) -> void: + body = value + + _last_position = body.global_position + _last_orientation = body.rotation + + position = GSTUtils.to_vector3(_last_position) + orientation = _last_orientation + + +func _on_body_ready() -> void: + body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") + _set_body(body) + + +func _on_SceneTree_frame() -> void: + var current_position: Vector2 = body.global_position + var current_orientation: float = body.rotation + + position = GSTUtils.to_vector3(current_position) + orientation = current_orientation + + if calculate_velocities: + if _applied_steering: + _applied_steering = false + else: + linear_velocity = GSTUtils.to_vector3(body.linear_velocity) + angular_velocity = body.angular_velocity diff --git a/project/src/Agents/GSTRigidBodyAgent.gd b/project/src/Agents/GSTRigidBodyAgent.gd new file mode 100644 index 0000000..cb5eb3d --- /dev/null +++ b/project/src/Agents/GSTRigidBodyAgent.gd @@ -0,0 +1,59 @@ +# A specialized steering agent that updates itself every frame so the user does +# not have to using a RigidBody +extends GSTSpecializedAgent +class_name GSTRigidBodyAgent + + +# The RigidBody to keep track of +var body: RigidBody setget _set_body + +var _last_position: Vector3 + + +func _init(body: RigidBody) -> void: + self.body = body + if body.is_inside_tree(): + body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") + else: + body.connect("ready", self, "_on_body_ready") + + +# Moves the agent's `body` by target `acceleration`. +# tags: virtual +func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: + _applied_steering = true + body.apply_central_impulse(acceleration.linear) + body.apply_torque_impulse(Vector3.UP * acceleration.angular) + if calculate_velocities: + linear_velocity = body.linear_velocity + angular_velocity = body.angular_velocity.y + + +func _set_body(value: RigidBody) -> void: + body = value + + _last_position = body.global_position + _last_orientation = body.rotation.y + + position = _last_position + orientation = _last_orientation + + +func _on_body_ready() -> void: + body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") + _set_body(body) + + +func _on_SceneTree_frame() -> void: + var current_position: Vector3 = body.global_position + var current_orientation: float = body.rotation.y + + position = current_position + orientation = current_orientation + + if calculate_velocities: + if _applied_steering: + _applied_steering = false + else: + linear_velocity = body.linear_velocity + angular_velocity = body.angular_velocity.y diff --git a/project/src/Agents/GSTSpatialAgent.gd b/project/src/Agents/GSTSpatialAgent.gd deleted file mode 100644 index b145530..0000000 --- a/project/src/Agents/GSTSpatialAgent.gd +++ /dev/null @@ -1,166 +0,0 @@ -# A specialized steering agent that updates itself every frame so the user does -# not have to. -extends GSTNodeAgent -class_name GSTSpatialAgent - - -# The Spatial to keep track of -var body: Spatial setget _set_body - -var _last_position: Vector3 - - -func _init(body: Spatial) -> void: - self.body = body - if body.is_inside_tree(): - body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") - else: - body.connect("ready", self, "_on_body_ready") - - -# Moves the agent's `body` by target `acceleration`. -# tags: virtual -func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: - _applied_steering = true - match _body_type: - BodyType.RIGID: - _apply_rigid_steering(acceleration) - BodyType.KINEMATIC: - match kinematic_movement_type: - MovementType.COLLIDE: - _apply_collide_steering(acceleration.linear, delta) - MovementType.SLIDE: - _apply_sliding_steering(acceleration.linear) - MovementType.POSITION: - _apply_normal_steering(acceleration.linear, delta) - BodyType.NODE: - _apply_normal_steering(acceleration.linear, delta) - if not _body_type == BodyType.RIGID: - _apply_orientation_steering(acceleration.angular, delta) - - -func _apply_rigid_steering(accel: GSTTargetAcceleration) -> void: - body.apply_central_impulse(GSTUtils.to_Vector3(accel.linear)) - body.apply_torque_impulse(accel.angular) - if calculate_velocities: - linear_velocity = body.linear_velocity - angular_velocity = body.angular_velocity.y - - -func _apply_sliding_steering(accel: Vector3) -> void: - var velocity := GSTUtils.clampedv3(linear_velocity + accel, linear_speed_max) - if apply_linear_drag: - velocity = velocity.linear_interpolate(Vector3.ZERO, linear_drag_percentage) - velocity = body.move_and_slide(velocity) - if calculate_velocities: - linear_velocity = velocity - - -func _apply_collide_steering(accel: Vector3, delta: float) -> void: - var velocity := GSTUtils.clampedv3(linear_velocity + accel, linear_speed_max) - if apply_linear_drag: - velocity = velocity.linear_interpolate( - Vector3.ZERO, - linear_drag_percentage - ) - body.move_and_collide(velocity * delta) - if calculate_velocities: - linear_velocity = velocity - - -func _apply_normal_steering(accel: Vector3, delta: float) -> void: - var velocity := GSTUtils.clampedv3(linear_velocity + accel, linear_speed_max) - if apply_linear_drag: - velocity = velocity.linear_interpolate( - Vector3.ZERO, - linear_drag_percentage - ) - body.global_position += velocity * delta - if calculate_velocities: - linear_velocity = velocity - - -func _apply_orientation_steering(angular_acceleration: float, delta: float) -> void: - var velocity = angular_velocity + angular_acceleration - if apply_angular_drag: - velocity = lerp(velocity, 0, angular_drag_percentage) - body.rotation += velocity * delta - if calculate_velocities: - angular_velocity = velocity - - -func _set_use_physics(value: bool) -> void: - if use_physics and not value: - body.get_tree().disconnect("idle_frame", self, "_on_SceneTree_frame") - body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") - elif not use_physics and value: - body.get_tree().disconnect("physics_frame", self, "_on_SceneTree_frame") - body.get_tree().connect("idle_frame", self, "_on_SceneTree_frame") - use_physics = value - - -func _set_body(value: Spatial) -> void: - body = value - if body is RigidBody: - _body_type = BodyType.RIGID - elif body is KinematicBody: - _body_type = BodyType.KINEMATIC - else: - _body_type = BodyType.NODE - - if _body_type == BodyType.RIGID: - linear_velocity = body.linear_velocity - angular_velocity = body.angular_velocity - else: - _last_position = body.global_position - _last_orientation = body.rotation.y - - position = _last_position - orientation = _last_orientation - - -func _on_body_ready() -> void: - body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") - body.disconnect("ready", self, "_on_body_ready") - _set_body(body) - - -func _on_SceneTree_frame() -> void: - var current_position: Vector3 = body.global_position - var current_orientation: float = body.rotation.y - - position = current_position - orientation = current_orientation - - if calculate_velocities: - if _applied_steering: - _applied_steering = false - else: - match _body_type: - BodyType.RIGID: - linear_velocity = GSTUtils.to_vector3(body.linear_velocity) - angular_velocity = body.angular_velocity - _: - linear_velocity = GSTUtils.clampedv3( - _last_position - current_position, - linear_speed_max - ) - if apply_linear_drag: - linear_velocity = linear_velocity.linear_interpolate( - Vector3.ZERO, - linear_drag_percentage - ) - angular_velocity = clamp( - _last_orientation - current_orientation, - -angular_speed_max, - angular_speed_max - ) - if apply_angular_drag: - angular_velocity = lerp( - angular_velocity, - 0, - angular_drag_percentage - ) - - _last_position = current_position - _last_orientation = current_orientation diff --git a/project/src/Agents/GSTSpecializedAgent.gd b/project/src/Agents/GSTSpecializedAgent.gd new file mode 100644 index 0000000..9392cd3 --- /dev/null +++ b/project/src/Agents/GSTSpecializedAgent.gd @@ -0,0 +1,40 @@ +# A base class for a specialized steering agent that updates itself every frame +# so the user does not have to. All other specialized agents derive from this. +# tags: abstract +extends GSTSteeringAgent +class_name GSTSpecializedAgent + + +# If `true`, calculates linear and angular velocities based on the previous +# frame. When `false`, the user must keep those values updated. +var calculate_velocities := true + +# If `true` and velocities and `calculate_velocities` is true, interpolates +# the current linear velocity towards 0 by the `linear_drag_percentage` value. +# Does not apply to `RigidBody` and `RigidBody2D` nodes. +var apply_linear_drag := true + +# If `true` and velocities and `calculate_velocities` is true, interpolates +# the current angular velocity towards 0 by the `angular_drag_percentage` value. +# Does not apply to `RigidBody` and `RigidBody2D` nodes. +var apply_angular_drag := true + +# The percentage between the current linear velocity and 0 to interpolate by if +# `calculate_velocities` and `apply_linear_drag` are true. +# Does not apply to `RigidBody` and `RigidBody2D` nodes. +var linear_drag_percentage := 0.0 + +# The percentage between the current angular velocity and 0 to interpolate by if +# `calculate_velocities` and `apply_angular_drag` are true. +# Does not apply to `RigidBody` and `RigidBody2D` nodes. +var angular_drag_percentage := 0.0 + +var _last_orientation: float +var _body_type: int +var _applied_steering := false + + +# Moves the agent's body by target `acceleration`. +# tags: virtual +func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: + pass From 1baed58659825332190b4fa38f3a36e2d403da03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=83zvan=20C=2E=20R=C4=83dulescu?= Date: Fri, 7 Feb 2020 12:29:45 +0200 Subject: [PATCH 5/6] Review smart agents I made minimal changes, mostly cosmetic like so: - rename KinematicMovementType to MovementType since GSTKinematicBody2DAgent.KinematicMovementType.COLLIDE for example is really more than a mouthful with repeated Kinematic in the name - add optional movement_type parameter to the constructor, otherwise we'd be forced to construct the object and then specify as an aditional step the type of movement if we want something else than the default - rewrote the constructor to yield on ready and removed _on_body_ready - renamed _apply_steering to apply_steering as this is a public method - renamed _on_SceneTree_frame to _on_SceneTree_physics_frame --- project/demos/Arrive/Arriver.gd | 2 +- project/demos/AvoidCollisions/Avoider.gd | 2 +- project/demos/Face/Turret.gd | 2 +- project/demos/FollowPath/PathFollower.gd | 2 +- project/demos/GroupBehaviors/Member.gd | 2 +- project/demos/SeekFlee/Seeker.gd | 2 +- project/src/Agents/GSTKinematicBody2DAgent.gd | 34 ++++++++----------- project/src/Agents/GSTKinematicBodyAgent.gd | 34 ++++++++----------- project/src/Agents/GSTRigidBody2DAgent.gd | 2 +- project/src/Agents/GSTRigidBodyAgent.gd | 2 +- project/src/Agents/GSTSpecializedAgent.gd | 2 +- 11 files changed, 39 insertions(+), 47 deletions(-) diff --git a/project/demos/Arrive/Arriver.gd b/project/demos/Arrive/Arriver.gd index 0d3b81d..dc7e196 100644 --- a/project/demos/Arrive/Arriver.gd +++ b/project/demos/Arrive/Arriver.gd @@ -12,7 +12,7 @@ var _drag := 0.1 func _physics_process(delta: float) -> void: arrive.calculate_steering(_accel) - agent._apply_steering(_accel, delta) + agent.apply_steering(_accel, delta) func setup( diff --git a/project/demos/AvoidCollisions/Avoider.gd b/project/demos/AvoidCollisions/Avoider.gd index dfb8281..894ae7e 100644 --- a/project/demos/AvoidCollisions/Avoider.gd +++ b/project/demos/AvoidCollisions/Avoider.gd @@ -31,7 +31,7 @@ func _physics_process(delta: float) -> void: target.position.y = agent.position.y + _direction.y*_radius priority.calculate_steering(_accel) - agent._apply_steering(_accel, delta) + agent.apply_steering(_accel, delta) func setup( diff --git a/project/demos/Face/Turret.gd b/project/demos/Face/Turret.gd index 8326837..30ca245 100644 --- a/project/demos/Face/Turret.gd +++ b/project/demos/Face/Turret.gd @@ -20,7 +20,7 @@ func _ready() -> void: func _physics_process(delta: float) -> void: face.calculate_steering(_accel) - agent._apply_steering(_accel, delta) + agent.apply_steering(_accel, delta) func _draw() -> void: diff --git a/project/demos/FollowPath/PathFollower.gd b/project/demos/FollowPath/PathFollower.gd index d9b54cb..67dd256 100644 --- a/project/demos/FollowPath/PathFollower.gd +++ b/project/demos/FollowPath/PathFollower.gd @@ -36,7 +36,7 @@ func setup( func _physics_process(delta: float) -> void: if _valid: follow.calculate_steering(_accel) - agent._apply_steering(_accel, delta) + agent.apply_steering(_accel, delta) func _on_Drawer_path_established(points: Array) -> void: diff --git a/project/demos/GroupBehaviors/Member.gd b/project/demos/GroupBehaviors/Member.gd index 183a681..4fe6168 100644 --- a/project/demos/GroupBehaviors/Member.gd +++ b/project/demos/GroupBehaviors/Member.gd @@ -46,7 +46,7 @@ func _draw() -> void: func _physics_process(delta: float) -> void: if blend: blend.calculate_steering(acceleration) - agent._apply_steering(acceleration, delta) + agent.apply_steering(acceleration, delta) func set_neighbors(neighbor: Array) -> void: diff --git a/project/demos/SeekFlee/Seeker.gd b/project/demos/SeekFlee/Seeker.gd index a18d111..896a420 100644 --- a/project/demos/SeekFlee/Seeker.gd +++ b/project/demos/SeekFlee/Seeker.gd @@ -27,4 +27,4 @@ func _physics_process(delta: float) -> void: else: flee.calculate_steering(accel) - agent._apply_steering(accel, delta) + agent.apply_steering(accel, delta) diff --git a/project/src/Agents/GSTKinematicBody2DAgent.gd b/project/src/Agents/GSTKinematicBody2DAgent.gd index 1f18176..4854939 100644 --- a/project/src/Agents/GSTKinematicBody2DAgent.gd +++ b/project/src/Agents/GSTKinematicBody2DAgent.gd @@ -4,7 +4,7 @@ extends GSTSpecializedAgent class_name GSTKinematicBody2DAgent -enum KinematicMovementType { SLIDE, COLLIDE, POSITION } +enum MovementType { SLIDE, COLLIDE, POSITION } # The KinematicBody2D to keep track of @@ -15,30 +15,31 @@ var body: KinematicBody2D setget _set_body # SLIDE uses use move_and_slide # COLLIDE uses move_and_collide # POSITION changes the global_position directly -var kinematic_movement_type: int = KinematicMovementType.SLIDE +var movement_type: int var _last_position: Vector2 -func _init(body: KinematicBody2D) -> void: +func _init(body: KinematicBody2D, movement_type: int = MovementType.SLIDE) -> void: + yield(body, "ready") + self.body = body - if body.is_inside_tree(): - body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") - else: - body.connect("ready", self, "_on_body_ready") + self.movement_type = movement_type + + body.get_tree().connect("physics_frame", self, "_on_SceneTree_physics_frame") # Moves the agent's `body` by target `acceleration`. # tags: virtual -func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: +func apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: _applied_steering = true - match kinematic_movement_type: - KinematicMovementType.COLLIDE: + match movement_type: + MovementType.COLLIDE: _apply_collide_steering(acceleration.linear, delta) - KinematicMovementType.SLIDE: + MovementType.SLIDE: _apply_sliding_steering(acceleration.linear) _: - _apply_normal_steering(acceleration.linear, delta) + _apply_position_steering(acceleration.linear, delta) _apply_orientation_steering(acceleration.angular, delta) @@ -64,7 +65,7 @@ func _apply_collide_steering(accel: Vector3, delta: float) -> void: linear_velocity = velocity -func _apply_normal_steering(accel: Vector3, delta: float) -> void: +func _apply_position_steering(accel: Vector3, delta: float) -> void: var velocity := GSTUtils.clampedv3(linear_velocity + accel, linear_speed_max) if apply_linear_drag: velocity = velocity.linear_interpolate( @@ -95,12 +96,7 @@ func _set_body(value: KinematicBody2D) -> void: orientation = _last_orientation -func _on_body_ready() -> void: - body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") - _set_body(body) - - -func _on_SceneTree_frame() -> void: +func _on_SceneTree_physics_frame() -> void: var current_position: Vector2 = body.global_position var current_orientation: float = body.rotation diff --git a/project/src/Agents/GSTKinematicBodyAgent.gd b/project/src/Agents/GSTKinematicBodyAgent.gd index 690c147..3744047 100644 --- a/project/src/Agents/GSTKinematicBodyAgent.gd +++ b/project/src/Agents/GSTKinematicBodyAgent.gd @@ -4,7 +4,7 @@ extends GSTSpecializedAgent class_name GSTKinematicBodyAgent -enum KinematicMovementType { SLIDE, COLLIDE, POSITION } +enum MovementType { SLIDE, COLLIDE, POSITION } # The KinematicBody to keep track of @@ -15,30 +15,31 @@ var body: KinematicBody setget _set_body # SLIDE uses use move_and_slide # COLLIDE uses move_and_collide # POSITION changes the global_position directly -var kinematic_movement_type: int = KinematicMovementType.SLIDE +var movement_type: int var _last_position: Vector3 -func _init(body: KinematicBody) -> void: +func _init(body: KinematicBody, movement_type: int = MovementType.SLIDE) -> void: + yield(body, "ready") + self.body = body - if body.is_inside_tree(): - body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") - else: - body.connect("ready", self, "_on_body_ready") + self.movement_type = movement_type + + body.get_tree().connect("physics_frame", self, "_on_SceneTree_physics_frame") # Moves the agent's `body` by target `acceleration`. # tags: virtual -func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: +func apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: _applied_steering = true - match kinematic_movement_type: - KinematicMovementType.COLLIDE: + match movement_type: + MovementType.COLLIDE: _apply_collide_steering(acceleration.linear, delta) - KinematicMovementType.SLIDE: + MovementType.SLIDE: _apply_sliding_steering(acceleration.linear) _: - _apply_normal_steering(acceleration.linear, delta) + _apply_position_steering(acceleration.linear, delta) _apply_orientation_steering(acceleration.angular, delta) @@ -64,7 +65,7 @@ func _apply_collide_steering(accel: Vector3, delta: float) -> void: linear_velocity = velocity -func _apply_normal_steering(accel: Vector3, delta: float) -> void: +func _apply_position_steering(accel: Vector3, delta: float) -> void: var velocity := GSTUtils.clampedv3(linear_velocity + accel, linear_speed_max) if apply_linear_drag: velocity = velocity.linear_interpolate( @@ -95,12 +96,7 @@ func _set_body(value: KinematicBody) -> void: orientation = _last_orientation -func _on_body_ready() -> void: - body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") - _set_body(body) - - -func _on_SceneTree_frame() -> void: +func _on_SceneTree_physics_frame() -> void: var current_position: Vector3 = body.global_position var current_orientation: float = body.rotation.y diff --git a/project/src/Agents/GSTRigidBody2DAgent.gd b/project/src/Agents/GSTRigidBody2DAgent.gd index 2222259..bb52652 100644 --- a/project/src/Agents/GSTRigidBody2DAgent.gd +++ b/project/src/Agents/GSTRigidBody2DAgent.gd @@ -20,7 +20,7 @@ func _init(body: RigidBody2D) -> void: # Moves the agent's `body` by target `acceleration`. # tags: virtual -func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: +func apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: _applied_steering = true body.apply_central_impulse(GSTUtils.to_vector2(acceleration.linear)) body.apply_torque_impulse(acceleration.angular) diff --git a/project/src/Agents/GSTRigidBodyAgent.gd b/project/src/Agents/GSTRigidBodyAgent.gd index cb5eb3d..499e6c4 100644 --- a/project/src/Agents/GSTRigidBodyAgent.gd +++ b/project/src/Agents/GSTRigidBodyAgent.gd @@ -20,7 +20,7 @@ func _init(body: RigidBody) -> void: # Moves the agent's `body` by target `acceleration`. # tags: virtual -func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: +func apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: _applied_steering = true body.apply_central_impulse(acceleration.linear) body.apply_torque_impulse(Vector3.UP * acceleration.angular) diff --git a/project/src/Agents/GSTSpecializedAgent.gd b/project/src/Agents/GSTSpecializedAgent.gd index 9392cd3..55b0bdf 100644 --- a/project/src/Agents/GSTSpecializedAgent.gd +++ b/project/src/Agents/GSTSpecializedAgent.gd @@ -36,5 +36,5 @@ var _applied_steering := false # Moves the agent's body by target `acceleration`. # tags: virtual -func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: +func apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: pass From dc9a57e7fd997d9fe46bfa109904417cf687a575 Mon Sep 17 00:00:00 2001 From: Francois Belair Date: Fri, 7 Feb 2020 09:15:03 -0500 Subject: [PATCH 6/6] Append _ to apply_steering and fix yield on ready --- project/demos/Arrive/Arriver.gd | 2 +- project/demos/AvoidCollisions/Avoider.gd | 2 +- project/demos/Face/Turret.gd | 2 +- project/demos/FollowPath/PathFollower.gd | 2 +- project/demos/GroupBehaviors/Member.gd | 2 +- project/demos/SeekFlee/Seeker.gd | 2 +- project/project.godot | 8 +++++++- project/src/Agents/GSTKinematicBody2DAgent.gd | 12 ++++++------ project/src/Agents/GSTKinematicBodyAgent.gd | 13 ++++++------- project/src/Agents/GSTRigidBody2DAgent.gd | 9 ++++----- project/src/Agents/GSTRigidBodyAgent.gd | 11 ++++++----- project/src/Agents/GSTSpecializedAgent.gd | 6 +++--- 12 files changed, 38 insertions(+), 33 deletions(-) diff --git a/project/demos/Arrive/Arriver.gd b/project/demos/Arrive/Arriver.gd index dc7e196..0d3b81d 100644 --- a/project/demos/Arrive/Arriver.gd +++ b/project/demos/Arrive/Arriver.gd @@ -12,7 +12,7 @@ var _drag := 0.1 func _physics_process(delta: float) -> void: arrive.calculate_steering(_accel) - agent.apply_steering(_accel, delta) + agent._apply_steering(_accel, delta) func setup( diff --git a/project/demos/AvoidCollisions/Avoider.gd b/project/demos/AvoidCollisions/Avoider.gd index 894ae7e..dfb8281 100644 --- a/project/demos/AvoidCollisions/Avoider.gd +++ b/project/demos/AvoidCollisions/Avoider.gd @@ -31,7 +31,7 @@ func _physics_process(delta: float) -> void: target.position.y = agent.position.y + _direction.y*_radius priority.calculate_steering(_accel) - agent.apply_steering(_accel, delta) + agent._apply_steering(_accel, delta) func setup( diff --git a/project/demos/Face/Turret.gd b/project/demos/Face/Turret.gd index 30ca245..8326837 100644 --- a/project/demos/Face/Turret.gd +++ b/project/demos/Face/Turret.gd @@ -20,7 +20,7 @@ func _ready() -> void: func _physics_process(delta: float) -> void: face.calculate_steering(_accel) - agent.apply_steering(_accel, delta) + agent._apply_steering(_accel, delta) func _draw() -> void: diff --git a/project/demos/FollowPath/PathFollower.gd b/project/demos/FollowPath/PathFollower.gd index 67dd256..d9b54cb 100644 --- a/project/demos/FollowPath/PathFollower.gd +++ b/project/demos/FollowPath/PathFollower.gd @@ -36,7 +36,7 @@ func setup( func _physics_process(delta: float) -> void: if _valid: follow.calculate_steering(_accel) - agent.apply_steering(_accel, delta) + agent._apply_steering(_accel, delta) func _on_Drawer_path_established(points: Array) -> void: diff --git a/project/demos/GroupBehaviors/Member.gd b/project/demos/GroupBehaviors/Member.gd index 4fe6168..183a681 100644 --- a/project/demos/GroupBehaviors/Member.gd +++ b/project/demos/GroupBehaviors/Member.gd @@ -46,7 +46,7 @@ func _draw() -> void: func _physics_process(delta: float) -> void: if blend: blend.calculate_steering(acceleration) - agent.apply_steering(acceleration, delta) + agent._apply_steering(acceleration, delta) func set_neighbors(neighbor: Array) -> void: diff --git a/project/demos/SeekFlee/Seeker.gd b/project/demos/SeekFlee/Seeker.gd index 896a420..a18d111 100644 --- a/project/demos/SeekFlee/Seeker.gd +++ b/project/demos/SeekFlee/Seeker.gd @@ -27,4 +27,4 @@ func _physics_process(delta: float) -> void: else: flee.calculate_steering(accel) - agent.apply_steering(accel, delta) + agent._apply_steering(accel, delta) diff --git a/project/project.godot b/project/project.godot index 11a6b05..888d2b6 100644 --- a/project/project.godot +++ b/project/project.godot @@ -153,6 +153,11 @@ _global_script_classes=[ { "class": "GSTUtils", "language": "GDScript", "path": "res://src/GSTUtils.gd" +}, { +"base": "EditorScript", +"class": "ReferenceCollector", +"language": "GDScript", +"path": "res://ReferenceCollector.gd" } ] _global_script_class_icons={ "GSTAgentLocation": "", @@ -183,7 +188,8 @@ _global_script_class_icons={ "GSTSteeringAgent": "", "GSTSteeringBehavior": "", "GSTTargetAcceleration": "", -"GSTUtils": "" +"GSTUtils": "", +"ReferenceCollector": "" } [application] diff --git a/project/src/Agents/GSTKinematicBody2DAgent.gd b/project/src/Agents/GSTKinematicBody2DAgent.gd index 4854939..4e01ba9 100644 --- a/project/src/Agents/GSTKinematicBody2DAgent.gd +++ b/project/src/Agents/GSTKinematicBody2DAgent.gd @@ -4,6 +4,9 @@ extends GSTSpecializedAgent class_name GSTKinematicBody2DAgent +# SLIDE uses `move_and_slide` +# COLLIDE uses `move_and_collide` +# POSITION changes the `global_position` directly enum MovementType { SLIDE, COLLIDE, POSITION } @@ -11,17 +14,14 @@ enum MovementType { SLIDE, COLLIDE, POSITION } var body: KinematicBody2D setget _set_body # The type of movement the body executes -# -# SLIDE uses use move_and_slide -# COLLIDE uses move_and_collide -# POSITION changes the global_position directly var movement_type: int var _last_position: Vector2 func _init(body: KinematicBody2D, movement_type: int = MovementType.SLIDE) -> void: - yield(body, "ready") + if not body.is_inside_tree(): + yield(body, "ready") self.body = body self.movement_type = movement_type @@ -31,7 +31,7 @@ func _init(body: KinematicBody2D, movement_type: int = MovementType.SLIDE) -> vo # Moves the agent's `body` by target `acceleration`. # tags: virtual -func apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: +func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: _applied_steering = true match movement_type: MovementType.COLLIDE: diff --git a/project/src/Agents/GSTKinematicBodyAgent.gd b/project/src/Agents/GSTKinematicBodyAgent.gd index 3744047..da84d23 100644 --- a/project/src/Agents/GSTKinematicBodyAgent.gd +++ b/project/src/Agents/GSTKinematicBodyAgent.gd @@ -3,7 +3,9 @@ extends GSTSpecializedAgent class_name GSTKinematicBodyAgent - +# SLIDE uses `move_and_slide` +# COLLIDE uses `move_and_collide` +# POSITION changes the global_position directly enum MovementType { SLIDE, COLLIDE, POSITION } @@ -11,17 +13,14 @@ enum MovementType { SLIDE, COLLIDE, POSITION } var body: KinematicBody setget _set_body # The type of movement the body executes -# -# SLIDE uses use move_and_slide -# COLLIDE uses move_and_collide -# POSITION changes the global_position directly var movement_type: int var _last_position: Vector3 func _init(body: KinematicBody, movement_type: int = MovementType.SLIDE) -> void: - yield(body, "ready") + if not body.is_inside_tree(): + yield(body, "ready") self.body = body self.movement_type = movement_type @@ -31,7 +30,7 @@ func _init(body: KinematicBody, movement_type: int = MovementType.SLIDE) -> void # Moves the agent's `body` by target `acceleration`. # tags: virtual -func apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: +func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: _applied_steering = true match movement_type: MovementType.COLLIDE: diff --git a/project/src/Agents/GSTRigidBody2DAgent.gd b/project/src/Agents/GSTRigidBody2DAgent.gd index bb52652..43e2a6b 100644 --- a/project/src/Agents/GSTRigidBody2DAgent.gd +++ b/project/src/Agents/GSTRigidBody2DAgent.gd @@ -11,16 +11,15 @@ var _last_position: Vector2 func _init(body: RigidBody2D) -> void: + if not body.is_inside_tree(): + yield(body, "ready") + self.body = body - if body.is_inside_tree(): - body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") - else: - body.connect("ready", self, "_on_body_ready") # Moves the agent's `body` by target `acceleration`. # tags: virtual -func apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: +func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: _applied_steering = true body.apply_central_impulse(GSTUtils.to_vector2(acceleration.linear)) body.apply_torque_impulse(acceleration.angular) diff --git a/project/src/Agents/GSTRigidBodyAgent.gd b/project/src/Agents/GSTRigidBodyAgent.gd index 499e6c4..c3d189c 100644 --- a/project/src/Agents/GSTRigidBodyAgent.gd +++ b/project/src/Agents/GSTRigidBodyAgent.gd @@ -11,16 +11,17 @@ var _last_position: Vector3 func _init(body: RigidBody) -> void: + if not body.is_inside_tree(): + yield(body, "ready") + self.body = body - if body.is_inside_tree(): - body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") - else: - body.connect("ready", self, "_on_body_ready") + body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") + # Moves the agent's `body` by target `acceleration`. # tags: virtual -func apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: +func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: _applied_steering = true body.apply_central_impulse(acceleration.linear) body.apply_torque_impulse(Vector3.UP * acceleration.angular) diff --git a/project/src/Agents/GSTSpecializedAgent.gd b/project/src/Agents/GSTSpecializedAgent.gd index 55b0bdf..2f97b7d 100644 --- a/project/src/Agents/GSTSpecializedAgent.gd +++ b/project/src/Agents/GSTSpecializedAgent.gd @@ -9,12 +9,12 @@ class_name GSTSpecializedAgent # frame. When `false`, the user must keep those values updated. var calculate_velocities := true -# If `true` and velocities and `calculate_velocities` is true, interpolates +# If `true` and `calculate_velocities` is true, interpolates # the current linear velocity towards 0 by the `linear_drag_percentage` value. # Does not apply to `RigidBody` and `RigidBody2D` nodes. var apply_linear_drag := true -# If `true` and velocities and `calculate_velocities` is true, interpolates +# If `true` and `calculate_velocities` is true, interpolates # the current angular velocity towards 0 by the `angular_drag_percentage` value. # Does not apply to `RigidBody` and `RigidBody2D` nodes. var apply_angular_drag := true @@ -36,5 +36,5 @@ var _applied_steering := false # Moves the agent's body by target `acceleration`. # tags: virtual -func apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: +func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: pass