mirror of
https://github.com/Relintai/godot-steering-ai-framework.git
synced 2024-12-24 05:37:15 +01:00
Merge pull request #6 from GDQuest/features/final-toys
Add path following and collision avoid toy demos
This commit is contained in:
commit
c7d776c2e0
@ -2,7 +2,7 @@ extends Node2D
|
|||||||
|
|
||||||
|
|
||||||
export(float, 0, 2000, 40) var max_linear_speed := 800.0 setget set_max_linear_speed
|
export(float, 0, 2000, 40) var max_linear_speed := 800.0 setget set_max_linear_speed
|
||||||
export(float, 0, 200, 1) var max_linear_acceleration := 80.0 setget set_max_linear_acceleration
|
export(float, 0, 200, 2.0) var max_linear_acceleration := 80.0 setget set_max_linear_acceleration
|
||||||
export(float, 0, 100, 0.1) var arrival_tolerance := 25.0 setget set_arrival_tolerance
|
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
|
export(float, 0, 500, 10) var deceleration_radius := 125.0 setget set_deceleration_radius
|
||||||
|
|
||||||
@ -36,34 +36,32 @@ func _draw():
|
|||||||
|
|
||||||
|
|
||||||
func set_arrival_tolerance(value: float) -> void:
|
func set_arrival_tolerance(value: float) -> void:
|
||||||
|
arrival_tolerance = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
arrival_tolerance = value
|
|
||||||
arriver.arrive.arrival_tolerance = value
|
arriver.arrive.arrival_tolerance = value
|
||||||
update()
|
|
||||||
|
|
||||||
|
|
||||||
func set_deceleration_radius(value: float) -> void:
|
func set_deceleration_radius(value: float) -> void:
|
||||||
|
deceleration_radius = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
deceleration_radius = value
|
|
||||||
arriver.arrive.deceleration_radius = value
|
arriver.arrive.deceleration_radius = value
|
||||||
update()
|
|
||||||
|
|
||||||
|
|
||||||
func set_max_linear_speed(value: float) -> void:
|
func set_max_linear_speed(value: float) -> void:
|
||||||
|
max_linear_speed = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
max_linear_speed = value
|
|
||||||
arriver.agent.max_linear_speed = value
|
arriver.agent.max_linear_speed = value
|
||||||
|
|
||||||
|
|
||||||
func set_max_linear_acceleration(value: float) -> void:
|
func set_max_linear_acceleration(value: float) -> void:
|
||||||
|
max_linear_acceleration = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
max_linear_acceleration = value
|
|
||||||
arriver.agent.max_linear_acceleration = value
|
arriver.agent.max_linear_acceleration = value
|
||||||
|
41
project/demos/AvoidCollisions/AvoidCollisionsDemo.gd
Normal file
41
project/demos/AvoidCollisions/AvoidCollisionsDemo.gd
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
extends Node2D
|
||||||
|
|
||||||
|
|
||||||
|
export(float, 0, 2000, 40) var max_linear_speed := 350.0 setget set_max_linear_speed
|
||||||
|
export(float, 0, 100, 2) var max_linear_acceleration := 40.0 setget set_max_linear_accel
|
||||||
|
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_max_linear_speed(value: float) -> void:
|
||||||
|
max_linear_speed = value
|
||||||
|
if not is_inside_tree():
|
||||||
|
return
|
||||||
|
|
||||||
|
spawner.set_max_linear_speed(value)
|
||||||
|
|
||||||
|
|
||||||
|
func set_max_linear_accel(value: float) -> void:
|
||||||
|
max_linear_acceleration = value
|
||||||
|
if not is_inside_tree():
|
||||||
|
return
|
||||||
|
|
||||||
|
spawner.set_max_linear_accel(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)
|
42
project/demos/AvoidCollisions/AvoidCollisionsDemo.tscn
Normal file
42
project/demos/AvoidCollisions/AvoidCollisionsDemo.tscn
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
[gd_scene load_steps=5 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://assets/theme/gdquest.theme" type="Theme" id=4]
|
||||||
|
|
||||||
|
[node name="AvoidCollisionsDemo" type="Node2D"]
|
||||||
|
script = ExtResource( 2 )
|
||||||
|
max_linear_speed = 360.0
|
||||||
|
proximity_radius = 100.0
|
||||||
|
|
||||||
|
[node name="Spawner" type="Node2D" parent="."]
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
avoider_template = ExtResource( 3 )
|
||||||
|
normal_color = Color( 0.94902, 0.0588235, 0.0588235, 1 )
|
||||||
|
highlight_color = Color( 0.0901961, 0.929412, 0.929412, 1 )
|
||||||
|
|
||||||
|
[node name="GUI" type="PanelContainer" parent="."]
|
||||||
|
margin_right = 1024.0
|
||||||
|
margin_bottom = 14.0
|
||||||
|
theme = ExtResource( 4 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="GUI"]
|
||||||
|
margin_right = 1024.0
|
||||||
|
margin_bottom = 116.0
|
||||||
|
|
||||||
|
[node name="RichTextLabel" type="RichTextLabel" parent="GUI/MarginContainer"]
|
||||||
|
margin_left = 16.0
|
||||||
|
margin_top = 16.0
|
||||||
|
margin_right = 1008.0
|
||||||
|
margin_bottom = 100.0
|
||||||
|
rect_min_size = Vector2( 0, 84 )
|
||||||
|
bbcode_enabled = true
|
||||||
|
bbcode_text = "Avoid Collisions Demo
|
||||||
|
Watch each agent try to keep traveling in a particular direction, but prioritize avoiding collisions with other agents."
|
||||||
|
text = "Avoid Collisions Demo
|
||||||
|
Watch each agent try to keep traveling in a particular direction, but prioritize avoiding collisions with other agents."
|
||||||
|
scroll_active = false
|
95
project/demos/AvoidCollisions/Avoider.gd
Normal file
95
project/demos/AvoidCollisions/Avoider.gd
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
extends KinematicBody2D
|
||||||
|
|
||||||
|
|
||||||
|
onready var collision := $CollisionShape2D
|
||||||
|
onready var agent := GSTSteeringAgent.new()
|
||||||
|
onready var proximity := GSTRadiusProximity.new(agent, [], 140)
|
||||||
|
onready var avoid := GSTAvoidCollisions.new(agent, proximity)
|
||||||
|
onready var target := GSTAgentLocation.new()
|
||||||
|
onready var seek := GSTSeek.new(agent, target)
|
||||||
|
onready var priority := GSTPriority.new(agent, 0.0001)
|
||||||
|
onready var sprite := $Sprite
|
||||||
|
|
||||||
|
var draw_proximity: bool
|
||||||
|
|
||||||
|
var _boundary_right: float
|
||||||
|
var _boundary_bottom: float
|
||||||
|
var _radius: float
|
||||||
|
var _accel := GSTTargetAcceleration.new()
|
||||||
|
var _velocity := Vector2.ZERO
|
||||||
|
var _direction := Vector2()
|
||||||
|
var _drag: = 0.1
|
||||||
|
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
if draw_proximity:
|
||||||
|
draw_circle(Vector2.ZERO, proximity.radius, Color(0, 1, 0, 0.1))
|
||||||
|
|
||||||
|
|
||||||
|
func _physics_process(delta: float) -> void:
|
||||||
|
_update_agent()
|
||||||
|
_accel = priority.calculate_steering(_accel)
|
||||||
|
_velocity += Vector2(_accel.linear.x, _accel.linear.y)
|
||||||
|
_velocity = _velocity.linear_interpolate(Vector2.ZERO, _drag)
|
||||||
|
_velocity = _velocity.clamped(agent.max_linear_speed)
|
||||||
|
_velocity = move_and_slide(_velocity)
|
||||||
|
|
||||||
|
|
||||||
|
func setup(
|
||||||
|
max_linear_speed: float,
|
||||||
|
max_linear_accel: 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()
|
||||||
|
_update_agent()
|
||||||
|
agent.max_linear_speed = max_linear_speed
|
||||||
|
agent.max_linear_acceleration = max_linear_accel
|
||||||
|
proximity.radius = proximity_radius
|
||||||
|
_boundary_bottom = boundary_bottom
|
||||||
|
_boundary_right = boundary_right
|
||||||
|
_radius = collision.shape.radius
|
||||||
|
agent.bounding_radius = _radius
|
||||||
|
|
||||||
|
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, min_distance_from_boundary: float) -> void:
|
||||||
|
var rng := RandomNumberGenerator.new()
|
||||||
|
rng.randomize()
|
||||||
|
var max_tries := max(100, others.size() * others.size())
|
||||||
|
while max_tries >= 0:
|
||||||
|
max_tries -= 1
|
||||||
|
global_position.x = rng.randf_range(
|
||||||
|
min_distance_from_boundary, _boundary_right-min_distance_from_boundary
|
||||||
|
)
|
||||||
|
global_position.y = rng.randf_range(
|
||||||
|
min_distance_from_boundary, _boundary_bottom-min_distance_from_boundary
|
||||||
|
)
|
||||||
|
var done := true
|
||||||
|
for i in range(others.size()):
|
||||||
|
var other: Node2D = others[i]
|
||||||
|
if other.global_position.distance_to(position) <= _radius*2 + min_distance_from_boundary:
|
||||||
|
done = false
|
||||||
|
if done:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
func _update_agent() -> void:
|
||||||
|
agent.position.x = global_position.x
|
||||||
|
agent.position.y = global_position.y
|
||||||
|
agent.linear_velocity.x = _velocity.x
|
||||||
|
agent.linear_velocity.y = _velocity.y
|
||||||
|
target.position.x = agent.position.x + _direction.x*_radius
|
||||||
|
target.position.y = agent.position.y + _direction.y*_radius
|
17
project/demos/AvoidCollisions/Avoider.tscn
Normal file
17
project/demos/AvoidCollisions/Avoider.tscn
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
[gd_scene load_steps=4 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://assets/sprites/small_circle.png" type="Texture" id=1]
|
||||||
|
[ext_resource path="res://demos/AvoidCollisions/Avoider.gd" type="Script" id=2]
|
||||||
|
|
||||||
|
[sub_resource type="CircleShape2D" id=1]
|
||||||
|
radius = 16.0
|
||||||
|
|
||||||
|
[node name="Avoider" type="KinematicBody2D"]
|
||||||
|
script = ExtResource( 2 )
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
|
shape = SubResource( 1 )
|
||||||
|
|
||||||
|
[node name="Sprite" type="Sprite" parent="."]
|
||||||
|
modulate = Color( 0.94902, 0.211765, 0.0901961, 1 )
|
||||||
|
texture = ExtResource( 1 )
|
65
project/demos/AvoidCollisions/Spawner.gd
Normal file
65
project/demos/AvoidCollisions/Spawner.gd
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
extends Node2D
|
||||||
|
|
||||||
|
|
||||||
|
export var avoider_template: PackedScene
|
||||||
|
export var normal_color := Color()
|
||||||
|
export var highlight_color := Color()
|
||||||
|
|
||||||
|
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(60):
|
||||||
|
var avoider := avoider_template.instance()
|
||||||
|
add_child(avoider)
|
||||||
|
avoider.setup(
|
||||||
|
owner.max_linear_speed,
|
||||||
|
owner.max_linear_acceleration,
|
||||||
|
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)
|
||||||
|
avoider.sprite.modulate = normal_color if i != 0 or not owner.draw_proximity else highlight_color
|
||||||
|
avoiders.append(avoider)
|
||||||
|
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_max_linear_speed(value: float) -> void:
|
||||||
|
for child in get_children():
|
||||||
|
child.agent.max_linear_speed = value
|
||||||
|
|
||||||
|
|
||||||
|
func set_max_linear_accel(value: float) -> void:
|
||||||
|
for child in get_children():
|
||||||
|
child.agent.max_linear_acceleration = 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
|
||||||
|
if not value:
|
||||||
|
child.sprite.modulate = normal_color
|
||||||
|
else:
|
||||||
|
child.sprite.modulate = highlight_color
|
||||||
|
child.update()
|
@ -5,11 +5,11 @@ onready var player := $Player
|
|||||||
onready var gui := $GUI
|
onready var gui := $GUI
|
||||||
onready var turret := $Turret
|
onready var turret := $Turret
|
||||||
|
|
||||||
export(int, 0, 359) var max_angular_speed := 90 setget set_max_angular_speed
|
export(int, 0, 359, 2) var max_angular_speed := 120 setget set_max_angular_speed
|
||||||
export(int, 0, 359) var max_angular_accel := 5 setget set_max_angular_accel
|
export(int, 0, 359, 2) var max_angular_accel := 10 setget set_max_angular_accel
|
||||||
export(int, 0, 180) var align_tolerance := 5 setget set_align_tolerance
|
export(int, 0, 180, 2) var align_tolerance := 5 setget set_align_tolerance
|
||||||
export(int, 0, 359) var deceleration_radius := 45 setget set_deceleration_radius
|
export(int, 0, 359, 2) var deceleration_radius := 45 setget set_deceleration_radius
|
||||||
export(float, 0, 1000) var player_speed := 600.0 setget set_player_speed
|
export(float, 0, 1000, 40) var player_speed := 600.0 setget set_player_speed
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
@ -24,40 +24,40 @@ func _ready() -> void:
|
|||||||
|
|
||||||
|
|
||||||
func set_align_tolerance(value: int) -> void:
|
func set_align_tolerance(value: int) -> void:
|
||||||
|
align_tolerance = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
align_tolerance = value
|
|
||||||
turret.face.alignment_tolerance = deg2rad(value)
|
turret.face.alignment_tolerance = deg2rad(value)
|
||||||
|
|
||||||
|
|
||||||
func set_deceleration_radius(value: int) -> void:
|
func set_deceleration_radius(value: int) -> void:
|
||||||
|
deceleration_radius = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
deceleration_radius = value
|
|
||||||
turret.face.deceleration_radius = deg2rad(value)
|
turret.face.deceleration_radius = deg2rad(value)
|
||||||
|
|
||||||
|
|
||||||
func set_max_angular_accel(value: int) -> void:
|
func set_max_angular_accel(value: int) -> void:
|
||||||
|
max_angular_accel = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
max_angular_accel = value
|
|
||||||
turret.agent.max_angular_acceleration = deg2rad(value)
|
turret.agent.max_angular_acceleration = deg2rad(value)
|
||||||
|
|
||||||
|
|
||||||
func set_max_angular_speed(value: int) -> void:
|
func set_max_angular_speed(value: int) -> void:
|
||||||
|
max_angular_speed = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
max_angular_speed = value
|
|
||||||
turret.agent.max_angular_speed = deg2rad(value)
|
turret.agent.max_angular_speed = deg2rad(value)
|
||||||
|
|
||||||
|
|
||||||
func set_player_speed(value: float) -> void:
|
func set_player_speed(value: float) -> void:
|
||||||
|
player_speed = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
player_speed = value
|
|
||||||
player.speed = player_speed
|
player.speed = player_speed
|
||||||
|
@ -5,7 +5,7 @@ var face: GSTFace
|
|||||||
var agent := GSTSteeringAgent.new()
|
var agent := GSTSteeringAgent.new()
|
||||||
|
|
||||||
var _accel := GSTTargetAcceleration.new()
|
var _accel := GSTTargetAcceleration.new()
|
||||||
var _angular_drag := 0.01
|
var _angular_drag := 0.1
|
||||||
var _cannon: Rect2
|
var _cannon: Rect2
|
||||||
|
|
||||||
onready var collision_shape := $CollisionShape2D
|
onready var collision_shape := $CollisionShape2D
|
||||||
|
58
project/demos/FollowPath/Drawer.gd
Normal file
58
project/demos/FollowPath/Drawer.gd
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
extends Node2D
|
||||||
|
|
||||||
|
|
||||||
|
signal path_established(points)
|
||||||
|
|
||||||
|
|
||||||
|
var active_points := []
|
||||||
|
var drawing := false
|
||||||
|
var distance_threshold := 100.0
|
||||||
|
|
||||||
|
|
||||||
|
func _unhandled_input(event: InputEvent) -> void:
|
||||||
|
if event is InputEventMouseMotion:
|
||||||
|
if 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)
|
||||||
|
drawing = true
|
||||||
|
update()
|
||||||
|
elif not event.pressed:
|
||||||
|
drawing = false
|
||||||
|
if active_points.size() >= 2:
|
||||||
|
_simplify()
|
||||||
|
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
if drawing:
|
||||||
|
for point in active_points:
|
||||||
|
draw_circle(point, 1, Color.red)
|
||||||
|
else:
|
||||||
|
if active_points.size() > 0:
|
||||||
|
draw_circle(active_points.front(), 2, Color.red)
|
||||||
|
draw_circle(active_points.back(), 2, Color.yellow)
|
||||||
|
for i in range(1, active_points.size()):
|
||||||
|
var start: Vector2 = active_points[i-1]
|
||||||
|
var end: Vector2 = active_points[i]
|
||||||
|
draw_line(start, end, Color.skyblue)
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
71
project/demos/FollowPath/FollowPathDemo.gd
Normal file
71
project/demos/FollowPath/FollowPathDemo.gd
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
extends Node2D
|
||||||
|
|
||||||
|
|
||||||
|
export(float, 0, 2000, 40) var max_linear_speed := 600.0 setget set_max_linear_speed
|
||||||
|
export(float, 0, 200, 10.0) var max_linear_acceleration := 40.0 setget set_max_linear_acceleration
|
||||||
|
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,
|
||||||
|
max_linear_acceleration,
|
||||||
|
max_linear_speed,
|
||||||
|
deceleration_radius,
|
||||||
|
arrival_tolerance
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func set_max_linear_speed(value: float) -> void:
|
||||||
|
max_linear_speed = value
|
||||||
|
if not is_inside_tree():
|
||||||
|
return
|
||||||
|
|
||||||
|
follower.agent.max_linear_speed = value
|
||||||
|
|
||||||
|
|
||||||
|
func set_max_linear_acceleration(value: float) -> void:
|
||||||
|
max_linear_acceleration = value
|
||||||
|
if not is_inside_tree():
|
||||||
|
return
|
||||||
|
|
||||||
|
follower.agent.max_linear_acceleration = 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
|
@ -1,3 +1,52 @@
|
|||||||
[gd_scene format=2]
|
[gd_scene load_steps=7 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://demos/FollowPath/Drawer.gd" type="Script" id=1]
|
||||||
|
[ext_resource path="res://assets/sprites/small_circle.png" type="Texture" 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://assets/theme/gdquest.theme" type="Theme" id=5]
|
||||||
|
|
||||||
|
[sub_resource type="CircleShape2D" id=1]
|
||||||
|
radius = 16.0
|
||||||
|
|
||||||
[node name="FollowPathDemo" type="Node2D"]
|
[node name="FollowPathDemo" type="Node2D"]
|
||||||
|
script = ExtResource( 4 )
|
||||||
|
|
||||||
|
[node name="Drawer" type="Node2D" parent="."]
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
|
[node name="PathFollower" type="KinematicBody2D" parent="."]
|
||||||
|
position = Vector2( 512, 300 )
|
||||||
|
script = ExtResource( 3 )
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="PathFollower"]
|
||||||
|
shape = SubResource( 1 )
|
||||||
|
|
||||||
|
[node name="Sprite" type="Sprite" parent="PathFollower"]
|
||||||
|
modulate = Color( 0.960784, 0.231373, 0.0392157, 1 )
|
||||||
|
texture = ExtResource( 2 )
|
||||||
|
|
||||||
|
[node name="GUI" type="PanelContainer" parent="."]
|
||||||
|
margin_right = 1024.0
|
||||||
|
margin_bottom = 14.0
|
||||||
|
theme = ExtResource( 5 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="GUI"]
|
||||||
|
margin_right = 1024.0
|
||||||
|
margin_bottom = 116.0
|
||||||
|
|
||||||
|
[node name="RichTextLabel" type="RichTextLabel" parent="GUI/MarginContainer"]
|
||||||
|
margin_left = 16.0
|
||||||
|
margin_top = 16.0
|
||||||
|
margin_right = 1008.0
|
||||||
|
margin_bottom = 100.0
|
||||||
|
rect_min_size = Vector2( 0, 84 )
|
||||||
|
bbcode_enabled = true
|
||||||
|
bbcode_text = "Follow Path Demo
|
||||||
|
Use the mouse to draw a path on screen and watch the [color=red]red \"Agent\"[/color] follow it to the end."
|
||||||
|
text = "Follow Path Demo
|
||||||
|
Use the mouse to draw a path on screen and watch the red \"Agent\" follow it to the end."
|
||||||
|
scroll_active = false
|
||||||
|
56
project/demos/FollowPath/PathFollower.gd
Normal file
56
project/demos/FollowPath/PathFollower.gd
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
extends KinematicBody2D
|
||||||
|
|
||||||
|
|
||||||
|
onready var agent := GSTSteeringAgent.new()
|
||||||
|
onready var path := GSTPath.new([
|
||||||
|
Vector3(global_position.x, global_position.y, 0),
|
||||||
|
Vector3(global_position.x, global_position.y, 0)
|
||||||
|
], true)
|
||||||
|
onready var follow := GSTFollowPath.new(agent, path, 0, 0)
|
||||||
|
|
||||||
|
var _velocity := Vector2.ZERO
|
||||||
|
var _accel := GSTTargetAcceleration.new()
|
||||||
|
var _valid := false
|
||||||
|
var _drag := 0.1
|
||||||
|
|
||||||
|
|
||||||
|
func setup(
|
||||||
|
path_offset: float,
|
||||||
|
predict_time: float,
|
||||||
|
max_accel: float,
|
||||||
|
max_speed: 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
|
||||||
|
agent.max_linear_acceleration = max_accel
|
||||||
|
agent.max_linear_speed = max_speed
|
||||||
|
follow.deceleration_radius = decel_radius
|
||||||
|
follow.arrival_tolerance = arrival_tolerance
|
||||||
|
|
||||||
|
|
||||||
|
func _physics_process(delta: float) -> void:
|
||||||
|
if _valid:
|
||||||
|
_update_agent()
|
||||||
|
_accel = follow.calculate_steering(_accel)
|
||||||
|
_velocity += Vector2(_accel.linear.x, _accel.linear.y)
|
||||||
|
_velocity = _velocity.linear_interpolate(Vector2.ZERO, _drag)
|
||||||
|
_velocity = _velocity.clamped(agent.max_linear_speed)
|
||||||
|
_velocity = move_and_slide(_velocity)
|
||||||
|
|
||||||
|
|
||||||
|
func _update_agent() -> void:
|
||||||
|
agent.position.x = global_position.x
|
||||||
|
agent.position.y = global_position.y
|
||||||
|
agent.linear_velocity.x = _velocity.x
|
||||||
|
agent.linear_velocity.y = _velocity.y
|
||||||
|
|
||||||
|
|
||||||
|
func _on_Drawer_path_established(points: Array) -> void:
|
||||||
|
var points3 := []
|
||||||
|
for p in points:
|
||||||
|
points3.append(Vector3(p.x, p.y, 0))
|
||||||
|
path.create_path(points3)
|
||||||
|
_valid = true
|
@ -3,12 +3,12 @@ extends Node2D
|
|||||||
|
|
||||||
onready var spawner := $Spawner
|
onready var spawner := $Spawner
|
||||||
|
|
||||||
export var max_linear_speed := 100.0 setget set_max_linear_speed
|
export(float, 0, 2000, 40.0) var max_linear_speed := 600.0 setget set_max_linear_speed
|
||||||
export var max_linear_accel := 25.0 setget set_max_linear_accel
|
export(float, 0, 200, 2.0) var max_linear_accel := 40.0 setget set_max_linear_accel
|
||||||
export var proximity_radius := 140.0 setget set_proximity_radius
|
export(float, 0, 300, 2.0) var proximity_radius := 140.0 setget set_proximity_radius
|
||||||
export var separation_decay_coefficient := 2000.0 setget set_separation_decay_coef
|
export(float, 0, 10000, 100) var separation_decay_coefficient := 2000.0 setget set_separation_decay_coef
|
||||||
export var cohesion_strength := 0.3 setget set_cohesion_strength
|
export(float, 0, 2, 0.1) var cohesion_strength := 0.1 setget set_cohesion_strength
|
||||||
export var separation_strength := 1.5 setget set_separation_strength
|
export(float, 0, 6, 0.1) var separation_strength := 1.5 setget set_separation_strength
|
||||||
export var show_proximity_radius := true setget set_show_proximity_radius
|
export var show_proximity_radius := true setget set_show_proximity_radius
|
||||||
|
|
||||||
|
|
||||||
@ -25,56 +25,56 @@ func _ready() -> void:
|
|||||||
|
|
||||||
|
|
||||||
func set_max_linear_speed(value: float) -> void:
|
func set_max_linear_speed(value: float) -> void:
|
||||||
|
max_linear_speed = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
max_linear_speed = value
|
|
||||||
spawner.set_max_linear_speed(value)
|
spawner.set_max_linear_speed(value)
|
||||||
|
|
||||||
|
|
||||||
func set_max_linear_accel(value: float) -> void:
|
func set_max_linear_accel(value: float) -> void:
|
||||||
|
max_linear_accel = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
max_linear_accel = value
|
|
||||||
spawner.set_max_linear_accel(value)
|
spawner.set_max_linear_accel(value)
|
||||||
|
|
||||||
|
|
||||||
func set_proximity_radius(value: float) -> void:
|
func set_proximity_radius(value: float) -> void:
|
||||||
|
proximity_radius = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
proximity_radius = value
|
|
||||||
spawner.set_proximity_radius(value)
|
spawner.set_proximity_radius(value)
|
||||||
|
|
||||||
|
|
||||||
func set_show_proximity_radius(value: bool) -> void:
|
func set_show_proximity_radius(value: bool) -> void:
|
||||||
|
show_proximity_radius = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
show_proximity_radius = value
|
|
||||||
spawner.set_show_proximity_radius(value)
|
spawner.set_show_proximity_radius(value)
|
||||||
|
|
||||||
|
|
||||||
func set_separation_decay_coef(value: float) -> void:
|
func set_separation_decay_coef(value: float) -> void:
|
||||||
|
separation_decay_coefficient = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
separation_decay_coefficient = value
|
|
||||||
spawner.set_separation_decay_coef(value)
|
spawner.set_separation_decay_coef(value)
|
||||||
|
|
||||||
|
|
||||||
func set_cohesion_strength(value: float) -> void:
|
func set_cohesion_strength(value: float) -> void:
|
||||||
|
cohesion_strength = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
cohesion_strength = value
|
|
||||||
spawner.set_cohesion_strength(value)
|
spawner.set_cohesion_strength(value)
|
||||||
|
|
||||||
|
|
||||||
func set_separation_strength(value: float) -> void:
|
func set_separation_strength(value: float) -> void:
|
||||||
|
separation_strength = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
separation_strength = value
|
|
||||||
spawner.set_separation_strength(value)
|
spawner.set_separation_strength(value)
|
||||||
|
@ -1,13 +1,41 @@
|
|||||||
[gd_scene load_steps=4 format=2]
|
[gd_scene load_steps=5 format=2]
|
||||||
|
|
||||||
[ext_resource path="res://demos/GroupBehaviors/Member.tscn" type="PackedScene" id=1]
|
[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/Spawner.gd" type="Script" id=2]
|
||||||
[ext_resource path="res://demos/GroupBehaviors/GroupBehaviorsDemo.gd" type="Script" id=3]
|
[ext_resource path="res://demos/GroupBehaviors/GroupBehaviorsDemo.gd" type="Script" id=3]
|
||||||
|
[ext_resource path="res://assets/theme/gdquest.theme" type="Theme" id=4]
|
||||||
|
|
||||||
[node name="GroupBehaviorsDemo" type="Node2D"]
|
[node name="GroupBehaviorsDemo" type="Node2D"]
|
||||||
script = ExtResource( 3 )
|
script = ExtResource( 3 )
|
||||||
|
cohesion_strength = 0.2
|
||||||
|
separation_strength = 4.5
|
||||||
|
|
||||||
[node name="Spawner" type="Node2D" parent="."]
|
[node name="Spawner" type="Node2D" parent="."]
|
||||||
position = Vector2( 512, 300 )
|
position = Vector2( 512, 300 )
|
||||||
script = ExtResource( 2 )
|
script = ExtResource( 2 )
|
||||||
member = ExtResource( 1 )
|
member = ExtResource( 1 )
|
||||||
|
|
||||||
|
[node name="GUI" type="PanelContainer" parent="."]
|
||||||
|
margin_right = 1024.0
|
||||||
|
margin_bottom = 14.0
|
||||||
|
theme = ExtResource( 4 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="GUI"]
|
||||||
|
margin_right = 1024.0
|
||||||
|
margin_bottom = 116.0
|
||||||
|
|
||||||
|
[node name="RichTextLabel" type="RichTextLabel" parent="GUI/MarginContainer"]
|
||||||
|
margin_left = 16.0
|
||||||
|
margin_top = 16.0
|
||||||
|
margin_right = 1008.0
|
||||||
|
margin_bottom = 100.0
|
||||||
|
rect_min_size = Vector2( 0, 84 )
|
||||||
|
bbcode_enabled = true
|
||||||
|
bbcode_text = "Group Behavior Demo
|
||||||
|
Each of the \"Agents\" are both attempting to stay separated and within reach of their nearest group's center of mass."
|
||||||
|
text = "Group Behavior Demo
|
||||||
|
Each of the \"Agents\" are both attempting to stay separated and within reach of their nearest group's center of mass."
|
||||||
|
scroll_active = false
|
||||||
|
@ -40,12 +40,13 @@ func _draw() -> void:
|
|||||||
draw_circle(Vector2.ZERO, proximity.radius, Color(0, 1, 0, 0.1))
|
draw_circle(Vector2.ZERO, proximity.radius, Color(0, 1, 0, 0.1))
|
||||||
|
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
func _physics_process(delta: float) -> void:
|
||||||
agent.position.x = global_position.x
|
agent.position.x = global_position.x
|
||||||
agent.position.y = global_position.y
|
agent.position.y = global_position.y
|
||||||
if blend:
|
if blend:
|
||||||
acceleration = blend.calculate_steering(acceleration)
|
acceleration = blend.calculate_steering(acceleration)
|
||||||
_velocity += Vector2(acceleration.linear.x, acceleration.linear.y)
|
_velocity += Vector2(acceleration.linear.x, acceleration.linear.y)
|
||||||
|
_velocity = _velocity.linear_interpolate(Vector2.ZERO, 0.1)
|
||||||
_velocity = _velocity.clamped(agent.max_linear_speed)
|
_velocity = _velocity.clamped(agent.max_linear_speed)
|
||||||
move_and_slide(_velocity)
|
move_and_slide(_velocity)
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
extends Node2D
|
extends Node2D
|
||||||
# Wraps the ships' positions around the world border, and controls their rendering clones.
|
# Wraps the ships' positions around the world border.
|
||||||
|
|
||||||
|
|
||||||
var _world_bounds: Vector2
|
var _world_bounds: Vector2
|
||||||
|
@ -4,7 +4,7 @@ extends KinematicBody2D
|
|||||||
|
|
||||||
onready var agent := GSTSteeringAgent.new()
|
onready var agent := GSTSteeringAgent.new()
|
||||||
|
|
||||||
export var thruster_strength := 250.0
|
export var thruster_strength := 175.0
|
||||||
export var side_thruster_strength := 10.0
|
export var side_thruster_strength := 10.0
|
||||||
export var max_velocity := 300.0
|
export var max_velocity := 300.0
|
||||||
export var max_angular_velocity := 2.0
|
export var max_angular_velocity := 2.0
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
extends Node2D
|
extends Node2D
|
||||||
|
|
||||||
|
|
||||||
export(float, 0, 2000, 40) var max_linear_speed := 200.0 setget set_max_linear_speed
|
export(float, 0, 2000, 40) var max_linear_speed := 120.0 setget set_max_linear_speed
|
||||||
export(float, 0, 200, 1) var max_linear_accel := 10.0 setget set_max_linear_accel
|
export(float, 0, 200, 2) var max_linear_accel := 10.0 setget set_max_linear_accel
|
||||||
export(float, 0, 5, 0.1) var predict_time := 2.0 setget set_predict_time
|
export(float, 0, 5, 0.1) var predict_time := 1.0 setget set_predict_time
|
||||||
|
|
||||||
onready var pursuer := $BoundaryManager/Pursuer
|
onready var pursuer := $BoundaryManager/Pursuer
|
||||||
onready var seeker := $BoundaryManager/Seeker
|
onready var seeker := $BoundaryManager/Seeker
|
||||||
@ -15,26 +15,26 @@ func _ready() -> void:
|
|||||||
|
|
||||||
|
|
||||||
func set_max_linear_speed(value: float) -> void:
|
func set_max_linear_speed(value: float) -> void:
|
||||||
|
max_linear_speed = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
max_linear_speed = value
|
|
||||||
pursuer.agent.max_linear_speed = value
|
pursuer.agent.max_linear_speed = value
|
||||||
seeker.agent.max_linear_speed = value
|
seeker.agent.max_linear_speed = value
|
||||||
|
|
||||||
|
|
||||||
func set_max_linear_accel(value: float) -> void:
|
func set_max_linear_accel(value: float) -> void:
|
||||||
|
max_linear_accel = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
max_linear_accel = value
|
|
||||||
pursuer.agent.max_linear_acceleration = value
|
pursuer.agent.max_linear_acceleration = value
|
||||||
seeker.agent.max_linear_acceleration = value
|
seeker.agent.max_linear_acceleration = value
|
||||||
|
|
||||||
|
|
||||||
func set_predict_time(value: float) -> void:
|
func set_predict_time(value: float) -> void:
|
||||||
|
predict_time = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
predict_time = value
|
|
||||||
pursuer._behavior.max_predict_time = value
|
pursuer._behavior.max_predict_time = value
|
||||||
|
@ -12,8 +12,7 @@ script = ExtResource( 4 )
|
|||||||
__meta__ = {
|
__meta__ = {
|
||||||
"_editor_description_": "Toy demo to demonstrate the use of the Pursue contrasted to the more naive Seek steering behavior."
|
"_editor_description_": "Toy demo to demonstrate the use of the Pursue contrasted to the more naive Seek steering behavior."
|
||||||
}
|
}
|
||||||
max_linear_speed = 120.0
|
max_linear_speed = 200.0
|
||||||
predict_time = 1.0
|
|
||||||
|
|
||||||
[node name="BoundaryManager" type="Node2D" parent="."]
|
[node name="BoundaryManager" type="Node2D" parent="."]
|
||||||
script = ExtResource( 3 )
|
script = ExtResource( 3 )
|
||||||
|
@ -14,7 +14,7 @@ var _behavior: GSTSteeringBehavior
|
|||||||
var _linear_velocity := Vector2()
|
var _linear_velocity := Vector2()
|
||||||
var _linear_drag_coefficient := 0.025
|
var _linear_drag_coefficient := 0.025
|
||||||
var _angular_velocity := 0.0
|
var _angular_velocity := 0.0
|
||||||
var _angular_drag := 1.0
|
var _angular_drag := 0.1
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
@ -22,13 +22,16 @@ func _ready() -> void:
|
|||||||
|
|
||||||
|
|
||||||
func _physics_process(delta: float) -> void:
|
func _physics_process(delta: float) -> void:
|
||||||
|
_update_agent()
|
||||||
|
|
||||||
accel = _orient_behavior.calculate_steering(accel)
|
accel = _orient_behavior.calculate_steering(accel)
|
||||||
_angular_velocity += accel.angular
|
_angular_velocity += accel.angular
|
||||||
|
|
||||||
if _angular_velocity < 0:
|
_angular_velocity = clamp(
|
||||||
_angular_velocity += _angular_drag * delta
|
lerp(_angular_velocity, 0, _angular_drag),
|
||||||
elif _angular_velocity > 0:
|
-agent.max_angular_speed,
|
||||||
_angular_velocity -= _angular_drag * delta
|
agent.max_angular_speed
|
||||||
|
)
|
||||||
|
|
||||||
rotation += _angular_velocity * delta
|
rotation += _angular_velocity * delta
|
||||||
|
|
||||||
@ -37,8 +40,6 @@ func _physics_process(delta: float) -> void:
|
|||||||
_linear_velocity = _linear_velocity.linear_interpolate(Vector2.ZERO, _linear_drag_coefficient)
|
_linear_velocity = _linear_velocity.linear_interpolate(Vector2.ZERO, _linear_drag_coefficient)
|
||||||
_linear_velocity = _linear_velocity.clamped(agent.max_linear_speed)
|
_linear_velocity = _linear_velocity.clamped(agent.max_linear_speed)
|
||||||
_linear_velocity = move_and_slide(_linear_velocity)
|
_linear_velocity = move_and_slide(_linear_velocity)
|
||||||
|
|
||||||
_update_agent()
|
|
||||||
|
|
||||||
|
|
||||||
func setup(predict_time: float, max_linear_speed: float, max_linear_accel: float) -> void:
|
func setup(predict_time: float, max_linear_speed: float, max_linear_accel: float) -> void:
|
||||||
|
@ -43,10 +43,10 @@ func _ready() -> void:
|
|||||||
|
|
||||||
|
|
||||||
func set_behavior_mode(mode: int) -> void:
|
func set_behavior_mode(mode: int) -> void:
|
||||||
|
behavior_mode = mode
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
behavior_mode = mode
|
|
||||||
match mode:
|
match mode:
|
||||||
Mode.SEEK:
|
Mode.SEEK:
|
||||||
for child in spawner.get_children():
|
for child in spawner.get_children():
|
||||||
@ -57,26 +57,26 @@ func set_behavior_mode(mode: int) -> void:
|
|||||||
|
|
||||||
|
|
||||||
func set_max_linear_speed(value: float) -> void:
|
func set_max_linear_speed(value: float) -> void:
|
||||||
|
max_linear_speed = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
max_linear_speed = value
|
|
||||||
for child in spawner.get_children():
|
for child in spawner.get_children():
|
||||||
child.agent.max_linear_speed = value
|
child.agent.max_linear_speed = value
|
||||||
|
|
||||||
|
|
||||||
func set_max_linear_accel(value: float) -> void:
|
func set_max_linear_accel(value: float) -> void:
|
||||||
|
max_linear_accel = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
max_linear_accel = value
|
|
||||||
for child in spawner.get_children():
|
for child in spawner.get_children():
|
||||||
child.agent.max_linear_acceleration = value
|
child.agent.max_linear_acceleration = value
|
||||||
|
|
||||||
|
|
||||||
func set_player_speed(value: float) -> void:
|
func set_player_speed(value: float) -> void:
|
||||||
|
player_speed = value
|
||||||
if not is_inside_tree():
|
if not is_inside_tree():
|
||||||
return
|
return
|
||||||
|
|
||||||
player_speed = value
|
|
||||||
player.speed = player_speed
|
player.speed = player_speed
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
extends GSTSteeringBehavior
|
|
||||||
class_name GSTArrive
|
class_name GSTArrive
|
||||||
|
extends GSTSteeringBehavior
|
||||||
# Calculates acceleration to take an agent to its target's location.
|
# Calculates acceleration to take an agent to its target's location.
|
||||||
# The calculation will attempt to arrive with zero remaining velocity.
|
# The calculation will attempt to arrive with zero remaining velocity.
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
extends GSTGroupBehavior
|
|
||||||
class_name GSTAvoidCollisions
|
class_name GSTAvoidCollisions
|
||||||
# Behavior that steers the agent to avoid obstacles lying in its path, approximated by a sphere.
|
extends GSTGroupBehavior
|
||||||
|
# Behavior that steers the agent to avoid obstacles lying in its path as approximated by a sphere.
|
||||||
|
|
||||||
|
|
||||||
var first_neighbor: GSTSteeringAgent
|
var first_neighbor: GSTSteeringAgent
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
extends GSTSteeringBehavior
|
|
||||||
class_name GSTBlend
|
class_name GSTBlend
|
||||||
|
extends GSTSteeringBehavior
|
||||||
# Blends multiple steering behaviors into one, and returns acceleration combining all of them.
|
# Blends multiple steering behaviors into one, and returns acceleration combining all of them.
|
||||||
|
|
||||||
# # Each behavior is associated with a weight - a modifier by which the result will be multiplied by,
|
# # Each behavior is associated with a weight - a modifier by which the result will be multiplied by,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
extends GSTGroupBehavior
|
|
||||||
class_name GSTCohesion
|
class_name GSTCohesion
|
||||||
|
extends GSTGroupBehavior
|
||||||
# Group behavior that produces linear acceleration that attempts to move the agent towards the
|
# Group behavior that produces linear acceleration that attempts to move the agent towards the
|
||||||
# center of mass of the agents in the area defined by the defined Proximity.
|
# center of mass of the agents in the area defined by the defined Proximity.
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
extends GSTPursue
|
|
||||||
class_name GSTEvade
|
class_name GSTEvade
|
||||||
|
extends GSTPursue
|
||||||
# Calculates acceleration to take an agent away from where a target agent will be.
|
# Calculates acceleration to take an agent away from where a target agent will be.
|
||||||
|
|
||||||
# # The `max_predict_time` variable represents how far ahead to calculate the intersection point.
|
# # The `max_predict_time` variable represents how far ahead to calculate the intersection point.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
extends GSTMatchOrientation
|
|
||||||
class_name GSTFace
|
class_name GSTFace
|
||||||
|
extends GSTMatchOrientation
|
||||||
# Calculates angular acceleration to rotate a target to face its target's position.
|
# Calculates angular acceleration to rotate a target to face its target's position.
|
||||||
# The acceleration will attempt to arrive with zero remaining angular velocity.
|
# The acceleration will attempt to arrive with zero remaining angular velocity.
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
extends GSTSeek
|
|
||||||
class_name GSTFlee
|
class_name GSTFlee
|
||||||
|
extends GSTSeek
|
||||||
# Calculates acceleration to take an agent directly away from a target agent.
|
# Calculates acceleration to take an agent directly away from a target agent.
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
extends GSTArrive
|
|
||||||
class_name GSTFollowPath
|
class_name GSTFollowPath
|
||||||
|
extends GSTArrive
|
||||||
# Produces a linear acceleration that moves the agent along the specified path.
|
# Produces a linear acceleration that moves the agent along the specified path.
|
||||||
|
|
||||||
|
|
||||||
var path: GSTPath
|
var path: GSTPath
|
||||||
var path_offset := 0.0
|
var path_offset := 0.0
|
||||||
|
|
||||||
var path_param := {}
|
var path_param := {segment_index = 0, distance = 0}
|
||||||
|
|
||||||
var arrive_enabled := true
|
var arrive_enabled := true
|
||||||
var prediction_time := 0.0
|
var prediction_time := 0.0
|
||||||
@ -32,7 +32,7 @@ func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAccele
|
|||||||
|
|
||||||
var target_position := path.calculate_target_position(path_param, target_distance)
|
var target_position := path.calculate_target_position(path_param, target_distance)
|
||||||
|
|
||||||
if arrive_enabled and path.is_open:
|
if arrive_enabled and path.open:
|
||||||
if path_offset >= 0:
|
if path_offset >= 0:
|
||||||
if target_distance > path.length - deceleration_radius:
|
if target_distance > path.length - deceleration_radius:
|
||||||
return _arrive(acceleration, target_position)
|
return _arrive(acceleration, target_position)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
extends GSTMatchOrientation
|
|
||||||
class_name GSTLookWhereYouGo
|
class_name GSTLookWhereYouGo
|
||||||
|
extends GSTMatchOrientation
|
||||||
# Calculates an angular acceleration to match an agent's orientation to its direction of travel.
|
# Calculates an angular acceleration to match an agent's orientation to its direction of travel.
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
extends GSTSteeringBehavior
|
|
||||||
class_name GSTMatchOrientation
|
class_name GSTMatchOrientation
|
||||||
|
extends GSTSteeringBehavior
|
||||||
# Calculates an angular acceleration to match an agent's orientation to its target's.
|
# Calculates an angular acceleration to match an agent's orientation to its target's.
|
||||||
# The calculation will attempt to arrive with zero remaining angular velocity.
|
# The calculation will attempt to arrive with zero remaining angular velocity.
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
extends GSTSteeringBehavior
|
|
||||||
class_name GSTPriority
|
class_name GSTPriority
|
||||||
|
extends GSTSteeringBehavior
|
||||||
# Contains multiple steering behaviors and returns only the result of the first that has a non-zero
|
# Contains multiple steering behaviors and returns only the result of the first that has a non-zero
|
||||||
# acceleration.
|
# acceleration.
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
extends GSTSteeringBehavior
|
|
||||||
class_name GSTPursue
|
class_name GSTPursue
|
||||||
|
extends GSTSteeringBehavior
|
||||||
# Calculates acceleration to take an agent to intersect with where a target agent will be.
|
# Calculates acceleration to take an agent to intersect with where a target agent will be.
|
||||||
|
|
||||||
# # The `max_predict_time` variable represents how far ahead to calculate the intersection point.
|
# # The `max_predict_time` variable represents how far ahead to calculate the intersection point.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
extends GSTSteeringBehavior
|
|
||||||
class_name GSTSeek
|
class_name GSTSeek
|
||||||
|
extends GSTSteeringBehavior
|
||||||
# Calculates acceleration to take an agent to a target agent's position as directly as possible
|
# Calculates acceleration to take an agent to a target agent's position as directly as possible
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
extends GSTGroupBehavior
|
|
||||||
class_name GSTSeparation
|
class_name GSTSeparation
|
||||||
|
extends GSTGroupBehavior
|
||||||
# Group behavior that produces acceleration repelling from the other neighbors that are in the
|
# Group behavior that produces acceleration repelling from the other neighbors that are in the
|
||||||
# immediate area defined by the given `GSTProximity`.
|
# immediate area defined by the given `GSTProximity`.
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ class_name GSTPath
|
|||||||
|
|
||||||
|
|
||||||
var open: bool
|
var open: bool
|
||||||
var path_length: float
|
var length: float
|
||||||
|
|
||||||
var _segments: Array
|
var _segments: Array
|
||||||
|
|
||||||
@ -25,10 +25,11 @@ func _init(waypoints: Array, open := false) -> void:
|
|||||||
func create_path(waypoints: Array) -> void:
|
func create_path(waypoints: Array) -> void:
|
||||||
if not waypoints or waypoints.size() < 2:
|
if not waypoints or waypoints.size() < 2:
|
||||||
printerr("Waypoints cannot be null and must contain at least two (2) waypoints.")
|
printerr("Waypoints cannot be null and must contain at least two (2) waypoints.")
|
||||||
|
return
|
||||||
|
|
||||||
_segments = []
|
_segments = []
|
||||||
path_length = 0
|
length = 0
|
||||||
var current: Vector3 = _segments[0]
|
var current: Vector3 = waypoints.front()
|
||||||
var previous: Vector3
|
var previous: Vector3
|
||||||
|
|
||||||
for i in range(1, waypoints.size(), 1):
|
for i in range(1, waypoints.size(), 1):
|
||||||
@ -40,12 +41,14 @@ func create_path(waypoints: Array) -> void:
|
|||||||
else:
|
else:
|
||||||
current = waypoints[0]
|
current = waypoints[0]
|
||||||
var segment := GSTSegment.new(previous, current)
|
var segment := GSTSegment.new(previous, current)
|
||||||
path_length += segment.length
|
length += segment.length
|
||||||
segment.cumulative_length = path_length
|
segment.cumulative_length = length
|
||||||
_segments.append(segment)
|
_segments.append(segment)
|
||||||
|
|
||||||
|
|
||||||
func calculate_distance(agent_current_position: Vector3, path_parameter: Dictionary) -> float:
|
func calculate_distance(agent_current_position: Vector3, path_parameter: Dictionary) -> float:
|
||||||
|
if _segments.size() == 0:
|
||||||
|
return 0.0
|
||||||
var smallest_distance_squared: float = INF
|
var smallest_distance_squared: float = INF
|
||||||
var nearest_segment: GSTSegment
|
var nearest_segment: GSTSegment
|
||||||
for i in range(_segments.size()):
|
for i in range(_segments.size()):
|
||||||
@ -53,7 +56,8 @@ func calculate_distance(agent_current_position: Vector3, path_parameter: Diction
|
|||||||
var distance_squared := _calculate_point_segment_distance_squared(
|
var distance_squared := _calculate_point_segment_distance_squared(
|
||||||
segment.begin,
|
segment.begin,
|
||||||
segment.end,
|
segment.end,
|
||||||
agent_current_position)
|
agent_current_position
|
||||||
|
)
|
||||||
|
|
||||||
if distance_squared < smallest_distance_squared:
|
if distance_squared < smallest_distance_squared:
|
||||||
_nearest_point_on_path = _nearest_point_on_segment
|
_nearest_point_on_path = _nearest_point_on_segment
|
||||||
@ -72,12 +76,12 @@ func calculate_distance(agent_current_position: Vector3, path_parameter: Diction
|
|||||||
|
|
||||||
func calculate_target_position(param: Dictionary, target_distance: float) -> Vector3:
|
func calculate_target_position(param: Dictionary, target_distance: float) -> Vector3:
|
||||||
if open:
|
if open:
|
||||||
target_distance = clamp(target_distance, 0, path_length)
|
target_distance = clamp(target_distance, 0, length)
|
||||||
else:
|
else:
|
||||||
if target_distance < 0:
|
if target_distance < 0:
|
||||||
target_distance = path_length + fmod(target_distance, path_length)
|
target_distance = length + fmod(target_distance, length)
|
||||||
elif target_distance > path_length:
|
elif target_distance > length:
|
||||||
target_distance = fmod(target_distance, path_length)
|
target_distance = fmod(target_distance, length)
|
||||||
|
|
||||||
var desired_segment: GSTSegment
|
var desired_segment: GSTSegment
|
||||||
for i in range(_segments.size()):
|
for i in range(_segments.size()):
|
||||||
@ -86,6 +90,9 @@ func calculate_target_position(param: Dictionary, target_distance: float) -> Vec
|
|||||||
desired_segment = segment
|
desired_segment = segment
|
||||||
break
|
break
|
||||||
|
|
||||||
|
if not desired_segment:
|
||||||
|
desired_segment = _segments.back()
|
||||||
|
|
||||||
var distance := desired_segment.cumulative_length - target_distance
|
var distance := desired_segment.cumulative_length - target_distance
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
Loading…
Reference in New Issue
Block a user