Add extra behaviours (wind, magnet, perching)

This commit is contained in:
rodolpheh 2023-10-15 22:07:35 +01:00
parent 957d6f97f1
commit c996fbf24b
4 changed files with 95 additions and 15 deletions

View File

@ -20,8 +20,8 @@ sky_material = SubResource("ProceduralSkyMaterial_d6oc0")
background_mode = 2
sky = SubResource("Sky_ggc3l")
[sub_resource type="CylinderShape3D" id="CylinderShape3D_s5kna"]
radius = 5.0
[sub_resource type="BoxShape3D" id="BoxShape3D_7ll4w"]
size = Vector3(5, 5, 5)
[sub_resource type="PlaneMesh" id="PlaneMesh_usmhe"]
size = Vector2(25, 25)
@ -45,8 +45,8 @@ transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 2,
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_ptyca")
[node name="Boids" type="Node3D" parent="." node_paths=PackedStringArray("resources")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 5, 0)
[node name="Boids" type="Node3D" parent="." node_paths=PackedStringArray("resources", "target")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, 0)
script = ExtResource("1_v84o5")
resources = NodePath("../ResourcePreloader")
start_count = 20
@ -57,7 +57,11 @@ avoid_factor = 1.0
matching_factor = 0.02
min_speed = 5.0
max_speed = 10.0
shape = SubResource("CylinderShape3D_s5kna")
shape = SubResource("BoxShape3D_7ll4w")
enable_wind = true
wind_velocity = Vector3(-2, 0, 0)
target = NodePath("../Magnet")
enable_perching = true
[node name="ResourcePreloader" type="ResourcePreloader" parent="."]
resources = [PackedStringArray("Boid", "Seagull", "SeagullTwo"), [ExtResource("2_did81"), ExtResource("3_4pkn6"), ExtResource("4_4rbpg")]]
@ -84,5 +88,8 @@ layout_mode = 2
text = "Touch events:"
[node name="CSGMesh3D" type="CSGMesh3D" parent="."]
visible = false
material_override = ExtResource("6_7a1uq")
mesh = SubResource("PlaneMesh_usmhe")
[node name="Magnet" type="Node3D" parent="."]

View File

@ -5,6 +5,9 @@ class_name Boid
@export var min_timer : float = 5
var velocity : Vector3 = Vector3(0, 0, 0)
var is_perching : bool = false
var perching_timer : Timer = Timer.new()
func _ready():
$Timer.wait_time = randf_range(min_timer, max_timer)
@ -18,3 +21,21 @@ func _on_timer_timeout():
$SeagullSound2.play()
else:
$SeagullSound1.play()
func start_perching(min_perch_time : float, max_perch_time : float):
if is_perching:
return
if not perching_timer.timeout.is_connected(stop_perching):
add_child(perching_timer)
perching_timer.one_shot = true
perching_timer.timeout.connect(stop_perching)
is_perching = true
velocity = Vector3.UP
perching_timer.wait_time = randf_range(min_perch_time, max_perch_time)
perching_timer.start()
func stop_perching():
perching_timer.stop()
is_perching = false

View File

@ -1,5 +1,7 @@
extends Node3D
# Cool resources : http://www.kfish.org/boids/pseudocode.html
@export var resources : ResourcePreloader
@export_subgroup("Initialisation")
@ -29,6 +31,23 @@ extends Node3D
@export var gravity_vector : Vector3 = Vector3(0, -9.807, 0)
@export var gravity_factor : float = 0.1
@export_subgroup("Wind")
@export var enable_wind : bool = false
@export var wind_velocity : Vector3 = Vector3.LEFT
@export_subgroup("Magnet")
@export var enable_magnet : bool = false
@export var target : Node3D
@export var magnet_factor : float = 1.0
@export_subgroup("Perching")
@export var enable_perching : bool = false
@export var perching_max_time : float = 5.0
@export var perching_min_time : float = 3.0
var boids : Array[Boid]
var boid_scene : PackedScene
@ -53,6 +72,15 @@ func _ready():
func _process(delta):
for boid in boids:
# Perching strategy, only works if magnet not enabled
if boid.global_position.y < 0 and enable_perching and not enable_magnet:
boid.global_position.y = 0
boid.start_perching(perching_min_time, perching_max_time)
# Go to next boid if this one is perching, a timer on the boid will unperch it after some time
if boid.is_perching:
continue
var neighboring_boids : int = 0
var close : Vector3 = Vector3.ZERO
@ -86,18 +114,39 @@ func _process(delta):
position_avg /= neighboring_boids
velocity_avg /= neighboring_boids
boid.velocity = (boid.velocity +
(position_avg - boid.position) * centering_factor +
(velocity_avg - boid.velocity) * matching_factor
)
# rule 1 : cohesion
# position_avg is the center of mass of other boids in view
var cohesion_velocity : Vector3 = (position_avg - boid.position) * centering_factor
# rule 2 : alignment
# velocity_avg is the "perceived velocity" of other boids in view
var alignment_velocity : Vector3 = (velocity_avg - boid.velocity) * matching_factor
boid.velocity = (boid.velocity +
cohesion_velocity +
alignment_velocity
)
# rule 3 : avoidance
# Add avoidance contribution to velocity
boid.velocity = boid.velocity + (close * avoid_factor)
# Edge avoidance
boid.velocity = apply_edge_avoidance(boid.position, boid.velocity)
# Gravity
if use_gravity:
boid.velocity = apply_gravity(boid.velocity, delta)
boid.velocity = apply_gravity(boid.velocity, delta)
# Wind
if enable_wind:
boid.velocity += wind_velocity * delta
# Magnet
if enable_magnet and target != null:
boid.velocity += (target.global_position - boid.global_position).normalized()
# Speed limits
boid.velocity = apply_speed_limits(boid.velocity)
# Update position, finally!
@ -161,9 +210,7 @@ func apply_sphere_edge_avoidance(position : Vector3, velocity : Vector3, sphere
func apply_gravity(velocity : Vector3, delta : float) -> Vector3:
if use_gravity:
velocity += gravity_vector * gravity_factor * delta
velocity += gravity_vector * gravity_factor * delta
return velocity

View File

@ -23,6 +23,11 @@ func _process(delta):
func _unhandled_input(event):
if event is InputEventMouseButton:
if event.button_index == MouseButton.MOUSE_BUTTON_WHEEL_UP:
$Tilt/Camera3D.position.z -= 0.1
elif event.button_index == MouseButton.MOUSE_BUTTON_WHEEL_DOWN:
$Tilt/Camera3D.position.z += 0.1
if event is InputEventScreenTouch:
if event.pressed:
events[event.index] = event
@ -42,6 +47,6 @@ func _unhandled_input(event):
drag_label.text = "Drag distance: {dist}".format({"dist": drag_distance})
if abs(drag_distance - last_drag_distance) > zoom_sensitivity:
var new_zoom = zoom_speed if drag_distance < last_drag_distance else zoom_speed
new_zoom = clamp($Camera3D.position.z + new_zoom, min_zoom, max_zoom)
$Camera3D.position.z = new_zoom
new_zoom = clamp($Tilt/Camera3D.position.z + new_zoom, min_zoom, max_zoom)
$Tilt/Camera3D.position.z = new_zoom
last_drag_distance = drag_distance