Split agent types into specialized classes

This commit is contained in:
Francois Belair 2020-02-06 16:29:48 -05:00
parent 7311b75456
commit 2ae06d3da3
16 changed files with 380 additions and 345 deletions

View File

@ -1,7 +1,7 @@
extends KinematicBody2D extends KinematicBody2D
var agent := GSTNode2DAgent.new(self) var agent := GSTKinematicBody2DAgent.new(self)
var target := GSTAgentLocation.new() var target := GSTAgentLocation.new()
var arrive := GSTArrive.new(agent, target) var arrive := GSTArrive.new(agent, target)
var _accel := GSTTargetAcceleration.new() var _accel := GSTTargetAcceleration.new()

View File

@ -13,7 +13,7 @@ var _drag := 0.1
var _color := Color(0.4, 1.0, 0.89, 0.3) var _color := Color(0.4, 1.0, 0.89, 0.3)
onready var collision := $CollisionShape2D 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 proximity := GSTRadiusProximity.new(agent, [], 140)
onready var avoid := GSTAvoidCollisions.new(agent, proximity) onready var avoid := GSTAvoidCollisions.new(agent, proximity)
onready var target := GSTAgentLocation.new() onready var target := GSTAgentLocation.new()

View File

@ -2,7 +2,7 @@ extends KinematicBody2D
var face: GSTFace var face: GSTFace
var agent := GSTNode2DAgent.new(self) var agent := GSTKinematicBody2DAgent.new(self)
var _accel := GSTTargetAcceleration.new() var _accel := GSTTargetAcceleration.new()
var _angular_drag := 0.1 var _angular_drag := 0.1

View File

@ -6,7 +6,7 @@ var _accel := GSTTargetAcceleration.new()
var _valid := false var _valid := false
var _drag := 0.1 var _drag := 0.1
onready var agent := GSTNode2DAgent.new(self) onready var agent := GSTKinematicBody2DAgent.new(self)
onready var path := GSTPath.new([ onready var path := GSTPath.new([
Vector3(global_position.x, global_position.y, 0), Vector3(global_position.x, global_position.y, 0),
Vector3(global_position.x, global_position.y, 0) Vector3(global_position.x, global_position.y, 0)

View File

@ -4,7 +4,7 @@ extends KinematicBody2D
var separation: GSTSeparation var separation: GSTSeparation
var cohesion: GSTCohesion var cohesion: GSTCohesion
var proximity: GSTRadiusProximity var proximity: GSTRadiusProximity
var agent := GSTNode2DAgent.new(self) var agent := GSTKinematicBody2DAgent.new(self)
var blend := GSTBlend.new(agent) var blend := GSTBlend.new(agent)
var acceleration := GSTTargetAcceleration.new() var acceleration := GSTTargetAcceleration.new()
var draw_proximity := false var draw_proximity := false

View File

@ -12,6 +12,5 @@ script = ExtResource( 1 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="."] [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
shape = SubResource( 1 ) shape = SubResource( 1 )
script = ExtResource( 3 ) script = ExtResource( 3 )
inner_color = Color( 0, 0, 0, 1 )
outer_color = Color( 0.301961, 0.65098, 1, 1 ) outer_color = Color( 0.301961, 0.65098, 1, 1 )
stroke = 4.0 stroke = 4.0

View File

@ -10,7 +10,7 @@ var _linear_drag_coefficient := 0.025
var _angular_drag := 0.1 var _angular_drag := 0.1
var _direction_face := GSTAgentLocation.new() var _direction_face := GSTAgentLocation.new()
onready var agent := GSTNode2DAgent.new(self) onready var agent := GSTKinematicBody2DAgent.new(self)
onready var accel := GSTTargetAcceleration.new() onready var accel := GSTTargetAcceleration.new()
onready var player_agent: GSTSteeringAgent = owner.find_node("Player", true, false).agent onready var player_agent: GSTSteeringAgent = owner.find_node("Player", true, false).agent

View File

@ -7,7 +7,7 @@ var start_speed: float
var start_accel: float var start_accel: float
var use_seek := true var use_seek := true
onready var agent := GSTNode2DAgent.new(self) onready var agent := GSTKinematicBody2DAgent.new(self)
onready var accel := GSTTargetAcceleration.new() onready var accel := GSTTargetAcceleration.new()
onready var seek := GSTSeek.new(agent, player_agent) onready var seek := GSTSeek.new(agent, player_agent)
onready var flee := GSTFlee.new(agent, player_agent) onready var flee := GSTFlee.new(agent, player_agent)

View File

@ -64,6 +64,16 @@ _global_script_classes=[ {
"language": "GDScript", "language": "GDScript",
"path": "res://src/Proximities/GSTInfiniteProximity.gd" "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", "base": "GSTMatchOrientation",
"class": "GSTLookWhereYouGo", "class": "GSTLookWhereYouGo",
"language": "GDScript", "language": "GDScript",
@ -74,16 +84,6 @@ _global_script_classes=[ {
"language": "GDScript", "language": "GDScript",
"path": "res://src/Behaviors/GSTMatchOrientation.gd" "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", "base": "Reference",
"class": "GSTPath", "class": "GSTPath",
"language": "GDScript", "language": "GDScript",
@ -109,6 +109,16 @@ _global_script_classes=[ {
"language": "GDScript", "language": "GDScript",
"path": "res://src/Proximities/GSTRadiusProximity.gd" "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", "base": "GSTSteeringBehavior",
"class": "GSTSeek", "class": "GSTSeek",
"language": "GDScript", "language": "GDScript",
@ -119,10 +129,10 @@ _global_script_classes=[ {
"language": "GDScript", "language": "GDScript",
"path": "res://src/Behaviors/GSTSeparation.gd" "path": "res://src/Behaviors/GSTSeparation.gd"
}, { }, {
"base": "GSTNodeAgent", "base": "GSTSteeringAgent",
"class": "GSTSpatialAgent", "class": "GSTSpecializedAgent",
"language": "GDScript", "language": "GDScript",
"path": "res://src/Agents/GSTSpatialAgent.gd" "path": "res://src/Agents/GSTSpecializedAgent.gd"
}, { }, {
"base": "GSTAgentLocation", "base": "GSTAgentLocation",
"class": "GSTSteeringAgent", "class": "GSTSteeringAgent",
@ -156,18 +166,20 @@ _global_script_class_icons={
"GSTFollowPath": "", "GSTFollowPath": "",
"GSTGroupBehavior": "", "GSTGroupBehavior": "",
"GSTInfiniteProximity": "", "GSTInfiniteProximity": "",
"GSTKinematicBody2DAgent": "",
"GSTKinematicBodyAgent": "",
"GSTLookWhereYouGo": "", "GSTLookWhereYouGo": "",
"GSTMatchOrientation": "", "GSTMatchOrientation": "",
"GSTNode2DAgent": "",
"GSTNodeAgent": "",
"GSTPath": "", "GSTPath": "",
"GSTPriority": "", "GSTPriority": "",
"GSTProximity": "", "GSTProximity": "",
"GSTPursue": "", "GSTPursue": "",
"GSTRadiusProximity": "", "GSTRadiusProximity": "",
"GSTRigidBody2DAgent": "",
"GSTRigidBodyAgent": "",
"GSTSeek": "", "GSTSeek": "",
"GSTSeparation": "", "GSTSeparation": "",
"GSTSpatialAgent": "", "GSTSpecializedAgent": "",
"GSTSteeringAgent": "", "GSTSteeringAgent": "",
"GSTSteeringBehavior": "", "GSTSteeringBehavior": "",
"GSTTargetAcceleration": "", "GSTTargetAcceleration": "",

View File

@ -1,16 +1,26 @@
# A specialized steering agent that updates itself every frame so the user does # A specialized steering agent that updates itself every frame so the user does
# not have to. # not have to using a KinematicBody2D
extends GSTNodeAgent extends GSTSpecializedAgent
class_name GSTNode2DAgent class_name GSTKinematicBody2DAgent
# The Node2D to keep track of enum KinematicMovementType { SLIDE, COLLIDE, POSITION }
var body: Node2D setget _set_body
# 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 var _last_position: Vector2
func _init(body: Node2D) -> void: func _init(body: KinematicBody2D) -> void:
self.body = body self.body = body
if body.is_inside_tree(): if body.is_inside_tree():
body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame") body.get_tree().connect("physics_frame", self, "_on_SceneTree_frame")
@ -22,31 +32,17 @@ func _init(body: Node2D) -> void:
# tags: virtual # tags: virtual
func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void: func _apply_steering(acceleration: GSTTargetAcceleration, delta: float) -> void:
_applied_steering = true _applied_steering = true
match _body_type:
BodyType.RIGID:
_apply_rigid_steering(acceleration)
BodyType.KINEMATIC:
match kinematic_movement_type: match kinematic_movement_type:
MovementType.COLLIDE: KinematicMovementType.COLLIDE:
_apply_collide_steering(acceleration.linear, delta) _apply_collide_steering(acceleration.linear, delta)
MovementType.SLIDE: KinematicMovementType.SLIDE:
_apply_sliding_steering(acceleration.linear) _apply_sliding_steering(acceleration.linear)
MovementType.POSITION: _:
_apply_normal_steering(acceleration.linear, delta) _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) _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: func _apply_sliding_steering(accel: Vector3) -> void:
var velocity := GSTUtils.to_vector2(linear_velocity + accel).clamped(linear_speed_max) var velocity := GSTUtils.to_vector2(linear_velocity + accel).clamped(linear_speed_max)
if apply_linear_drag: if apply_linear_drag:
@ -89,29 +85,9 @@ func _apply_orientation_steering(angular_acceleration: float, delta: float) -> v
angular_velocity = velocity angular_velocity = velocity
func _set_use_physics(value: bool) -> void: func _set_body(value: KinematicBody2D) -> 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 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_position = body.global_position
_last_orientation = body.rotation _last_orientation = body.rotation
@ -135,11 +111,6 @@ func _on_SceneTree_frame() -> void:
if _applied_steering: if _applied_steering:
_applied_steering = false _applied_steering = false
else: else:
match _body_type:
BodyType.RIGID:
linear_velocity = GSTUtils.to_vector3(body.linear_velocity)
angular_velocity = body.angular_velocity
_:
linear_velocity = GSTUtils.clampedv3( linear_velocity = GSTUtils.clampedv3(
GSTUtils.to_vector3(_last_position - current_position), GSTUtils.to_vector3(_last_position - current_position),
linear_speed_max linear_speed_max
@ -149,11 +120,13 @@ func _on_SceneTree_frame() -> void:
Vector3.ZERO, Vector3.ZERO,
linear_drag_percentage linear_drag_percentage
) )
angular_velocity = clamp( angular_velocity = clamp(
_last_orientation - current_orientation, _last_orientation - current_orientation,
-angular_speed_max, -angular_speed_max,
angular_speed_max angular_speed_max
) )
if apply_angular_drag: if apply_angular_drag:
angular_velocity = lerp( angular_velocity = lerp(
angular_velocity, angular_velocity,

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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