diff --git a/mvp.md b/docs/mvp.md similarity index 100% rename from mvp.md rename to docs/mvp.md diff --git a/techdetails.md b/docs/techdetails.md similarity index 100% rename from techdetails.md rename to docs/techdetails.md diff --git a/default_env.tres b/project/default_env.tres similarity index 100% rename from default_env.tres rename to project/default_env.tres diff --git a/src/Steering/Demos/SeekFlee/Boundary.gd b/project/demos/seek_and_flee/Boundary.gd similarity index 100% rename from src/Steering/Demos/SeekFlee/Boundary.gd rename to project/demos/seek_and_flee/Boundary.gd diff --git a/src/Steering/Demos/SeekFlee/Coward.gd b/project/demos/seek_and_flee/Coward.gd similarity index 82% rename from src/Steering/Demos/SeekFlee/Coward.gd rename to project/demos/seek_and_flee/Coward.gd index b596ee1..5434234 100644 --- a/src/Steering/Demos/SeekFlee/Coward.gd +++ b/project/demos/seek_and_flee/Coward.gd @@ -6,21 +6,19 @@ AI agent that seeks to move away from the player's location as directly as possi onready var radius: = ($CollisionShape2D.shape as CircleShape2D).radius -var agent: SteeringAgent -var player_agent: AgentLocation -var flee: Flee -var accel: = TargetAcceleration.new() +onready var agent: = GSTSteeringAgent.new() +onready var accel: = GSTTargetAcceleration.new() +onready var flee: = GSTFlee.new(agent, player_agent) + +var player_agent: GSTAgentLocation var velocity: = Vector2.ZERO var speed: float var color: Color func _ready() -> void: - agent = SteeringAgent.new() agent.max_linear_acceleration = speed/10 agent.max_linear_speed = speed - - flee = Flee.new(agent, player_agent) func _draw() -> void: diff --git a/src/Steering/Demos/SeekFlee/Coward.tscn b/project/demos/seek_and_flee/Coward.tscn similarity index 76% rename from src/Steering/Demos/SeekFlee/Coward.tscn rename to project/demos/seek_and_flee/Coward.tscn index 5240047..b0a2c84 100644 --- a/src/Steering/Demos/SeekFlee/Coward.tscn +++ b/project/demos/seek_and_flee/Coward.tscn @@ -1,6 +1,6 @@ [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] diff --git a/src/Steering/Demos/SeekFlee/Player.gd b/project/demos/seek_and_flee/Player.gd similarity index 61% rename from src/Steering/Demos/SeekFlee/Player.gd rename to project/demos/seek_and_flee/Player.gd index 00ef813..4be9822 100644 --- a/src/Steering/Demos/SeekFlee/Player.gd +++ b/project/demos/seek_and_flee/Player.gd @@ -5,19 +5,18 @@ Class to control the player in basic left/right up/down movement. onready var _radius: = ($CollisionShape2D.shape as CircleShape2D).radius +onready var agent: = GSTAgentLocation.new() export var speed: = 150.0 -var player_agent: = AgentLocation.new() - func _draw() -> void: draw_circle(Vector2.ZERO, _radius, Color.red) func _get_movement() -> Vector2: - 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")) + 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")) func _physics_process(delta: float) -> void: @@ -26,4 +25,4 @@ func _physics_process(delta: float) -> void: return 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) diff --git a/src/Steering/Demos/SeekFlee/SeekFlee.tscn b/project/demos/seek_and_flee/SeekFlee.tscn similarity index 70% rename from src/Steering/Demos/SeekFlee/SeekFlee.tscn rename to project/demos/seek_and_flee/SeekFlee.tscn index 09a2cad..7b9c9b7 100644 --- a/src/Steering/Demos/SeekFlee/SeekFlee.tscn +++ b/project/demos/seek_and_flee/SeekFlee.tscn @@ -1,11 +1,11 @@ [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://src/Steering/Demos/SeekFlee/Spawner.gd" type="Script" id=2] -[ext_resource path="res://src/Steering/Demos/SeekFlee/SeekFleeDemo.gd" type="Script" id=3] -[ext_resource path="res://src/Steering/Demos/SeekFlee/Seeker.tscn" type="PackedScene" id=4] -[ext_resource path="res://src/Steering/Demos/SeekFlee/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/Player.gd" type="Script" id=1] +[ext_resource path="res://demos/seek_and_flee/Spawner.gd" type="Script" id=2] +[ext_resource path="res://demos/seek_and_flee/SeekFleeDemo.gd" type="Script" id=3] +[ext_resource path="res://demos/seek_and_flee/Seeker.tscn" type="PackedScene" id=4] +[ext_resource path="res://demos/seek_and_flee/Boundary.gd" type="Script" id=5] +[ext_resource path="res://demos/seek_and_flee/Coward.tscn" type="PackedScene" id=6] [sub_resource type="CircleShape2D" id=1] radius = 30.0 @@ -68,11 +68,13 @@ script = ExtResource( 5 ) [node name="CollisionShape2D" type="CollisionShape2D" parent="BottomBoundary"] shape = SubResource( 3 ) -[node name="SeekerSpawner" type="Node2D" parent="."] -script = ExtResource( 2 ) -agent_scene = ExtResource( 4 ) +[node name="Spawners" type="Node2D" parent="."] -[node name="FleeerSpawner" type="Node2D" parent="."] +[node name="SeekerSpawner" type="Node2D" parent="Spawners"] script = ExtResource( 2 ) -agent_scene = ExtResource( 6 ) -agent_color = Color( 0.0980392, 0.886275, 0.517647, 1 ) +Entity = ExtResource( 4 ) + +[node name="CowardSpawner" type="Node2D" parent="Spawners"] +script = ExtResource( 2 ) +Entity = ExtResource( 6 ) +entity_color = Color( 0, 1, 0.741176, 1 ) diff --git a/project/demos/seek_and_flee/SeekFleeDemo.gd b/project/demos/seek_and_flee/SeekFleeDemo.gd new file mode 100644 index 0000000..6f589cb --- /dev/null +++ b/project/demos/seek_and_flee/SeekFleeDemo.gd @@ -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) diff --git a/src/Steering/Demos/SeekFlee/Seeker.gd b/project/demos/seek_and_flee/Seeker.gd similarity index 82% rename from src/Steering/Demos/SeekFlee/Seeker.gd rename to project/demos/seek_and_flee/Seeker.gd index 3ec5946..22598a3 100644 --- a/src/Steering/Demos/SeekFlee/Seeker.gd +++ b/project/demos/seek_and_flee/Seeker.gd @@ -6,21 +6,19 @@ 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 -var agent: SteeringAgent -var player_agent: AgentLocation -var seek: Seek -var accel: = TargetAcceleration.new() +onready var agent: = GSTSteeringAgent.new() +onready var accel: = GSTTargetAcceleration.new() +onready var seek: = GSTSeek.new(agent, player_agent) + +var player_agent: GSTAgentLocation var velocity: = Vector2.ZERO var speed: float var color: Color func _ready() -> void: - agent = SteeringAgent.new() agent.max_linear_acceleration = speed/10 agent.max_linear_speed = speed - - seek = Seek.new(agent, player_agent) func _draw() -> void: diff --git a/src/Steering/Demos/SeekFlee/Seeker.tscn b/project/demos/seek_and_flee/Seeker.tscn similarity index 76% rename from src/Steering/Demos/SeekFlee/Seeker.tscn rename to project/demos/seek_and_flee/Seeker.tscn index 4ea2577..511241e 100644 --- a/src/Steering/Demos/SeekFlee/Seeker.tscn +++ b/project/demos/seek_and_flee/Seeker.tscn @@ -1,6 +1,6 @@ [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] diff --git a/project/demos/seek_and_flee/Spawner.gd b/project/demos/seek_and_flee/Spawner.gd new file mode 100644 index 0000000..6caa254 --- /dev/null +++ b/project/demos/seek_and_flee/Spawner.gd @@ -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 diff --git a/icon.png b/project/icon.png similarity index 100% rename from icon.png rename to project/icon.png diff --git a/icon.png.import b/project/icon.png.import similarity index 100% rename from icon.png.import rename to project/icon.png.import diff --git a/project.godot b/project/project.godot similarity index 64% rename from project.godot rename to project/project.godot index 29e0df1..92be641 100644 --- a/project.godot +++ b/project/project.godot @@ -10,77 +10,83 @@ config_version=4 _global_script_classes=[ { "base": "Reference", -"class": "AgentLocation", +"class": "GSTAgentLocation", "language": "GDScript", -"path": "res://src/Steering/AgentLocation.gd" +"path": "res://src/GSTAgentLocation.gd" }, { -"base": "SteeringBehavior", -"class": "Arrive", +"base": "GSTSteeringBehavior", +"class": "GSTArrive", "language": "GDScript", -"path": "res://src/Steering/Behaviors/Arrive.gd" +"path": "res://src/behaviors/GSTArrive.gd" }, { -"base": "Pursue", -"class": "Evade", +"base": "GSTPursue", +"class": "GSTEvade", "language": "GDScript", -"path": "res://src/Steering/Behaviors/Evade.gd" +"path": "res://src/behaviors/GSTEvade.gd" }, { -"base": "MatchOrientation", -"class": "Face", +"base": "GSTMatchOrientation", +"class": "GSTFace", "language": "GDScript", -"path": "res://src/Steering/Behaviors/Face.gd" +"path": "res://src/behaviors/GSTFace.gd" }, { -"base": "Seek", -"class": "Flee", +"base": "GSTSeek", +"class": "GSTFlee", "language": "GDScript", -"path": "res://src/Steering/Behaviors/Flee.gd" +"path": "res://src/behaviors/GSTFlee.gd" }, { -"base": "SteeringBehavior", -"class": "MatchOrientation", +"base": "GSTSteeringBehavior", +"class": "GSTMatchOrientation", "language": "GDScript", -"path": "res://src/Steering/Behaviors/MatchOrientation.gd" +"path": "res://src/behaviors/GSTMatchOrientation.gd" }, { -"base": "SteeringBehavior", -"class": "Pursue", +"base": "GSTSteeringBehavior", +"class": "GSTPursue", "language": "GDScript", -"path": "res://src/Steering/Behaviors/Pursue.gd" +"path": "res://src/behaviors/GSTPursue.gd" }, { -"base": "SteeringBehavior", -"class": "Seek", +"base": "GSTSteeringBehavior", +"class": "GSTSeek", "language": "GDScript", -"path": "res://src/Steering/Behaviors/Seek.gd" +"path": "res://src/behaviors/GSTSeek.gd" }, { -"base": "AgentLocation", -"class": "SteeringAgent", +"base": "GSTAgentLocation", +"class": "GSTSteeringAgent", "language": "GDScript", -"path": "res://src/Steering/SteeringAgent.gd" +"path": "res://src/GSTSteeringAgent.gd" }, { "base": "Reference", -"class": "SteeringBehavior", +"class": "GSTSteeringBehavior", "language": "GDScript", -"path": "res://src/Steering/SteeringBehavior.gd" +"path": "res://src/GSTSteeringBehavior.gd" }, { "base": "Reference", -"class": "TargetAcceleration", +"class": "GSTTargetAcceleration", "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={ -"AgentLocation": "", -"Arrive": "", -"Evade": "", -"Face": "", -"Flee": "", -"MatchOrientation": "", -"Pursue": "", -"Seek": "", -"SteeringAgent": "", -"SteeringBehavior": "", -"TargetAcceleration": "" +"GSTAgentLocation": "", +"GSTArrive": "", +"GSTEvade": "", +"GSTFace": "", +"GSTFlee": "", +"GSTMatchOrientation": "", +"GSTPursue": "", +"GSTSeek": "", +"GSTSteeringAgent": "", +"GSTSteeringBehavior": "", +"GSTTargetAcceleration": "", +"Utils": "" } [application] -config/name="godot-steering-toolkit" +config/name="SteeringToolkit" config/icon="res://icon.png" [input] diff --git a/src/Steering/AgentLocation.gd b/project/src/GSTAgentLocation.gd similarity index 84% rename from src/Steering/AgentLocation.gd rename to project/src/GSTAgentLocation.gd index e0cea19..577e878 100644 --- a/src/Steering/AgentLocation.gd +++ b/project/src/GSTAgentLocation.gd @@ -1,5 +1,5 @@ extends Reference -class_name AgentLocation +class_name GSTAgentLocation """ Data type to represent an agent with a location and an orientation """ diff --git a/src/Steering/SteeringAgent.gd b/project/src/GSTSteeringAgent.gd similarity index 86% rename from src/Steering/SteeringAgent.gd rename to project/src/GSTSteeringAgent.gd index 3f9a06c..3a75d02 100644 --- a/src/Steering/SteeringAgent.gd +++ b/project/src/GSTSteeringAgent.gd @@ -1,5 +1,5 @@ -extends AgentLocation -class_name SteeringAgent +extends GSTAgentLocation +class_name GSTSteeringAgent """ Extended agent data type that adds velocity and speed data. """ diff --git a/project/src/GSTSteeringBehavior.gd b/project/src/GSTSteeringBehavior.gd new file mode 100644 index 0000000..9ba6f54 --- /dev/null +++ b/project/src/GSTSteeringBehavior.gd @@ -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 diff --git a/src/Steering/TargetAcceleration.gd b/project/src/GSTTargetAcceleration.gd similarity index 69% rename from src/Steering/TargetAcceleration.gd rename to project/src/GSTTargetAcceleration.gd index 2a2a937..6ce7259 100644 --- a/src/Steering/TargetAcceleration.gd +++ b/project/src/GSTTargetAcceleration.gd @@ -1,5 +1,5 @@ extends Reference -class_name TargetAcceleration +class_name GSTTargetAcceleration """ A linear and angular amount of acceleration. """ @@ -9,9 +9,8 @@ var linear: = Vector3.ZERO var angular: = 0.0 -func set_zero() -> TargetAcceleration: +func set_zero() -> void: linear.x = 0.0 linear.y = 0.0 linear.z = 0.0 angular = 0.0 - return self diff --git a/project/src/Utils.gd b/project/src/Utils.gd new file mode 100644 index 0000000..6fad795 --- /dev/null +++ b/project/src/Utils.gd @@ -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 diff --git a/project/src/behaviors/GSTArrive.gd b/project/src/behaviors/GSTArrive.gd new file mode 100644 index 0000000..feedcc6 --- /dev/null +++ b/project/src/behaviors/GSTArrive.gd @@ -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) diff --git a/src/Steering/Behaviors/Evade.gd b/project/src/behaviors/GSTEvade.gd similarity index 52% rename from src/Steering/Behaviors/Evade.gd rename to project/src/behaviors/GSTEvade.gd index 091d48d..001069c 100644 --- a/src/Steering/Behaviors/Evade.gd +++ b/project/src/behaviors/GSTEvade.gd @@ -1,5 +1,5 @@ -extends Pursue -class_name Evade +extends GSTPursue +class_name GSTEvade """ 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 -func get_max_linear_acceleration() -> float: +func _get_modified_acceleration() -> float: return -agent.max_linear_acceleration diff --git a/project/src/behaviors/GSTFace.gd b/project/src/behaviors/GSTFace.gd new file mode 100644 index 0000000..c467bcf --- /dev/null +++ b/project/src/behaviors/GSTFace.gd @@ -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) diff --git a/project/src/behaviors/GSTFlee.gd b/project/src/behaviors/GSTFlee.gd new file mode 100644 index 0000000..73208b0 --- /dev/null +++ b/project/src/behaviors/GSTFlee.gd @@ -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 diff --git a/src/Steering/Behaviors/MatchOrientation.gd b/project/src/behaviors/GSTMatchOrientation.gd similarity index 53% rename from src/Steering/Behaviors/MatchOrientation.gd rename to project/src/behaviors/GSTMatchOrientation.gd index fa7b6ca..90eaf03 100644 --- a/src/Steering/Behaviors/MatchOrientation.gd +++ b/project/src/behaviors/GSTMatchOrientation.gd @@ -1,37 +1,37 @@ -extends SteeringBehavior -class_name MatchOrientation +extends GSTSteeringBehavior +class_name GSTMatchOrientation """ 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. """ -var target: AgentLocation +var target: GSTAgentLocation var alignment_tolerance: 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 -func _match_orientation(acceleration: TargetAcceleration, target_orientation: float) -> TargetAcceleration: - var rotation: = wrapf(target_orientation - agent.orientation, -PI, PI) +func _match_orientation(acceleration: GSTTargetAcceleration, desired_orientation: float) -> GSTTargetAcceleration: + var rotation: = wrapf(desired_orientation - agent.orientation, -PI, PI) var rotation_size: = -rotation if rotation < 0 else rotation if rotation_size <= alignment_tolerance: return acceleration.set_zero() - var target_rotation: = agent.max_angular_speed + var desired_rotation: = agent.max_angular_speed 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 if limited_acceleration > agent.max_angular_acceleration: @@ -42,5 +42,5 @@ func _match_orientation(acceleration: TargetAcceleration, target_orientation: fl return acceleration -func _calculate_internal_steering(acceleration: TargetAcceleration) -> TargetAcceleration: +func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration: return _match_orientation(acceleration, target.orientation) diff --git a/src/Steering/Behaviors/Pursue.gd b/project/src/behaviors/GSTPursue.gd similarity index 61% rename from src/Steering/Behaviors/Pursue.gd rename to project/src/behaviors/GSTPursue.gd index 9124c72..ccb45f2 100644 --- a/src/Steering/Behaviors/Pursue.gd +++ b/project/src/behaviors/GSTPursue.gd @@ -1,5 +1,5 @@ -extends SteeringBehavior -class_name Pursue +extends GSTSteeringBehavior +class_name GSTPursue """ 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 -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.max_predict_time = max_predict_time -func get_max_linear_acceleration() -> float: - return agent.max_linear_acceleration - - -func _calculate_internal_steering(acceleration: TargetAcceleration) -> TargetAcceleration: +func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration: var target_position: = target.position 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: predict_time = sqrt(predict_time_squared) - acceleration.linear = ((target_position + (target.linear_velocity * predict_time))-agent.position).normalized() - acceleration.linear *= agent.max_linear_acceleration + acceleration.linear = (( + target_position + (target.linear_velocity * predict_time))-agent.position).normalized() + acceleration.linear *= _get_modified_acceleration() acceleration.angular = 0 return acceleration + + +func _get_modified_acceleration() -> float: + return agent.max_linear_acceleration diff --git a/project/src/behaviors/GSTSeek.gd b/project/src/behaviors/GSTSeek.gd new file mode 100644 index 0000000..89a0b3d --- /dev/null +++ b/project/src/behaviors/GSTSeek.gd @@ -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 diff --git a/root.tscn b/root.tscn deleted file mode 100644 index b171e8d..0000000 --- a/root.tscn +++ /dev/null @@ -1,3 +0,0 @@ -[gd_scene format=2] - -[node name="Node2D" type="Node2D"] diff --git a/src/Steering/Behaviors/Arrive.gd b/src/Steering/Behaviors/Arrive.gd deleted file mode 100644 index e972990..0000000 --- a/src/Steering/Behaviors/Arrive.gd +++ /dev/null @@ -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 diff --git a/src/Steering/Behaviors/Face.gd b/src/Steering/Behaviors/Face.gd deleted file mode 100644 index e80ee5b..0000000 --- a/src/Steering/Behaviors/Face.gd +++ /dev/null @@ -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) diff --git a/src/Steering/Behaviors/Flee.gd b/src/Steering/Behaviors/Flee.gd deleted file mode 100644 index f3fba43..0000000 --- a/src/Steering/Behaviors/Flee.gd +++ /dev/null @@ -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 diff --git a/src/Steering/Behaviors/Seek.gd b/src/Steering/Behaviors/Seek.gd deleted file mode 100644 index 610a6c1..0000000 --- a/src/Steering/Behaviors/Seek.gd +++ /dev/null @@ -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 diff --git a/src/Steering/Demos/SeekFlee/SeekFleeDemo.gd b/src/Steering/Demos/SeekFlee/SeekFleeDemo.gd deleted file mode 100644 index 5f01a2c..0000000 --- a/src/Steering/Demos/SeekFlee/SeekFleeDemo.gd +++ /dev/null @@ -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"]) - ) diff --git a/src/Steering/Demos/SeekFlee/Spawner.gd b/src/Steering/Demos/SeekFlee/Spawner.gd deleted file mode 100644 index e94c5df..0000000 --- a/src/Steering/Demos/SeekFlee/Spawner.gd +++ /dev/null @@ -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) diff --git a/src/Steering/SteeringBehavior.gd b/src/Steering/SteeringBehavior.gd deleted file mode 100644 index dfb8c54..0000000 --- a/src/Steering/SteeringBehavior.gd +++ /dev/null @@ -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()