diff --git a/CHANGELOG.md b/CHANGELOG.md
index 10bbfad..9a867c2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,9 @@ This document lists new features, improvements, changes, and bug fixes in every
## Master
+- Removed the demos repository and brought demos back into main repo
+- Added a repository with just the files for [submodule](https://github.com/GDQuest/godot-steering-ai-framework-submodule) usage.
+
## Godot Steering AI Framework 3.0.0
### Changes
diff --git a/README.md b/README.md
index e615538..f82e435 100644
--- a/README.md
+++ b/README.md
@@ -8,23 +8,21 @@ This project is a framework to code complex and smooth AI movement in the [Godot
It supports all essential steering behaviors like flee, follow, look at, but also blended behaviors, group behaviors, avoiding neighbors, following a path, following the leader, and much more.
-
-
-**Table of Contents**
-
-- [Introduction](#introduction)
-- [The framework](#the-framework)
-- [Installation](#installation)
-- [Getting Started](#getting-started)
- - [More information and resources](#more-information-and-resources)
-- [Example usage](#example-usage)
-
+- [Godot Steering AI Framework](#godot-steering-ai-framework)
+ - [Getting the framework](#getting-the-framework)
+ - [Introduction](#introduction)
+ - [The framework](#the-framework)
+ - [How it works](#how-it-works)
+ - [Documentation](#documentation)
+ - [Contributing](#contributing)
+ - [Support us](#support-us)
+ - [Join the community](#join-the-community)
## Getting the framework
-This repository contains just the framework to make it easy for you to install it.
+This repository contains the framework and some demos for learning purposes.
-You should also check out the [Steering AI Framework Demos](https://github.com/GDQuest/godot-steering-ai-framework-demos) repository! It contains many demos to learn to use the framework and see what you can achieve with it.
+If you want just the framework with nothing else to get in the way or to create a Git submodule, use the [Godot Steering AI Framework Submodules](https://github.com/GDQuest/godot-steering-ai-framework-submodule) repository.
## Introduction
diff --git a/godot/Demos/Arrive/ArriveDemo.gd b/godot/Demos/Arrive/ArriveDemo.gd
new file mode 100644
index 0000000..c18049b
--- /dev/null
+++ b/godot/Demos/Arrive/ArriveDemo.gd
@@ -0,0 +1,51 @@
+extends Node
+
+export (float, 0, 3200, 100) var linear_speed_max := 800.0 setget set_linear_speed_max
+export (float, 0, 10000, 100) var linear_acceleration_max := 80.0 setget set_linear_acceleration_max
+export (float, 0, 100, 0.1) var arrival_tolerance := 25.0 setget set_arrival_tolerance
+export (float, 0, 500, 10) var deceleration_radius := 125.0 setget set_deceleration_radius
+
+onready var arriver := $Arriver
+onready var target_drawer := $TargetDrawer
+
+
+func _ready() -> void:
+ arriver.setup(linear_speed_max, linear_acceleration_max, arrival_tolerance, deceleration_radius)
+
+
+func _unhandled_input(event: InputEvent) -> void:
+ if event is InputEventMouseButton and event.button_index == BUTTON_LEFT and event.is_pressed():
+ arriver.target.position = Vector3(event.position.x, event.position.y, 0)
+ target_drawer.update()
+
+
+func set_arrival_tolerance(value: float) -> void:
+ arrival_tolerance = value
+ if not is_inside_tree():
+ return
+
+ arriver.arrive.arrival_tolerance = value
+
+
+func set_deceleration_radius(value: float) -> void:
+ deceleration_radius = value
+ if not is_inside_tree():
+ return
+
+ arriver.arrive.deceleration_radius = value
+
+
+func set_linear_speed_max(value: float) -> void:
+ linear_speed_max = value
+ if not is_inside_tree():
+ return
+
+ arriver.agent.linear_speed_max = value
+
+
+func set_linear_acceleration_max(value: float) -> void:
+ linear_acceleration_max = value
+ if not is_inside_tree():
+ return
+
+ arriver.agent.linear_acceleration_max = value
diff --git a/godot/Demos/Arrive/ArriveDemo.tscn b/godot/Demos/Arrive/ArriveDemo.tscn
new file mode 100644
index 0000000..8b02e8e
--- /dev/null
+++ b/godot/Demos/Arrive/ArriveDemo.tscn
@@ -0,0 +1,39 @@
+[gd_scene load_steps=8 format=2]
+
+[ext_resource path="res://Demos/Arrive/Arriver.gd" type="Script" id=1]
+[ext_resource path="res://Demos/Utils/DemoInterface.tscn" type="PackedScene" id=2]
+[ext_resource path="res://Demos/Arrive/ArriveDemo.gd" type="Script" id=3]
+[ext_resource path="res://Demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=4]
+[ext_resource path="res://Demos/Arrive/TargetDrawer.gd" type="Script" id=5]
+[ext_resource path="res://Demos/Utils/CircleDraw.gd" type="Script" id=6]
+
+[sub_resource type="CircleShape2D" id=1]
+radius = 23.2163
+
+[node name="ArriveDemo" type="Node"]
+script = ExtResource( 3 )
+linear_speed_max = 1600.0
+linear_acceleration_max = 5000.0
+arrival_tolerance = 35.0
+deceleration_radius = 180.0
+
+[node name="BackgroudLayer" parent="." instance=ExtResource( 4 )]
+
+[node name="TargetDrawer" type="Node2D" parent="."]
+script = ExtResource( 5 )
+
+[node name="Arriver" type="KinematicBody2D" parent="."]
+show_behind_parent = true
+position = Vector2( 960, 540 )
+script = ExtResource( 1 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Arriver"]
+shape = SubResource( 1 )
+script = ExtResource( 6 )
+inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
+outer_color = Color( 0.560784, 0.870588, 0.364706, 1 )
+stroke = 6.0
+
+[node name="DemoInterface" parent="." instance=ExtResource( 2 )]
+text_bbcode = "Arrive Demo
+Mouse click to make the [color=lime]green \"Player\"[/color] move to the [color=fuchsia]purple target[/color]"
diff --git a/godot/Demos/Arrive/ArriveDemo.tscn.bak b/godot/Demos/Arrive/ArriveDemo.tscn.bak
new file mode 100644
index 0000000..ab7af6a
--- /dev/null
+++ b/godot/Demos/Arrive/ArriveDemo.tscn.bak
@@ -0,0 +1,39 @@
+[gd_scene load_steps=8 format=2]
+
+[ext_resource path="res://demos/Arrive/Arriver.gd" type="Script" id=1]
+[ext_resource path="res://demos/Utils/DemoInterface.tscn" type="PackedScene" id=2]
+[ext_resource path="res://demos/Arrive/ArriveDemo.gd" type="Script" id=3]
+[ext_resource path="res://demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=4]
+[ext_resource path="res://demos/Arrive/TargetDrawer.gd" type="Script" id=5]
+[ext_resource path="res://demos/Utils/CircleDraw.gd" type="Script" id=6]
+
+[sub_resource type="CircleShape2D" id=1]
+radius = 23.2163
+
+[node name="ArriveDemo" type="Node"]
+script = ExtResource( 3 )
+linear_speed_max = 1600.0
+linear_acceleration_max = 5000.0
+arrival_tolerance = 35.0
+deceleration_radius = 180.0
+
+[node name="BackgroudLayer" parent="." instance=ExtResource( 4 )]
+
+[node name="TargetDrawer" type="Node2D" parent="."]
+script = ExtResource( 5 )
+
+[node name="Arriver" type="KinematicBody2D" parent="."]
+show_behind_parent = true
+position = Vector2( 960, 540 )
+script = ExtResource( 1 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Arriver"]
+shape = SubResource( 1 )
+script = ExtResource( 6 )
+inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
+outer_color = Color( 0.560784, 0.870588, 0.364706, 1 )
+stroke = 6.0
+
+[node name="DemoInterface" parent="." instance=ExtResource( 2 )]
+text_bbcode = "Arrive Demo
+Mouse click to make the [color=lime]green \"Player\"[/color] move to the [color=fuchsia]purple target[/color]"
diff --git a/godot/Demos/Arrive/Arriver.gd b/godot/Demos/Arrive/Arriver.gd
new file mode 100644
index 0000000..8646b6b
--- /dev/null
+++ b/godot/Demos/Arrive/Arriver.gd
@@ -0,0 +1,28 @@
+extends KinematicBody2D
+
+var agent := GSAIKinematicBody2DAgent.new(self)
+var target := GSAIAgentLocation.new()
+var arrive := GSAIArrive.new(agent, target)
+var _accel := GSAITargetAcceleration.new()
+
+var _velocity := Vector2()
+var _drag := 0.1
+
+
+func _physics_process(delta: float) -> void:
+ arrive.calculate_steering(_accel)
+ agent._apply_steering(_accel, delta)
+
+
+func setup(
+ linear_speed_max: float,
+ linear_acceleration_max: float,
+ arrival_tolerance: float,
+ deceleration_radius: float
+) -> void:
+ agent.linear_speed_max = linear_speed_max
+ agent.linear_acceleration_max = linear_acceleration_max
+ agent.linear_drag_percentage = _drag
+ arrive.deceleration_radius = deceleration_radius
+ arrive.arrival_tolerance = arrival_tolerance
+ target.position = agent.position
diff --git a/godot/Demos/Arrive/TargetDrawer.gd b/godot/Demos/Arrive/TargetDrawer.gd
new file mode 100644
index 0000000..3bdfc31
--- /dev/null
+++ b/godot/Demos/Arrive/TargetDrawer.gd
@@ -0,0 +1,19 @@
+extends Node2D
+
+const COLORS := {
+ deceleration_radius = Color(1.0, 0.419, 0.592, 0.5),
+ arrival_tolerance = Color(0.278, 0.231, 0.47, 0.3)
+}
+
+var arriver: Node2D
+
+
+func _ready() -> void:
+ yield(owner, "ready")
+ arriver = owner.arriver
+
+
+func _draw():
+ var target_position := GSAIUtils.to_vector2(arriver.target.position)
+ draw_circle(target_position, owner.deceleration_radius, COLORS.deceleration_radius)
+ draw_circle(target_position, owner.arrival_tolerance, COLORS.arrival_tolerance)
diff --git a/godot/Demos/Arrive3d/Arrive3dDemo.tscn b/godot/Demos/Arrive3d/Arrive3dDemo.tscn
new file mode 100644
index 0000000..8ffcc48
--- /dev/null
+++ b/godot/Demos/Arrive3d/Arrive3dDemo.tscn
@@ -0,0 +1,96 @@
+[gd_scene load_steps=14 format=2]
+
+[ext_resource path="res://Demos/Utils/DemoInterface.tscn" type="PackedScene" id=1]
+[ext_resource path="res://Demos/Arrive3d/Camera.gd" type="Script" id=2]
+[ext_resource path="res://Demos/Arrive3d/Seek3dDemo.gd" type="Script" id=3]
+[ext_resource path="res://Demos/Arrive3d/Seeker.gd" type="Script" id=4]
+[ext_resource path="res://Demos/Arrive3d/SeekerMat.tres" type="Material" id=5]
+
+[sub_resource type="CapsuleShape" id=1]
+
+[sub_resource type="CapsuleMesh" id=2]
+
+[sub_resource type="CubeMesh" id=3]
+material = ExtResource( 5 )
+size = Vector3( 0.5, 0.5, 1 )
+
+[sub_resource type="CylinderMesh" id=4]
+top_radius = 2.0
+bottom_radius = 2.0
+height = 0.1
+
+[sub_resource type="SpatialMaterial" id=5]
+albedo_color = Color( 0.945098, 0.85098, 0.0745098, 1 )
+
+[sub_resource type="BoxShape" id=6]
+extents = Vector3( 1000, 0.1, 1000 )
+
+[sub_resource type="PlaneMesh" id=7]
+size = Vector2( 250, 250 )
+
+[sub_resource type="SpatialMaterial" id=8]
+albedo_color = Color( 0.0941176, 0.235294, 0.486275, 1 )
+
+[node name="Arrive3dDemo" type="Node"]
+script = ExtResource( 3 )
+linear_speed_max = 50.0
+linear_acceleration_max = 53.2
+deceleration_radius = 10.8
+angular_speed_max = 550
+angular_accel_max = 910
+
+[node name="Arriver" type="KinematicBody" parent="."]
+script = ExtResource( 4 )
+
+[node name="CollisionShape" type="CollisionShape" parent="Arriver"]
+transform = Transform( 1, 0, 0, 0, -1.62921e-07, 1, 0, -1, -1.62921e-07, 0, 1.5, 0 )
+shape = SubResource( 1 )
+
+[node name="Capsule" type="MeshInstance" parent="Arriver"]
+transform = Transform( 1, 0, 0, 0, -1.62921e-07, 1, 0, -1, -1.62921e-07, 0, 1.5, 0 )
+mesh = SubResource( 2 )
+material/0 = ExtResource( 5 )
+
+[node name="Nose" type="MeshInstance" parent="Arriver"]
+transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 1.25 )
+mesh = SubResource( 3 )
+material/0 = null
+
+[node name="Camera" type="Camera" parent="."]
+transform = Transform( 0.989952, 0.0720094, -0.121693, 0.0339305, 0.714503, 0.69881, 0.137271, -0.695917, 0.70488, -7.68317, 14.1265, 25.616 )
+current = true
+script = ExtResource( 2 )
+
+[node name="RayCast" type="RayCast" parent="Camera"]
+enabled = true
+cast_to = Vector3( -627, 200, -777 )
+collision_mask = 2
+
+[node name="MouseTarget" type="Spatial" parent="."]
+transform = Transform( 1, 0, 7.45058e-09, 0, 1, 0, 7.45058e-09, 0, 1, -4.76837e-07, 9.53674e-07, 1.90735e-06 )
+
+[node name="MeshInstance" type="MeshInstance" parent="MouseTarget"]
+mesh = SubResource( 4 )
+material/0 = SubResource( 5 )
+
+[node name="StaticBody" type="StaticBody" parent="."]
+transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.1, 0 )
+collision_layer = 2
+collision_mask = 2
+
+[node name="CollisionShape" type="CollisionShape" parent="StaticBody"]
+shape = SubResource( 6 )
+
+[node name="Ground" type="MeshInstance" parent="."]
+mesh = SubResource( 7 )
+material/0 = SubResource( 8 )
+
+[node name="DirectionalLight" type="DirectionalLight" parent="."]
+transform = Transform( -0.588165, 0.462179, -0.663666, -0.804031, -0.245728, 0.541436, 0.087159, 0.852061, 0.516134, -17.6076, 12.1748, 0 )
+light_energy = 0.5
+shadow_enabled = true
+
+[node name="DemoInterface" parent="." instance=ExtResource( 1 )]
+mouse_filter = 2
+text_bbcode = "3D Arrive Demo
+Move the mouse about the field to have the agent turn towards and smoothly arrive at the target marker."
diff --git a/godot/Demos/Arrive3d/Arrive3dDemo.tscn.bak b/godot/Demos/Arrive3d/Arrive3dDemo.tscn.bak
new file mode 100644
index 0000000..75f9899
--- /dev/null
+++ b/godot/Demos/Arrive3d/Arrive3dDemo.tscn.bak
@@ -0,0 +1,97 @@
+[gd_scene load_steps=14 format=2]
+
+[ext_resource path="res://src/Utils/DemoInterface.tscn" type="PackedScene" id=1]
+[ext_resource path="res://demos/Arrive3d/Camera.gd" type="Script" id=2]
+[ext_resource path="res://demos/Arrive3d/Seek3dDemo.gd" type="Script" id=3]
+[ext_resource path="res://demos/Arrive3d/Seeker.gd" type="Script" id=4]
+[ext_resource path="res://demos/Arrive3d/SeekerMat.tres" type="Material" id=5]
+
+
+[sub_resource type="CapsuleShape" id=1]
+
+[sub_resource type="CapsuleMesh" id=2]
+
+[sub_resource type="CubeMesh" id=3]
+material = ExtResource( 5 )
+size = Vector3( 0.5, 0.5, 1 )
+
+[sub_resource type="CylinderMesh" id=4]
+top_radius = 2.0
+bottom_radius = 2.0
+height = 0.1
+
+[sub_resource type="SpatialMaterial" id=5]
+albedo_color = Color( 0.945098, 0.85098, 0.0745098, 1 )
+
+[sub_resource type="BoxShape" id=6]
+extents = Vector3( 1000, 0.1, 1000 )
+
+[sub_resource type="PlaneMesh" id=7]
+size = Vector2( 250, 250 )
+
+[sub_resource type="SpatialMaterial" id=8]
+albedo_color = Color( 0.0941176, 0.235294, 0.486275, 1 )
+
+[node name="Arrive3dDemo" type="Node"]
+script = ExtResource( 3 )
+linear_speed_max = 50.0
+linear_acceleration_max = 53.2
+deceleration_radius = 10.8
+angular_speed_max = 550
+angular_accel_max = 910
+
+[node name="Arriver" type="KinematicBody" parent="."]
+script = ExtResource( 4 )
+
+[node name="CollisionShape" type="CollisionShape" parent="Arriver"]
+transform = Transform( 1, 0, 0, 0, -1.62921e-07, 1, 0, -1, -1.62921e-07, 0, 1.5, 0 )
+shape = SubResource( 1 )
+
+[node name="Capsule" type="MeshInstance" parent="Arriver"]
+transform = Transform( 1, 0, 0, 0, -1.62921e-07, 1, 0, -1, -1.62921e-07, 0, 1.5, 0 )
+mesh = SubResource( 2 )
+material/0 = ExtResource( 5 )
+
+[node name="Nose" type="MeshInstance" parent="Arriver"]
+transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 1.25 )
+mesh = SubResource( 3 )
+material/0 = null
+
+[node name="Camera" type="Camera" parent="."]
+transform = Transform( 0.989952, 0.0720094, -0.121693, 0.0339305, 0.714503, 0.69881, 0.137271, -0.695917, 0.70488, -7.68317, 14.1265, 25.616 )
+current = true
+script = ExtResource( 2 )
+
+[node name="RayCast" type="RayCast" parent="Camera"]
+enabled = true
+cast_to = Vector3( -627, 200, -777 )
+collision_mask = 2
+
+[node name="MouseTarget" type="Spatial" parent="."]
+transform = Transform( 1, 0, 7.45058e-09, 0, 1, 0, 7.45058e-09, 0, 1, -4.76837e-07, 9.53674e-07, 1.90735e-06 )
+
+[node name="MeshInstance" type="MeshInstance" parent="MouseTarget"]
+mesh = SubResource( 4 )
+material/0 = SubResource( 5 )
+
+[node name="StaticBody" type="StaticBody" parent="."]
+transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.1, 0 )
+collision_layer = 2
+collision_mask = 2
+
+[node name="CollisionShape" type="CollisionShape" parent="StaticBody"]
+shape = SubResource( 6 )
+
+[node name="Ground" type="MeshInstance" parent="."]
+mesh = SubResource( 7 )
+material/0 = SubResource( 8 )
+
+[node name="DirectionalLight" type="DirectionalLight" parent="."]
+transform = Transform( -0.588165, 0.462179, -0.663666, -0.804031, -0.245728, 0.541436, 0.087159, 0.852061, 0.516134, -17.6076, 12.1748, 0 )
+light_energy = 0.5
+shadow_enabled = true
+
+[node name="DemoInterface" parent="." instance=ExtResource( 1 )]
+mouse_filter = 2
+text_bbcode = "3D Arrive Demo
+Move the mouse about the field to have the agent turn towards and smoothly arrive at the target marker."
diff --git a/godot/Demos/Arrive3d/Camera.gd b/godot/Demos/Arrive3d/Camera.gd
new file mode 100644
index 0000000..4970295
--- /dev/null
+++ b/godot/Demos/Arrive3d/Camera.gd
@@ -0,0 +1,24 @@
+extends Camera
+
+var target: Spatial
+
+onready var ray := $RayCast
+
+
+func _unhandled_input(event: InputEvent) -> void:
+ if event is InputEventMouseMotion:
+ _set_target_position(event.position)
+
+
+func setup(_target: Spatial) -> void:
+ self.target = _target
+ _set_target_position(get_viewport().get_mouse_position())
+
+
+func _set_target_position(position: Vector2) -> void:
+ var to = project_local_ray_normal(position) * 10000
+ ray.cast_to = to
+ ray.force_raycast_update()
+ if ray.is_colliding():
+ var point = ray.get_collision_point()
+ target.transform.origin = point
diff --git a/godot/Demos/Arrive3d/Seek3dDemo.gd b/godot/Demos/Arrive3d/Seek3dDemo.gd
new file mode 100644
index 0000000..151ed7b
--- /dev/null
+++ b/godot/Demos/Arrive3d/Seek3dDemo.gd
@@ -0,0 +1,92 @@
+extends Node
+
+export (float, 0, 100, 5) var linear_speed_max := 10.0 setget set_linear_speed_max
+export (float, 0, 100, 0.1) var linear_acceleration_max := 1.0 setget set_linear_acceleration_max
+export (float, 0, 50, 0.1) var arrival_tolerance := 0.5 setget set_arrival_tolerance
+export (float, 0, 50, 0.1) var deceleration_radius := 5.0 setget set_deceleration_radius
+export (int, 0, 1080, 10) var angular_speed_max := 270 setget set_angular_speed_max
+export (int, 0, 2048, 10) var angular_accel_max := 45 setget set_angular_accel_max
+export (int, 0, 178, 2) var align_tolerance := 5 setget set_align_tolerance
+export (int, 0, 180, 2) var angular_deceleration_radius := 45 setget set_angular_deceleration_radius
+
+onready var target := $MouseTarget
+onready var arriver := $Arriver
+
+
+func _ready() -> void:
+ arriver.setup(
+ deg2rad(align_tolerance),
+ deg2rad(angular_deceleration_radius),
+ deg2rad(angular_accel_max),
+ deg2rad(angular_speed_max),
+ deceleration_radius,
+ arrival_tolerance,
+ linear_acceleration_max,
+ linear_speed_max,
+ target
+ )
+ $Camera.setup(target)
+
+
+func set_align_tolerance(value: int) -> void:
+ align_tolerance = value
+ if not is_inside_tree():
+ return
+
+ arriver.face.alignment_tolerance = deg2rad(value)
+
+
+func set_angular_deceleration_radius(value: int) -> void:
+ deceleration_radius = value
+ if not is_inside_tree():
+ return
+
+ arriver.face.deceleration_radius = deg2rad(value)
+
+
+func set_angular_accel_max(value: int) -> void:
+ angular_accel_max = value
+ if not is_inside_tree():
+ return
+
+ arriver.agent.angular_acceleration_max = deg2rad(value)
+
+
+func set_angular_speed_max(value: int) -> void:
+ angular_speed_max = value
+ if not is_inside_tree():
+ return
+
+ arriver.agent.angular_speed_max = deg2rad(value)
+
+
+func set_arrival_tolerance(value: float) -> void:
+ arrival_tolerance = value
+ if not is_inside_tree():
+ return
+
+ arriver.arrive.arrival_tolerance = value
+
+
+func set_deceleration_radius(value: float) -> void:
+ deceleration_radius = value
+ if not is_inside_tree():
+ return
+
+ arriver.arrive.deceleration_radius = value
+
+
+func set_linear_speed_max(value: float) -> void:
+ linear_speed_max = value
+ if not is_inside_tree():
+ return
+
+ arriver.agent.linear_speed_max = value
+
+
+func set_linear_acceleration_max(value: float) -> void:
+ linear_acceleration_max = value
+ if not is_inside_tree():
+ return
+
+ arriver.agent.linear_acceleration_max = value
diff --git a/godot/Demos/Arrive3d/Seeker.gd b/godot/Demos/Arrive3d/Seeker.gd
new file mode 100644
index 0000000..ad4be91
--- /dev/null
+++ b/godot/Demos/Arrive3d/Seeker.gd
@@ -0,0 +1,47 @@
+extends KinematicBody
+
+var target_node: Spatial
+
+onready var agent := GSAIKinematicBody3DAgent.new(self)
+onready var target := GSAIAgentLocation.new()
+onready var accel := GSAITargetAcceleration.new()
+onready var blend := GSAIBlend.new(agent)
+onready var face := GSAIFace.new(agent, target, true)
+onready var arrive := GSAIArrive.new(agent, target)
+
+
+func _physics_process(delta: float) -> void:
+ target.position = target_node.transform.origin
+ target.position.y = transform.origin.y
+ blend.calculate_steering(accel)
+ agent._apply_steering(accel, delta)
+
+
+func setup(
+ align_tolerance: float,
+ angular_deceleration_radius: float,
+ angular_accel_max: float,
+ angular_speed_max: float,
+ deceleration_radius: float,
+ arrival_tolerance: float,
+ linear_acceleration_max: float,
+ linear_speed_max: float,
+ _target: Spatial
+) -> void:
+ agent.linear_speed_max = linear_speed_max
+ agent.linear_acceleration_max = linear_acceleration_max
+ agent.linear_drag_percentage = 0.05
+ agent.angular_acceleration_max = angular_accel_max
+ agent.angular_speed_max = angular_speed_max
+ agent.angular_drag_percentage = 0.1
+
+ arrive.arrival_tolerance = arrival_tolerance
+ arrive.deceleration_radius = deceleration_radius
+
+ face.alignment_tolerance = align_tolerance
+ face.deceleration_radius = angular_deceleration_radius
+
+ target_node = _target
+ self.target.position = target_node.transform.origin
+ blend.add(arrive, 1)
+ blend.add(face, 1)
diff --git a/godot/Demos/Arrive3d/SeekerMat.tres b/godot/Demos/Arrive3d/SeekerMat.tres
new file mode 100644
index 0000000..8a9f1f9
--- /dev/null
+++ b/godot/Demos/Arrive3d/SeekerMat.tres
@@ -0,0 +1,4 @@
+[gd_resource type="SpatialMaterial" format=2]
+
+[resource]
+albedo_color = Color( 0.152941, 0.764706, 0.247059, 1 )
diff --git a/godot/Demos/AvoidCollisions/AvoidCollisionsDemo.gd b/godot/Demos/AvoidCollisions/AvoidCollisionsDemo.gd
new file mode 100644
index 0000000..f82b2a1
--- /dev/null
+++ b/godot/Demos/AvoidCollisions/AvoidCollisionsDemo.gd
@@ -0,0 +1,40 @@
+extends Node
+
+export (float, 0, 1000, 40) var linear_speed_max := 350.0 setget set_linear_speed_max
+export (float, 0, 4000, 2) var linear_acceleration_max := 40.0 setget set_linear_accel_max
+export (float, 0, 500, 10) var proximity_radius := 140.0 setget set_proximity_radius
+export var draw_proximity := true setget set_draw_proximity
+
+onready var spawner := $Spawner
+
+
+func set_linear_speed_max(value: float) -> void:
+ linear_speed_max = value
+ if not is_inside_tree():
+ return
+
+ spawner.set_linear_speed_max(value)
+
+
+func set_linear_accel_max(value: float) -> void:
+ linear_acceleration_max = value
+ if not is_inside_tree():
+ return
+
+ spawner.set_linear_accel_max(value)
+
+
+func set_proximity_radius(value: float) -> void:
+ proximity_radius = value
+ if not is_inside_tree():
+ return
+
+ spawner.set_proximity_radius(value)
+
+
+func set_draw_proximity(value: bool) -> void:
+ draw_proximity = value
+ if not is_inside_tree():
+ return
+
+ spawner.set_draw_proximity(value)
diff --git a/godot/Demos/AvoidCollisions/AvoidCollisionsDemo.tscn b/godot/Demos/AvoidCollisions/AvoidCollisionsDemo.tscn
new file mode 100644
index 0000000..8dfadb0
--- /dev/null
+++ b/godot/Demos/AvoidCollisions/AvoidCollisionsDemo.tscn
@@ -0,0 +1,26 @@
+[gd_scene load_steps=6 format=2]
+
+[ext_resource path="res://Demos/AvoidCollisions/Spawner.gd" type="Script" id=1]
+[ext_resource path="res://Demos/AvoidCollisions/AvoidCollisionsDemo.gd" type="Script" id=2]
+[ext_resource path="res://Demos/AvoidCollisions/Avoider.tscn" type="PackedScene" id=3]
+[ext_resource path="res://Demos/Utils/DemoInterface.tscn" type="PackedScene" id=4]
+[ext_resource path="res://Demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=5]
+
+[node name="AvoidCollisionsDemo" type="Node"]
+script = ExtResource( 2 )
+linear_speed_max = 520.0
+linear_acceleration_max = 2250.0
+proximity_radius = 100.0
+
+[node name="BackgroudLayer" parent="." instance=ExtResource( 5 )]
+
+[node name="Spawner" type="Node2D" parent="."]
+script = ExtResource( 1 )
+avoider_template = ExtResource( 3 )
+inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
+outer_color = Color( 0.560784, 0.870588, 0.364706, 1 )
+agent_count = 80
+
+[node name="DemoInterface" parent="." instance=ExtResource( 4 )]
+text_bbcode = "Avoid Collisions Demo
+Watch each agent try to keep traveling in a particular direction, but prioritize avoiding collisions with other agents."
diff --git a/godot/Demos/AvoidCollisions/AvoidCollisionsDemo.tscn.bak b/godot/Demos/AvoidCollisions/AvoidCollisionsDemo.tscn.bak
new file mode 100644
index 0000000..5bf239e
--- /dev/null
+++ b/godot/Demos/AvoidCollisions/AvoidCollisionsDemo.tscn.bak
@@ -0,0 +1,26 @@
+[gd_scene load_steps=6 format=2]
+
+[ext_resource path="res://demos/AvoidCollisions/Spawner.gd" type="Script" id=1]
+[ext_resource path="res://demos/AvoidCollisions/AvoidCollisionsDemo.gd" type="Script" id=2]
+[ext_resource path="res://demos/AvoidCollisions/Avoider.tscn" type="PackedScene" id=3]
+[ext_resource path="res://demos/Utils/DemoInterface.tscn" type="PackedScene" id=4]
+[ext_resource path="res://demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=5]
+
+[node name="AvoidCollisionsDemo" type="Node"]
+script = ExtResource( 2 )
+linear_speed_max = 520.0
+linear_acceleration_max = 2250.0
+proximity_radius = 100.0
+
+[node name="BackgroudLayer" parent="." instance=ExtResource( 5 )]
+
+[node name="Spawner" type="Node2D" parent="."]
+script = ExtResource( 1 )
+avoider_template = ExtResource( 3 )
+inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
+outer_color = Color( 0.560784, 0.870588, 0.364706, 1 )
+agent_count = 80
+
+[node name="DemoInterface" parent="." instance=ExtResource( 4 )]
+text_bbcode = "Avoid Collisions Demo
+Watch each agent try to keep traveling in a particular direction, but prioritize avoiding collisions with other agents."
diff --git a/godot/Demos/AvoidCollisions/Avoider.gd b/godot/Demos/AvoidCollisions/Avoider.gd
new file mode 100644
index 0000000..7fcfb17
--- /dev/null
+++ b/godot/Demos/AvoidCollisions/Avoider.gd
@@ -0,0 +1,91 @@
+extends KinematicBody2D
+
+var draw_proximity: bool
+
+var _boundary_right: float
+var _boundary_bottom: float
+var _radius: float
+var _accel := GSAITargetAcceleration.new()
+var _velocity := Vector2.ZERO
+var _direction := Vector2()
+var _drag := 0.1
+var _color := Color(0.4, 1.0, 0.89, 0.3)
+
+onready var collision := $CollisionShape2D
+onready var agent := GSAIKinematicBody2DAgent.new(self)
+onready var proximity := GSAIRadiusProximity.new(agent, [], 140)
+onready var avoid := GSAIAvoidCollisions.new(agent, proximity)
+onready var target := GSAIAgentLocation.new()
+onready var seek := GSAISeek.new(agent, target)
+onready var priority := GSAIPriority.new(agent, 0.0001)
+
+
+func _draw() -> void:
+ if draw_proximity:
+ draw_circle(Vector2.ZERO, proximity.radius, _color)
+
+
+func _physics_process(delta: float) -> void:
+ target.position.x = agent.position.x + _direction.x * _radius
+ target.position.y = agent.position.y + _direction.y * _radius
+
+ priority.calculate_steering(_accel)
+ agent._apply_steering(_accel, delta)
+
+
+func setup(
+ linear_speed_max: float,
+ linear_accel_max: float,
+ proximity_radius: float,
+ boundary_right: float,
+ boundary_bottom: float,
+ _draw_proximity: bool,
+ rng: RandomNumberGenerator
+) -> void:
+ rng.randomize()
+ _direction = Vector2(rng.randf_range(-1, 1), rng.randf_range(-1, 1)).normalized()
+
+ agent.linear_speed_max = linear_speed_max
+ agent.linear_acceleration_max = linear_accel_max
+
+ proximity.radius = proximity_radius
+ _boundary_bottom = boundary_bottom
+ _boundary_right = boundary_right
+
+ _radius = collision.shape.radius
+ agent.bounding_radius = _radius
+
+ agent.linear_drag_percentage = _drag
+
+ self.draw_proximity = _draw_proximity
+
+ priority.add(avoid)
+ priority.add(seek)
+
+
+func set_proximity_agents(agents: Array) -> void:
+ proximity.agents = agents
+
+
+func set_random_nonoverlapping_position(others: Array, distance_from_boundary_min: float) -> void:
+ var rng := RandomNumberGenerator.new()
+ rng.randomize()
+ var tries_max := max(100, others.size() * others.size())
+ while tries_max > 0:
+ tries_max -= 1
+ global_position.x = rng.randf_range(
+ distance_from_boundary_min, _boundary_right - distance_from_boundary_min
+ )
+ global_position.y = rng.randf_range(
+ distance_from_boundary_min, _boundary_bottom - distance_from_boundary_min
+ )
+ var done := true
+ for i in range(others.size()):
+ var other: Node2D = others[i]
+ if (
+ other.global_position.distance_to(position)
+ <= _radius * 2 + distance_from_boundary_min
+ ):
+ done = false
+ if done:
+ break
diff --git a/godot/Demos/AvoidCollisions/Avoider.tscn b/godot/Demos/AvoidCollisions/Avoider.tscn
new file mode 100644
index 0000000..97f32cc
--- /dev/null
+++ b/godot/Demos/AvoidCollisions/Avoider.tscn
@@ -0,0 +1,17 @@
+[gd_scene load_steps=4 format=2]
+
+[ext_resource path="res://Demos/Utils/CircleDraw.gd" type="Script" id=1]
+[ext_resource path="res://Demos/AvoidCollisions/Avoider.gd" type="Script" id=2]
+
+[sub_resource type="CircleShape2D" id=1]
+radius = 21.3503
+
+[node name="Avoider" type="KinematicBody2D"]
+script = ExtResource( 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+shape = SubResource( 1 )
+script = ExtResource( 1 )
+inner_color = Color( 0.890196, 0.411765, 0.337255, 1 )
+outer_color = Color( 1, 0.709804, 0.439216, 1 )
+stroke = 5.0
diff --git a/godot/Demos/AvoidCollisions/Avoider.tscn.bak b/godot/Demos/AvoidCollisions/Avoider.tscn.bak
new file mode 100644
index 0000000..044f107
--- /dev/null
+++ b/godot/Demos/AvoidCollisions/Avoider.tscn.bak
@@ -0,0 +1,17 @@
+[gd_scene load_steps=4 format=2]
+
+[ext_resource path="res://demos/Utils/CircleDraw.gd" type="Script" id=1]
+[ext_resource path="res://demos/AvoidCollisions/Avoider.gd" type="Script" id=2]
+
+[sub_resource type="CircleShape2D" id=1]
+radius = 21.3503
+
+[node name="Avoider" type="KinematicBody2D"]
+script = ExtResource( 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+shape = SubResource( 1 )
+script = ExtResource( 1 )
+inner_color = Color( 0.890196, 0.411765, 0.337255, 1 )
+outer_color = Color( 1, 0.709804, 0.439216, 1 )
+stroke = 5.0
diff --git a/godot/Demos/AvoidCollisions/Spawner.gd b/godot/Demos/AvoidCollisions/Spawner.gd
new file mode 100644
index 0000000..fedb269
--- /dev/null
+++ b/godot/Demos/AvoidCollisions/Spawner.gd
@@ -0,0 +1,66 @@
+extends Node2D
+
+export var avoider_template: PackedScene
+export var inner_color := Color()
+export var outer_color := Color()
+export var agent_count := 60
+
+var boundaries: Vector2
+
+
+func _ready() -> void:
+ boundaries = Vector2(
+ ProjectSettings["display/window/size/width"], ProjectSettings["display/window/size/height"]
+ )
+ var rng := RandomNumberGenerator.new()
+ var avoiders := []
+ var avoider_agents := []
+ for i in range(agent_count):
+ var avoider := avoider_template.instance()
+ add_child(avoider)
+ avoider.setup(
+ owner.linear_speed_max,
+ owner.linear_acceleration_max,
+ owner.proximity_radius,
+ boundaries.x,
+ boundaries.y,
+ true if i == 0 and owner.draw_proximity else false,
+ rng
+ )
+ avoider_agents.append(avoider.agent)
+ avoider.set_random_nonoverlapping_position(avoiders, 16)
+ if i == 0:
+ avoider.collision.inner_color = inner_color
+ avoider.collision.outer_color = outer_color
+ avoiders.append(avoider)
+ if i % 10 == 0:
+ yield(get_tree(), "idle_frame")
+ for child in get_children():
+ child.set_proximity_agents(avoider_agents)
+
+
+func _physics_process(_delta: float) -> void:
+ for child in get_children():
+ child.global_position = child.global_position.posmodv(boundaries)
+
+
+func set_linear_speed_max(value: float) -> void:
+ for child in get_children():
+ child.agent.linear_speed_max = value
+
+
+func set_linear_accel_max(value: float) -> void:
+ for child in get_children():
+ child.agent.linear_acceleration_max = value
+
+
+func set_proximity_radius(value: float) -> void:
+ for child in get_children():
+ child.proximity.radius = value
+ get_child(0).update()
+
+
+func set_draw_proximity(value: bool) -> void:
+ var child := get_child(0)
+ child.draw_proximity = value
+ child.update()
diff --git a/godot/Demos/DemoPickerUI.gd b/godot/Demos/DemoPickerUI.gd
new file mode 100644
index 0000000..657d5cc
--- /dev/null
+++ b/godot/Demos/DemoPickerUI.gd
@@ -0,0 +1,28 @@
+class_name DemoPickerUI
+extends Control
+
+# warning-ignore:unused_signal
+signal demo_requested
+
+var demo_path := "" setget set_demo_path
+
+onready var list: ItemList = $VBoxContainer/ItemList
+onready var button: Button = $VBoxContainer/Button
+
+
+func _ready() -> void:
+ # warning-ignore:return_value_discarded
+ list.connect("demo_selected", self, "set_demo_path")
+ # warning-ignore:return_value_discarded
+ list.connect("item_activated", self, "_on_ItemList_item_activated")
+ # warning-ignore:return_value_discarded
+ button.connect("pressed", self, "emit_signal", ["demo_requested"])
+ demo_path = list.file_paths[0]
+
+
+func set_demo_path(value: String) -> void:
+ demo_path = value
+
+
+func _on_ItemList_item_activated(_index: int) -> void:
+ emit_signal("demo_requested")
diff --git a/godot/Demos/DemoPlayer.gd b/godot/Demos/DemoPlayer.gd
new file mode 100644
index 0000000..cfcfa9f
--- /dev/null
+++ b/godot/Demos/DemoPlayer.gd
@@ -0,0 +1,16 @@
+extends Node2D
+
+
+func load_demo(scene_path: String) -> void:
+ if not scene_path:
+ return
+
+ var demo = load(scene_path)
+ if demo:
+ add_child(demo.instance())
+
+
+func unload() -> void:
+ for node in get_children():
+ call_deferred("remove_child", node)
+ node.queue_free()
diff --git a/godot/Demos/DemoSelector.tscn b/godot/Demos/DemoSelector.tscn
new file mode 100644
index 0000000..12d8cf2
--- /dev/null
+++ b/godot/Demos/DemoSelector.tscn
@@ -0,0 +1,84 @@
+[gd_scene load_steps=7 format=2]
+
+[ext_resource path="res://Demos/PopulateItemList.gd" type="Script" id=1]
+[ext_resource path="res://assets/theme/gdquest.theme" type="Theme" id=2]
+[ext_resource path="res://assets/sprites/background.png" type="Texture" id=3]
+[ext_resource path="res://Demos/DemoPickerUI.gd" type="Script" id=4]
+[ext_resource path="res://Demos/DemoPlayer.gd" type="Script" id=5]
+[ext_resource path="res://Demos/Demos.gd" type="Script" id=6]
+
+[node name="Demos" type="Node"]
+script = ExtResource( 6 )
+
+[node name="DemoPlayer" type="Node2D" parent="."]
+script = ExtResource( 5 )
+
+[node name="DemoPickerUI" type="Control" parent="."]
+anchor_right = 1.0
+anchor_bottom = 1.0
+theme = ExtResource( 2 )
+script = ExtResource( 4 )
+__meta__ = {
+"_edit_use_anchors_": false
+}
+
+[node name="TextureRect" type="TextureRect" parent="DemoPickerUI"]
+anchor_right = 1.0
+anchor_bottom = 1.0
+rect_min_size = Vector2( 1024, 600 )
+size_flags_horizontal = 3
+size_flags_vertical = 3
+texture = ExtResource( 3 )
+expand = true
+stretch_mode = 2
+
+[node name="VBoxContainer" type="VBoxContainer" parent="DemoPickerUI"]
+anchor_left = 0.5
+anchor_top = 0.5
+anchor_right = 0.5
+anchor_bottom = 0.5
+margin_left = -341.0
+margin_top = -290.0
+margin_right = 341.0
+margin_bottom = 290.0
+rect_min_size = Vector2( 682, 0 )
+size_flags_horizontal = 3
+size_flags_vertical = 3
+alignment = 1
+__meta__ = {
+"_edit_use_anchors_": false
+}
+
+[node name="ItemList" type="ItemList" parent="DemoPickerUI/VBoxContainer"]
+margin_top = 231.0
+margin_right = 682.0
+margin_bottom = 240.0
+auto_height = true
+script = ExtResource( 1 )
+
+[node name="Button" type="Button" parent="DemoPickerUI/VBoxContainer"]
+margin_left = 201.0
+margin_top = 248.0
+margin_right = 481.0
+margin_bottom = 348.0
+rect_min_size = Vector2( 280, 100 )
+size_flags_horizontal = 4
+size_flags_vertical = 13
+text = "Load scene"
+
+[node name="ButtonGoBack" type="Button" parent="."]
+visible = false
+anchor_top = 1.0
+anchor_bottom = 1.0
+margin_left = 48.0
+margin_top = -156.0
+margin_right = 328.0
+margin_bottom = -56.0
+rect_min_size = Vector2( 280, 100 )
+size_flags_horizontal = 4
+size_flags_vertical = 13
+theme = ExtResource( 2 )
+text = "Go back"
+__meta__ = {
+"_edit_use_anchors_": false
+}
diff --git a/godot/Demos/Demos.gd b/godot/Demos/Demos.gd
new file mode 100644
index 0000000..e8a9150
--- /dev/null
+++ b/godot/Demos/Demos.gd
@@ -0,0 +1,30 @@
+extends Node
+
+onready var demo_picker: DemoPickerUI = $DemoPickerUI
+onready var demo_player := $DemoPlayer
+onready var button_go_back: Button = $ButtonGoBack
+
+
+func _ready() -> void:
+ # warning-ignore:return_value_discarded
+ demo_picker.connect("demo_requested", self, "_on_DemoPickerUI_demo_requested")
+ # warning-ignore:return_value_discarded
+ button_go_back.connect("pressed", self, "_on_ButtonGoBack_pressed")
+
+
+func _input(event: InputEvent) -> void:
+ if event.is_action_pressed("toggle_fullscreen"):
+ OS.window_fullscreen = not OS.window_fullscreen
+ get_tree().set_input_as_handled()
+
+
+func _on_DemoPickerUI_demo_requested() -> void:
+ demo_player.load_demo(demo_picker.demo_path)
+ demo_picker.hide()
+ button_go_back.show()
+
+
+func _on_ButtonGoBack_pressed() -> void:
+ demo_player.unload()
+ button_go_back.hide()
+ demo_picker.show()
diff --git a/godot/Demos/Face/FaceDemo.gd b/godot/Demos/Face/FaceDemo.gd
new file mode 100644
index 0000000..282d941
--- /dev/null
+++ b/godot/Demos/Face/FaceDemo.gd
@@ -0,0 +1,61 @@
+extends Node
+
+export (int, 0, 1080, 2) var angular_speed_max := 120 setget set_angular_speed_max
+export (int, 0, 2048, 2) var angular_accel_max := 10 setget set_angular_accel_max
+export (int, 0, 180, 2) var align_tolerance := 5 setget set_align_tolerance
+export (int, 0, 359, 2) var deceleration_radius := 45 setget set_deceleration_radius
+export (float, 0, 1000, 40) var player_speed := 600.0 setget set_player_speed
+
+onready var player := $Player
+onready var turret := $Turret
+
+
+func _ready() -> void:
+ player.speed = player_speed
+ turret.setup(
+ player.agent,
+ deg2rad(align_tolerance),
+ deg2rad(deceleration_radius),
+ deg2rad(angular_accel_max),
+ deg2rad(angular_speed_max)
+ )
+
+
+func set_align_tolerance(value: int) -> void:
+ align_tolerance = value
+ if not is_inside_tree():
+ return
+
+ turret.face.alignment_tolerance = deg2rad(value)
+
+
+func set_deceleration_radius(value: int) -> void:
+ deceleration_radius = value
+ if not is_inside_tree():
+ return
+
+ turret.face.deceleration_radius = deg2rad(value)
+
+
+func set_angular_accel_max(value: int) -> void:
+ angular_accel_max = value
+ if not is_inside_tree():
+ return
+
+ turret.agent.angular_acceleration_max = deg2rad(value)
+
+
+func set_angular_speed_max(value: int) -> void:
+ angular_speed_max = value
+ if not is_inside_tree():
+ return
+
+ turret.agent.angular_speed_max = deg2rad(value)
+
+
+func set_player_speed(value: float) -> void:
+ player_speed = value
+ if not is_inside_tree():
+ return
+
+ player.speed = player_speed
diff --git a/godot/Demos/Face/FaceDemo.tscn b/godot/Demos/Face/FaceDemo.tscn
new file mode 100644
index 0000000..8115e44
--- /dev/null
+++ b/godot/Demos/Face/FaceDemo.tscn
@@ -0,0 +1,48 @@
+[gd_scene load_steps=9 format=2]
+
+[ext_resource path="res://Demos/Face/Turret.gd" type="Script" id=1]
+[ext_resource path="res://Demos/Face/FaceDemo.gd" type="Script" id=2]
+[ext_resource path="res://Demos/Face/Player.gd" type="Script" id=3]
+[ext_resource path="res://Demos/Utils/DemoInterface.tscn" type="PackedScene" id=4]
+[ext_resource path="res://Demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=5]
+[ext_resource path="res://Demos/Utils/CircleDraw.gd" type="Script" id=8]
+
+[sub_resource type="CircleShape2D" id=1]
+radius = 20.2633
+
+[sub_resource type="CircleShape2D" id=2]
+radius = 37.1052
+
+[node name="FaceDemo" type="Node"]
+script = ExtResource( 2 )
+angular_speed_max = 662
+angular_accel_max = 924
+deceleration_radius = 136
+
+[node name="BackgroudLayer" parent="." instance=ExtResource( 5 )]
+
+[node name="Player" type="KinematicBody2D" parent="."]
+position = Vector2( 687.363, 351.005 )
+script = ExtResource( 3 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Player"]
+shape = SubResource( 1 )
+script = ExtResource( 8 )
+inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
+outer_color = Color( 0.560784, 0.870588, 0.364706, 1 )
+stroke = 6.0
+
+[node name="Turret" type="KinematicBody2D" parent="."]
+position = Vector2( 984.348, 571.959 )
+script = ExtResource( 1 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Turret"]
+shape = SubResource( 2 )
+script = ExtResource( 8 )
+inner_color = Color( 0.890196, 0.411765, 0.337255, 1 )
+outer_color = Color( 1, 0.709804, 0.439216, 1 )
+stroke = 8.0
+
+[node name="DemoInterface" parent="." instance=ExtResource( 4 )]
+text_bbcode = "Face Demo
+Move the [color=lime]green player[/color] around with WASD and notice the [color=#ffb570]orange turret[/color] orient itself"
diff --git a/godot/Demos/Face/FaceDemo.tscn.bak b/godot/Demos/Face/FaceDemo.tscn.bak
new file mode 100644
index 0000000..348b293
--- /dev/null
+++ b/godot/Demos/Face/FaceDemo.tscn.bak
@@ -0,0 +1,48 @@
+[gd_scene load_steps=9 format=2]
+
+[ext_resource path="res://demos/Face/Turret.gd" type="Script" id=1]
+[ext_resource path="res://demos/Face/FaceDemo.gd" type="Script" id=2]
+[ext_resource path="res://demos/Face/Player.gd" type="Script" id=3]
+[ext_resource path="res://demos/Utils/DemoInterface.tscn" type="PackedScene" id=4]
+[ext_resource path="res://demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=5]
+[ext_resource path="res://demos/Utils/CircleDraw.gd" type="Script" id=8]
+
+[sub_resource type="CircleShape2D" id=1]
+radius = 20.2633
+
+[sub_resource type="CircleShape2D" id=2]
+radius = 37.1052
+
+[node name="FaceDemo" type="Node"]
+script = ExtResource( 2 )
+angular_speed_max = 662
+angular_accel_max = 924
+deceleration_radius = 136
+
+[node name="BackgroudLayer" parent="." instance=ExtResource( 5 )]
+
+[node name="Player" type="KinematicBody2D" parent="."]
+position = Vector2( 687.363, 351.005 )
+script = ExtResource( 3 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Player"]
+shape = SubResource( 1 )
+script = ExtResource( 8 )
+inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
+outer_color = Color( 0.560784, 0.870588, 0.364706, 1 )
+stroke = 6.0
+
+[node name="Turret" type="KinematicBody2D" parent="."]
+position = Vector2( 984.348, 571.959 )
+script = ExtResource( 1 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Turret"]
+shape = SubResource( 2 )
+script = ExtResource( 8 )
+inner_color = Color( 0.890196, 0.411765, 0.337255, 1 )
+outer_color = Color( 1, 0.709804, 0.439216, 1 )
+stroke = 8.0
+
+[node name="DemoInterface" parent="." instance=ExtResource( 4 )]
+text_bbcode = "Face Demo
+Move the [color=lime]green player[/color] around with WASD and notice the [color=#ffb570]orange turret[/color] orient itself"
diff --git a/godot/Demos/Face/Player.gd b/godot/Demos/Face/Player.gd
new file mode 100644
index 0000000..d37cc17
--- /dev/null
+++ b/godot/Demos/Face/Player.gd
@@ -0,0 +1,18 @@
+extends KinematicBody2D
+
+var speed: float
+
+onready var agent := GSAIAgentLocation.new()
+
+
+func _physics_process(_delta: float) -> void:
+ var movement := _get_movement()
+ move_and_slide(movement * speed)
+ agent.position = Vector3(global_position.x, global_position.y, 0)
+
+
+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")
+ )
diff --git a/godot/Demos/Face/Turret.gd b/godot/Demos/Face/Turret.gd
new file mode 100644
index 0000000..1657316
--- /dev/null
+++ b/godot/Demos/Face/Turret.gd
@@ -0,0 +1,43 @@
+extends KinematicBody2D
+
+var face: GSAIFace
+var agent := GSAIKinematicBody2DAgent.new(self)
+
+var _accel := GSAITargetAcceleration.new()
+var _angular_drag := 0.1
+var _cannon: Rect2
+var _color: Color
+
+onready var collision_shape := $CollisionShape2D
+
+
+func _ready() -> void:
+ var radius = collision_shape.shape.radius
+ _cannon = Rect2(Vector2(-5, 0), Vector2(10, -radius * 2))
+ _color = collision_shape.outer_color
+
+
+func _physics_process(delta: float) -> void:
+ face.calculate_steering(_accel)
+ agent._apply_steering(_accel, delta)
+
+
+func _draw() -> void:
+ draw_rect(_cannon, _color)
+
+
+func setup(
+ player_agent: GSAIAgentLocation,
+ align_tolerance: float,
+ deceleration_radius: float,
+ angular_accel_max: float,
+ angular_speed_max: float
+) -> void:
+ face = GSAIFace.new(agent, player_agent)
+
+ face.alignment_tolerance = align_tolerance
+ face.deceleration_radius = deceleration_radius
+
+ agent.angular_acceleration_max = angular_accel_max
+ agent.angular_speed_max = angular_speed_max
+ agent.angular_drag_percentage = _angular_drag
diff --git a/godot/Demos/FollowPath/Drawer.gd b/godot/Demos/FollowPath/Drawer.gd
new file mode 100644
index 0000000..fcecf1d
--- /dev/null
+++ b/godot/Demos/FollowPath/Drawer.gd
@@ -0,0 +1,53 @@
+extends Node2D
+
+signal path_established(points)
+
+var active_points := []
+var is_drawing := false
+var distance_threshold := 100.0
+
+
+func _unhandled_input(event: InputEvent) -> void:
+ if event is InputEventMouseMotion:
+ if is_drawing:
+ active_points.append(event.position)
+ update()
+ elif event is InputEventMouseButton:
+ if event.pressed and event.button_index == BUTTON_LEFT:
+ active_points.clear()
+ active_points.append(event.position)
+ is_drawing = true
+ update()
+ elif not event.pressed:
+ is_drawing = false
+ if active_points.size() >= 2:
+ _simplify()
+
+
+func _draw() -> void:
+ if is_drawing:
+ for point in active_points:
+ draw_circle(point, 2, Color.red)
+ else:
+ if active_points.size() > 0:
+ draw_circle(active_points.front(), 2, Color.red)
+ draw_circle(active_points.back(), 2, Color.yellow)
+ draw_polyline(active_points, Color.skyblue, 1.0)
+
+
+func _simplify() -> void:
+ var first: Vector2 = active_points.front()
+ var last: Vector2 = active_points.back()
+ var key := first
+ var simplified_path := [first]
+ for i in range(1, active_points.size()):
+ var point: Vector2 = active_points[i]
+ var distance := point.distance_to(key)
+ if distance > distance_threshold:
+ key = point
+ simplified_path.append(key)
+ active_points = simplified_path
+ if active_points.back() != last:
+ active_points.append(last)
+ update()
+ emit_signal("path_established", active_points)
diff --git a/godot/Demos/FollowPath/FollowPathDemo.gd b/godot/Demos/FollowPath/FollowPathDemo.gd
new file mode 100644
index 0000000..cc26ce3
--- /dev/null
+++ b/godot/Demos/FollowPath/FollowPathDemo.gd
@@ -0,0 +1,70 @@
+extends Node
+
+export (float, 0, 2000, 40) var linear_speed_max := 600.0 setget set_linear_speed_max
+export (float, 0, 9000, 10.0) var linear_acceleration_max := 40.0 setget set_linear_acceleration_max
+export (float, 0, 100, 0.1) var arrival_tolerance := 10.0 setget set_arrival_tolerance
+export (float, 0, 500, 10) var deceleration_radius := 100.0 setget set_deceleration_radius
+export (float, 0, 5, 0.1) var predict_time := 0.3 setget set_predict_time
+export (float, 0, 200, 10.0) var path_offset := 20.0 setget set_path_offset
+
+onready var drawer := $Drawer
+onready var follower := $PathFollower
+
+
+func _ready() -> void:
+ follower.setup(
+ path_offset,
+ predict_time,
+ linear_acceleration_max,
+ linear_speed_max,
+ deceleration_radius,
+ arrival_tolerance
+ )
+
+
+func set_linear_speed_max(value: float) -> void:
+ linear_speed_max = value
+ if not is_inside_tree():
+ return
+
+ follower.agent.linear_speed_max = value
+
+
+func set_linear_acceleration_max(value: float) -> void:
+ linear_acceleration_max = value
+ if not is_inside_tree():
+ return
+
+ follower.agent.linear_acceleration_max = value
+
+
+func set_arrival_tolerance(value: float) -> void:
+ arrival_tolerance = value
+ if not is_inside_tree():
+ return
+
+ follower.follow.arrival_tolerance = value
+
+
+func set_deceleration_radius(value: float) -> void:
+ deceleration_radius = value
+ if not is_inside_tree():
+ return
+
+ follower.follow.deceleration_radius = value
+
+
+func set_predict_time(value: float) -> void:
+ predict_time = value
+ if not is_inside_tree():
+ return
+
+ follower.follow.prediction_time = value
+
+
+func set_path_offset(value: float) -> void:
+ path_offset = value
+ if not is_inside_tree():
+ return
+
+ follower.follow.path_offset = value
diff --git a/godot/Demos/FollowPath/FollowPathDemo.tscn b/godot/Demos/FollowPath/FollowPathDemo.tscn
new file mode 100644
index 0000000..9614780
--- /dev/null
+++ b/godot/Demos/FollowPath/FollowPathDemo.tscn
@@ -0,0 +1,37 @@
+[gd_scene load_steps=8 format=2]
+
+[ext_resource path="res://Demos/FollowPath/Drawer.gd" type="Script" id=1]
+[ext_resource path="res://Demos/Utils/DemoInterface.tscn" type="PackedScene" id=2]
+[ext_resource path="res://Demos/FollowPath/PathFollower.gd" type="Script" id=3]
+[ext_resource path="res://Demos/FollowPath/FollowPathDemo.gd" type="Script" id=4]
+[ext_resource path="res://Demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=5]
+[ext_resource path="res://Demos/Utils/CircleDraw.gd" type="Script" id=6]
+
+[sub_resource type="CircleShape2D" id=1]
+radius = 24.1954
+
+[node name="FollowPathDemo" type="Node"]
+script = ExtResource( 4 )
+linear_speed_max = 920.0
+linear_acceleration_max = 3740.0
+deceleration_radius = 200.0
+
+[node name="BackgroudLayer" parent="." instance=ExtResource( 5 )]
+
+[node name="Drawer" type="Node2D" parent="."]
+script = ExtResource( 1 )
+
+[node name="PathFollower" type="KinematicBody2D" parent="."]
+position = Vector2( 960, 540 )
+script = ExtResource( 3 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="PathFollower"]
+shape = SubResource( 1 )
+script = ExtResource( 6 )
+inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
+outer_color = Color( 0.560784, 0.870588, 0.364706, 1 )
+stroke = 6.0
+
+[node name="DemoInterface" parent="." instance=ExtResource( 2 )]
+text_bbcode = "Follow Path Demo
+Use the mouse to draw a path on screen and watch the [color=lime]green \"Agent\"[/color] follow it to the end."
diff --git a/godot/Demos/FollowPath/FollowPathDemo.tscn.bak b/godot/Demos/FollowPath/FollowPathDemo.tscn.bak
new file mode 100644
index 0000000..3935b61
--- /dev/null
+++ b/godot/Demos/FollowPath/FollowPathDemo.tscn.bak
@@ -0,0 +1,37 @@
+[gd_scene load_steps=8 format=2]
+
+[ext_resource path="res://demos/FollowPath/Drawer.gd" type="Script" id=1]
+[ext_resource path="res://demos/Utils/DemoInterface.tscn" type="PackedScene" id=2]
+[ext_resource path="res://demos/FollowPath/PathFollower.gd" type="Script" id=3]
+[ext_resource path="res://demos/FollowPath/FollowPathDemo.gd" type="Script" id=4]
+[ext_resource path="res://demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=5]
+[ext_resource path="res://demos/Utils/CircleDraw.gd" type="Script" id=6]
+
+[sub_resource type="CircleShape2D" id=1]
+radius = 24.1954
+
+[node name="FollowPathDemo" type="Node"]
+script = ExtResource( 4 )
+linear_speed_max = 920.0
+linear_acceleration_max = 3740.0
+deceleration_radius = 200.0
+
+[node name="BackgroudLayer" parent="." instance=ExtResource( 5 )]
+
+[node name="Drawer" type="Node2D" parent="."]
+script = ExtResource( 1 )
+
+[node name="PathFollower" type="KinematicBody2D" parent="."]
+position = Vector2( 960, 540 )
+script = ExtResource( 3 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="PathFollower"]
+shape = SubResource( 1 )
+script = ExtResource( 6 )
+inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
+outer_color = Color( 0.560784, 0.870588, 0.364706, 1 )
+stroke = 6.0
+
+[node name="DemoInterface" parent="." instance=ExtResource( 2 )]
+text_bbcode = "Follow Path Demo
+Use the mouse to draw a path on screen and watch the [color=lime]green \"Agent\"[/color] follow it to the end."
diff --git a/godot/Demos/FollowPath/PathFollower.gd b/godot/Demos/FollowPath/PathFollower.gd
new file mode 100644
index 0000000..4429248
--- /dev/null
+++ b/godot/Demos/FollowPath/PathFollower.gd
@@ -0,0 +1,49 @@
+extends KinematicBody2D
+
+var _velocity := Vector2.ZERO
+var _accel := GSAITargetAcceleration.new()
+var _valid := false
+var _drag := 0.1
+
+onready var agent := GSAIKinematicBody2DAgent.new(self)
+onready var path := GSAIPath.new(
+ [
+ Vector3(global_position.x, global_position.y, 0),
+ Vector3(global_position.x, global_position.y, 0)
+ ],
+ true
+)
+onready var follow := GSAIFollowPath.new(agent, path, 0, 0)
+
+
+func setup(
+ path_offset: float,
+ predict_time: float,
+ accel_max: float,
+ speed_max: float,
+ decel_radius: float,
+ arrival_tolerance: float
+) -> void:
+ owner.drawer.connect("path_established", self, "_on_Drawer_path_established")
+ follow.path_offset = path_offset
+ follow.prediction_time = predict_time
+ follow.deceleration_radius = decel_radius
+ follow.arrival_tolerance = arrival_tolerance
+
+ agent.linear_acceleration_max = accel_max
+ agent.linear_speed_max = speed_max
+ agent.linear_drag_percentage = _drag
+
+
+func _physics_process(delta: float) -> void:
+ if _valid:
+ follow.calculate_steering(_accel)
+ agent._apply_steering(_accel, delta)
+
+
+func _on_Drawer_path_established(points: Array) -> void:
+ var positions := PoolVector3Array()
+ for p in points:
+ positions.append(Vector3(p.x, p.y, 0))
+ path.create_path(positions)
+ _valid = true
diff --git a/godot/Demos/GroupBehaviors/GroupBehaviorsDemo.gd b/godot/Demos/GroupBehaviors/GroupBehaviorsDemo.gd
new file mode 100644
index 0000000..51ab7ea
--- /dev/null
+++ b/godot/Demos/GroupBehaviors/GroupBehaviorsDemo.gd
@@ -0,0 +1,79 @@
+extends Node
+
+onready var spawner := $Spawner
+
+export (float, 0, 2000, 40.0) var linear_speed_max := 600.0 setget set_linear_speed_max
+export (float, 0, 9000, 2.0) var linear_accel_max := 40.0 setget set_linear_accel_max
+export (float, 0, 300, 2.0) var proximity_radius := 140.0 setget set_proximity_radius
+export (float, 0, 200000, 250) var separation_decay_coefficient := 2000.0 setget set_separation_decay_coef
+export (float, 0, 2, 0.1) var cohesion_strength := 0.1 setget set_cohesion_strength
+export (float, 0, 10, 0.2) var separation_strength := 1.5 setget set_separation_strength
+export var show_proximity_radius := true setget set_show_proximity_radius
+
+
+func _ready() -> void:
+ spawner.setup(
+ linear_speed_max,
+ linear_accel_max,
+ proximity_radius,
+ separation_decay_coefficient,
+ cohesion_strength,
+ separation_strength,
+ show_proximity_radius
+ )
+
+
+func set_linear_speed_max(value: float) -> void:
+ linear_speed_max = value
+ if not is_inside_tree():
+ return
+
+ spawner.set_linear_speed_max(value)
+
+
+func set_linear_accel_max(value: float) -> void:
+ linear_accel_max = value
+ if not is_inside_tree():
+ return
+
+ spawner.set_linear_accel_max(value)
+
+
+func set_proximity_radius(value: float) -> void:
+ proximity_radius = value
+ if not is_inside_tree():
+ return
+
+ spawner.set_proximity_radius(value)
+
+
+func set_show_proximity_radius(value: bool) -> void:
+ show_proximity_radius = value
+ if not is_inside_tree():
+ return
+
+ spawner.set_show_proximity_radius(value)
+
+
+func set_separation_decay_coef(value: float) -> void:
+ separation_decay_coefficient = value
+ if not is_inside_tree():
+ return
+
+ spawner.set_separation_decay_coef(value)
+
+
+func set_cohesion_strength(value: float) -> void:
+ cohesion_strength = value
+ if not is_inside_tree():
+ return
+
+ spawner.set_cohesion_strength(value)
+
+
+func set_separation_strength(value: float) -> void:
+ separation_strength = value
+ if not is_inside_tree():
+ return
+
+ spawner.set_separation_strength(value)
diff --git a/godot/Demos/GroupBehaviors/GroupBehaviorsDemo.tscn b/godot/Demos/GroupBehaviors/GroupBehaviorsDemo.tscn
new file mode 100644
index 0000000..2f27d9a
--- /dev/null
+++ b/godot/Demos/GroupBehaviors/GroupBehaviorsDemo.tscn
@@ -0,0 +1,26 @@
+[gd_scene load_steps=6 format=2]
+
+[ext_resource path="res://Demos/GroupBehaviors/Member.tscn" type="PackedScene" id=1]
+[ext_resource path="res://Demos/GroupBehaviors/Spawner.gd" type="Script" id=2]
+[ext_resource path="res://Demos/GroupBehaviors/GroupBehaviorsDemo.gd" type="Script" id=3]
+[ext_resource path="res://Demos/Utils/DemoInterface.tscn" type="PackedScene" id=4]
+[ext_resource path="res://Demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=5]
+
+[node name="GroupBehaviorsDemo" type="Node"]
+script = ExtResource( 3 )
+linear_accel_max = 4234.0
+proximity_radius = 158.0
+separation_decay_coefficient = 121500.0
+cohesion_strength = 0.2
+separation_strength = 8.8
+
+[node name="BackgroudLayer" parent="." instance=ExtResource( 5 )]
+
+[node name="Spawner" type="Node2D" parent="."]
+position = Vector2( 512, 300 )
+script = ExtResource( 2 )
+member = ExtResource( 1 )
+
+[node name="DemoInterface" parent="." instance=ExtResource( 4 )]
+text_bbcode = "Group Behavior Demo
+Each of the \"Agents\" are both attempting to stay separated from each other but within reach of their nearest group's center of mass."
diff --git a/godot/Demos/GroupBehaviors/GroupBehaviorsDemo.tscn.bak b/godot/Demos/GroupBehaviors/GroupBehaviorsDemo.tscn.bak
new file mode 100644
index 0000000..b288389
--- /dev/null
+++ b/godot/Demos/GroupBehaviors/GroupBehaviorsDemo.tscn.bak
@@ -0,0 +1,26 @@
+[gd_scene load_steps=6 format=2]
+
+[ext_resource path="res://demos/GroupBehaviors/Member.tscn" type="PackedScene" id=1]
+[ext_resource path="res://demos/GroupBehaviors/Spawner.gd" type="Script" id=2]
+[ext_resource path="res://demos/GroupBehaviors/GroupBehaviorsDemo.gd" type="Script" id=3]
+[ext_resource path="res://demos/Utils/DemoInterface.tscn" type="PackedScene" id=4]
+[ext_resource path="res://demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=5]
+
+[node name="GroupBehaviorsDemo" type="Node"]
+script = ExtResource( 3 )
+linear_accel_max = 4234.0
+proximity_radius = 158.0
+separation_decay_coefficient = 121500.0
+cohesion_strength = 0.2
+separation_strength = 8.8
+
+[node name="BackgroudLayer" parent="." instance=ExtResource( 5 )]
+
+[node name="Spawner" type="Node2D" parent="."]
+position = Vector2( 512, 300 )
+script = ExtResource( 2 )
+member = ExtResource( 1 )
+
+[node name="DemoInterface" parent="." instance=ExtResource( 4 )]
+text_bbcode = "Group Behavior Demo
+Each of the \"Agents\" are both attempting to stay separated from each other but within reach of their nearest group's center of mass."
diff --git a/godot/Demos/GroupBehaviors/Member.gd b/godot/Demos/GroupBehaviors/Member.gd
new file mode 100644
index 0000000..e068884
--- /dev/null
+++ b/godot/Demos/GroupBehaviors/Member.gd
@@ -0,0 +1,52 @@
+extends KinematicBody2D
+
+var separation: GSAISeparation
+var cohesion: GSAICohesion
+var proximity: GSAIRadiusProximity
+var agent := GSAIKinematicBody2DAgent.new(self)
+var blend := GSAIBlend.new(agent)
+var acceleration := GSAITargetAcceleration.new()
+var draw_proximity := false
+
+var _color := Color.red
+var _velocity := Vector2()
+
+onready var collision_shape := $CollisionShape2D
+
+
+func setup(
+ linear_speed_max: float,
+ linear_accel_max: float,
+ proximity_radius: float,
+ separation_decay_coefficient: float,
+ cohesion_strength: float,
+ separation_strength: float
+) -> void:
+ _color = Color(rand_range(0.5, 1), rand_range(0.25, 1), rand_range(0, 1))
+ collision_shape.inner_color = _color
+
+ agent.linear_acceleration_max = linear_accel_max
+ agent.linear_speed_max = linear_speed_max
+ agent.linear_drag_percentage = 0.1
+
+ proximity = GSAIRadiusProximity.new(agent, [], proximity_radius)
+ separation = GSAISeparation.new(agent, proximity)
+ separation.decay_coefficient = separation_decay_coefficient
+ cohesion = GSAICohesion.new(agent, proximity)
+ blend.add(separation, separation_strength)
+ blend.add(cohesion, cohesion_strength)
+
+
+func _draw() -> void:
+ if draw_proximity:
+ draw_circle(Vector2.ZERO, proximity.radius, Color(0.4, 1.0, 0.89, 0.3))
+
+
+func _physics_process(delta: float) -> void:
+ if blend:
+ blend.calculate_steering(acceleration)
+ agent._apply_steering(acceleration, delta)
+
+
+func set_neighbors(neighbor: Array) -> void:
+ proximity.agents = neighbor
diff --git a/godot/Demos/GroupBehaviors/Member.tscn b/godot/Demos/GroupBehaviors/Member.tscn
new file mode 100644
index 0000000..63207e1
--- /dev/null
+++ b/godot/Demos/GroupBehaviors/Member.tscn
@@ -0,0 +1,16 @@
+[gd_scene load_steps=4 format=2]
+
+[ext_resource path="res://Demos/GroupBehaviors/Member.gd" type="Script" id=1]
+[ext_resource path="res://Demos/Utils/CircleDraw.gd" type="Script" id=3]
+
+[sub_resource type="CircleShape2D" id=1]
+radius = 16.0
+
+[node name="Member" type="KinematicBody2D"]
+script = ExtResource( 1 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+shape = SubResource( 1 )
+script = ExtResource( 3 )
+outer_color = Color( 0.301961, 0.65098, 1, 1 )
+stroke = 4.0
diff --git a/godot/Demos/GroupBehaviors/Member.tscn.bak b/godot/Demos/GroupBehaviors/Member.tscn.bak
new file mode 100644
index 0000000..0baef77
--- /dev/null
+++ b/godot/Demos/GroupBehaviors/Member.tscn.bak
@@ -0,0 +1,16 @@
+[gd_scene load_steps=4 format=2]
+
+[ext_resource path="res://demos/GroupBehaviors/Member.gd" type="Script" id=1]
+[ext_resource path="res://demos/Utils/CircleDraw.gd" type="Script" id=3]
+
+[sub_resource type="CircleShape2D" id=1]
+radius = 16.0
+
+[node name="Member" type="KinematicBody2D"]
+script = ExtResource( 1 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+shape = SubResource( 1 )
+script = ExtResource( 3 )
+outer_color = Color( 0.301961, 0.65098, 1, 1 )
+stroke = 4.0
diff --git a/godot/Demos/GroupBehaviors/Spawner.gd b/godot/Demos/GroupBehaviors/Spawner.gd
new file mode 100644
index 0000000..d4b7193
--- /dev/null
+++ b/godot/Demos/GroupBehaviors/Spawner.gd
@@ -0,0 +1,73 @@
+extends Node2D
+
+export var member: PackedScene
+
+
+func setup(
+ linear_speed_max: float,
+ linear_accel_max: float,
+ proximity_radius: float,
+ separation_decay_coefficient: float,
+ cohesion_strength: float,
+ separation_strength: float,
+ show_proximity_radius: bool
+) -> void:
+ var followers := []
+ for i in range(19):
+ var follower := member.instance()
+ add_child(follower)
+ follower.position += Vector2(rand_range(-60, 60), rand_range(-60, 60))
+ followers.append(follower)
+ follower.setup(
+ linear_speed_max,
+ linear_accel_max,
+ proximity_radius,
+ separation_decay_coefficient,
+ cohesion_strength,
+ separation_strength
+ )
+ if i == 0 and show_proximity_radius:
+ follower.draw_proximity = true
+ follower.update()
+ var agents := []
+ for i in followers:
+ agents.append(i.agent)
+ for i in followers:
+ i.proximity.agents = agents
+
+
+func set_linear_speed_max(value: float) -> void:
+ for child in get_children():
+ child.agent.linear_speed_max = value
+
+
+func set_linear_accel_max(value: float) -> void:
+ for child in get_children():
+ child.agent.linear_acceleration_max = value
+
+
+func set_proximity_radius(value: float) -> void:
+ for child in get_children():
+ child.proximity.radius = value
+ if child == get_child(0):
+ child.update()
+
+
+func set_show_proximity_radius(value: bool) -> void:
+ get_child(0).draw_proximity = value
+ get_child(0).update()
+
+
+func set_separation_decay_coef(value: float) -> void:
+ for child in get_children():
+ child.separation.decay_coefficient = value
+
+
+func set_cohesion_strength(value: float) -> void:
+ for child in get_children():
+ child.blend.get_behavior_at(1).weight = value
+
+
+func set_separation_strength(value: float) -> void:
+ for child in get_children():
+ child.blend.get_behavior_at(0).weight = value
diff --git a/godot/Demos/PopulateItemList.gd b/godot/Demos/PopulateItemList.gd
new file mode 100644
index 0000000..cd1bf6e
--- /dev/null
+++ b/godot/Demos/PopulateItemList.gd
@@ -0,0 +1,68 @@
+extends ItemList
+
+signal demo_selected(scene_path)
+
+var file_paths := PoolStringArray()
+
+
+func _ready() -> void:
+ # warning-ignore:return_value_discarded
+ self.connect("item_selected", self, "_on_item_selected")
+
+ var this_directory: String = get_tree().current_scene.filename.rsplit("/", false, 1)[0]
+ file_paths = _find_files(this_directory, ["*Demo.tscn"], true)
+ populate(file_paths)
+ select(0)
+
+
+func populate(demos: PoolStringArray) -> void:
+ for path in demos:
+ var demo_name: String = path.rsplit("/", true, 1)[-1]
+ demo_name = demo_name.rsplit("Demo", true, 1)[0]
+ demo_name = sentencify(demo_name)
+ add_item(demo_name)
+
+
+func sentencify(line: String) -> String:
+ var regex := RegEx.new()
+ # warning-ignore:return_value_discarded
+ regex.compile("[A-Z]")
+
+ line = line.split(".", true, 1)[0]
+ line = regex.sub(line, " $0", true)
+ return line
+
+
+func _find_files(
+ dirpath := "", patterns := PoolStringArray(), is_recursive := false, do_skip_hidden := true
+) -> PoolStringArray:
+ var paths := PoolStringArray()
+ var directory := Directory.new()
+
+ if not directory.dir_exists(dirpath):
+ printerr("The directory does not exist: %s" % dirpath)
+ return paths
+ if not directory.open(dirpath) == OK:
+ printerr("Could not open the following dirpath: %s" % dirpath)
+ return paths
+
+ # warning-ignore:return_value_discarded
+ directory.list_dir_begin(true, do_skip_hidden)
+ var file_name := directory.get_next()
+ while file_name != "":
+ if directory.current_is_dir() and is_recursive:
+ var subdirectory := dirpath.plus_file(file_name)
+ paths.append_array(_find_files(subdirectory, patterns, is_recursive))
+ else:
+ for pattern in patterns:
+ if file_name.match(pattern):
+ paths.append(dirpath.plus_file(file_name))
+ file_name = directory.get_next()
+
+ directory.list_dir_end()
+ return paths
+
+
+func _on_item_selected(index: int) -> void:
+ var demo_path := file_paths[index]
+ emit_signal("demo_selected", demo_path)
diff --git a/godot/Demos/PursueSeek/BoundaryManager.gd b/godot/Demos/PursueSeek/BoundaryManager.gd
new file mode 100644
index 0000000..a5062cb
--- /dev/null
+++ b/godot/Demos/PursueSeek/BoundaryManager.gd
@@ -0,0 +1,15 @@
+extends Node2D
+# Wraps the ships' positions around the world border.
+
+var _world_bounds: Vector2
+
+
+func _ready() -> void:
+ _world_bounds = Vector2(
+ ProjectSettings["display/window/size/width"], ProjectSettings["display/window/size/height"]
+ )
+
+
+func _physics_process(_delta: float) -> void:
+ for ship in get_children():
+ ship.position = ship.position.posmodv(_world_bounds)
diff --git a/godot/Demos/PursueSeek/Player.gd b/godot/Demos/PursueSeek/Player.gd
new file mode 100644
index 0000000..8bc3588
--- /dev/null
+++ b/godot/Demos/PursueSeek/Player.gd
@@ -0,0 +1,96 @@
+extends KinematicBody2D
+# Controls the player ship's movements based on player input.
+
+export var thruster_strength := 175.0
+export var side_thruster_strength := 10.0
+export var velocity_max := 300.0
+export var angular_velocity_max := 2.0
+export var angular_drag := 0.025
+export var linear_drag := 0.025
+
+var _linear_velocity := Vector2()
+var _angular_velocity := 0.0
+
+onready var agent := GSAISteeringAgent.new()
+
+
+func _physics_process(delta: float) -> void:
+ var movement := _get_movement()
+ _angular_velocity = _calculate_angular_velocity(
+ movement.x,
+ _angular_velocity,
+ side_thruster_strength,
+ angular_velocity_max,
+ angular_drag,
+ delta
+ )
+ rotation += _angular_velocity * delta
+
+ _linear_velocity = _calculate_linear_velocity(
+ movement.y,
+ _linear_velocity,
+ Vector2.UP.rotated(rotation),
+ linear_drag,
+ thruster_strength,
+ velocity_max,
+ delta
+ )
+
+ _linear_velocity = move_and_slide(_linear_velocity)
+ _update_agent()
+
+
+func _calculate_angular_velocity(
+ horizontal_movement: float,
+ current_velocity: float,
+ _thruster_strength: float,
+ _velocity_max: float,
+ ship_drag: float,
+ delta: float
+) -> float:
+ var velocity := clamp(
+ current_velocity + _thruster_strength * horizontal_movement * delta,
+ -_velocity_max,
+ _velocity_max
+ )
+
+ velocity = lerp(velocity, 0, ship_drag)
+
+ return velocity
+
+
+func _calculate_linear_velocity(
+ vertical_movement: float,
+ current_velocity: Vector2,
+ facing_direction: Vector2,
+ ship_drag_coefficient: float,
+ strength: float,
+ speed_max: float,
+ delta: float
+) -> Vector2:
+ var actual_strength := 0.0
+ if vertical_movement > 0:
+ actual_strength = strength
+ elif vertical_movement < 0:
+ actual_strength = -strength / 1.5
+
+ var velocity := current_velocity + facing_direction * actual_strength * delta
+ velocity = velocity.linear_interpolate(Vector2.ZERO, ship_drag_coefficient)
+
+ return velocity.clamped(speed_max)
+
+
+func _get_movement() -> Vector2:
+ return Vector2(
+ Input.get_action_strength("sf_right") - Input.get_action_strength("sf_left"),
+ Input.get_action_strength("sf_up") - Input.get_action_strength("sf_down")
+ )
+
+
+func _update_agent() -> void:
+ agent.position.x = global_position.x
+ agent.position.y = global_position.y
+ agent.linear_velocity.x = _linear_velocity.x
+ agent.linear_velocity.y = _linear_velocity.y
+ agent.angular_velocity = _angular_velocity
+ agent.orientation = rotation
diff --git a/godot/Demos/PursueSeek/PursueAndSeekDemo.gd b/godot/Demos/PursueSeek/PursueAndSeekDemo.gd
new file mode 100644
index 0000000..e888235
--- /dev/null
+++ b/godot/Demos/PursueSeek/PursueAndSeekDemo.gd
@@ -0,0 +1,39 @@
+extends Node
+
+export (float, 0, 2000, 40) var linear_speed_max := 120.0 setget set_linear_speed_max
+export (float, 0, 2000, 20) var linear_accel_max := 10.0 setget set_linear_accel_max
+export (float, 0, 5, 0.1) var predict_time := 1.0 setget set_predict_time
+
+onready var pursuer := $BoundaryManager/Pursuer
+onready var seeker := $BoundaryManager/Seeker
+
+
+func _ready() -> void:
+ pursuer.setup(predict_time, linear_speed_max, linear_accel_max)
+ seeker.setup(predict_time, linear_speed_max, linear_accel_max)
+
+
+func set_linear_speed_max(value: float) -> void:
+ linear_speed_max = value
+ if not is_inside_tree():
+ return
+
+ pursuer.agent.linear_speed_max = value
+ seeker.agent.linear_speed_max = value
+
+
+func set_linear_accel_max(value: float) -> void:
+ linear_accel_max = value
+ if not is_inside_tree():
+ return
+
+ pursuer.agent.linear_acceleration_max = value
+ seeker.agent.linear_acceleration_max = value
+
+
+func set_predict_time(value: float) -> void:
+ predict_time = value
+ if not is_inside_tree():
+ return
+
+ pursuer._behavior.predict_time_max = value
diff --git a/godot/Demos/PursueSeek/PursueAndSeekDemo.tscn b/godot/Demos/PursueSeek/PursueAndSeekDemo.tscn
new file mode 100644
index 0000000..2196f05
--- /dev/null
+++ b/godot/Demos/PursueSeek/PursueAndSeekDemo.tscn
@@ -0,0 +1,92 @@
+[gd_scene load_steps=8 format=2]
+
+[ext_resource path="res://Demos/PursueSeek/Pursuer.gd" type="Script" id=1]
+[ext_resource path="res://Demos/PursueSeek/Player.gd" type="Script" id=2]
+[ext_resource path="res://Demos/PursueSeek/BoundaryManager.gd" type="Script" id=3]
+[ext_resource path="res://Demos/PursueSeek/PursueAndSeekDemo.gd" type="Script" id=4]
+[ext_resource path="res://Demos/Utils/DemoInterface.tscn" type="PackedScene" id=5]
+[ext_resource path="res://Demos/Utils/Line2DDraw.gd" type="Script" id=6]
+[ext_resource path="res://Demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=7]
+
+[node name="PursueVSSeekDemo" type="Node"]
+script = ExtResource( 4 )
+linear_speed_max = 1280.0
+linear_accel_max = 1040.0
+predict_time = 1.1
+
+[node name="BackgroudLayer" parent="." instance=ExtResource( 7 )]
+
+[node name="BoundaryManager" type="Node2D" parent="."]
+script = ExtResource( 3 )
+
+[node name="Player" type="KinematicBody2D" parent="BoundaryManager"]
+position = Vector2( 307.552, 555.999 )
+rotation = 1.5708
+collision_mask = 2
+script = ExtResource( 2 )
+__meta__ = {
+"_edit_group_": true
+}
+thruster_strength = 1000.0
+side_thruster_strength = 40.0
+velocity_max = 450.0
+angular_velocity_max = 3.0
+
+[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="BoundaryManager/Player"]
+polygon = PoolVector2Array( 0, -32, -24, 32, 24, 32 )
+
+[node name="Line2D" type="Line2D" parent="BoundaryManager/Player"]
+points = PoolVector2Array( 0, 32, 24, 32, 0, -32, -24, 32, 0, 32 )
+width = 8.0
+default_color = Color( 0.560784, 0.870588, 0.364706, 1 )
+joint_mode = 2
+antialiased = true
+script = ExtResource( 6 )
+inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
+
+[node name="Pursuer" type="KinematicBody2D" parent="BoundaryManager"]
+position = Vector2( 1240.22, 866.784 )
+collision_layer = 2
+script = ExtResource( 1 )
+__meta__ = {
+"_edit_group_": true
+}
+
+[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="BoundaryManager/Pursuer"]
+polygon = PoolVector2Array( 0, -32, -24, 32, 24, 32 )
+
+[node name="Line2D" type="Line2D" parent="BoundaryManager/Pursuer"]
+points = PoolVector2Array( 0, 32, 24, 32, 0, -32, -24, 32, 0, 32 )
+width = 8.0
+default_color = Color( 1, 0.709804, 0.439216, 1 )
+joint_mode = 2
+antialiased = true
+script = ExtResource( 6 )
+inner_color = Color( 0.890196, 0.411765, 0.337255, 1 )
+
+[node name="Seeker" type="KinematicBody2D" parent="BoundaryManager"]
+position = Vector2( 1240.22, 280.108 )
+rotation = 3.14159
+collision_layer = 2
+script = ExtResource( 1 )
+__meta__ = {
+"_edit_group_": true
+}
+use_seek = true
+
+[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="BoundaryManager/Seeker"]
+polygon = PoolVector2Array( 0, -32, -24, 32, 24, 32 )
+
+[node name="Line2D" type="Line2D" parent="BoundaryManager/Seeker"]
+points = PoolVector2Array( 0, 32, 24, 32, 0, -32, -24, 32, 0, 32 )
+width = 8.0
+default_color = Color( 0.301961, 0.65098, 1, 1 )
+joint_mode = 2
+antialiased = true
+script = ExtResource( 6 )
+inner_color = Color( 0.294118, 0.356863, 0.670588, 1 )
+
+[node name="DemoInterface" parent="." instance=ExtResource( 5 )]
+text_bbcode = "Pursue vs. Seek Demo
+Move the player around with WASD and notice the [color=#ffb570]orange Pursuer[/color] and the [color=aqua]blue Seeker[/color] follow
+the [color=lime]green \"Ship\"[/color] around"
diff --git a/godot/Demos/PursueSeek/PursueAndSeekDemo.tscn.bak b/godot/Demos/PursueSeek/PursueAndSeekDemo.tscn.bak
new file mode 100644
index 0000000..f7417cc
--- /dev/null
+++ b/godot/Demos/PursueSeek/PursueAndSeekDemo.tscn.bak
@@ -0,0 +1,92 @@
+[gd_scene load_steps=8 format=2]
+
+[ext_resource path="res://demos/PursueSeek/Pursuer.gd" type="Script" id=1]
+[ext_resource path="res://demos/PursueSeek/Player.gd" type="Script" id=2]
+[ext_resource path="res://demos/PursueSeek/BoundaryManager.gd" type="Script" id=3]
+[ext_resource path="res://demos/PursueSeek/PursueAndSeekDemo.gd" type="Script" id=4]
+[ext_resource path="res://demos/Utils/DemoInterface.tscn" type="PackedScene" id=5]
+[ext_resource path="res://demos/Utils/Line2DDraw.gd" type="Script" id=6]
+[ext_resource path="res://demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=7]
+
+[node name="PursueVSSeekDemo" type="Node"]
+script = ExtResource( 4 )
+linear_speed_max = 1280.0
+linear_accel_max = 1040.0
+predict_time = 1.1
+
+[node name="BackgroudLayer" parent="." instance=ExtResource( 7 )]
+
+[node name="BoundaryManager" type="Node2D" parent="."]
+script = ExtResource( 3 )
+
+[node name="Player" type="KinematicBody2D" parent="BoundaryManager"]
+position = Vector2( 307.552, 555.999 )
+rotation = 1.5708
+collision_mask = 2
+script = ExtResource( 2 )
+__meta__ = {
+"_edit_group_": true
+}
+thruster_strength = 1000.0
+side_thruster_strength = 40.0
+velocity_max = 450.0
+angular_velocity_max = 3.0
+
+[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="BoundaryManager/Player"]
+polygon = PoolVector2Array( 0, -32, -24, 32, 24, 32 )
+
+[node name="Line2D" type="Line2D" parent="BoundaryManager/Player"]
+points = PoolVector2Array( 0, 32, 24, 32, 0, -32, -24, 32, 0, 32 )
+width = 8.0
+default_color = Color( 0.560784, 0.870588, 0.364706, 1 )
+joint_mode = 2
+antialiased = true
+script = ExtResource( 6 )
+inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
+
+[node name="Pursuer" type="KinematicBody2D" parent="BoundaryManager"]
+position = Vector2( 1240.22, 866.784 )
+collision_layer = 2
+script = ExtResource( 1 )
+__meta__ = {
+"_edit_group_": true
+}
+
+[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="BoundaryManager/Pursuer"]
+polygon = PoolVector2Array( 0, -32, -24, 32, 24, 32 )
+
+[node name="Line2D" type="Line2D" parent="BoundaryManager/Pursuer"]
+points = PoolVector2Array( 0, 32, 24, 32, 0, -32, -24, 32, 0, 32 )
+width = 8.0
+default_color = Color( 1, 0.709804, 0.439216, 1 )
+joint_mode = 2
+antialiased = true
+script = ExtResource( 6 )
+inner_color = Color( 0.890196, 0.411765, 0.337255, 1 )
+
+[node name="Seeker" type="KinematicBody2D" parent="BoundaryManager"]
+position = Vector2( 1240.22, 280.108 )
+rotation = 3.14159
+collision_layer = 2
+script = ExtResource( 1 )
+__meta__ = {
+"_edit_group_": true
+}
+use_seek = true
+
+[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="BoundaryManager/Seeker"]
+polygon = PoolVector2Array( 0, -32, -24, 32, 24, 32 )
+
+[node name="Line2D" type="Line2D" parent="BoundaryManager/Seeker"]
+points = PoolVector2Array( 0, 32, 24, 32, 0, -32, -24, 32, 0, 32 )
+width = 8.0
+default_color = Color( 0.301961, 0.65098, 1, 1 )
+joint_mode = 2
+antialiased = true
+script = ExtResource( 6 )
+inner_color = Color( 0.294118, 0.356863, 0.670588, 1 )
+
+[node name="DemoInterface" parent="." instance=ExtResource( 5 )]
+text_bbcode = "Pursue vs. Seek Demo
+Move the player around with WASD and notice the [color=#ffb570]orange Pursuer[/color] and the [color=aqua]blue Seeker[/color] follow
+the [color=lime]green \"Ship\"[/color] around"
diff --git a/godot/Demos/PursueSeek/Pursuer.gd b/godot/Demos/PursueSeek/Pursuer.gd
new file mode 100644
index 0000000..04ebdf6
--- /dev/null
+++ b/godot/Demos/PursueSeek/Pursuer.gd
@@ -0,0 +1,65 @@
+extends KinematicBody2D
+# Represents a ship that chases after the player.
+
+export var use_seek: bool = false
+
+var _blend: GSAIBlend
+
+var _linear_drag_coefficient := 0.025
+var _angular_drag := 0.1
+var _direction_face := GSAIAgentLocation.new()
+
+onready var agent := GSAIKinematicBody2DAgent.new(self)
+onready var accel := GSAITargetAcceleration.new()
+onready var player_agent: GSAISteeringAgent = owner.find_node("Player", true, false).agent
+
+
+func _ready() -> void:
+ agent.calculate_velocities = false
+ set_physics_process(false)
+
+
+func _physics_process(delta: float) -> void:
+ _direction_face.position = agent.position + accel.linear.normalized()
+
+ _blend.calculate_steering(accel)
+
+ agent.angular_velocity = clamp(
+ agent.angular_velocity + accel.angular * delta, -agent.angular_speed_max, agent.angular_speed_max
+ )
+ agent.angular_velocity = lerp(agent.angular_velocity, 0, _angular_drag)
+
+ rotation += agent.angular_velocity * delta
+
+ var linear_velocity := (
+ GSAIUtils.to_vector2(agent.linear_velocity)
+ + (GSAIUtils.angle_to_vector2(rotation) * -agent.linear_acceleration_max * delta)
+ )
+ linear_velocity = linear_velocity.clamped(agent.linear_speed_max)
+ linear_velocity = linear_velocity.linear_interpolate(Vector2.ZERO, _linear_drag_coefficient)
+
+ linear_velocity = move_and_slide(linear_velocity)
+ agent.linear_velocity = GSAIUtils.to_vector3(linear_velocity)
+
+
+func setup(predict_time: float, linear_speed_max: float, linear_accel_max: float) -> void:
+ var behavior: GSAISteeringBehavior
+ if use_seek:
+ behavior = GSAISeek.new(agent, player_agent)
+ else:
+ behavior = GSAIPursue.new(agent, player_agent, predict_time)
+
+ var orient_behavior := GSAIFace.new(agent, _direction_face)
+ orient_behavior.alignment_tolerance = deg2rad(5)
+ orient_behavior.deceleration_radius = deg2rad(30)
+
+ _blend = GSAIBlend.new(agent)
+ _blend.add(behavior, 1)
+ _blend.add(orient_behavior, 1)
+
+ agent.angular_acceleration_max = deg2rad(1080)
+ agent.angular_speed_max = deg2rad(360)
+ agent.linear_acceleration_max = linear_accel_max
+ agent.linear_speed_max = linear_speed_max
+
+ set_physics_process(true)
diff --git a/godot/Demos/Quickstart/Agent.gd b/godot/Demos/Quickstart/Agent.gd
new file mode 100644
index 0000000..5c90316
--- /dev/null
+++ b/godot/Demos/Quickstart/Agent.gd
@@ -0,0 +1,167 @@
+extends KinematicBody2D
+
+# Maximum possible linear velocity
+export var speed_max := 450.0
+# Maximum change in linear velocity
+export var acceleration_max := 50.0
+# Maximum rotation velocity represented in degrees
+export var angular_speed_max := 240
+# Maximum change in rotation velocity represented in degrees
+export var angular_acceleration_max := 40
+
+export var health_max := 100
+export var flee_health_threshold := 20
+
+var velocity := Vector2.ZERO
+var angular_velocity := 0.0
+var linear_drag := 0.1
+var angular_drag := 0.1
+
+# Holds the linear and angular components calculated by our steering behaviors.
+var acceleration := GSAITargetAcceleration.new()
+
+onready var current_health := health_max
+
+# GSAISteeringAgent holds our agent's position, orientation, maximum speed and acceleration.
+onready var agent := GSAISteeringAgent.new()
+
+onready var player: Node = get_tree().get_nodes_in_group("Player")[0]
+# This assumes that our player class will keep its own agent updated.
+onready var player_agent: GSAISteeringAgent = player.agent
+
+# Proximities represent an area with which an agent can identify where neighbors in its relevant
+# group are. In our case, the group will feature the player, which will be used to avoid a
+# collision with them. We use a radius proximity so the player is only relevant inside 100 pixels.
+onready var proximity := GSAIRadiusProximity.new(agent, [player_agent], 100)
+
+# GSAIBlend combines behaviors together, calculating all of their acceleration together and adding
+# them together, multiplied by a strength. We will have one for fleeing, and one for pursuing,
+# toggling them depending on the agent's health. Since we want the agent to rotate AND move, then
+# we aim to blend them together.
+onready var flee_blend := GSAIBlend.new(agent)
+onready var pursue_blend := GSAIBlend.new(agent)
+
+# GSAIPriority will be the main steering behavior we use. It holds sub-behaviors and will pick the
+# first one that returns non-zero acceleration, ignoring any afterwards.
+onready var priority := GSAIPriority.new(agent)
+
+
+func _ready() -> void:
+ # ---------- Configuration for our agent ----------
+ agent.linear_speed_max = speed_max
+ agent.linear_acceleration_max = acceleration_max
+ agent.angular_speed_max = deg2rad(angular_speed_max)
+ agent.angular_acceleration_max = deg2rad(angular_acceleration_max)
+ agent.bounding_radius = calculate_radius($CollisionPolygon2D.polygon)
+ update_agent()
+
+ # ---------- Configuration for our behaviors ----------
+ # Pursue will happen while the agent is in good health. It produces acceleration that takes
+ # the agent on an intercept course with the target, predicting its position in the future.
+ var pursue := GSAIPursue.new(agent, player_agent)
+ pursue.predict_time_max = 1.5
+
+ # Flee will happen while the agent is in bad health, so will start disabled. It produces
+ # acceleration that takes the agent directly away from the target with no prediction.
+ var flee := GSAIFlee.new(agent, player_agent)
+
+ # AvoidCollision tries to keep the agent from running into any of the neighbors found in its
+ # proximity group. In our case, this will be the player, if they are close enough.
+ var avoid := GSAIAvoidCollisions.new(agent, proximity)
+
+ # Face turns the agent to keep looking towards its target. It will be enabled while the agent
+ # is not fleeing due to low health. It tries to arrive 'on alignment' with 0 remaining velocity.
+ var face := GSAIFace.new(agent, player_agent)
+
+ # We use deg2rad because the math in the toolkit assumes radians.
+ # How close for the agent to be 'aligned', if not exact.
+ face.alignment_tolerance = deg2rad(5)
+ # When to start slowing down
+ face.deceleration_radius = deg2rad(60)
+
+ # LookWhereYouGo turns the agent to keep looking towards its direction of travel. It will only
+ # be enabled while the agent is at low health.
+ var look := GSAILookWhereYouGo.new(agent)
+ # How close for the agent to be 'aligned', if not exact
+ look.alignment_tolerance = deg2rad(5)
+ # When to start slowing down.
+ look.deceleration_radius = deg2rad(60)
+
+ # Behaviors that are not enabled produce 0 acceleration.
+ # Adding our fleeing behaviors to a blend. The order does not matter.
+ flee_blend.is_enabled = false
+ flee_blend.add(look, 1)
+ flee_blend.add(flee, 1)
+
+ # Adding our pursuit behaviors to a blend. The order does not matter.
+ pursue_blend.add(face, 1)
+ pursue_blend.add(pursue, 1)
+
+ # Adding our final behaviors to the main priority behavior. The order does matter here.
+ # We want to avoid collision with the player first, flee from the player second when enabled,
+ # and pursue the player last when enabled.
+ priority.add(avoid)
+ priority.add(flee_blend)
+ priority.add(pursue_blend)
+
+
+func _physics_process(delta: float) -> void:
+ # Make sure any change in position and speed has been recorded.
+ update_agent()
+
+ if current_health <= flee_health_threshold:
+ pursue_blend.is_enabled = false
+ flee_blend.is_enabled = true
+
+ # Calculate the desired acceleration.
+ priority.calculate_steering(acceleration)
+
+ # We add the discovered acceleration to our linear velocity. The toolkit does not limit
+ # velocity, just acceleration, so we clamp the result ourselves here.
+ velocity = (velocity + Vector2(acceleration.linear.x, acceleration.linear.y) * delta).clamped(
+ agent.linear_speed_max
+ )
+
+ # This applies drag on the agent's motion, helping it to slow down naturally.
+ velocity = velocity.linear_interpolate(Vector2.ZERO, linear_drag)
+
+ # And since we're using a KinematicBody2D, we use Godot's excellent move_and_slide to actually
+ # apply the final movement, and record any change in velocity the physics engine discovered.
+ velocity = move_and_slide(velocity)
+
+ # We then do something similar to apply our agent's rotational speed.
+ angular_velocity = clamp(
+ angular_velocity + acceleration.angular * delta, -agent.angular_speed_max, agent.angular_speed_max
+ )
+ # This applies drag on the agent's rotation, helping it slow down naturally.
+ angular_velocity = lerp(angular_velocity, 0, angular_drag)
+ rotation += angular_velocity * delta
+
+
+# In order to support both 2D and 3D, the toolkit uses Vector3, so the conversion is required
+# when using 2D nodes. The Z component can be left to 0 safely.
+func update_agent() -> void:
+ agent.position.x = global_position.x
+ agent.position.y = global_position.y
+ agent.orientation = rotation
+ agent.linear_velocity.x = velocity.x
+ agent.linear_velocity.y = velocity.y
+ agent.angular_velocity = angular_velocity
+
+
+# We calculate the radius from the collision shape - this will approximate the agent's size in the
+# game world, to avoid collisions with the player.
+func calculate_radius(polygon: PoolVector2Array) -> float:
+ var furthest_point := Vector2(-INF, -INF)
+ for p in polygon:
+ if abs(p.x) > furthest_point.x:
+ furthest_point.x = p.x
+ if abs(p.y) > furthest_point.y:
+ furthest_point.y = p.y
+ return furthest_point.length()
+
+
+func damage(amount: int) -> void:
+ current_health -= amount
+ if current_health <= 0:
+ queue_free()
diff --git a/godot/Demos/Quickstart/Bullet.gd b/godot/Demos/Quickstart/Bullet.gd
new file mode 100644
index 0000000..a33fc8f
--- /dev/null
+++ b/godot/Demos/Quickstart/Bullet.gd
@@ -0,0 +1,33 @@
+extends KinematicBody2D
+
+export var speed := 1500.0
+
+var velocity := Vector2.ZERO
+var player: Node
+
+onready var timer := $Lifetime
+
+
+func _ready() -> void:
+ timer.connect("timeout", self, "_on_Lifetime_timeout")
+ timer.start()
+
+
+func _physics_process(delta: float) -> void:
+ var collision := move_and_collide(velocity * delta)
+ if collision:
+ timer.stop()
+ clear()
+ collision.collider.damage(10)
+
+
+func start(direction: Vector2) -> void:
+ velocity = direction * speed
+
+
+func clear() -> void:
+ queue_free()
+
+
+func _on_Lifetime_timeout() -> void:
+ clear()
diff --git a/godot/Demos/Quickstart/Bullet.tscn b/godot/Demos/Quickstart/Bullet.tscn
new file mode 100644
index 0000000..60ceb8d
--- /dev/null
+++ b/godot/Demos/Quickstart/Bullet.tscn
@@ -0,0 +1,23 @@
+[gd_scene load_steps=4 format=2]
+
+[ext_resource path="res://Demos/Utils/CircleDraw.gd" type="Script" id=1]
+[ext_resource path="res://Demos/Quickstart/Bullet.gd" type="Script" id=2]
+
+[sub_resource type="CircleShape2D" id=1]
+radius = 4.0
+
+[node name="Bullet" type="KinematicBody2D"]
+collision_layer = 4
+collision_mask = 2
+script = ExtResource( 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+shape = SubResource( 1 )
+script = ExtResource( 1 )
+inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
+outer_color = Color( 0.560784, 0.870588, 0.364706, 1 )
+stroke = 2.0
+
+[node name="Lifetime" type="Timer" parent="."]
+process_mode = 0
+wait_time = 3.0
diff --git a/godot/Demos/Quickstart/Bullet.tscn.bak b/godot/Demos/Quickstart/Bullet.tscn.bak
new file mode 100644
index 0000000..7f6d9b4
--- /dev/null
+++ b/godot/Demos/Quickstart/Bullet.tscn.bak
@@ -0,0 +1,23 @@
+[gd_scene load_steps=4 format=2]
+
+[ext_resource path="res://demos/Utils/CircleDraw.gd" type="Script" id=1]
+[ext_resource path="res://demos/Quickstart/Bullet.gd" type="Script" id=2]
+
+[sub_resource type="CircleShape2D" id=1]
+radius = 4.0
+
+[node name="Bullet" type="KinematicBody2D"]
+collision_layer = 4
+collision_mask = 2
+script = ExtResource( 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+shape = SubResource( 1 )
+script = ExtResource( 1 )
+inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
+outer_color = Color( 0.560784, 0.870588, 0.364706, 1 )
+stroke = 2.0
+
+[node name="Lifetime" type="Timer" parent="."]
+process_mode = 0
+wait_time = 3.0
diff --git a/godot/Demos/Quickstart/Player.gd b/godot/Demos/Quickstart/Player.gd
new file mode 100644
index 0000000..40bcc4c
--- /dev/null
+++ b/godot/Demos/Quickstart/Player.gd
@@ -0,0 +1,92 @@
+extends KinematicBody2D
+
+export var speed_max := 650.0
+export var acceleration_max := 70.0
+export var rotation_speed_max := 240
+export var rotation_accel_max := 40
+export var bullet: PackedScene
+
+var velocity := Vector2.ZERO
+var angular_velocity := 0.0
+var direction := Vector2.RIGHT
+
+onready var agent := GSAISteeringAgent.new()
+onready var proxy_target := GSAIAgentLocation.new()
+onready var face := GSAIFace.new(agent, proxy_target)
+onready var accel := GSAITargetAcceleration.new()
+onready var bullets := owner.get_node("Bullets")
+
+
+func _ready() -> void:
+ agent.linear_speed_max = speed_max
+ agent.linear_acceleration_max = acceleration_max
+ agent.angular_speed_max = deg2rad(rotation_speed_max)
+ agent.angular_acceleration_max = deg2rad(rotation_accel_max)
+ agent.bounding_radius = calculate_radius($CollisionPolygon2D.polygon)
+ update_agent()
+
+ var mouse_pos := get_global_mouse_position()
+ proxy_target.position.x = mouse_pos.x
+ proxy_target.position.y = mouse_pos.y
+
+ face.alignment_tolerance = deg2rad(5)
+ face.deceleration_radius = deg2rad(45)
+
+
+func _physics_process(delta: float) -> void:
+ update_agent()
+
+ var movement := get_movement()
+
+ direction = GSAIUtils.angle_to_vector2(rotation)
+
+ velocity += direction * acceleration_max * movement * delta
+ velocity = velocity.clamped(speed_max)
+ velocity = velocity.linear_interpolate(Vector2.ZERO, 0.1)
+ velocity = move_and_slide(velocity)
+
+ face.calculate_steering(accel)
+ angular_velocity += accel.angular * delta
+ angular_velocity = clamp(angular_velocity, -agent.angular_speed_max, agent.angular_speed_max)
+ angular_velocity = lerp(angular_velocity, 0, 0.1)
+ rotation += angular_velocity * delta
+
+
+func _unhandled_input(event: InputEvent) -> void:
+ if event is InputEventMouseMotion:
+ var mouse_pos: Vector2 = event.position
+ proxy_target.position.x = mouse_pos.x
+ proxy_target.position.y = mouse_pos.y
+ elif event is InputEventMouseButton:
+ if event.button_index == BUTTON_LEFT and event.pressed:
+ var next_bullet := bullet.instance()
+ next_bullet.global_position = (
+ global_position
+ - direction * (agent.bounding_radius - 5)
+ )
+ next_bullet.player = self
+ next_bullet.start(-direction)
+ bullets.add_child(next_bullet)
+
+
+func get_movement() -> float:
+ return Input.get_action_strength("sf_down") - Input.get_action_strength("sf_up")
+
+
+func update_agent() -> void:
+ agent.position.x = global_position.x
+ agent.position.y = global_position.y
+ agent.orientation = rotation
+ agent.linear_velocity.x = velocity.x
+ agent.linear_velocity.y = velocity.y
+ agent.angular_velocity = angular_velocity
+
+
+func calculate_radius(polygon: PoolVector2Array) -> float:
+ var furthest_point := Vector2(-INF, -INF)
+ for p in polygon:
+ if abs(p.x) > furthest_point.x:
+ furthest_point.x = p.x
+ if abs(p.y) > furthest_point.y:
+ furthest_point.y = p.y
+ return furthest_point.length()
diff --git a/godot/Demos/Quickstart/QuickStartDemo.tscn b/godot/Demos/Quickstart/QuickStartDemo.tscn
new file mode 100644
index 0000000..19e2854
--- /dev/null
+++ b/godot/Demos/Quickstart/QuickStartDemo.tscn
@@ -0,0 +1,61 @@
+[gd_scene load_steps=6 format=2]
+
+[ext_resource path="res://Demos/Utils/Line2DDraw.gd" type="Script" id=1]
+[ext_resource path="res://Demos/Quickstart/Agent.gd" type="Script" id=2]
+[ext_resource path="res://Demos/Quickstart/Player.gd" type="Script" id=3]
+[ext_resource path="res://Demos/Quickstart/Bullet.tscn" type="PackedScene" id=4]
+[ext_resource path="res://Demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=5]
+
+[node name="QuickStartDemo" type="Node"]
+
+[node name="BackgroudLayer" parent="." instance=ExtResource( 5 )]
+
+[node name="Player" type="KinematicBody2D" parent="." groups=[
+"Player",
+]]
+position = Vector2( 402.346, 573.791 )
+rotation = 1.5708
+collision_mask = 2
+script = ExtResource( 3 )
+speed_max = 900.0
+acceleration_max = 4200.0
+rotation_speed_max = 360
+rotation_accel_max = 1280
+bullet = ExtResource( 4 )
+
+[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Player"]
+polygon = PoolVector2Array( 0, -32, -24, 32, 24, 32 )
+
+[node name="Line2D" type="Line2D" parent="Player"]
+points = PoolVector2Array( 0, 32, 24, 32, 0, -32, -24, 32, 0, 32 )
+width = 8.0
+default_color = Color( 0.560784, 0.870588, 0.364706, 1 )
+joint_mode = 2
+antialiased = true
+script = ExtResource( 1 )
+inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
+
+[node name="Agent" type="KinematicBody2D" parent="."]
+position = Vector2( 974.675, 266.224 )
+rotation = 1.5708
+collision_layer = 2
+collision_mask = 5
+script = ExtResource( 2 )
+speed_max = 600.0
+acceleration_max = 2800.0
+angular_speed_max = 360
+angular_acceleration_max = 1280
+
+[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Agent"]
+polygon = PoolVector2Array( 0, -32, -24, 32, 24, 32 )
+
+[node name="Line2D" type="Line2D" parent="Agent"]
+points = PoolVector2Array( 0, 32, 24, 32, 0, -32, -24, 32, 0, 32 )
+width = 8.0
+default_color = Color( 1, 0.709804, 0.439216, 1 )
+joint_mode = 2
+antialiased = true
+script = ExtResource( 1 )
+inner_color = Color( 0.890196, 0.411765, 0.337255, 1 )
+
+[node name="Bullets" type="Node2D" parent="."]
diff --git a/godot/Demos/Quickstart/QuickStartDemo.tscn.bak b/godot/Demos/Quickstart/QuickStartDemo.tscn.bak
new file mode 100644
index 0000000..bbbca17
--- /dev/null
+++ b/godot/Demos/Quickstart/QuickStartDemo.tscn.bak
@@ -0,0 +1,61 @@
+[gd_scene load_steps=6 format=2]
+
+[ext_resource path="res://demos/Utils/Line2DDraw.gd" type="Script" id=1]
+[ext_resource path="res://demos/Quickstart/Agent.gd" type="Script" id=2]
+[ext_resource path="res://demos/Quickstart/Player.gd" type="Script" id=3]
+[ext_resource path="res://demos/Quickstart/Bullet.tscn" type="PackedScene" id=4]
+[ext_resource path="res://demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=5]
+
+[node name="QuickStartDemo" type="Node"]
+
+[node name="BackgroudLayer" parent="." instance=ExtResource( 5 )]
+
+[node name="Player" type="KinematicBody2D" parent="." groups=[
+"Player",
+]]
+position = Vector2( 402.346, 573.791 )
+rotation = 1.5708
+collision_mask = 2
+script = ExtResource( 3 )
+speed_max = 900.0
+acceleration_max = 4200.0
+rotation_speed_max = 360
+rotation_accel_max = 1280
+bullet = ExtResource( 4 )
+
+[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Player"]
+polygon = PoolVector2Array( 0, -32, -24, 32, 24, 32 )
+
+[node name="Line2D" type="Line2D" parent="Player"]
+points = PoolVector2Array( 0, 32, 24, 32, 0, -32, -24, 32, 0, 32 )
+width = 8.0
+default_color = Color( 0.560784, 0.870588, 0.364706, 1 )
+joint_mode = 2
+antialiased = true
+script = ExtResource( 1 )
+inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
+
+[node name="Agent" type="KinematicBody2D" parent="."]
+position = Vector2( 974.675, 266.224 )
+rotation = 1.5708
+collision_layer = 2
+collision_mask = 5
+script = ExtResource( 2 )
+speed_max = 600.0
+acceleration_max = 2800.0
+angular_speed_max = 360
+angular_acceleration_max = 1280
+
+[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Agent"]
+polygon = PoolVector2Array( 0, -32, -24, 32, 24, 32 )
+
+[node name="Line2D" type="Line2D" parent="Agent"]
+points = PoolVector2Array( 0, 32, 24, 32, 0, -32, -24, 32, 0, 32 )
+width = 8.0
+default_color = Color( 1, 0.709804, 0.439216, 1 )
+joint_mode = 2
+antialiased = true
+script = ExtResource( 1 )
+inner_color = Color( 0.890196, 0.411765, 0.337255, 1 )
+
+[node name="Bullets" type="Node2D" parent="."]
diff --git a/godot/Demos/SeekFlee/Boundaries.gd b/godot/Demos/SeekFlee/Boundaries.gd
new file mode 100644
index 0000000..f54e6cf
--- /dev/null
+++ b/godot/Demos/SeekFlee/Boundaries.gd
@@ -0,0 +1,32 @@
+extends Node2D
+
+const COLOR := Color("8fde5d")
+
+
+func _ready() -> void:
+ get_tree().root.connect("size_changed", self, "_on_SceneTree_size_changed")
+ _on_SceneTree_size_changed()
+
+
+func _draw() -> void:
+ for b in get_children():
+ var extents: Vector2 = b.get_node("CollisionShape2D").shape.extents
+ draw_rect(Rect2(b.global_position - extents, extents * 2), COLOR)
+
+
+func _on_SceneTree_size_changed() -> void:
+ var size := Vector2(
+ ProjectSettings["display/window/size/width"], ProjectSettings["display/window/size/height"]
+ )
+ for b in get_children():
+ var boundary: String = b.name.rsplit("Boundary")[0]
+ match boundary:
+ "Left":
+ b.global_position = Vector2(0, size.y / 2)
+ "Right":
+ b.global_position = Vector2(size.x, size.y / 2)
+ "Top":
+ b.global_position = Vector2(size.x / 2, 0)
+ "Bottom":
+ b.global_position = Vector2(size.x / 2, size.y)
+ update()
diff --git a/godot/Demos/SeekFlee/Player.gd b/godot/Demos/SeekFlee/Player.gd
new file mode 100644
index 0000000..7008704
--- /dev/null
+++ b/godot/Demos/SeekFlee/Player.gd
@@ -0,0 +1,26 @@
+extends KinematicBody2D
+# Class to control the player in basic left/right up/down movement.
+
+var speed: float
+onready var agent := GSAIAgentLocation.new()
+
+
+func _ready() -> void:
+ agent.position = GSAIUtils.to_vector3(global_position)
+
+
+func _physics_process(_delta: float) -> void:
+ var movement := _get_movement()
+ if movement.length_squared() < 0.01:
+ return
+
+ # warning-ignore:return_value_discarded
+ move_and_slide(movement * speed)
+ agent.position = GSAIUtils.to_vector3(global_position)
+
+
+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")
+ )
diff --git a/godot/Demos/SeekFlee/SeekFleeDemo.gd b/godot/Demos/SeekFlee/SeekFleeDemo.gd
new file mode 100644
index 0000000..027693c
--- /dev/null
+++ b/godot/Demos/SeekFlee/SeekFleeDemo.gd
@@ -0,0 +1,82 @@
+extends Node
+# Access helper class for children to access window boundaries.
+
+enum Mode { FLEE, SEEK }
+
+export (Mode) var behavior_mode := Mode.SEEK setget set_behavior_mode
+export (float, 0, 1000, 30) var linear_speed_max := 200.0 setget set_linear_speed_max
+export (float, 0, 2000, 40) var linear_accel_max := 10.0 setget set_linear_accel_max
+export (float) var player_speed := 600.0 setget set_player_speed
+
+var camera_boundaries: Rect2
+
+onready var player: KinematicBody2D = $Player
+onready var spawner: Node2D = $Spawner
+
+
+func _ready() -> void:
+ camera_boundaries = Rect2(
+ Vector2.ZERO,
+ Vector2(
+ ProjectSettings["display/window/size/width"],
+ ProjectSettings["display/window/size/height"]
+ )
+ )
+
+ var rng := RandomNumberGenerator.new()
+ rng.randomize()
+
+ player.speed = player_speed
+
+ for i in range(spawner.entity_count):
+ var new_pos := Vector2(
+ rng.randf_range(0, camera_boundaries.size.x),
+ rng.randf_range(0, camera_boundaries.size.y)
+ )
+ var entity: KinematicBody2D = spawner.Entity.instance()
+ entity.global_position = new_pos
+ entity.player_agent = player.agent
+ entity.start_speed = linear_speed_max
+ entity.start_accel = linear_accel_max
+ entity.use_seek = behavior_mode == Mode.SEEK
+ spawner.add_child(entity)
+
+
+func set_behavior_mode(mode: int) -> void:
+ behavior_mode = mode
+ if not is_inside_tree():
+ return
+
+ match mode:
+ Mode.SEEK:
+ for child in spawner.get_children():
+ child.use_seek = true
+ Mode.FLEE:
+ for child in spawner.get_children():
+ child.use_seek = false
+
+
+func set_linear_speed_max(value: float) -> void:
+ linear_speed_max = value
+ if not is_inside_tree():
+ return
+
+ for child in spawner.get_children():
+ child.agent.linear_speed_max = value
+
+
+func set_linear_accel_max(value: float) -> void:
+ linear_accel_max = value
+ if not is_inside_tree():
+ return
+
+ for child in spawner.get_children():
+ child.agent.linear_acceleration_max = value
+
+
+func set_player_speed(value: float) -> void:
+ player_speed = value
+ if not is_inside_tree():
+ return
+
+ player.speed = player_speed
diff --git a/godot/Demos/SeekFlee/SeekFleeDemo.tscn b/godot/Demos/SeekFlee/SeekFleeDemo.tscn
new file mode 100644
index 0000000..2b75042
--- /dev/null
+++ b/godot/Demos/SeekFlee/SeekFleeDemo.tscn
@@ -0,0 +1,81 @@
+[gd_scene load_steps=12 format=2]
+
+[ext_resource path="res://Demos/SeekFlee/Player.gd" type="Script" id=2]
+[ext_resource path="res://Demos/SeekFlee/SeekFleeDemo.gd" type="Script" id=3]
+[ext_resource path="res://Demos/SeekFlee/Spawner.gd" type="Script" id=4]
+[ext_resource path="res://Demos/Utils/DemoInterface.tscn" type="PackedScene" id=5]
+[ext_resource path="res://Demos/SeekFlee/Seeker.tscn" type="PackedScene" id=6]
+[ext_resource path="res://Demos/Utils/CircleDraw.gd" type="Script" id=7]
+[ext_resource path="res://Demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=8]
+[ext_resource path="res://Demos/SeekFlee/Boundaries.gd" type="Script" id=9]
+
+[sub_resource type="CircleShape2D" id=1]
+radius = 32.0
+
+[sub_resource type="RectangleShape2D" id=2]
+extents = Vector2( 10, 542 )
+
+[sub_resource type="RectangleShape2D" id=3]
+extents = Vector2( 965.654, 10 )
+
+[node name="SeekFleeDemo" type="Node"]
+script = ExtResource( 3 )
+linear_speed_max = 570.0
+linear_accel_max = 1160.0
+
+[node name="BackgroudLayer" parent="." instance=ExtResource( 8 )]
+
+[node name="Player" type="KinematicBody2D" parent="."]
+position = Vector2( 960, 540 )
+collision_mask = 2
+script = ExtResource( 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Player"]
+shape = SubResource( 1 )
+script = ExtResource( 7 )
+inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
+outer_color = Color( 0.560784, 0.870588, 0.364706, 1 )
+stroke = 4.0
+
+[node name="Boundaries" type="Node2D" parent="."]
+script = ExtResource( 9 )
+
+[node name="LeftBoundary" type="StaticBody2D" parent="Boundaries"]
+position = Vector2( 0, 540 )
+collision_layer = 2
+collision_mask = 5
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Boundaries/LeftBoundary"]
+shape = SubResource( 2 )
+
+[node name="RightBoundary" type="StaticBody2D" parent="Boundaries"]
+position = Vector2( 1920, 540 )
+collision_layer = 2
+collision_mask = 5
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Boundaries/RightBoundary"]
+shape = SubResource( 2 )
+
+[node name="TopBoundary" type="StaticBody2D" parent="Boundaries"]
+position = Vector2( 960, 0 )
+collision_layer = 2
+collision_mask = 5
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Boundaries/TopBoundary"]
+shape = SubResource( 3 )
+
+[node name="BottomBoundary" type="StaticBody2D" parent="Boundaries"]
+position = Vector2( 960, 1080 )
+collision_layer = 2
+collision_mask = 5
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Boundaries/BottomBoundary"]
+shape = SubResource( 3 )
+
+[node name="Spawner" type="Node2D" parent="."]
+script = ExtResource( 4 )
+Entity = ExtResource( 6 )
+
+[node name="DemoInterface" parent="." instance=ExtResource( 5 )]
+text_bbcode = "Seek & Flee Demo
+Move the [color=lime]green \"Player\"[/color] around with WASD and notice the [color=#ffb570]orange \"Enemies\"[/color] try to seek to or flee from the player."
diff --git a/godot/Demos/SeekFlee/SeekFleeDemo.tscn.bak b/godot/Demos/SeekFlee/SeekFleeDemo.tscn.bak
new file mode 100644
index 0000000..974d3ed
--- /dev/null
+++ b/godot/Demos/SeekFlee/SeekFleeDemo.tscn.bak
@@ -0,0 +1,81 @@
+[gd_scene load_steps=12 format=2]
+
+[ext_resource path="res://demos/SeekFlee/Player.gd" type="Script" id=2]
+[ext_resource path="res://demos/SeekFlee/SeekFleeDemo.gd" type="Script" id=3]
+[ext_resource path="res://demos/SeekFlee/Spawner.gd" type="Script" id=4]
+[ext_resource path="res://demos/Utils/DemoInterface.tscn" type="PackedScene" id=5]
+[ext_resource path="res://demos/SeekFlee/Seeker.tscn" type="PackedScene" id=6]
+[ext_resource path="res://demos/Utils/CircleDraw.gd" type="Script" id=7]
+[ext_resource path="res://demos/Utils/BackgroudLayer.tscn" type="PackedScene" id=8]
+[ext_resource path="res://demos/SeekFlee/Boundaries.gd" type="Script" id=9]
+
+[sub_resource type="CircleShape2D" id=1]
+radius = 32.0
+
+[sub_resource type="RectangleShape2D" id=2]
+extents = Vector2( 10, 542 )
+
+[sub_resource type="RectangleShape2D" id=3]
+extents = Vector2( 965.654, 10 )
+
+[node name="SeekFleeDemo" type="Node"]
+script = ExtResource( 3 )
+linear_speed_max = 570.0
+linear_accel_max = 1160.0
+
+[node name="BackgroudLayer" parent="." instance=ExtResource( 8 )]
+
+[node name="Player" type="KinematicBody2D" parent="."]
+position = Vector2( 960, 540 )
+collision_mask = 2
+script = ExtResource( 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Player"]
+shape = SubResource( 1 )
+script = ExtResource( 7 )
+inner_color = Color( 0.235294, 0.639216, 0.439216, 1 )
+outer_color = Color( 0.560784, 0.870588, 0.364706, 1 )
+stroke = 4.0
+
+[node name="Boundaries" type="Node2D" parent="."]
+script = ExtResource( 9 )
+
+[node name="LeftBoundary" type="StaticBody2D" parent="Boundaries"]
+position = Vector2( 0, 540 )
+collision_layer = 2
+collision_mask = 5
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Boundaries/LeftBoundary"]
+shape = SubResource( 2 )
+
+[node name="RightBoundary" type="StaticBody2D" parent="Boundaries"]
+position = Vector2( 1920, 540 )
+collision_layer = 2
+collision_mask = 5
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Boundaries/RightBoundary"]
+shape = SubResource( 2 )
+
+[node name="TopBoundary" type="StaticBody2D" parent="Boundaries"]
+position = Vector2( 960, 0 )
+collision_layer = 2
+collision_mask = 5
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Boundaries/TopBoundary"]
+shape = SubResource( 3 )
+
+[node name="BottomBoundary" type="StaticBody2D" parent="Boundaries"]
+position = Vector2( 960, 1080 )
+collision_layer = 2
+collision_mask = 5
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Boundaries/BottomBoundary"]
+shape = SubResource( 3 )
+
+[node name="Spawner" type="Node2D" parent="."]
+script = ExtResource( 4 )
+Entity = ExtResource( 6 )
+
+[node name="DemoInterface" parent="." instance=ExtResource( 5 )]
+text_bbcode = "Seek & Flee Demo
+Move the [color=lime]green \"Player\"[/color] around with WASD and notice the [color=#ffb570]orange \"Enemies\"[/color] try to seek to or flee from the player."
diff --git a/godot/Demos/SeekFlee/Seeker.gd b/godot/Demos/SeekFlee/Seeker.gd
new file mode 100644
index 0000000..e2252f3
--- /dev/null
+++ b/godot/Demos/SeekFlee/Seeker.gd
@@ -0,0 +1,29 @@
+extends KinematicBody2D
+
+var player_agent: GSAIAgentLocation
+var velocity := Vector2.ZERO
+var start_speed: float
+var start_accel: float
+var use_seek := true
+
+onready var agent := GSAIKinematicBody2DAgent.new(self)
+onready var accel := GSAITargetAcceleration.new()
+onready var seek := GSAISeek.new(agent, player_agent)
+onready var flee := GSAIFlee.new(agent, player_agent)
+
+
+func _ready() -> void:
+ agent.linear_acceleration_max = start_accel
+ agent.linear_speed_max = start_speed
+
+
+func _physics_process(delta: float) -> void:
+ if not player_agent:
+ return
+
+ if use_seek:
+ seek.calculate_steering(accel)
+ else:
+ flee.calculate_steering(accel)
+
+ agent._apply_steering(accel, delta)
diff --git a/godot/Demos/SeekFlee/Seeker.tscn b/godot/Demos/SeekFlee/Seeker.tscn
new file mode 100644
index 0000000..e65c072
--- /dev/null
+++ b/godot/Demos/SeekFlee/Seeker.tscn
@@ -0,0 +1,19 @@
+[gd_scene load_steps=4 format=2]
+
+[ext_resource path="res://Demos/SeekFlee/Seeker.gd" type="Script" id=1]
+[ext_resource path="res://Demos/Utils/CircleDraw.gd" type="Script" id=2]
+
+[sub_resource type="CircleShape2D" id=1]
+radius = 16.0
+
+[node name="Seeker" type="KinematicBody2D"]
+collision_layer = 4
+collision_mask = 2
+script = ExtResource( 1 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+shape = SubResource( 1 )
+script = ExtResource( 2 )
+inner_color = Color( 0.890196, 0.411765, 0.337255, 1 )
+outer_color = Color( 1, 0.709804, 0.439216, 1 )
+stroke = 4.0
diff --git a/godot/Demos/SeekFlee/Seeker.tscn.bak b/godot/Demos/SeekFlee/Seeker.tscn.bak
new file mode 100644
index 0000000..9452469
--- /dev/null
+++ b/godot/Demos/SeekFlee/Seeker.tscn.bak
@@ -0,0 +1,19 @@
+[gd_scene load_steps=4 format=2]
+
+[ext_resource path="res://demos/SeekFlee/Seeker.gd" type="Script" id=1]
+[ext_resource path="res://demos/Utils/CircleDraw.gd" type="Script" id=2]
+
+[sub_resource type="CircleShape2D" id=1]
+radius = 16.0
+
+[node name="Seeker" type="KinematicBody2D"]
+collision_layer = 4
+collision_mask = 2
+script = ExtResource( 1 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+shape = SubResource( 1 )
+script = ExtResource( 2 )
+inner_color = Color( 0.890196, 0.411765, 0.337255, 1 )
+outer_color = Color( 1, 0.709804, 0.439216, 1 )
+stroke = 4.0
diff --git a/godot/Demos/SeekFlee/Spawner.gd b/godot/Demos/SeekFlee/Spawner.gd
new file mode 100644
index 0000000..abd3929
--- /dev/null
+++ b/godot/Demos/SeekFlee/Spawner.gd
@@ -0,0 +1,6 @@
+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
diff --git a/godot/Demos/Utils/BackgroudLayer.tscn b/godot/Demos/Utils/BackgroudLayer.tscn
new file mode 100644
index 0000000..9b6a8f1
--- /dev/null
+++ b/godot/Demos/Utils/BackgroudLayer.tscn
@@ -0,0 +1,17 @@
+[gd_scene load_steps=2 format=2]
+
+[ext_resource path="res://assets/sprites/background.png" type="Texture" id=1]
+
+[node name="BackgroudLayer" type="CanvasLayer"]
+layer = -1
+
+[node name="Background" type="TextureRect" parent="."]
+anchor_right = 1.0
+anchor_bottom = 1.0
+mouse_filter = 2
+texture = ExtResource( 1 )
+expand = true
+stretch_mode = 7
+__meta__ = {
+"_edit_use_anchors_": false
+}
diff --git a/godot/Demos/Utils/CircleDraw.gd b/godot/Demos/Utils/CircleDraw.gd
new file mode 100644
index 0000000..1c51f05
--- /dev/null
+++ b/godot/Demos/Utils/CircleDraw.gd
@@ -0,0 +1,26 @@
+tool
+extends CollisionShape2D
+
+export (Color) var inner_color := Color() setget set_inner_color
+export (Color) var outer_color := Color() setget set_outer_color
+export (float) var stroke := 0.0 setget set_stroke
+
+
+func _draw() -> void:
+ draw_circle(Vector2.ZERO, shape.radius + stroke, outer_color)
+ draw_circle(Vector2.ZERO, shape.radius, inner_color)
+
+
+func set_inner_color(val: Color) -> void:
+ inner_color = val
+ update()
+
+
+func set_outer_color(val: Color) -> void:
+ outer_color = val
+ update()
+
+
+func set_stroke(val: float) -> void:
+ stroke = val
+ update()
diff --git a/godot/Demos/Utils/DemoInterface.gd b/godot/Demos/Utils/DemoInterface.gd
new file mode 100644
index 0000000..93b7082
--- /dev/null
+++ b/godot/Demos/Utils/DemoInterface.gd
@@ -0,0 +1,13 @@
+tool
+extends PanelContainer
+
+export (String, MULTILINE) var text_bbcode := "" setget set_text_bbcode
+
+onready var rich_text_label: RichTextLabel = $MarginContainer/RichTextLabel
+
+
+func set_text_bbcode(value: String) -> void:
+ text_bbcode = value
+ if not rich_text_label:
+ yield(self, "ready")
+ rich_text_label.bbcode_text = text_bbcode
diff --git a/godot/Demos/Utils/DemoInterface.tscn b/godot/Demos/Utils/DemoInterface.tscn
new file mode 100644
index 0000000..7855926
--- /dev/null
+++ b/godot/Demos/Utils/DemoInterface.tscn
@@ -0,0 +1,37 @@
+[gd_scene load_steps=4 format=2]
+
+[ext_resource path="res://assets/theme/gdquest.theme" type="Theme" id=1]
+[ext_resource path="res://Demos/Utils/DemoInterface.gd" type="Script" id=2]
+
+[sub_resource type="GDScript" id=1]
+script/source = "tool
+extends RichTextLabel
+
+"
+
+[node name="DemoInterface" type="PanelContainer"]
+anchor_right = 1.0
+margin_bottom = 140.0
+rect_min_size = Vector2( 1024, 0 )
+theme = ExtResource( 1 )
+script = ExtResource( 2 )
+__meta__ = {
+"_edit_use_anchors_": false
+}
+text_bbcode = "Replace this text for the demo."
+
+[node name="MarginContainer" type="MarginContainer" parent="."]
+margin_right = 1920.0
+margin_bottom = 140.0
+
+[node name="RichTextLabel" type="RichTextLabel" parent="MarginContainer"]
+margin_left = 16.0
+margin_top = 16.0
+margin_right = 1904.0
+margin_bottom = 124.0
+rect_min_size = Vector2( 0, 55 )
+bbcode_enabled = true
+bbcode_text = "Replace this text for the demo."
+text = "Replace this text for the demo."
+scroll_active = false
+script = SubResource( 1 )
diff --git a/godot/Demos/Utils/DemoInterface.tscn.bak b/godot/Demos/Utils/DemoInterface.tscn.bak
new file mode 100644
index 0000000..6c100ee
--- /dev/null
+++ b/godot/Demos/Utils/DemoInterface.tscn.bak
@@ -0,0 +1,37 @@
+[gd_scene load_steps=4 format=2]
+
+[ext_resource path="res://assets/theme/gdquest.theme" type="Theme" id=1]
+[ext_resource path="res://demos/Utils/DemoInterface.gd" type="Script" id=2]
+
+[sub_resource type="GDScript" id=1]
+script/source = "tool
+extends RichTextLabel
+
+"
+
+[node name="DemoInterface" type="PanelContainer"]
+anchor_right = 1.0
+margin_bottom = 140.0
+rect_min_size = Vector2( 1024, 0 )
+theme = ExtResource( 1 )
+script = ExtResource( 2 )
+__meta__ = {
+"_edit_use_anchors_": false
+}
+text_bbcode = "Replace this text for the demo."
+
+[node name="MarginContainer" type="MarginContainer" parent="."]
+margin_right = 1920.0
+margin_bottom = 140.0
+
+[node name="RichTextLabel" type="RichTextLabel" parent="MarginContainer"]
+margin_left = 16.0
+margin_top = 16.0
+margin_right = 1904.0
+margin_bottom = 124.0
+rect_min_size = Vector2( 0, 55 )
+bbcode_enabled = true
+bbcode_text = "Replace this text for the demo."
+text = "Replace this text for the demo."
+scroll_active = false
+script = SubResource( 1 )
diff --git a/godot/Demos/Utils/Line2DDraw.gd b/godot/Demos/Utils/Line2DDraw.gd
new file mode 100644
index 0000000..d1a7b5e
--- /dev/null
+++ b/godot/Demos/Utils/Line2DDraw.gd
@@ -0,0 +1,13 @@
+tool
+extends Line2D
+
+export (Color) var inner_color := Color() setget set_inner_color
+
+
+func _draw() -> void:
+ draw_colored_polygon(points, inner_color)
+
+
+func set_inner_color(val: Color) -> void:
+ inner_color = val
+ update()
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Agents/GSAIKinematicBody2DAgent.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Agents/GSAIKinematicBody2DAgent.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Agents/GSAIKinematicBody2DAgent.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Agents/GSAIKinematicBody2DAgent.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Agents/GSAIKinematicBody3DAgent.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Agents/GSAIKinematicBody3DAgent.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Agents/GSAIKinematicBody3DAgent.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Agents/GSAIKinematicBody3DAgent.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Agents/GSAIRigidBody2DAgent.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Agents/GSAIRigidBody2DAgent.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Agents/GSAIRigidBody2DAgent.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Agents/GSAIRigidBody2DAgent.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Agents/GSAIRigidBody3DAgent.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Agents/GSAIRigidBody3DAgent.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Agents/GSAIRigidBody3DAgent.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Agents/GSAIRigidBody3DAgent.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Agents/GSAISpecializedAgent.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Agents/GSAISpecializedAgent.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Agents/GSAISpecializedAgent.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Agents/GSAISpecializedAgent.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIArrive.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIArrive.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIArrive.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIArrive.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIAvoidCollisions.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIAvoidCollisions.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIAvoidCollisions.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIAvoidCollisions.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIBlend.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIBlend.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIBlend.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIBlend.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAICohesion.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAICohesion.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAICohesion.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAICohesion.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIEvade.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIEvade.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIEvade.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIEvade.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIFace.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIFace.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIFace.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIFace.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIFlee.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIFlee.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIFlee.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIFlee.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIFollowPath.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIFollowPath.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIFollowPath.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIFollowPath.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAILookWhereYouGo.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAILookWhereYouGo.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAILookWhereYouGo.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAILookWhereYouGo.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIMatchOrientation.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIMatchOrientation.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIMatchOrientation.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIMatchOrientation.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIPriority.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIPriority.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIPriority.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIPriority.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIPursue.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIPursue.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIPursue.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIPursue.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAISeek.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAISeek.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAISeek.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAISeek.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAISeparation.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAISeparation.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAISeparation.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAISeparation.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/GSAIAgentLocation.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/GSAIAgentLocation.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/GSAIAgentLocation.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/GSAIAgentLocation.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/GSAIGroupBehavior.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/GSAIGroupBehavior.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/GSAIGroupBehavior.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/GSAIGroupBehavior.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/GSAIPath.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/GSAIPath.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/GSAIPath.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/GSAIPath.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/GSAISteeringAgent.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/GSAISteeringAgent.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/GSAISteeringAgent.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/GSAISteeringAgent.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/GSAISteeringBehavior.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/GSAISteeringBehavior.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/GSAISteeringBehavior.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/GSAISteeringBehavior.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/GSAITargetAcceleration.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/GSAITargetAcceleration.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/GSAITargetAcceleration.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/GSAITargetAcceleration.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/GSAIUtils.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/GSAIUtils.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/GSAIUtils.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/GSAIUtils.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Proximities/GSAIInfiniteProximity.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Proximities/GSAIInfiniteProximity.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Proximities/GSAIInfiniteProximity.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Proximities/GSAIInfiniteProximity.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Proximities/GSAIProximity.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Proximities/GSAIProximity.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Proximities/GSAIProximity.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Proximities/GSAIProximity.gd
diff --git a/addons/com.gdquest.godot-steering-ai-framework/Proximities/GSAIRadiusProximity.gd b/godot/addons/com.gdquest.godot-steering-ai-framework/Proximities/GSAIRadiusProximity.gd
similarity index 100%
rename from addons/com.gdquest.godot-steering-ai-framework/Proximities/GSAIRadiusProximity.gd
rename to godot/addons/com.gdquest.godot-steering-ai-framework/Proximities/GSAIRadiusProximity.gd
diff --git a/godot/assets/icon.png b/godot/assets/icon.png
new file mode 100644
index 0000000..ed8f05d
Binary files /dev/null and b/godot/assets/icon.png differ
diff --git a/godot/assets/icon.png.import b/godot/assets/icon.png.import
new file mode 100644
index 0000000..4e9f7bb
--- /dev/null
+++ b/godot/assets/icon.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="StreamTexture"
+path="res://.import/icon.png-b6a7fb2db36edd3d95dc42f1dc8c1c5d.stex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/icon.png"
+dest_files=[ "res://.import/icon.png-b6a7fb2db36edd3d95dc42f1dc8c1c5d.stex" ]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_mode=0
+compress/bptc_ldr=0
+compress/normal_map=0
+flags/repeat=0
+flags/filter=true
+flags/mipmaps=false
+flags/anisotropic=false
+flags/srgb=2
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/HDR_as_SRGB=false
+process/invert_color=false
+stream=false
+size_limit=0
+detect_3d=true
+svg/scale=1.0
diff --git a/godot/assets/icon.svg b/godot/assets/icon.svg
new file mode 100644
index 0000000..b690016
--- /dev/null
+++ b/godot/assets/icon.svg
@@ -0,0 +1,151 @@
+
+
diff --git a/godot/assets/icon.svg.import b/godot/assets/icon.svg.import
new file mode 100644
index 0000000..d499e66
--- /dev/null
+++ b/godot/assets/icon.svg.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="StreamTexture"
+path="res://.import/icon.svg-56083ea2a1f1a4f1e49773bdc6d7826c.stex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/icon.svg"
+dest_files=[ "res://.import/icon.svg-56083ea2a1f1a4f1e49773bdc6d7826c.stex" ]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_mode=0
+compress/bptc_ldr=0
+compress/normal_map=0
+flags/repeat=0
+flags/filter=true
+flags/mipmaps=false
+flags/anisotropic=false
+flags/srgb=2
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/HDR_as_SRGB=false
+process/invert_color=false
+stream=false
+size_limit=0
+detect_3d=true
+svg/scale=1.0
diff --git a/godot/assets/sprites/background.png b/godot/assets/sprites/background.png
new file mode 100644
index 0000000..ad7e8ba
Binary files /dev/null and b/godot/assets/sprites/background.png differ
diff --git a/godot/assets/sprites/background.png.import b/godot/assets/sprites/background.png.import
new file mode 100644
index 0000000..8d1c5f6
--- /dev/null
+++ b/godot/assets/sprites/background.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="StreamTexture"
+path="res://.import/background.png-dde469fb1f19281f3784b52d4bea96cd.stex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/sprites/background.png"
+dest_files=[ "res://.import/background.png-dde469fb1f19281f3784b52d4bea96cd.stex" ]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_mode=0
+compress/bptc_ldr=0
+compress/normal_map=0
+flags/repeat=0
+flags/filter=true
+flags/mipmaps=false
+flags/anisotropic=false
+flags/srgb=2
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/HDR_as_SRGB=false
+process/invert_color=false
+stream=false
+size_limit=0
+detect_3d=true
+svg/scale=1.0
diff --git a/godot/assets/theme/button/disabled.stylebox b/godot/assets/theme/button/disabled.stylebox
new file mode 100644
index 0000000..252f924
Binary files /dev/null and b/godot/assets/theme/button/disabled.stylebox differ
diff --git a/godot/assets/theme/button/focused.stylebox b/godot/assets/theme/button/focused.stylebox
new file mode 100644
index 0000000..04863c6
Binary files /dev/null and b/godot/assets/theme/button/focused.stylebox differ
diff --git a/godot/assets/theme/button/hover.stylebox b/godot/assets/theme/button/hover.stylebox
new file mode 100644
index 0000000..08fb085
Binary files /dev/null and b/godot/assets/theme/button/hover.stylebox differ
diff --git a/godot/assets/theme/button/normal.stylebox b/godot/assets/theme/button/normal.stylebox
new file mode 100644
index 0000000..999edcf
Binary files /dev/null and b/godot/assets/theme/button/normal.stylebox differ
diff --git a/godot/assets/theme/button/pressed.stylebox b/godot/assets/theme/button/pressed.stylebox
new file mode 100644
index 0000000..7cb801b
Binary files /dev/null and b/godot/assets/theme/button/pressed.stylebox differ
diff --git a/godot/assets/theme/empty.stylebox b/godot/assets/theme/empty.stylebox
new file mode 100644
index 0000000..4467232
Binary files /dev/null and b/godot/assets/theme/empty.stylebox differ
diff --git a/godot/assets/theme/fonts/default_font.tres b/godot/assets/theme/fonts/default_font.tres
new file mode 100644
index 0000000..7ca6e3a
--- /dev/null
+++ b/godot/assets/theme/fonts/default_font.tres
@@ -0,0 +1,8 @@
+[gd_resource type="DynamicFont" load_steps=2 format=2]
+
+[ext_resource path="res://assets/theme/fonts/montserrat/Montserrat-Medium.ttf" type="DynamicFontData" id=1]
+
+[resource]
+size = 26
+use_filter = true
+font_data = ExtResource( 1 )
diff --git a/godot/assets/theme/fonts/default_font_bold.tres b/godot/assets/theme/fonts/default_font_bold.tres
new file mode 100644
index 0000000..92dcae0
--- /dev/null
+++ b/godot/assets/theme/fonts/default_font_bold.tres
@@ -0,0 +1,8 @@
+[gd_resource type="DynamicFont" load_steps=2 format=2]
+
+[ext_resource path="res://assets/theme/fonts/montserrat/Montserrat-Bold.ttf" type="DynamicFontData" id=1]
+
+[resource]
+size = 26
+use_filter = true
+font_data = ExtResource( 1 )
diff --git a/godot/assets/theme/fonts/default_font_code.tres b/godot/assets/theme/fonts/default_font_code.tres
new file mode 100644
index 0000000..0138558
--- /dev/null
+++ b/godot/assets/theme/fonts/default_font_code.tres
@@ -0,0 +1,8 @@
+[gd_resource type="DynamicFont" load_steps=2 format=2]
+
+[ext_resource path="res://assets/theme/fonts/source_code_pro/SourceCodePro-Medium.otf" type="DynamicFontData" id=1]
+
+[resource]
+size = 26
+use_filter = true
+font_data = ExtResource( 1 )
diff --git a/godot/assets/theme/fonts/font_title.tres b/godot/assets/theme/fonts/font_title.tres
new file mode 100644
index 0000000..a1788d3
--- /dev/null
+++ b/godot/assets/theme/fonts/font_title.tres
@@ -0,0 +1,8 @@
+[gd_resource type="DynamicFont" load_steps=2 format=2]
+
+[ext_resource path="res://assets/theme/fonts/montserrat/Montserrat-Black.ttf" type="DynamicFontData" id=1]
+
+[resource]
+size = 34
+use_filter = true
+font_data = ExtResource( 1 )
diff --git a/godot/assets/theme/fonts/montserrat/Montserrat-Black.ttf b/godot/assets/theme/fonts/montserrat/Montserrat-Black.ttf
new file mode 100644
index 0000000..f0d24ad
Binary files /dev/null and b/godot/assets/theme/fonts/montserrat/Montserrat-Black.ttf differ
diff --git a/godot/assets/theme/fonts/montserrat/Montserrat-Bold.ttf b/godot/assets/theme/fonts/montserrat/Montserrat-Bold.ttf
new file mode 100644
index 0000000..9a425b9
Binary files /dev/null and b/godot/assets/theme/fonts/montserrat/Montserrat-Bold.ttf differ
diff --git a/godot/assets/theme/fonts/montserrat/Montserrat-Medium.ttf b/godot/assets/theme/fonts/montserrat/Montserrat-Medium.ttf
new file mode 100644
index 0000000..db5b1af
Binary files /dev/null and b/godot/assets/theme/fonts/montserrat/Montserrat-Medium.ttf differ
diff --git a/godot/assets/theme/fonts/source_code_pro/SourceCodePro-Medium.otf b/godot/assets/theme/fonts/source_code_pro/SourceCodePro-Medium.otf
new file mode 100644
index 0000000..1b42738
Binary files /dev/null and b/godot/assets/theme/fonts/source_code_pro/SourceCodePro-Medium.otf differ
diff --git a/godot/assets/theme/gdquest.theme b/godot/assets/theme/gdquest.theme
new file mode 100644
index 0000000..61b83dd
Binary files /dev/null and b/godot/assets/theme/gdquest.theme differ
diff --git a/godot/assets/theme/icons/chevron-right.svg b/godot/assets/theme/icons/chevron-right.svg
new file mode 100644
index 0000000..258de41
--- /dev/null
+++ b/godot/assets/theme/icons/chevron-right.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/godot/assets/theme/icons/chevron-right.svg.import b/godot/assets/theme/icons/chevron-right.svg.import
new file mode 100644
index 0000000..000f669
--- /dev/null
+++ b/godot/assets/theme/icons/chevron-right.svg.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="StreamTexture"
+path="res://.import/chevron-right.svg-f77dee7a088177a2ac1d467f4c7cd3e1.stex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/theme/icons/chevron-right.svg"
+dest_files=[ "res://.import/chevron-right.svg-f77dee7a088177a2ac1d467f4c7cd3e1.stex" ]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_mode=0
+compress/bptc_ldr=0
+compress/normal_map=0
+flags/repeat=0
+flags/filter=true
+flags/mipmaps=false
+flags/anisotropic=false
+flags/srgb=2
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/HDR_as_SRGB=false
+process/invert_color=false
+stream=false
+size_limit=0
+detect_3d=true
+svg/scale=1.0
diff --git a/godot/assets/theme/icons/chevron-up.svg b/godot/assets/theme/icons/chevron-up.svg
new file mode 100644
index 0000000..4eb5ecc
--- /dev/null
+++ b/godot/assets/theme/icons/chevron-up.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/godot/assets/theme/icons/chevron-up.svg.import b/godot/assets/theme/icons/chevron-up.svg.import
new file mode 100644
index 0000000..14e96f7
--- /dev/null
+++ b/godot/assets/theme/icons/chevron-up.svg.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="StreamTexture"
+path="res://.import/chevron-up.svg-48b5b69265734774d0a7516dcc6f0863.stex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/theme/icons/chevron-up.svg"
+dest_files=[ "res://.import/chevron-up.svg-48b5b69265734774d0a7516dcc6f0863.stex" ]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_mode=0
+compress/bptc_ldr=0
+compress/normal_map=0
+flags/repeat=0
+flags/filter=true
+flags/mipmaps=false
+flags/anisotropic=false
+flags/srgb=2
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/HDR_as_SRGB=false
+process/invert_color=false
+stream=false
+size_limit=0
+detect_3d=true
+svg/scale=1.0
diff --git a/godot/assets/theme/panel/panel.stylebox b/godot/assets/theme/panel/panel.stylebox
new file mode 100644
index 0000000..0c557d0
Binary files /dev/null and b/godot/assets/theme/panel/panel.stylebox differ
diff --git a/godot/assets/theme/separator/line.tres b/godot/assets/theme/separator/line.tres
new file mode 100644
index 0000000..49130dc
--- /dev/null
+++ b/godot/assets/theme/separator/line.tres
@@ -0,0 +1,5 @@
+[gd_resource type="StyleBoxLine" format=2]
+
+[resource]
+color = Color( 1, 1, 1, 0.196078 )
+thickness = 2
diff --git a/godot/assets/theme/slider/grabber_area.stylebox b/godot/assets/theme/slider/grabber_area.stylebox
new file mode 100644
index 0000000..5fd31a9
Binary files /dev/null and b/godot/assets/theme/slider/grabber_area.stylebox differ
diff --git a/godot/assets/theme/slider/slider.stylebox b/godot/assets/theme/slider/slider.stylebox
new file mode 100644
index 0000000..f89f29b
Binary files /dev/null and b/godot/assets/theme/slider/slider.stylebox differ
diff --git a/godot/default_env.tres b/godot/default_env.tres
new file mode 100644
index 0000000..20207a4
--- /dev/null
+++ b/godot/default_env.tres
@@ -0,0 +1,7 @@
+[gd_resource type="Environment" load_steps=2 format=2]
+
+[sub_resource type="ProceduralSky" id=1]
+
+[resource]
+background_mode = 2
+background_sky = SubResource( 1 )
diff --git a/godot/project.godot b/godot/project.godot
new file mode 100644
index 0000000..2de5182
--- /dev/null
+++ b/godot/project.godot
@@ -0,0 +1,245 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+; [section] ; section goes between []
+; param=value ; assign values to parameters
+
+config_version=4
+
+_global_script_classes=[ {
+"base": "Reference",
+"class": "DemoPickerUI",
+"language": "GDScript",
+"path": "res://Demos/DemoPickerUI.gd"
+}, {
+"base": "Reference",
+"class": "GSAIAgentLocation",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/GSAIAgentLocation.gd"
+}, {
+"base": "GSAISteeringBehavior",
+"class": "GSAIArrive",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIArrive.gd"
+}, {
+"base": "GSAIGroupBehavior",
+"class": "GSAIAvoidCollisions",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIAvoidCollisions.gd"
+}, {
+"base": "GSAISteeringBehavior",
+"class": "GSAIBlend",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIBlend.gd"
+}, {
+"base": "GSAIGroupBehavior",
+"class": "GSAICohesion",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAICohesion.gd"
+}, {
+"base": "GSAIPursue",
+"class": "GSAIEvade",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIEvade.gd"
+}, {
+"base": "GSAIMatchOrientation",
+"class": "GSAIFace",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIFace.gd"
+}, {
+"base": "GSAISeek",
+"class": "GSAIFlee",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIFlee.gd"
+}, {
+"base": "GSAIArrive",
+"class": "GSAIFollowPath",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIFollowPath.gd"
+}, {
+"base": "GSAISteeringBehavior",
+"class": "GSAIGroupBehavior",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/GSAIGroupBehavior.gd"
+}, {
+"base": "GSAIProximity",
+"class": "GSAIInfiniteProximity",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Proximities/GSAIInfiniteProximity.gd"
+}, {
+"base": "GSAISpecializedAgent",
+"class": "GSAIKinematicBody2DAgent",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Agents/GSAIKinematicBody2DAgent.gd"
+}, {
+"base": "GSAISpecializedAgent",
+"class": "GSAIKinematicBody3DAgent",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Agents/GSAIKinematicBody3DAgent.gd"
+}, {
+"base": "GSAIMatchOrientation",
+"class": "GSAILookWhereYouGo",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAILookWhereYouGo.gd"
+}, {
+"base": "GSAISteeringBehavior",
+"class": "GSAIMatchOrientation",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIMatchOrientation.gd"
+}, {
+"base": "Reference",
+"class": "GSAIPath",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/GSAIPath.gd"
+}, {
+"base": "GSAISteeringBehavior",
+"class": "GSAIPriority",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIPriority.gd"
+}, {
+"base": "Reference",
+"class": "GSAIProximity",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Proximities/GSAIProximity.gd"
+}, {
+"base": "GSAISteeringBehavior",
+"class": "GSAIPursue",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAIPursue.gd"
+}, {
+"base": "GSAIProximity",
+"class": "GSAIRadiusProximity",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Proximities/GSAIRadiusProximity.gd"
+}, {
+"base": "GSAISpecializedAgent",
+"class": "GSAIRigidBody2DAgent",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Agents/GSAIRigidBody2DAgent.gd"
+}, {
+"base": "GSAISpecializedAgent",
+"class": "GSAIRigidBody3DAgent",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Agents/GSAIRigidBody3DAgent.gd"
+}, {
+"base": "GSAISteeringBehavior",
+"class": "GSAISeek",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAISeek.gd"
+}, {
+"base": "GSAIGroupBehavior",
+"class": "GSAISeparation",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Behaviors/GSAISeparation.gd"
+}, {
+"base": "GSAISteeringAgent",
+"class": "GSAISpecializedAgent",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/Agents/GSAISpecializedAgent.gd"
+}, {
+"base": "GSAIAgentLocation",
+"class": "GSAISteeringAgent",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/GSAISteeringAgent.gd"
+}, {
+"base": "Reference",
+"class": "GSAISteeringBehavior",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/GSAISteeringBehavior.gd"
+}, {
+"base": "Reference",
+"class": "GSAITargetAcceleration",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/GSAITargetAcceleration.gd"
+}, {
+"base": "Reference",
+"class": "GSAIUtils",
+"language": "GDScript",
+"path": "res://addons/com.gdquest.godot-steering-ai-framework/GSAIUtils.gd"
+} ]
+_global_script_class_icons={
+"DemoPickerUI": "",
+"GSAIAgentLocation": "",
+"GSAIArrive": "",
+"GSAIAvoidCollisions": "",
+"GSAIBlend": "",
+"GSAICohesion": "",
+"GSAIEvade": "",
+"GSAIFace": "",
+"GSAIFlee": "",
+"GSAIFollowPath": "",
+"GSAIGroupBehavior": "",
+"GSAIInfiniteProximity": "",
+"GSAIKinematicBody2DAgent": "",
+"GSAIKinematicBody3DAgent": "",
+"GSAILookWhereYouGo": "",
+"GSAIMatchOrientation": "",
+"GSAIPath": "",
+"GSAIPriority": "",
+"GSAIProximity": "",
+"GSAIPursue": "",
+"GSAIRadiusProximity": "",
+"GSAIRigidBody2DAgent": "",
+"GSAIRigidBody3DAgent": "",
+"GSAISeek": "",
+"GSAISeparation": "",
+"GSAISpecializedAgent": "",
+"GSAISteeringAgent": "",
+"GSAISteeringBehavior": "",
+"GSAITargetAcceleration": "",
+"GSAIUtils": ""
+}
+
+[application]
+
+config/name="Godot Steering AI Framework Demos"
+run/main_scene="res://Demos/DemoSelector.tscn"
+config/icon="res://assets/icon.png"
+
+[display]
+
+window/size/width=1920
+window/size/height=1080
+window/size/always_on_top=true
+window/size/test_width=1280
+window/size/test_height=720
+window/stretch/mode="2d"
+window/stretch/aspect="expand"
+
+[input]
+
+sf_left={
+"deadzone": 0.5,
+"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":65,"unicode":0,"echo":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":-1.0,"script":null)
+ ]
+}
+sf_right={
+"deadzone": 0.5,
+"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":68,"unicode":0,"echo":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":1.0,"script":null)
+ ]
+}
+sf_up={
+"deadzone": 0.5,
+"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":87,"unicode":0,"echo":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":-1.0,"script":null)
+ ]
+}
+sf_down={
+"deadzone": 0.5,
+"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":83,"unicode":0,"echo":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":1.0,"script":null)
+ ]
+}
+toggle_fullscreen={
+"deadzone": 0.5,
+"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777254,"unicode":0,"echo":false,"script":null)
+ ]
+}
+
+[rendering]
+
+environment/default_environment="res://default_env.tres"