mirror of
https://github.com/Relintai/godot-steering-ai-framework.git
synced 2024-11-14 04:57:19 +01:00
Reorganize project
The GST namespace has been added to prevent class name conflicts, and the project has been reorganized to make extensions and purpose easier.
This commit is contained in:
parent
7520939bdd
commit
fb538b72cb
@ -6,22 +6,20 @@ AI agent that seeks to move away from the player's location as directly as possi
|
||||
|
||||
onready var radius: = ($CollisionShape2D.shape as CircleShape2D).radius
|
||||
|
||||
var agent: SteeringAgent
|
||||
var player_agent: AgentLocation
|
||||
var flee: Flee
|
||||
var accel: = TargetAcceleration.new()
|
||||
onready var agent: = GSTSteeringAgent.new()
|
||||
onready var accel: = GSTTargetAcceleration.new()
|
||||
onready var flee: = GSTFlee.new(agent, player_agent)
|
||||
|
||||
var player_agent: GSTAgentLocation
|
||||
var velocity: = Vector2.ZERO
|
||||
var speed: float
|
||||
var color: Color
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
agent = SteeringAgent.new()
|
||||
agent.max_linear_acceleration = speed/10
|
||||
agent.max_linear_speed = speed
|
||||
|
||||
flee = Flee.new(agent, player_agent)
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
draw_circle(Vector2.ZERO, radius, color)
|
@ -1,6 +1,6 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://src/Steering/Demos/SeekFlee/Coward.gd" type="Script" id=1]
|
||||
[ext_resource path="res://demos/seek_and_flee/Coward.gd" type="Script" id=1]
|
||||
|
||||
[sub_resource type="CircleShape2D" id=1]
|
||||
|
@ -5,18 +5,17 @@ Class to control the player in basic left/right up/down movement.
|
||||
|
||||
|
||||
onready var _radius: = ($CollisionShape2D.shape as CircleShape2D).radius
|
||||
onready var agent: = GSTAgentLocation.new()
|
||||
|
||||
export var speed: = 150.0
|
||||
|
||||
var player_agent: = AgentLocation.new()
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
draw_circle(Vector2.ZERO, _radius, Color.red)
|
||||
|
||||
|
||||
func _get_movement() -> Vector2:
|
||||
return Vector2(Input.get_action_strength("sf_right") - Input.get_action_strength("sf_left"),
|
||||
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"))
|
||||
|
||||
|
||||
@ -26,4 +25,4 @@ func _physics_process(delta: float) -> void:
|
||||
return
|
||||
|
||||
move_and_slide(movement * speed)
|
||||
player_agent.position = Vector3(global_position.x, global_position.y, 0)
|
||||
agent.position = Vector3(global_position.x, global_position.y, 0)
|
@ -1,11 +1,11 @@
|
||||
[gd_scene load_steps=10 format=2]
|
||||
|
||||
[ext_resource path="res://src/Steering/Demos/SeekFlee/Player.gd" type="Script" id=1]
|
||||
[ext_resource path="res://src/Steering/Demos/SeekFlee/Spawner.gd" type="Script" id=2]
|
||||
[ext_resource path="res://src/Steering/Demos/SeekFlee/SeekFleeDemo.gd" type="Script" id=3]
|
||||
[ext_resource path="res://src/Steering/Demos/SeekFlee/Seeker.tscn" type="PackedScene" id=4]
|
||||
[ext_resource path="res://src/Steering/Demos/SeekFlee/Boundary.gd" type="Script" id=5]
|
||||
[ext_resource path="res://src/Steering/Demos/SeekFlee/Coward.tscn" type="PackedScene" id=6]
|
||||
[ext_resource path="res://demos/seek_and_flee/Player.gd" type="Script" id=1]
|
||||
[ext_resource path="res://demos/seek_and_flee/Spawner.gd" type="Script" id=2]
|
||||
[ext_resource path="res://demos/seek_and_flee/SeekFleeDemo.gd" type="Script" id=3]
|
||||
[ext_resource path="res://demos/seek_and_flee/Seeker.tscn" type="PackedScene" id=4]
|
||||
[ext_resource path="res://demos/seek_and_flee/Boundary.gd" type="Script" id=5]
|
||||
[ext_resource path="res://demos/seek_and_flee/Coward.tscn" type="PackedScene" id=6]
|
||||
|
||||
[sub_resource type="CircleShape2D" id=1]
|
||||
radius = 30.0
|
||||
@ -68,11 +68,13 @@ script = ExtResource( 5 )
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="BottomBoundary"]
|
||||
shape = SubResource( 3 )
|
||||
|
||||
[node name="SeekerSpawner" type="Node2D" parent="."]
|
||||
script = ExtResource( 2 )
|
||||
agent_scene = ExtResource( 4 )
|
||||
[node name="Spawners" type="Node2D" parent="."]
|
||||
|
||||
[node name="FleeerSpawner" type="Node2D" parent="."]
|
||||
[node name="SeekerSpawner" type="Node2D" parent="Spawners"]
|
||||
script = ExtResource( 2 )
|
||||
agent_scene = ExtResource( 6 )
|
||||
agent_color = Color( 0.0980392, 0.886275, 0.517647, 1 )
|
||||
Entity = ExtResource( 4 )
|
||||
|
||||
[node name="CowardSpawner" type="Node2D" parent="Spawners"]
|
||||
script = ExtResource( 2 )
|
||||
Entity = ExtResource( 6 )
|
||||
entity_color = Color( 0, 1, 0.741176, 1 )
|
37
project/demos/seek_and_flee/SeekFleeDemo.gd
Normal file
37
project/demos/seek_and_flee/SeekFleeDemo.gd
Normal file
@ -0,0 +1,37 @@
|
||||
extends Node2D
|
||||
"""
|
||||
Access helper class for children to access window boundaries.
|
||||
"""
|
||||
|
||||
onready var player: KinematicBody2D = $Player
|
||||
onready var spawners: Node2D = $Spawners
|
||||
|
||||
var camera_boundaries: Rect2
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
camera_boundaries = Rect2(
|
||||
Vector2.ZERO,
|
||||
Vector2(
|
||||
ProjectSettings["display/window/size/width"],
|
||||
ProjectSettings["display/window/size/height"]
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
var rng: = RandomNumberGenerator.new()
|
||||
rng.randomize()
|
||||
|
||||
for spawner in spawners.get_children():
|
||||
for i in range(spawner.entity_count):
|
||||
var new_pos: = Vector2(
|
||||
rng.randf_range(-camera_boundaries.size.x/2, camera_boundaries.size.x/2),
|
||||
rng.randf_range(-camera_boundaries.size.y/2, camera_boundaries.size.y/2)
|
||||
)
|
||||
var entity: KinematicBody2D = spawner.Entity.instance()
|
||||
entity.global_position = new_pos
|
||||
entity.player_agent = player.agent
|
||||
entity.speed = rng.randf_range(spawner.min_speed, spawner.max_speed)
|
||||
entity.color = spawner.entity_color
|
||||
spawner.add_child(entity)
|
@ -6,22 +6,20 @@ AI agent that uses the Seek behavior to hone in on the player's location as dire
|
||||
|
||||
onready var radius: = ($CollisionShape2D.shape as CircleShape2D).radius
|
||||
|
||||
var agent: SteeringAgent
|
||||
var player_agent: AgentLocation
|
||||
var seek: Seek
|
||||
var accel: = TargetAcceleration.new()
|
||||
onready var agent: = GSTSteeringAgent.new()
|
||||
onready var accel: = GSTTargetAcceleration.new()
|
||||
onready var seek: = GSTSeek.new(agent, player_agent)
|
||||
|
||||
var player_agent: GSTAgentLocation
|
||||
var velocity: = Vector2.ZERO
|
||||
var speed: float
|
||||
var color: Color
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
agent = SteeringAgent.new()
|
||||
agent.max_linear_acceleration = speed/10
|
||||
agent.max_linear_speed = speed
|
||||
|
||||
seek = Seek.new(agent, player_agent)
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
draw_circle(Vector2.ZERO, radius, color)
|
@ -1,6 +1,6 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://src/Steering/Demos/SeekFlee/Seeker.gd" type="Script" id=1]
|
||||
[ext_resource path="res://demos/seek_and_flee/Seeker.gd" type="Script" id=1]
|
||||
|
||||
[sub_resource type="CircleShape2D" id=1]
|
||||
|
11
project/demos/seek_and_flee/Spawner.gd
Normal file
11
project/demos/seek_and_flee/Spawner.gd
Normal file
@ -0,0 +1,11 @@
|
||||
extends Node2D
|
||||
"""
|
||||
Holds data to instantiate and configure a number of agent entities.
|
||||
"""
|
||||
|
||||
|
||||
export(PackedScene) var Entity: PackedScene
|
||||
export var entity_count: = 10
|
||||
export var entity_color: = Color.blue
|
||||
export var min_speed: = 50.0
|
||||
export var max_speed: = 125.0
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
@ -10,77 +10,83 @@ config_version=4
|
||||
|
||||
_global_script_classes=[ {
|
||||
"base": "Reference",
|
||||
"class": "AgentLocation",
|
||||
"class": "GSTAgentLocation",
|
||||
"language": "GDScript",
|
||||
"path": "res://src/Steering/AgentLocation.gd"
|
||||
"path": "res://src/GSTAgentLocation.gd"
|
||||
}, {
|
||||
"base": "SteeringBehavior",
|
||||
"class": "Arrive",
|
||||
"base": "GSTSteeringBehavior",
|
||||
"class": "GSTArrive",
|
||||
"language": "GDScript",
|
||||
"path": "res://src/Steering/Behaviors/Arrive.gd"
|
||||
"path": "res://src/behaviors/GSTArrive.gd"
|
||||
}, {
|
||||
"base": "Pursue",
|
||||
"class": "Evade",
|
||||
"base": "GSTPursue",
|
||||
"class": "GSTEvade",
|
||||
"language": "GDScript",
|
||||
"path": "res://src/Steering/Behaviors/Evade.gd"
|
||||
"path": "res://src/behaviors/GSTEvade.gd"
|
||||
}, {
|
||||
"base": "MatchOrientation",
|
||||
"class": "Face",
|
||||
"base": "GSTMatchOrientation",
|
||||
"class": "GSTFace",
|
||||
"language": "GDScript",
|
||||
"path": "res://src/Steering/Behaviors/Face.gd"
|
||||
"path": "res://src/behaviors/GSTFace.gd"
|
||||
}, {
|
||||
"base": "Seek",
|
||||
"class": "Flee",
|
||||
"base": "GSTSeek",
|
||||
"class": "GSTFlee",
|
||||
"language": "GDScript",
|
||||
"path": "res://src/Steering/Behaviors/Flee.gd"
|
||||
"path": "res://src/behaviors/GSTFlee.gd"
|
||||
}, {
|
||||
"base": "SteeringBehavior",
|
||||
"class": "MatchOrientation",
|
||||
"base": "GSTSteeringBehavior",
|
||||
"class": "GSTMatchOrientation",
|
||||
"language": "GDScript",
|
||||
"path": "res://src/Steering/Behaviors/MatchOrientation.gd"
|
||||
"path": "res://src/behaviors/GSTMatchOrientation.gd"
|
||||
}, {
|
||||
"base": "SteeringBehavior",
|
||||
"class": "Pursue",
|
||||
"base": "GSTSteeringBehavior",
|
||||
"class": "GSTPursue",
|
||||
"language": "GDScript",
|
||||
"path": "res://src/Steering/Behaviors/Pursue.gd"
|
||||
"path": "res://src/behaviors/GSTPursue.gd"
|
||||
}, {
|
||||
"base": "SteeringBehavior",
|
||||
"class": "Seek",
|
||||
"base": "GSTSteeringBehavior",
|
||||
"class": "GSTSeek",
|
||||
"language": "GDScript",
|
||||
"path": "res://src/Steering/Behaviors/Seek.gd"
|
||||
"path": "res://src/behaviors/GSTSeek.gd"
|
||||
}, {
|
||||
"base": "AgentLocation",
|
||||
"class": "SteeringAgent",
|
||||
"base": "GSTAgentLocation",
|
||||
"class": "GSTSteeringAgent",
|
||||
"language": "GDScript",
|
||||
"path": "res://src/Steering/SteeringAgent.gd"
|
||||
"path": "res://src/GSTSteeringAgent.gd"
|
||||
}, {
|
||||
"base": "Reference",
|
||||
"class": "SteeringBehavior",
|
||||
"class": "GSTSteeringBehavior",
|
||||
"language": "GDScript",
|
||||
"path": "res://src/Steering/SteeringBehavior.gd"
|
||||
"path": "res://src/GSTSteeringBehavior.gd"
|
||||
}, {
|
||||
"base": "Reference",
|
||||
"class": "TargetAcceleration",
|
||||
"class": "GSTTargetAcceleration",
|
||||
"language": "GDScript",
|
||||
"path": "res://src/Steering/TargetAcceleration.gd"
|
||||
"path": "res://src/GSTTargetAcceleration.gd"
|
||||
}, {
|
||||
"base": "Reference",
|
||||
"class": "Utils",
|
||||
"language": "GDScript",
|
||||
"path": "res://src/Utils.gd"
|
||||
} ]
|
||||
_global_script_class_icons={
|
||||
"AgentLocation": "",
|
||||
"Arrive": "",
|
||||
"Evade": "",
|
||||
"Face": "",
|
||||
"Flee": "",
|
||||
"MatchOrientation": "",
|
||||
"Pursue": "",
|
||||
"Seek": "",
|
||||
"SteeringAgent": "",
|
||||
"SteeringBehavior": "",
|
||||
"TargetAcceleration": ""
|
||||
"GSTAgentLocation": "",
|
||||
"GSTArrive": "",
|
||||
"GSTEvade": "",
|
||||
"GSTFace": "",
|
||||
"GSTFlee": "",
|
||||
"GSTMatchOrientation": "",
|
||||
"GSTPursue": "",
|
||||
"GSTSeek": "",
|
||||
"GSTSteeringAgent": "",
|
||||
"GSTSteeringBehavior": "",
|
||||
"GSTTargetAcceleration": "",
|
||||
"Utils": ""
|
||||
}
|
||||
|
||||
[application]
|
||||
|
||||
config/name="godot-steering-toolkit"
|
||||
config/name="SteeringToolkit"
|
||||
config/icon="res://icon.png"
|
||||
|
||||
[input]
|
@ -1,5 +1,5 @@
|
||||
extends Reference
|
||||
class_name AgentLocation
|
||||
class_name GSTAgentLocation
|
||||
"""
|
||||
Data type to represent an agent with a location and an orientation
|
||||
"""
|
@ -1,5 +1,5 @@
|
||||
extends AgentLocation
|
||||
class_name SteeringAgent
|
||||
extends GSTAgentLocation
|
||||
class_name GSTSteeringAgent
|
||||
"""
|
||||
Extended agent data type that adds velocity and speed data.
|
||||
"""
|
26
project/src/GSTSteeringBehavior.gd
Normal file
26
project/src/GSTSteeringBehavior.gd
Normal file
@ -0,0 +1,26 @@
|
||||
extends Reference
|
||||
class_name GSTSteeringBehavior
|
||||
"""
|
||||
Base class to calculate how an AI agent steers itself.
|
||||
"""
|
||||
|
||||
|
||||
var enabled: = true
|
||||
var agent: GSTSteeringAgent
|
||||
|
||||
|
||||
func _init(agent: GSTSteeringAgent) -> void:
|
||||
self.agent = agent
|
||||
|
||||
|
||||
func calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration:
|
||||
if enabled:
|
||||
return _calculate_steering(acceleration)
|
||||
else:
|
||||
acceleration.set_zero()
|
||||
return acceleration
|
||||
|
||||
|
||||
func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration:
|
||||
acceleration.set_zero()
|
||||
return acceleration
|
@ -1,5 +1,5 @@
|
||||
extends Reference
|
||||
class_name TargetAcceleration
|
||||
class_name GSTTargetAcceleration
|
||||
"""
|
||||
A linear and angular amount of acceleration.
|
||||
"""
|
||||
@ -9,9 +9,8 @@ var linear: = Vector3.ZERO
|
||||
var angular: = 0.0
|
||||
|
||||
|
||||
func set_zero() -> TargetAcceleration:
|
||||
func set_zero() -> void:
|
||||
linear.x = 0.0
|
||||
linear.y = 0.0
|
||||
linear.z = 0.0
|
||||
angular = 0.0
|
||||
return self
|
9
project/src/Utils.gd
Normal file
9
project/src/Utils.gd
Normal file
@ -0,0 +1,9 @@
|
||||
class_name Utils
|
||||
|
||||
|
||||
static func clmapedv3(vector: Vector3, limit: float) -> Vector3:
|
||||
var len2: = vector.length_squared()
|
||||
var limit2: = limit * limit
|
||||
if len2 > limit2:
|
||||
vector *= sqrt(limit2 / len2)
|
||||
return vector
|
42
project/src/behaviors/GSTArrive.gd
Normal file
42
project/src/behaviors/GSTArrive.gd
Normal file
@ -0,0 +1,42 @@
|
||||
extends GSTSteeringBehavior
|
||||
class_name GSTArrive
|
||||
"""
|
||||
Calculates acceleration to take an agent to its target's location.
|
||||
The calculation will attempt to arrive with zero remaining velocity.
|
||||
"""
|
||||
|
||||
|
||||
var target: GSTAgentLocation
|
||||
var arrival_tolerance: float
|
||||
var deceleration_radius: float
|
||||
var time_to_reach: = 0.1
|
||||
|
||||
|
||||
func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent) -> void:
|
||||
self.target = target
|
||||
|
||||
|
||||
func _arrive(acceleration: GSTTargetAcceleration, target_position: Vector3) -> GSTTargetAcceleration:
|
||||
var to_target: = target_position - agent.position
|
||||
var distance: = to_target.length()
|
||||
|
||||
if distance <= arrival_tolerance:
|
||||
acceleration.set_zero()
|
||||
else:
|
||||
var desired_speed: = agent.max_linear_speed
|
||||
|
||||
if distance <= deceleration_radius:
|
||||
desired_speed *= distance / deceleration_radius
|
||||
|
||||
var desired_velocity: = to_target * desired_speed/distance
|
||||
|
||||
desired_velocity = (desired_velocity - agent.linear_velocity) * 1.0 / time_to_reach
|
||||
|
||||
acceleration.linear = Utils.clampedv3(desired_velocity, agent.max_linear_acceleration)
|
||||
acceleration.angular = 0
|
||||
|
||||
return acceleration
|
||||
|
||||
|
||||
func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration:
|
||||
return _arrive(acceleration, target.position)
|
@ -1,5 +1,5 @@
|
||||
extends Pursue
|
||||
class_name Evade
|
||||
extends GSTPursue
|
||||
class_name GSTEvade
|
||||
"""
|
||||
Calculates acceleration to take an agent away from where a target agent will be.
|
||||
|
||||
@ -7,9 +7,12 @@ The `max_predict_time` variable represents how far ahead to calculate the inters
|
||||
"""
|
||||
|
||||
|
||||
func _init(agent: SteeringAgent, target: SteeringAgent, max_predict_time: = 1.0).(agent, target, max_predict_time):
|
||||
func _init(
|
||||
agent: GSTSteeringAgent,
|
||||
target: GSTSteeringAgent,
|
||||
max_predict_time: = 1.0).(agent, target, max_predict_time):
|
||||
pass
|
||||
|
||||
|
||||
func get_max_linear_acceleration() -> float:
|
||||
func _get_modified_acceleration() -> float:
|
||||
return -agent.max_linear_acceleration
|
26
project/src/behaviors/GSTFace.gd
Normal file
26
project/src/behaviors/GSTFace.gd
Normal file
@ -0,0 +1,26 @@
|
||||
extends GSTMatchOrientation
|
||||
class_name GSTFace
|
||||
"""
|
||||
Calculates angular acceleration to rotate a target to face its target's position.
|
||||
The acceleration will attempt to arrive with zero remaining angular velocity.
|
||||
"""
|
||||
|
||||
|
||||
func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent, target) -> void:
|
||||
pass
|
||||
|
||||
|
||||
func _face(acceleration: GSTTargetAcceleration, target_position: Vector3) -> GSTTargetAcceleration:
|
||||
var to_target: = target_position - agent.position
|
||||
var distance_squared: = to_target.length_squared()
|
||||
|
||||
if distance_squared < agent.zero_linear_speed_threshold:
|
||||
acceleration.set_zero()
|
||||
return acceleration
|
||||
else:
|
||||
var orientation = atan2(to_target.x, -to_target.y)
|
||||
return _match_orientation(acceleration, orientation)
|
||||
|
||||
|
||||
func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration:
|
||||
return _face(acceleration, target.position)
|
17
project/src/behaviors/GSTFlee.gd
Normal file
17
project/src/behaviors/GSTFlee.gd
Normal file
@ -0,0 +1,17 @@
|
||||
extends GSTSeek
|
||||
class_name GSTFlee
|
||||
"""
|
||||
Calculates acceleration to take an agent directly away from a target agent.
|
||||
"""
|
||||
|
||||
|
||||
func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent, target) -> void:
|
||||
pass
|
||||
|
||||
|
||||
func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration:
|
||||
acceleration.linear = (
|
||||
(agent.position - target.position).normalized() * agent.max_linear_acceleration)
|
||||
acceleration.angular = 0
|
||||
|
||||
return acceleration
|
@ -1,37 +1,37 @@
|
||||
extends SteeringBehavior
|
||||
class_name MatchOrientation
|
||||
extends GSTSteeringBehavior
|
||||
class_name GSTMatchOrientation
|
||||
"""
|
||||
Calculates an angular acceleration to match an agent's orientation to its target's.
|
||||
The calculation will attempt to arrive with zero remaining angular velocity.
|
||||
"""
|
||||
|
||||
|
||||
var target: AgentLocation
|
||||
var target: GSTAgentLocation
|
||||
var alignment_tolerance: float
|
||||
var deceleration_radius: float
|
||||
var time_to_target: float = 0.1
|
||||
var time_to_reach: float = 0.1
|
||||
|
||||
|
||||
func _init(agent: SteeringAgent, target: AgentLocation).(agent) -> void:
|
||||
func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent) -> void:
|
||||
self.target = target
|
||||
|
||||
|
||||
func _match_orientation(acceleration: TargetAcceleration, target_orientation: float) -> TargetAcceleration:
|
||||
var rotation: = wrapf(target_orientation - agent.orientation, -PI, PI)
|
||||
func _match_orientation(acceleration: GSTTargetAcceleration, desired_orientation: float) -> GSTTargetAcceleration:
|
||||
var rotation: = wrapf(desired_orientation - agent.orientation, -PI, PI)
|
||||
|
||||
var rotation_size: = -rotation if rotation < 0 else rotation
|
||||
|
||||
if rotation_size <= alignment_tolerance:
|
||||
return acceleration.set_zero()
|
||||
|
||||
var target_rotation: = agent.max_angular_speed
|
||||
var desired_rotation: = agent.max_angular_speed
|
||||
|
||||
if rotation_size <= deceleration_radius:
|
||||
target_rotation *= rotation_size / deceleration_radius
|
||||
desired_rotation *= rotation_size / deceleration_radius
|
||||
|
||||
target_rotation *= rotation / rotation_size
|
||||
desired_rotation *= rotation / rotation_size
|
||||
|
||||
acceleration.angular = (target_rotation - agent.angular_velocity) / time_to_target
|
||||
acceleration.angular = (desired_rotation - agent.angular_velocity) / time_to_reach
|
||||
|
||||
var limited_acceleration: = -acceleration.angular if acceleration.angular < 0 else acceleration.angular
|
||||
if limited_acceleration > agent.max_angular_acceleration:
|
||||
@ -42,5 +42,5 @@ func _match_orientation(acceleration: TargetAcceleration, target_orientation: fl
|
||||
return acceleration
|
||||
|
||||
|
||||
func _calculate_internal_steering(acceleration: TargetAcceleration) -> TargetAcceleration:
|
||||
func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration:
|
||||
return _match_orientation(acceleration, target.orientation)
|
@ -1,5 +1,5 @@
|
||||
extends SteeringBehavior
|
||||
class_name Pursue
|
||||
extends GSTSteeringBehavior
|
||||
class_name GSTPursue
|
||||
"""
|
||||
Calculates acceleration to take an agent to intersect with where a target agent will be.
|
||||
|
||||
@ -7,20 +7,19 @@ The `max_predict_time` variable represents how far ahead to calculate the inters
|
||||
"""
|
||||
|
||||
|
||||
var target: SteeringAgent
|
||||
var target: GSTSteeringAgent
|
||||
var max_predict_time: float
|
||||
|
||||
|
||||
func _init(agent: SteeringAgent, target: SteeringAgent, max_predict_time: = 1.0).(agent) -> void:
|
||||
func _init(
|
||||
agent: GSTSteeringAgent,
|
||||
target: GSTSteeringAgent,
|
||||
max_predict_time: = 1.0).(agent) -> void:
|
||||
self.target = target
|
||||
self.max_predict_time = max_predict_time
|
||||
|
||||
|
||||
func get_max_linear_acceleration() -> float:
|
||||
return agent.max_linear_acceleration
|
||||
|
||||
|
||||
func _calculate_internal_steering(acceleration: TargetAcceleration) -> TargetAcceleration:
|
||||
func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration:
|
||||
var target_position: = target.position
|
||||
var distance_squared: = (target_position - agent.position).length_squared()
|
||||
|
||||
@ -32,9 +31,14 @@ func _calculate_internal_steering(acceleration: TargetAcceleration) -> TargetAcc
|
||||
if predict_time_squared < max_predict_time * max_predict_time:
|
||||
predict_time = sqrt(predict_time_squared)
|
||||
|
||||
acceleration.linear = ((target_position + (target.linear_velocity * predict_time))-agent.position).normalized()
|
||||
acceleration.linear *= agent.max_linear_acceleration
|
||||
acceleration.linear = ((
|
||||
target_position + (target.linear_velocity * predict_time))-agent.position).normalized()
|
||||
acceleration.linear *= _get_modified_acceleration()
|
||||
|
||||
acceleration.angular = 0
|
||||
|
||||
return acceleration
|
||||
|
||||
|
||||
func _get_modified_acceleration() -> float:
|
||||
return agent.max_linear_acceleration
|
20
project/src/behaviors/GSTSeek.gd
Normal file
20
project/src/behaviors/GSTSeek.gd
Normal file
@ -0,0 +1,20 @@
|
||||
extends GSTSteeringBehavior
|
||||
class_name GSTSeek
|
||||
"""
|
||||
Calculates acceleration to take an agent to a target agent's position as directly as possible
|
||||
"""
|
||||
|
||||
|
||||
var target: GSTAgentLocation
|
||||
|
||||
|
||||
func _init(agent: GSTSteeringAgent, target: GSTAgentLocation).(agent) -> void:
|
||||
self.target = target
|
||||
|
||||
|
||||
func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration:
|
||||
acceleration.linear = (
|
||||
(target.position - agent.position).normalized() * agent.max_linear_acceleration)
|
||||
acceleration.angular = 0
|
||||
|
||||
return acceleration
|
@ -1,50 +0,0 @@
|
||||
extends SteeringBehavior
|
||||
class_name Arrive
|
||||
"""
|
||||
Calculates acceleration to take an agent to its target's location.
|
||||
The calculation will attempt to arrive with zero remaining velocity.
|
||||
"""
|
||||
|
||||
|
||||
var target: AgentLocation
|
||||
var arrival_tolerance: float
|
||||
var deceleration_radius: float
|
||||
var time_to_target: = 0.1
|
||||
|
||||
|
||||
func _init(agent: SteeringAgent, target: AgentLocation).(agent) -> void:
|
||||
self.target = target
|
||||
|
||||
|
||||
func _arrive(acceleration: TargetAcceleration, target_position: Vector3) -> TargetAcceleration:
|
||||
var to_target: = target_position - agent.position
|
||||
var distance: = to_target.length()
|
||||
|
||||
if distance <= arrival_tolerance:
|
||||
return acceleration.set_zero()
|
||||
|
||||
var target_speed: = agent.max_linear_speed
|
||||
|
||||
if distance <= deceleration_radius:
|
||||
target_speed *= distance / deceleration_radius
|
||||
|
||||
var target_velocity: = to_target * target_speed/distance
|
||||
|
||||
target_velocity = (target_velocity - agent.linear_velocity) * 1.0 / time_to_target
|
||||
|
||||
acceleration.linear = limit_length(target_velocity, agent.max_linear_acceleration)
|
||||
acceleration.angular = 0
|
||||
|
||||
return acceleration
|
||||
|
||||
|
||||
func _calculate_internal_steering(acceleration: TargetAcceleration) -> TargetAcceleration:
|
||||
return _arrive(acceleration, target.position)
|
||||
|
||||
|
||||
static func limit_length(vector: Vector3, limit: float) -> Vector3:
|
||||
var len2: = vector.length_squared()
|
||||
var limit2: = limit * limit
|
||||
if len2 > limit2:
|
||||
vector *= sqrt(limit2 / len2)
|
||||
return vector
|
@ -1,26 +0,0 @@
|
||||
extends MatchOrientation
|
||||
class_name Face
|
||||
"""
|
||||
Calculates angular acceleration to rotate a target to face its target's position.
|
||||
The acceleration will attempt to arrive with zero remaining angular velocity.
|
||||
"""
|
||||
|
||||
|
||||
func _init(agent: SteeringAgent, target: AgentLocation).(agent, target) -> void:
|
||||
pass
|
||||
|
||||
|
||||
func _face(acceleration: TargetAcceleration, target_position: Vector3) -> TargetAcceleration:
|
||||
var to_target: = target_position - agent.position
|
||||
|
||||
var distance_squared: = to_target.length_squared()
|
||||
if distance_squared < agent.zero_linear_speed_threshold:
|
||||
return acceleration.set_zero()
|
||||
|
||||
var orientation = Vector3.UP.angle_to(to_target)
|
||||
|
||||
return _match_orientation(acceleration, orientation)
|
||||
|
||||
|
||||
func _calculate_internal_steering(acceleration: TargetAcceleration) -> TargetAcceleration:
|
||||
return _face(acceleration, target.position)
|
@ -1,16 +0,0 @@
|
||||
extends Seek
|
||||
class_name Flee
|
||||
"""
|
||||
Calculates acceleration to take an agent directly away from a target agent.
|
||||
"""
|
||||
|
||||
|
||||
func _init(agent: SteeringAgent, target: AgentLocation).(agent, target) -> void:
|
||||
pass
|
||||
|
||||
|
||||
func _calculate_internal_steering(acceleration: TargetAcceleration) -> TargetAcceleration:
|
||||
acceleration.linear = (agent.position - target.position).normalized() * agent.max_linear_acceleration
|
||||
acceleration.angular = 0
|
||||
|
||||
return acceleration
|
@ -1,19 +0,0 @@
|
||||
extends SteeringBehavior
|
||||
class_name Seek
|
||||
"""
|
||||
Calculates acceleration to take an agent to a target agent's position as directly as possible
|
||||
"""
|
||||
|
||||
|
||||
var target: AgentLocation
|
||||
|
||||
|
||||
func _init(agent: SteeringAgent, target: AgentLocation).(agent) -> void:
|
||||
self.target = target
|
||||
|
||||
|
||||
func _calculate_internal_steering(acceleration: TargetAcceleration) -> TargetAcceleration:
|
||||
acceleration.linear = (target.position - agent.position).normalized() * agent.max_linear_acceleration
|
||||
acceleration.angular = 0
|
||||
|
||||
return acceleration
|
@ -1,14 +0,0 @@
|
||||
extends Node2D
|
||||
"""
|
||||
Access helper class for children to access window boundaries.
|
||||
"""
|
||||
|
||||
|
||||
var camera_boundaries: Rect2
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
camera_boundaries = Rect2(
|
||||
Vector2.ZERO,
|
||||
Vector2(ProjectSettings["display/window/size/width"], ProjectSettings["display/window/size/height"])
|
||||
)
|
@ -1,30 +0,0 @@
|
||||
extends Node2D
|
||||
"""
|
||||
Instantiates and configures a number of agent scenes within the level boundaries.
|
||||
"""
|
||||
|
||||
|
||||
onready var player_agent: AgentLocation = owner.get_node("Player").player_agent
|
||||
|
||||
|
||||
export(PackedScene) var agent_scene: PackedScene
|
||||
export var agent_count: = 10
|
||||
export var min_speed: = 50.0
|
||||
export var max_speed: = 125.0
|
||||
export var agent_color: = Color.blue
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
var boundaries: Rect2 = owner.camera_boundaries
|
||||
randomize()
|
||||
for i in range(agent_count):
|
||||
var new_pos: = Vector2(
|
||||
rand_range(-boundaries.size.x/2, boundaries.size.x/2),
|
||||
rand_range(-boundaries.size.y/2, boundaries.size.y/2)
|
||||
)
|
||||
var agent: = agent_scene.instance()
|
||||
agent.global_position = new_pos
|
||||
agent.player_agent = player_agent
|
||||
agent.speed = rand_range(min_speed, max_speed)
|
||||
agent.color = agent_color
|
||||
add_child(agent)
|
@ -1,21 +0,0 @@
|
||||
extends Reference
|
||||
class_name SteeringBehavior
|
||||
"""
|
||||
Base class to calculate how an AI agent steers itself.
|
||||
"""
|
||||
|
||||
|
||||
var enabled: = true
|
||||
var agent: SteeringAgent
|
||||
|
||||
|
||||
func _init(agent: SteeringAgent) -> void:
|
||||
self.agent = agent
|
||||
|
||||
|
||||
func calculate_steering(acceleration: TargetAcceleration) -> TargetAcceleration:
|
||||
return _calculate_internal_steering(acceleration) if enabled else acceleration.zero()
|
||||
|
||||
|
||||
func _calculate_internal_steering(acceleration: TargetAcceleration) -> TargetAcceleration:
|
||||
return acceleration.set_zero()
|
Loading…
Reference in New Issue
Block a user