Add avoid collisions demo

This commit is contained in:
Francois Belair 2020-01-16 17:14:50 -05:00
parent 6e6f27505c
commit dffec9efa6
20 changed files with 279 additions and 15 deletions

View 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)

View 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

View 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(rand_range(-1, 1), rand_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

View 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 )

View 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()

View File

@ -161,6 +161,10 @@ _global_script_class_icons={
config/name="SteeringToolkit"
config/icon="res://icon.png"
[display]
window/size/always_on_top=true
[input]
sf_left={

View File

@ -1,5 +1,5 @@
extends GSTSteeringBehavior
class_name GSTArrive
extends GSTSteeringBehavior
# Calculates acceleration to take an agent to its target's location.
# The calculation will attempt to arrive with zero remaining velocity.

View File

@ -1,6 +1,6 @@
extends GSTGroupBehavior
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

View File

@ -1,5 +1,5 @@
extends GSTSteeringBehavior
class_name GSTBlend
extends GSTSteeringBehavior
# 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,

View File

@ -1,5 +1,5 @@
extends GSTGroupBehavior
class_name GSTCohesion
extends GSTGroupBehavior
# 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.

View File

@ -1,5 +1,5 @@
extends GSTPursue
class_name GSTEvade
extends GSTPursue
# 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.

View File

@ -1,5 +1,5 @@
extends GSTMatchOrientation
class_name GSTFace
extends GSTMatchOrientation
# Calculates angular acceleration to rotate a target to face its target's position.
# The acceleration will attempt to arrive with zero remaining angular velocity.

View File

@ -1,5 +1,5 @@
extends GSTSeek
class_name GSTFlee
extends GSTSeek
# Calculates acceleration to take an agent directly away from a target agent.

View File

@ -1,5 +1,5 @@
extends GSTArrive
class_name GSTFollowPath
extends GSTArrive
# Produces a linear acceleration that moves the agent along the specified path.

View File

@ -1,5 +1,5 @@
extends GSTMatchOrientation
class_name GSTLookWhereYouGo
extends GSTMatchOrientation
# Calculates an angular acceleration to match an agent's orientation to its direction of travel.

View File

@ -1,5 +1,5 @@
extends GSTSteeringBehavior
class_name GSTMatchOrientation
extends GSTSteeringBehavior
# 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.

View File

@ -1,5 +1,5 @@
extends GSTSteeringBehavior
class_name GSTPriority
extends GSTSteeringBehavior
# Contains multiple steering behaviors and returns only the result of the first that has a non-zero
# acceleration.

View File

@ -1,5 +1,5 @@
extends GSTSteeringBehavior
class_name GSTPursue
extends GSTSteeringBehavior
# 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.

View File

@ -1,5 +1,5 @@
extends GSTSteeringBehavior
class_name GSTSeek
extends GSTSteeringBehavior
# Calculates acceleration to take an agent to a target agent's position as directly as possible

View File

@ -1,5 +1,5 @@
extends GSTGroupBehavior
class_name GSTSeparation
extends GSTGroupBehavior
# Group behavior that produces acceleration repelling from the other neighbors that are in the
# immediate area defined by the given `GSTProximity`.