Reorganize project

The GST namespace has been added to prevent class name conflicts, and
the project has been reorganized to make extensions and purpose easier.
This commit is contained in:
Francois Belair 2019-12-19 14:04:08 -05:00
parent 7520939bdd
commit fb538b72cb
35 changed files with 305 additions and 287 deletions

View File

View File

@ -6,22 +6,20 @@ AI agent that seeks to move away from the player's location as directly as possi
onready var radius: = ($CollisionShape2D.shape as CircleShape2D).radius onready var radius: = ($CollisionShape2D.shape as CircleShape2D).radius
var agent: SteeringAgent onready var agent: = GSTSteeringAgent.new()
var player_agent: AgentLocation onready var accel: = GSTTargetAcceleration.new()
var flee: Flee onready var flee: = GSTFlee.new(agent, player_agent)
var accel: = TargetAcceleration.new()
var player_agent: GSTAgentLocation
var velocity: = Vector2.ZERO var velocity: = Vector2.ZERO
var speed: float var speed: float
var color: Color var color: Color
func _ready() -> void: func _ready() -> void:
agent = SteeringAgent.new()
agent.max_linear_acceleration = speed/10 agent.max_linear_acceleration = speed/10
agent.max_linear_speed = speed agent.max_linear_speed = speed
flee = Flee.new(agent, player_agent)
func _draw() -> void: func _draw() -> void:
draw_circle(Vector2.ZERO, radius, color) draw_circle(Vector2.ZERO, radius, color)

View File

@ -1,6 +1,6 @@
[gd_scene load_steps=3 format=2] [gd_scene load_steps=3 format=2]
[ext_resource path="res://src/Steering/Demos/SeekFlee/Coward.gd" type="Script" id=1] [ext_resource path="res://demos/seek_and_flee/Coward.gd" type="Script" id=1]
[sub_resource type="CircleShape2D" id=1] [sub_resource type="CircleShape2D" id=1]

View File

@ -5,18 +5,17 @@ Class to control the player in basic left/right up/down movement.
onready var _radius: = ($CollisionShape2D.shape as CircleShape2D).radius onready var _radius: = ($CollisionShape2D.shape as CircleShape2D).radius
onready var agent: = GSTAgentLocation.new()
export var speed: = 150.0 export var speed: = 150.0
var player_agent: = AgentLocation.new()
func _draw() -> void: func _draw() -> void:
draw_circle(Vector2.ZERO, _radius, Color.red) draw_circle(Vector2.ZERO, _radius, Color.red)
func _get_movement() -> Vector2: func _get_movement() -> Vector2:
return Vector2(Input.get_action_strength("sf_right") - Input.get_action_strength("sf_left"), return Vector2( Input.get_action_strength("sf_right") - Input.get_action_strength("sf_left"),
Input.get_action_strength("sf_down") - Input.get_action_strength("sf_up")) Input.get_action_strength("sf_down") - Input.get_action_strength("sf_up"))
@ -26,4 +25,4 @@ func _physics_process(delta: float) -> void:
return return
move_and_slide(movement * speed) move_and_slide(movement * speed)
player_agent.position = Vector3(global_position.x, global_position.y, 0) agent.position = Vector3(global_position.x, global_position.y, 0)

View File

@ -1,11 +1,11 @@
[gd_scene load_steps=10 format=2] [gd_scene load_steps=10 format=2]
[ext_resource path="res://src/Steering/Demos/SeekFlee/Player.gd" type="Script" id=1] [ext_resource path="res://demos/seek_and_flee/Player.gd" type="Script" id=1]
[ext_resource path="res://src/Steering/Demos/SeekFlee/Spawner.gd" type="Script" id=2] [ext_resource path="res://demos/seek_and_flee/Spawner.gd" type="Script" id=2]
[ext_resource path="res://src/Steering/Demos/SeekFlee/SeekFleeDemo.gd" type="Script" id=3] [ext_resource path="res://demos/seek_and_flee/SeekFleeDemo.gd" type="Script" id=3]
[ext_resource path="res://src/Steering/Demos/SeekFlee/Seeker.tscn" type="PackedScene" id=4] [ext_resource path="res://demos/seek_and_flee/Seeker.tscn" type="PackedScene" id=4]
[ext_resource path="res://src/Steering/Demos/SeekFlee/Boundary.gd" type="Script" id=5] [ext_resource path="res://demos/seek_and_flee/Boundary.gd" type="Script" id=5]
[ext_resource path="res://src/Steering/Demos/SeekFlee/Coward.tscn" type="PackedScene" id=6] [ext_resource path="res://demos/seek_and_flee/Coward.tscn" type="PackedScene" id=6]
[sub_resource type="CircleShape2D" id=1] [sub_resource type="CircleShape2D" id=1]
radius = 30.0 radius = 30.0
@ -68,11 +68,13 @@ script = ExtResource( 5 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="BottomBoundary"] [node name="CollisionShape2D" type="CollisionShape2D" parent="BottomBoundary"]
shape = SubResource( 3 ) shape = SubResource( 3 )
[node name="SeekerSpawner" type="Node2D" parent="."] [node name="Spawners" type="Node2D" parent="."]
script = ExtResource( 2 )
agent_scene = ExtResource( 4 )
[node name="FleeerSpawner" type="Node2D" parent="."] [node name="SeekerSpawner" type="Node2D" parent="Spawners"]
script = ExtResource( 2 ) script = ExtResource( 2 )
agent_scene = ExtResource( 6 ) Entity = ExtResource( 4 )
agent_color = Color( 0.0980392, 0.886275, 0.517647, 1 )
[node name="CowardSpawner" type="Node2D" parent="Spawners"]
script = ExtResource( 2 )
Entity = ExtResource( 6 )
entity_color = Color( 0, 1, 0.741176, 1 )

View File

@ -0,0 +1,37 @@
extends Node2D
"""
Access helper class for children to access window boundaries.
"""
onready var player: KinematicBody2D = $Player
onready var spawners: Node2D = $Spawners
var camera_boundaries: Rect2
func _init() -> void:
camera_boundaries = Rect2(
Vector2.ZERO,
Vector2(
ProjectSettings["display/window/size/width"],
ProjectSettings["display/window/size/height"]
)
)
func _ready() -> void:
var rng: = RandomNumberGenerator.new()
rng.randomize()
for spawner in spawners.get_children():
for i in range(spawner.entity_count):
var new_pos: = Vector2(
rng.randf_range(-camera_boundaries.size.x/2, camera_boundaries.size.x/2),
rng.randf_range(-camera_boundaries.size.y/2, camera_boundaries.size.y/2)
)
var entity: KinematicBody2D = spawner.Entity.instance()
entity.global_position = new_pos
entity.player_agent = player.agent
entity.speed = rng.randf_range(spawner.min_speed, spawner.max_speed)
entity.color = spawner.entity_color
spawner.add_child(entity)

View File

@ -6,22 +6,20 @@ AI agent that uses the Seek behavior to hone in on the player's location as dire
onready var radius: = ($CollisionShape2D.shape as CircleShape2D).radius onready var radius: = ($CollisionShape2D.shape as CircleShape2D).radius
var agent: SteeringAgent onready var agent: = GSTSteeringAgent.new()
var player_agent: AgentLocation onready var accel: = GSTTargetAcceleration.new()
var seek: Seek onready var seek: = GSTSeek.new(agent, player_agent)
var accel: = TargetAcceleration.new()
var player_agent: GSTAgentLocation
var velocity: = Vector2.ZERO var velocity: = Vector2.ZERO
var speed: float var speed: float
var color: Color var color: Color
func _ready() -> void: func _ready() -> void:
agent = SteeringAgent.new()
agent.max_linear_acceleration = speed/10 agent.max_linear_acceleration = speed/10
agent.max_linear_speed = speed agent.max_linear_speed = speed
seek = Seek.new(agent, player_agent)
func _draw() -> void: func _draw() -> void:
draw_circle(Vector2.ZERO, radius, color) draw_circle(Vector2.ZERO, radius, color)

View File

@ -1,6 +1,6 @@
[gd_scene load_steps=3 format=2] [gd_scene load_steps=3 format=2]
[ext_resource path="res://src/Steering/Demos/SeekFlee/Seeker.gd" type="Script" id=1] [ext_resource path="res://demos/seek_and_flee/Seeker.gd" type="Script" id=1]
[sub_resource type="CircleShape2D" id=1] [sub_resource type="CircleShape2D" id=1]

View File

@ -0,0 +1,11 @@
extends Node2D
"""
Holds data to instantiate and configure a number of agent entities.
"""
export(PackedScene) var Entity: PackedScene
export var entity_count: = 10
export var entity_color: = Color.blue
export var min_speed: = 50.0
export var max_speed: = 125.0

View File

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -10,77 +10,83 @@ config_version=4
_global_script_classes=[ { _global_script_classes=[ {
"base": "Reference", "base": "Reference",
"class": "AgentLocation", "class": "GSTAgentLocation",
"language": "GDScript", "language": "GDScript",
"path": "res://src/Steering/AgentLocation.gd" "path": "res://src/GSTAgentLocation.gd"
}, { }, {
"base": "SteeringBehavior", "base": "GSTSteeringBehavior",
"class": "Arrive", "class": "GSTArrive",
"language": "GDScript", "language": "GDScript",
"path": "res://src/Steering/Behaviors/Arrive.gd" "path": "res://src/behaviors/GSTArrive.gd"
}, { }, {
"base": "Pursue", "base": "GSTPursue",
"class": "Evade", "class": "GSTEvade",
"language": "GDScript", "language": "GDScript",
"path": "res://src/Steering/Behaviors/Evade.gd" "path": "res://src/behaviors/GSTEvade.gd"
}, { }, {
"base": "MatchOrientation", "base": "GSTMatchOrientation",
"class": "Face", "class": "GSTFace",
"language": "GDScript", "language": "GDScript",
"path": "res://src/Steering/Behaviors/Face.gd" "path": "res://src/behaviors/GSTFace.gd"
}, { }, {
"base": "Seek", "base": "GSTSeek",
"class": "Flee", "class": "GSTFlee",
"language": "GDScript", "language": "GDScript",
"path": "res://src/Steering/Behaviors/Flee.gd" "path": "res://src/behaviors/GSTFlee.gd"
}, { }, {
"base": "SteeringBehavior", "base": "GSTSteeringBehavior",
"class": "MatchOrientation", "class": "GSTMatchOrientation",
"language": "GDScript", "language": "GDScript",
"path": "res://src/Steering/Behaviors/MatchOrientation.gd" "path": "res://src/behaviors/GSTMatchOrientation.gd"
}, { }, {
"base": "SteeringBehavior", "base": "GSTSteeringBehavior",
"class": "Pursue", "class": "GSTPursue",
"language": "GDScript", "language": "GDScript",
"path": "res://src/Steering/Behaviors/Pursue.gd" "path": "res://src/behaviors/GSTPursue.gd"
}, { }, {
"base": "SteeringBehavior", "base": "GSTSteeringBehavior",
"class": "Seek", "class": "GSTSeek",
"language": "GDScript", "language": "GDScript",
"path": "res://src/Steering/Behaviors/Seek.gd" "path": "res://src/behaviors/GSTSeek.gd"
}, { }, {
"base": "AgentLocation", "base": "GSTAgentLocation",
"class": "SteeringAgent", "class": "GSTSteeringAgent",
"language": "GDScript", "language": "GDScript",
"path": "res://src/Steering/SteeringAgent.gd" "path": "res://src/GSTSteeringAgent.gd"
}, { }, {
"base": "Reference", "base": "Reference",
"class": "SteeringBehavior", "class": "GSTSteeringBehavior",
"language": "GDScript", "language": "GDScript",
"path": "res://src/Steering/SteeringBehavior.gd" "path": "res://src/GSTSteeringBehavior.gd"
}, { }, {
"base": "Reference", "base": "Reference",
"class": "TargetAcceleration", "class": "GSTTargetAcceleration",
"language": "GDScript", "language": "GDScript",
"path": "res://src/Steering/TargetAcceleration.gd" "path": "res://src/GSTTargetAcceleration.gd"
}, {
"base": "Reference",
"class": "Utils",
"language": "GDScript",
"path": "res://src/Utils.gd"
} ] } ]
_global_script_class_icons={ _global_script_class_icons={
"AgentLocation": "", "GSTAgentLocation": "",
"Arrive": "", "GSTArrive": "",
"Evade": "", "GSTEvade": "",
"Face": "", "GSTFace": "",
"Flee": "", "GSTFlee": "",
"MatchOrientation": "", "GSTMatchOrientation": "",
"Pursue": "", "GSTPursue": "",
"Seek": "", "GSTSeek": "",
"SteeringAgent": "", "GSTSteeringAgent": "",
"SteeringBehavior": "", "GSTSteeringBehavior": "",
"TargetAcceleration": "" "GSTTargetAcceleration": "",
"Utils": ""
} }
[application] [application]
config/name="godot-steering-toolkit" config/name="SteeringToolkit"
config/icon="res://icon.png" config/icon="res://icon.png"
[input] [input]

View File

@ -1,5 +1,5 @@
extends Reference extends Reference
class_name AgentLocation class_name GSTAgentLocation
""" """
Data type to represent an agent with a location and an orientation Data type to represent an agent with a location and an orientation
""" """

View File

@ -1,5 +1,5 @@
extends AgentLocation extends GSTAgentLocation
class_name SteeringAgent class_name GSTSteeringAgent
""" """
Extended agent data type that adds velocity and speed data. Extended agent data type that adds velocity and speed data.
""" """

View File

@ -0,0 +1,26 @@
extends Reference
class_name GSTSteeringBehavior
"""
Base class to calculate how an AI agent steers itself.
"""
var enabled: = true
var agent: GSTSteeringAgent
func _init(agent: GSTSteeringAgent) -> void:
self.agent = agent
func calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration:
if enabled:
return _calculate_steering(acceleration)
else:
acceleration.set_zero()
return acceleration
func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration:
acceleration.set_zero()
return acceleration

View File

@ -1,5 +1,5 @@
extends Reference extends Reference
class_name TargetAcceleration class_name GSTTargetAcceleration
""" """
A linear and angular amount of acceleration. A linear and angular amount of acceleration.
""" """
@ -9,9 +9,8 @@ var linear: = Vector3.ZERO
var angular: = 0.0 var angular: = 0.0
func set_zero() -> TargetAcceleration: func set_zero() -> void:
linear.x = 0.0 linear.x = 0.0
linear.y = 0.0 linear.y = 0.0
linear.z = 0.0 linear.z = 0.0
angular = 0.0 angular = 0.0
return self

9
project/src/Utils.gd Normal file
View File

@ -0,0 +1,9 @@
class_name Utils
static func clmapedv3(vector: Vector3, limit: float) -> Vector3:
var len2: = vector.length_squared()
var limit2: = limit * limit
if len2 > limit2:
vector *= sqrt(limit2 / len2)
return vector

View File

@ -0,0 +1,42 @@
extends GSTSteeringBehavior
class_name GSTArrive
"""
Calculates acceleration to take an agent to its target's location.
The calculation will attempt to arrive with zero remaining velocity.
"""
var target: GSTAgentLocation
var arrival_tolerance: float
var deceleration_radius: float
var time_to_reach: = 0.1
func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent) -> void:
self.target = target
func _arrive(acceleration: GSTTargetAcceleration, target_position: Vector3) -> GSTTargetAcceleration:
var to_target: = target_position - agent.position
var distance: = to_target.length()
if distance <= arrival_tolerance:
acceleration.set_zero()
else:
var desired_speed: = agent.max_linear_speed
if distance <= deceleration_radius:
desired_speed *= distance / deceleration_radius
var desired_velocity: = to_target * desired_speed/distance
desired_velocity = (desired_velocity - agent.linear_velocity) * 1.0 / time_to_reach
acceleration.linear = Utils.clampedv3(desired_velocity, agent.max_linear_acceleration)
acceleration.angular = 0
return acceleration
func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration:
return _arrive(acceleration, target.position)

View File

@ -1,5 +1,5 @@
extends Pursue extends GSTPursue
class_name Evade class_name GSTEvade
""" """
Calculates acceleration to take an agent away from where a target agent will be. Calculates acceleration to take an agent away from where a target agent will be.
@ -7,9 +7,12 @@ The `max_predict_time` variable represents how far ahead to calculate the inters
""" """
func _init(agent: SteeringAgent, target: SteeringAgent, max_predict_time: = 1.0).(agent, target, max_predict_time): func _init(
agent: GSTSteeringAgent,
target: GSTSteeringAgent,
max_predict_time: = 1.0).(agent, target, max_predict_time):
pass pass
func get_max_linear_acceleration() -> float: func _get_modified_acceleration() -> float:
return -agent.max_linear_acceleration return -agent.max_linear_acceleration

View File

@ -0,0 +1,26 @@
extends GSTMatchOrientation
class_name GSTFace
"""
Calculates angular acceleration to rotate a target to face its target's position.
The acceleration will attempt to arrive with zero remaining angular velocity.
"""
func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent, target) -> void:
pass
func _face(acceleration: GSTTargetAcceleration, target_position: Vector3) -> GSTTargetAcceleration:
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 = atan2(to_target.x, -to_target.y)
return _match_orientation(acceleration, orientation)
func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration:
return _face(acceleration, target.position)

View File

@ -0,0 +1,17 @@
extends GSTSeek
class_name GSTFlee
"""
Calculates acceleration to take an agent directly away from a target agent.
"""
func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent, target) -> void:
pass
func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration:
acceleration.linear = (
(agent.position - target.position).normalized() * agent.max_linear_acceleration)
acceleration.angular = 0
return acceleration

View File

@ -1,37 +1,37 @@
extends SteeringBehavior extends GSTSteeringBehavior
class_name MatchOrientation class_name GSTMatchOrientation
""" """
Calculates an angular acceleration to match an agent's orientation to its target's. Calculates an angular acceleration to match an agent's orientation to its target's.
The calculation will attempt to arrive with zero remaining angular velocity. The calculation will attempt to arrive with zero remaining angular velocity.
""" """
var target: AgentLocation var target: GSTAgentLocation
var alignment_tolerance: float var alignment_tolerance: float
var deceleration_radius: float var deceleration_radius: float
var time_to_target: float = 0.1 var time_to_reach: float = 0.1
func _init(agent: SteeringAgent, target: AgentLocation).(agent) -> void: func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent) -> void:
self.target = target self.target = target
func _match_orientation(acceleration: TargetAcceleration, target_orientation: float) -> TargetAcceleration: func _match_orientation(acceleration: GSTTargetAcceleration, desired_orientation: float) -> GSTTargetAcceleration:
var rotation: = wrapf(target_orientation - agent.orientation, -PI, PI) var rotation: = wrapf(desired_orientation - agent.orientation, -PI, PI)
var rotation_size: = -rotation if rotation < 0 else rotation var rotation_size: = -rotation if rotation < 0 else rotation
if rotation_size <= alignment_tolerance: if rotation_size <= alignment_tolerance:
return acceleration.set_zero() return acceleration.set_zero()
var target_rotation: = agent.max_angular_speed var desired_rotation: = agent.max_angular_speed
if rotation_size <= deceleration_radius: if rotation_size <= deceleration_radius:
target_rotation *= rotation_size / deceleration_radius desired_rotation *= rotation_size / deceleration_radius
target_rotation *= rotation / rotation_size desired_rotation *= rotation / rotation_size
acceleration.angular = (target_rotation - agent.angular_velocity) / time_to_target acceleration.angular = (desired_rotation - agent.angular_velocity) / time_to_reach
var limited_acceleration: = -acceleration.angular if acceleration.angular < 0 else acceleration.angular var limited_acceleration: = -acceleration.angular if acceleration.angular < 0 else acceleration.angular
if limited_acceleration > agent.max_angular_acceleration: if limited_acceleration > agent.max_angular_acceleration:
@ -42,5 +42,5 @@ func _match_orientation(acceleration: TargetAcceleration, target_orientation: fl
return acceleration return acceleration
func _calculate_internal_steering(acceleration: TargetAcceleration) -> TargetAcceleration: func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration:
return _match_orientation(acceleration, target.orientation) return _match_orientation(acceleration, target.orientation)

View File

@ -1,5 +1,5 @@
extends SteeringBehavior extends GSTSteeringBehavior
class_name Pursue class_name GSTPursue
""" """
Calculates acceleration to take an agent to intersect with where a target agent will be. Calculates acceleration to take an agent to intersect with where a target agent will be.
@ -7,20 +7,19 @@ The `max_predict_time` variable represents how far ahead to calculate the inters
""" """
var target: SteeringAgent var target: GSTSteeringAgent
var max_predict_time: float var max_predict_time: float
func _init(agent: SteeringAgent, target: SteeringAgent, max_predict_time: = 1.0).(agent) -> void: func _init(
agent: GSTSteeringAgent,
target: GSTSteeringAgent,
max_predict_time: = 1.0).(agent) -> void:
self.target = target self.target = target
self.max_predict_time = max_predict_time self.max_predict_time = max_predict_time
func get_max_linear_acceleration() -> float: func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration:
return agent.max_linear_acceleration
func _calculate_internal_steering(acceleration: TargetAcceleration) -> TargetAcceleration:
var target_position: = target.position var target_position: = target.position
var distance_squared: = (target_position - agent.position).length_squared() var distance_squared: = (target_position - agent.position).length_squared()
@ -32,9 +31,14 @@ func _calculate_internal_steering(acceleration: TargetAcceleration) -> TargetAcc
if predict_time_squared < max_predict_time * max_predict_time: if predict_time_squared < max_predict_time * max_predict_time:
predict_time = sqrt(predict_time_squared) predict_time = sqrt(predict_time_squared)
acceleration.linear = ((target_position + (target.linear_velocity * predict_time))-agent.position).normalized() acceleration.linear = ((
acceleration.linear *= agent.max_linear_acceleration target_position + (target.linear_velocity * predict_time))-agent.position).normalized()
acceleration.linear *= _get_modified_acceleration()
acceleration.angular = 0 acceleration.angular = 0
return acceleration return acceleration
func _get_modified_acceleration() -> float:
return agent.max_linear_acceleration

View File

@ -0,0 +1,20 @@
extends GSTSteeringBehavior
class_name GSTSeek
"""
Calculates acceleration to take an agent to a target agent's position as directly as possible
"""
var target: GSTAgentLocation
func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent) -> void:
self.target = target
func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration:
acceleration.linear = (
(target.position - agent.position).normalized() * agent.max_linear_acceleration)
acceleration.angular = 0
return acceleration

View File

@ -1,3 +0,0 @@
[gd_scene format=2]
[node name="Node2D" type="Node2D"]

View File

@ -1,50 +0,0 @@
extends SteeringBehavior
class_name Arrive
"""
Calculates acceleration to take an agent to its target's location.
The calculation will attempt to arrive with zero remaining velocity.
"""
var target: AgentLocation
var arrival_tolerance: float
var deceleration_radius: float
var time_to_target: = 0.1
func _init(agent: SteeringAgent, target: AgentLocation).(agent) -> void:
self.target = target
func _arrive(acceleration: TargetAcceleration, target_position: Vector3) -> TargetAcceleration:
var to_target: = target_position - agent.position
var distance: = to_target.length()
if distance <= arrival_tolerance:
return acceleration.set_zero()
var target_speed: = agent.max_linear_speed
if distance <= deceleration_radius:
target_speed *= distance / deceleration_radius
var target_velocity: = to_target * target_speed/distance
target_velocity = (target_velocity - agent.linear_velocity) * 1.0 / time_to_target
acceleration.linear = limit_length(target_velocity, agent.max_linear_acceleration)
acceleration.angular = 0
return acceleration
func _calculate_internal_steering(acceleration: TargetAcceleration) -> TargetAcceleration:
return _arrive(acceleration, target.position)
static func limit_length(vector: Vector3, limit: float) -> Vector3:
var len2: = vector.length_squared()
var limit2: = limit * limit
if len2 > limit2:
vector *= sqrt(limit2 / len2)
return vector

View File

@ -1,26 +0,0 @@
extends MatchOrientation
class_name Face
"""
Calculates angular acceleration to rotate a target to face its target's position.
The acceleration will attempt to arrive with zero remaining angular velocity.
"""
func _init(agent: SteeringAgent, target: AgentLocation).(agent, target) -> void:
pass
func _face(acceleration: TargetAcceleration, target_position: Vector3) -> TargetAcceleration:
var to_target: = target_position - agent.position
var distance_squared: = to_target.length_squared()
if distance_squared < agent.zero_linear_speed_threshold:
return acceleration.set_zero()
var orientation = Vector3.UP.angle_to(to_target)
return _match_orientation(acceleration, orientation)
func _calculate_internal_steering(acceleration: TargetAcceleration) -> TargetAcceleration:
return _face(acceleration, target.position)

View File

@ -1,16 +0,0 @@
extends Seek
class_name Flee
"""
Calculates acceleration to take an agent directly away from a target agent.
"""
func _init(agent: SteeringAgent, target: AgentLocation).(agent, target) -> void:
pass
func _calculate_internal_steering(acceleration: TargetAcceleration) -> TargetAcceleration:
acceleration.linear = (agent.position - target.position).normalized() * agent.max_linear_acceleration
acceleration.angular = 0
return acceleration

View File

@ -1,19 +0,0 @@
extends SteeringBehavior
class_name Seek
"""
Calculates acceleration to take an agent to a target agent's position as directly as possible
"""
var target: AgentLocation
func _init(agent: SteeringAgent, target: AgentLocation).(agent) -> void:
self.target = target
func _calculate_internal_steering(acceleration: TargetAcceleration) -> TargetAcceleration:
acceleration.linear = (target.position - agent.position).normalized() * agent.max_linear_acceleration
acceleration.angular = 0
return acceleration

View File

@ -1,14 +0,0 @@
extends Node2D
"""
Access helper class for children to access window boundaries.
"""
var camera_boundaries: Rect2
func _init() -> void:
camera_boundaries = Rect2(
Vector2.ZERO,
Vector2(ProjectSettings["display/window/size/width"], ProjectSettings["display/window/size/height"])
)

View File

@ -1,30 +0,0 @@
extends Node2D
"""
Instantiates and configures a number of agent scenes within the level boundaries.
"""
onready var player_agent: AgentLocation = owner.get_node("Player").player_agent
export(PackedScene) var agent_scene: PackedScene
export var agent_count: = 10
export var min_speed: = 50.0
export var max_speed: = 125.0
export var agent_color: = Color.blue
func _ready() -> void:
var boundaries: Rect2 = owner.camera_boundaries
randomize()
for i in range(agent_count):
var new_pos: = Vector2(
rand_range(-boundaries.size.x/2, boundaries.size.x/2),
rand_range(-boundaries.size.y/2, boundaries.size.y/2)
)
var agent: = agent_scene.instance()
agent.global_position = new_pos
agent.player_agent = player_agent
agent.speed = rand_range(min_speed, max_speed)
agent.color = agent_color
add_child(agent)

View File

@ -1,21 +0,0 @@
extends Reference
class_name SteeringBehavior
"""
Base class to calculate how an AI agent steers itself.
"""
var enabled: = true
var agent: SteeringAgent
func _init(agent: SteeringAgent) -> void:
self.agent = agent
func calculate_steering(acceleration: TargetAcceleration) -> TargetAcceleration:
return _calculate_internal_steering(acceleration) if enabled else acceleration.zero()
func _calculate_internal_steering(acceleration: TargetAcceleration) -> TargetAcceleration:
return acceleration.set_zero()