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