Add extra behaviours (wind, magnet, perching)
This commit is contained in:
parent
957d6f97f1
commit
c996fbf24b
|
@ -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="."]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue