commit 957d6f97f14de97a9c27e898141f25dc4db8fbc8 Author: Rodolphe Houdas Date: Thu Oct 5 22:49:04 2023 +0100 Dump project so far diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8ad74f7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Normalize EOL for all files that Git considers text files. +* text=auto eol=lf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4807767 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +# Godot 4+ specific ignores +.godot/ +android/ +builds/ \ No newline at end of file diff --git a/audio/263786__steaq__seagull-single-call.ogg b/audio/263786__steaq__seagull-single-call.ogg new file mode 100644 index 0000000..6bd637e Binary files /dev/null and b/audio/263786__steaq__seagull-single-call.ogg differ diff --git a/audio/263786__steaq__seagull-single-call.ogg.import b/audio/263786__steaq__seagull-single-call.ogg.import new file mode 100644 index 0000000..dd9fe4f --- /dev/null +++ b/audio/263786__steaq__seagull-single-call.ogg.import @@ -0,0 +1,19 @@ +[remap] + +importer="oggvorbisstr" +type="AudioStreamOggVorbis" +uid="uid://bqu3h3gaj6eqr" +path="res://.godot/imported/263786__steaq__seagull-single-call.ogg-b5ba7a89fd68ec1083d6e14132014866.oggvorbisstr" + +[deps] + +source_file="res://audio/263786__steaq__seagull-single-call.ogg" +dest_files=["res://.godot/imported/263786__steaq__seagull-single-call.ogg-b5ba7a89fd68ec1083d6e14132014866.oggvorbisstr"] + +[params] + +loop=false +loop_offset=0 +bpm=0 +beat_count=0 +bar_beats=4 diff --git a/audio/468245__christianand__1_1_gaviota.wav b/audio/468245__christianand__1_1_gaviota.wav new file mode 100644 index 0000000..7d7f11b Binary files /dev/null and b/audio/468245__christianand__1_1_gaviota.wav differ diff --git a/audio/468245__christianand__1_1_gaviota.wav.import b/audio/468245__christianand__1_1_gaviota.wav.import new file mode 100644 index 0000000..7965a78 --- /dev/null +++ b/audio/468245__christianand__1_1_gaviota.wav.import @@ -0,0 +1,24 @@ +[remap] + +importer="wav" +type="AudioStreamWAV" +uid="uid://cqetbevo485vt" +path="res://.godot/imported/468245__christianand__1_1_gaviota.wav-3e3a11453f0d4f55c9940cba021d8af8.sample" + +[deps] + +source_file="res://audio/468245__christianand__1_1_gaviota.wav" +dest_files=["res://.godot/imported/468245__christianand__1_1_gaviota.wav-3e3a11453f0d4f55c9940cba021d8af8.sample"] + +[params] + +force/8_bit=false +force/mono=false +force/max_rate=false +force/max_rate_hz=44100 +edit/trim=false +edit/normalize=false +edit/loop_mode=0 +edit/loop_begin=0 +edit/loop_end=-1 +compress/mode=0 diff --git a/export_presets.cfg b/export_presets.cfg new file mode 100644 index 0000000..cea26c9 --- /dev/null +++ b/export_presets.cfg @@ -0,0 +1,201 @@ +[preset.0] + +name="Android" +platform="Android" +runnable=true +dedicated_server=false +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="builds/Boids.apk" +encryption_include_filters="" +encryption_exclude_filters="" +encrypt_pck=false +encrypt_directory=false + +[preset.0.options] + +custom_template/debug="" +custom_template/release="" +gradle_build/use_gradle_build=false +gradle_build/export_format=0 +gradle_build/min_sdk="" +gradle_build/target_sdk="" +architectures/armeabi-v7a=false +architectures/arm64-v8a=true +architectures/x86=false +architectures/x86_64=false +version/code=1 +version/name="" +package/unique_name="com.example.$genname" +package/name="" +package/signed=true +package/app_category=2 +package/retain_data_on_uninstall=false +package/exclude_from_recents=false +package/show_in_android_tv=false +package/show_in_app_library=true +package/show_as_launcher_app=false +launcher_icons/main_192x192="" +launcher_icons/adaptive_foreground_432x432="" +launcher_icons/adaptive_background_432x432="" +graphics/opengl_debug=false +xr_features/xr_mode=0 +screen/immersive_mode=true +screen/support_small=true +screen/support_normal=true +screen/support_large=true +screen/support_xlarge=true +user_data_backup/allow=false +command_line/extra_args="" +apk_expansion/enable=false +apk_expansion/SALT="" +apk_expansion/public_key="" +permissions/custom_permissions=PackedStringArray() +permissions/access_checkin_properties=false +permissions/access_coarse_location=false +permissions/access_fine_location=false +permissions/access_location_extra_commands=false +permissions/access_mock_location=false +permissions/access_network_state=false +permissions/access_surface_flinger=false +permissions/access_wifi_state=false +permissions/account_manager=false +permissions/add_voicemail=false +permissions/authenticate_accounts=false +permissions/battery_stats=false +permissions/bind_accessibility_service=false +permissions/bind_appwidget=false +permissions/bind_device_admin=false +permissions/bind_input_method=false +permissions/bind_nfc_service=false +permissions/bind_notification_listener_service=false +permissions/bind_print_service=false +permissions/bind_remoteviews=false +permissions/bind_text_service=false +permissions/bind_vpn_service=false +permissions/bind_wallpaper=false +permissions/bluetooth=false +permissions/bluetooth_admin=false +permissions/bluetooth_privileged=false +permissions/brick=false +permissions/broadcast_package_removed=false +permissions/broadcast_sms=false +permissions/broadcast_sticky=false +permissions/broadcast_wap_push=false +permissions/call_phone=false +permissions/call_privileged=false +permissions/camera=false +permissions/capture_audio_output=false +permissions/capture_secure_video_output=false +permissions/capture_video_output=false +permissions/change_component_enabled_state=false +permissions/change_configuration=false +permissions/change_network_state=false +permissions/change_wifi_multicast_state=false +permissions/change_wifi_state=false +permissions/clear_app_cache=false +permissions/clear_app_user_data=false +permissions/control_location_updates=false +permissions/delete_cache_files=false +permissions/delete_packages=false +permissions/device_power=false +permissions/diagnostic=false +permissions/disable_keyguard=false +permissions/dump=false +permissions/expand_status_bar=false +permissions/factory_test=false +permissions/flashlight=false +permissions/force_back=false +permissions/get_accounts=false +permissions/get_package_size=false +permissions/get_tasks=false +permissions/get_top_activity_info=false +permissions/global_search=false +permissions/hardware_test=false +permissions/inject_events=false +permissions/install_location_provider=false +permissions/install_packages=false +permissions/install_shortcut=false +permissions/internal_system_window=false +permissions/internet=false +permissions/kill_background_processes=false +permissions/location_hardware=false +permissions/manage_accounts=false +permissions/manage_app_tokens=false +permissions/manage_documents=false +permissions/manage_external_storage=false +permissions/master_clear=false +permissions/media_content_control=false +permissions/modify_audio_settings=false +permissions/modify_phone_state=false +permissions/mount_format_filesystems=false +permissions/mount_unmount_filesystems=false +permissions/nfc=false +permissions/persistent_activity=false +permissions/process_outgoing_calls=false +permissions/read_calendar=false +permissions/read_call_log=false +permissions/read_contacts=false +permissions/read_external_storage=false +permissions/read_frame_buffer=false +permissions/read_history_bookmarks=false +permissions/read_input_state=false +permissions/read_logs=false +permissions/read_phone_state=false +permissions/read_profile=false +permissions/read_sms=false +permissions/read_social_stream=false +permissions/read_sync_settings=false +permissions/read_sync_stats=false +permissions/read_user_dictionary=false +permissions/reboot=false +permissions/receive_boot_completed=false +permissions/receive_mms=false +permissions/receive_sms=false +permissions/receive_wap_push=false +permissions/record_audio=false +permissions/reorder_tasks=false +permissions/restart_packages=false +permissions/send_respond_via_message=false +permissions/send_sms=false +permissions/set_activity_watcher=false +permissions/set_alarm=false +permissions/set_always_finish=false +permissions/set_animation_scale=false +permissions/set_debug_app=false +permissions/set_orientation=false +permissions/set_pointer_speed=false +permissions/set_preferred_applications=false +permissions/set_process_limit=false +permissions/set_time=false +permissions/set_time_zone=false +permissions/set_wallpaper=false +permissions/set_wallpaper_hints=false +permissions/signal_persistent_processes=false +permissions/status_bar=false +permissions/subscribed_feeds_read=false +permissions/subscribed_feeds_write=false +permissions/system_alert_window=false +permissions/transmit_ir=false +permissions/uninstall_shortcut=false +permissions/update_device_stats=false +permissions/use_credentials=false +permissions/use_sip=false +permissions/vibrate=false +permissions/wake_lock=false +permissions/write_apn_settings=false +permissions/write_calendar=false +permissions/write_call_log=false +permissions/write_contacts=false +permissions/write_external_storage=false +permissions/write_gservices=false +permissions/write_history_bookmarks=false +permissions/write_profile=false +permissions/write_secure_settings=false +permissions/write_settings=false +permissions/write_sms=false +permissions/write_social_stream=false +permissions/write_sync_settings=false +permissions/write_user_dictionary=false diff --git a/icon.svg b/icon.svg new file mode 100644 index 0000000..b370ceb --- /dev/null +++ b/icon.svg @@ -0,0 +1 @@ + diff --git a/icon.svg.import b/icon.svg.import new file mode 100644 index 0000000..c7821fc --- /dev/null +++ b/icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://fd8hv8pnk3yh" +path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.svg" +dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/materials/Floor.tres b/materials/Floor.tres new file mode 100644 index 0000000..f2f2e9a --- /dev/null +++ b/materials/Floor.tres @@ -0,0 +1,16 @@ +[gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://bstu27rlas6p3"] + +[sub_resource type="Gradient" id="Gradient_xinc1"] +offsets = PackedFloat32Array(0, 0.673759, 1) +colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_ufltb"] +gradient = SubResource("Gradient_xinc1") +width = 1080 +height = 1080 +fill = 1 +fill_from = Vector2(0.5, 0.5) + +[resource] +transparency = 1 +albedo_texture = SubResource("GradientTexture2D_ufltb") diff --git a/models/Flying gull.glb b/models/Flying gull.glb new file mode 100644 index 0000000..70ed473 Binary files /dev/null and b/models/Flying gull.glb differ diff --git a/models/Flying gull.glb.import b/models/Flying gull.glb.import new file mode 100644 index 0000000..8cf8b33 --- /dev/null +++ b/models/Flying gull.glb.import @@ -0,0 +1,32 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://cqxgihqmydjne" +path="res://.godot/imported/Flying gull.glb-506646a523b2aedea32925cfeeaf86f8.scn" + +[deps] + +source_file="res://models/Flying gull.glb" +dest_files=["res://.godot/imported/Flying gull.glb-506646a523b2aedea32925cfeeaf86f8.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/apply_root_scale=true +nodes/root_scale=0.01 +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +import_script/path="" +_subresources={} +gltf/embedded_image_handling=1 diff --git a/models/Flying gull_Gull tex1.png b/models/Flying gull_Gull tex1.png new file mode 100644 index 0000000..a620a72 Binary files /dev/null and b/models/Flying gull_Gull tex1.png differ diff --git a/models/Flying gull_Gull tex1.png.import b/models/Flying gull_Gull tex1.png.import new file mode 100644 index 0000000..503347f --- /dev/null +++ b/models/Flying gull_Gull tex1.png.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cdg8likswgkmq" +path.s3tc="res://.godot/imported/Flying gull_Gull tex1.png-a95c50707d425b143a8393cd99cc0da3.s3tc.ctex" +path.etc2="res://.godot/imported/Flying gull_Gull tex1.png-a95c50707d425b143a8393cd99cc0da3.etc2.ctex" +metadata={ +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true +} +generator_parameters={} + +[deps] + +source_file="res://models/Flying gull_Gull tex1.png" +dest_files=["res://.godot/imported/Flying gull_Gull tex1.png-a95c50707d425b143a8393cd99cc0da3.s3tc.ctex", "res://.godot/imported/Flying gull_Gull tex1.png-a95c50707d425b143a8393cd99cc0da3.etc2.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/project.godot b/project.godot new file mode 100644 index 0000000..30d0e5b --- /dev/null +++ b/project.godot @@ -0,0 +1,24 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=5 + +[application] + +config/name="Boids" +run/main_scene="res://scenes/Main.tscn" +config/features=PackedStringArray("4.1", "Forward Plus") +config/icon="res://icon.svg" + +[input_devices] + +pointing/emulate_touch_from_mouse=true + +[rendering] + +textures/vram_compression/import_etc2_astc=true diff --git a/scenes/Boid.tscn b/scenes/Boid.tscn new file mode 100644 index 0000000..9b4aee4 --- /dev/null +++ b/scenes/Boid.tscn @@ -0,0 +1,24 @@ +[gd_scene load_steps=5 format=3 uid="uid://bi3r8vqt5ykrt"] + +[ext_resource type="PackedScene" uid="uid://cqxgihqmydjne" path="res://models/Flying gull.glb" id="1_4clbi"] +[ext_resource type="Script" path="res://scripts/Boid.gd" id="1_vg173"] +[ext_resource type="AudioStream" uid="uid://bqu3h3gaj6eqr" path="res://audio/263786__steaq__seagull-single-call.ogg" id="3_tean7"] +[ext_resource type="AudioStream" uid="uid://cqetbevo485vt" path="res://audio/468245__christianand__1_1_gaviota.wav" id="4_pieko"] + +[node name="Boid" type="Node3D"] +script = ExtResource("1_vg173") +max_timer = 30.0 +min_timer = 10.0 + +[node name="Flying gull" parent="." instance=ExtResource("1_4clbi")] +transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 0, 0, 0) + +[node name="SeagullSound1" type="AudioStreamPlayer3D" parent="."] +stream = ExtResource("3_tean7") + +[node name="SeagullSound2" type="AudioStreamPlayer3D" parent="."] +stream = ExtResource("4_pieko") + +[node name="Timer" type="Timer" parent="."] + +[connection signal="timeout" from="Timer" to="." method="_on_timer_timeout"] diff --git a/scenes/Main.tscn b/scenes/Main.tscn new file mode 100644 index 0000000..a195a36 --- /dev/null +++ b/scenes/Main.tscn @@ -0,0 +1,88 @@ +[gd_scene load_steps=12 format=3 uid="uid://p2vvd6l1rose"] + +[ext_resource type="Script" path="res://scripts/CameraControl.gd" id="1_tck22"] +[ext_resource type="Script" path="res://scripts/BoidsManager.gd" id="1_v84o5"] +[ext_resource type="PackedScene" uid="uid://bi3r8vqt5ykrt" path="res://scenes/Boid.tscn" id="2_did81"] +[ext_resource type="AudioStream" uid="uid://bqu3h3gaj6eqr" path="res://audio/263786__steaq__seagull-single-call.ogg" id="3_4pkn6"] +[ext_resource type="AudioStream" uid="uid://cqetbevo485vt" path="res://audio/468245__christianand__1_1_gaviota.wav" id="4_4rbpg"] +[ext_resource type="Material" uid="uid://bstu27rlas6p3" path="res://materials/Floor.tres" id="6_7a1uq"] + +[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_d6oc0"] +sky_top_color = Color(1, 1, 1, 1) +sky_horizon_color = Color(0.835294, 0.839216, 0.847059, 1) +ground_bottom_color = Color(0.898039, 0.898039, 0.898039, 1) +ground_horizon_color = Color(0.835355, 0.839277, 0.847089, 1) + +[sub_resource type="Sky" id="Sky_ggc3l"] +sky_material = SubResource("ProceduralSkyMaterial_d6oc0") + +[sub_resource type="Environment" id="Environment_ptyca"] +background_mode = 2 +sky = SubResource("Sky_ggc3l") + +[sub_resource type="CylinderShape3D" id="CylinderShape3D_s5kna"] +radius = 5.0 + +[sub_resource type="PlaneMesh" id="PlaneMesh_usmhe"] +size = Vector2(25, 25) + +[node name="Node3D" type="Node3D"] + +[node name="Pan" type="Node3D" parent="." node_paths=PackedStringArray("events_label", "drag_label")] +script = ExtResource("1_tck22") +events_label = NodePath("../Panel/VBoxContainer/Count") +drag_label = NodePath("../Panel/VBoxContainer/Drag") + +[node name="Tilt" type="Node3D" parent="Pan"] +transform = Transform3D(1, 0, 0, 0, 0.996195, 0.0871557, 0, -0.0871557, 0.996195, 0, 0, 0) + +[node name="Camera3D" type="Camera3D" parent="Pan/Tilt"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 10) + +[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] +transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 2, 0) + +[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) +script = ExtResource("1_v84o5") +resources = NodePath("../ResourcePreloader") +start_count = 20 +spawn_volume = Vector3(10, 5, 10) +protected_range = 2.0 +visual_range = 3.0 +avoid_factor = 1.0 +matching_factor = 0.02 +min_speed = 5.0 +max_speed = 10.0 +shape = SubResource("CylinderShape3D_s5kna") + +[node name="ResourcePreloader" type="ResourcePreloader" parent="."] +resources = [PackedStringArray("Boid", "Seagull", "SeagullTwo"), [ExtResource("2_did81"), ExtResource("3_4pkn6"), ExtResource("4_4rbpg")]] + +[node name="Panel" type="Panel" parent="."] +visible = false +offset_right = 301.0 +offset_bottom = 157.0 + +[node name="VBoxContainer" type="VBoxContainer" parent="Panel"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="Count" type="Label" parent="Panel/VBoxContainer"] +layout_mode = 2 +text = "Touch events:" + +[node name="Drag" type="Label" parent="Panel/VBoxContainer"] +layout_mode = 2 +text = "Touch events:" + +[node name="CSGMesh3D" type="CSGMesh3D" parent="."] +material_override = ExtResource("6_7a1uq") +mesh = SubResource("PlaneMesh_usmhe") diff --git a/scripts/Boid.gd b/scripts/Boid.gd new file mode 100644 index 0000000..b137bc4 --- /dev/null +++ b/scripts/Boid.gd @@ -0,0 +1,20 @@ +extends Node3D +class_name Boid + +@export var max_timer : float = 10 +@export var min_timer : float = 5 + +var velocity : Vector3 = Vector3(0, 0, 0) + +func _ready(): + $Timer.wait_time = randf_range(min_timer, max_timer) + $Timer.start() + +func _on_timer_timeout(): + $Timer.wait_time = randf_range(min_timer, max_timer) + + var dice : int = (randi() % 6) + 1 + if dice == 6: + $SeagullSound2.play() + else: + $SeagullSound1.play() diff --git a/scripts/BoidsManager.gd b/scripts/BoidsManager.gd new file mode 100644 index 0000000..a8b1256 --- /dev/null +++ b/scripts/BoidsManager.gd @@ -0,0 +1,202 @@ +extends Node3D + +@export var resources : ResourcePreloader + +@export_subgroup("Initialisation") + +@export var start_count : int = 10 +@export var spawn_volume : Vector3 = Vector3.ONE + +@export_subgroup("Boid settings") + +@export var protected_range : float = 1.0 +@export var visual_range : float = 2.0 +@export var centering_factor : float = 0.0005 +@export var avoid_factor : float = 0.05 +@export var matching_factor : float = 0.05 +@export var min_speed : float = 2.0 +@export var max_speed : float = 3.0 +@export var turn_factor : float = 0.2 +@export var margin : float = 0.3 + +@export_subgroup("Edges") + +@export var shape : Shape3D + +@export_subgroup("Gravity") + +@export var use_gravity : bool = true +@export var gravity_vector : Vector3 = Vector3(0, -9.807, 0) +@export var gravity_factor : float = 0.1 + +var boids : Array[Boid] +var boid_scene : PackedScene + +var protected_range_squared : float +var visual_range_squared : float + +# Called when the node enters the scene tree for the first time. +func _ready(): + protected_range_squared = pow(protected_range, 2) + visual_range_squared = pow(visual_range, 2) + + boid_scene = resources.get_resource("Boid") + for i in range(start_count): + var boid : Boid = boid_scene.instantiate() + boid.position = random_pos() + boid.velocity = random_vel() + add_child(boid) + boids.push_back(boid) + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +func _process(delta): + for boid in boids: + + var neighboring_boids : int = 0 + + var close : Vector3 = Vector3.ZERO + var position_avg : Vector3 = Vector3.ZERO + var velocity_avg : Vector3 = Vector3.ZERO + + for other_boid in boids.filter(func(cur): return cur != boid): + # Micro optimization, don't compute distance yet, just check if it's in the range by checking + # individual dimension distances + var diff : Vector3 = other_boid.position - boid.position + + if abs(diff.x) < visual_range and abs(diff.y) < visual_range and abs(diff.z) < visual_range: + # Using the squared distance so it performs better + var squared_distance : float = boid.position.distance_squared_to(other_boid.position) + + # If other boid too close, add the difference (if multiple boids too close, it should average naturally) + if squared_distance < protected_range_squared: + close -= diff + + # If other boid in visual range, we add its position and velocity + elif squared_distance < visual_range_squared: + position_avg += other_boid.position + velocity_avg += other_boid.velocity + + neighboring_boids += 1 + + # We collected all data related to neighboring boids + # Let's change our boid behavior + + if neighboring_boids > 0: + position_avg /= neighboring_boids + velocity_avg /= neighboring_boids + + boid.velocity = (boid.velocity + + (position_avg - boid.position) * centering_factor + + (velocity_avg - boid.velocity) * matching_factor + ) + + # Add avoidance contribution to velocity + boid.velocity = boid.velocity + (close * avoid_factor) + + # Edge avoidance + boid.velocity = apply_edge_avoidance(boid.position, boid.velocity) + + boid.velocity = apply_gravity(boid.velocity, delta) + boid.velocity = apply_speed_limits(boid.velocity) + + # Update position, finally! + boid.position += boid.velocity * delta + boid.look_at(boid.global_position + boid.velocity.normalized()) + + +func apply_edge_avoidance(position : Vector3, velocity : Vector3) -> Vector3: + if shape is BoxShape3D: + velocity = apply_cube_edge_avoidance(position, velocity, shape as BoxShape3D) + elif shape is CylinderShape3D: + velocity = apply_cylinder_edge_avoidance(position, velocity, shape as CylinderShape3D) + elif shape is SphereShape3D: + velocity = apply_sphere_edge_avoidance(position, velocity, shape as SphereShape3D) + else: + print("Shape not implemented!") + return velocity + + +func apply_cube_edge_avoidance(position : Vector3, velocity : Vector3, box : BoxShape3D) -> Vector3: + if position.x < (-box.size.x / 2.0) + margin: + velocity.x += turn_factor + if position.x > (box.size.x / 2.0) - margin: + velocity.x -= turn_factor + if position.y < (-box.size.y / 2.0) + margin: + velocity.y += turn_factor + if position.y > (box.size.y / 2.0) - margin: + velocity.y -= turn_factor + if position.z < (-box.size.z / 2.0) + margin: + velocity.z += turn_factor + if position.z > (box.size.z / 2.0) - margin: + velocity.z -= turn_factor + + return velocity + + +func apply_cylinder_edge_avoidance(position : Vector3, velocity : Vector3, cylinder : CylinderShape3D) -> Vector3: + if position.y < (-cylinder.height / 2.0) + margin: + velocity.y += turn_factor + if position.y > (cylinder.height / 2.0) - margin: + velocity.y -= turn_factor + + # We're centering around zero so let's take the position as direction + var direction : Vector2 = Vector2(position.x, position.z) + + if direction.length() > cylinder.radius - margin: + var turn : Vector2 = -direction.normalized() * turn_factor + velocity.x += turn.x + velocity.z += turn.y + + return velocity + + +func apply_sphere_edge_avoidance(position : Vector3, velocity : Vector3, sphere : SphereShape3D) -> Vector3: + var direction : Vector3 = position + + if direction.length() > sphere.radius - margin: + velocity = -direction.normalized() * turn_factor + + return velocity + + +func apply_gravity(velocity : Vector3, delta : float) -> Vector3: + if use_gravity: + velocity += gravity_vector * gravity_factor * delta + + return velocity + + +func apply_speed_limits(velocity : Vector3) -> Vector3: + # Boid's speed + var speed : float = velocity.length() + + # Enforce max and min speed + if speed < min_speed: + velocity = (velocity / speed) * min_speed + if speed > max_speed: + velocity = (velocity / speed) * max_speed + + return velocity + + +func random_pos() -> Vector3: + var x_range : Vector2 = Vector2(-spawn_volume.x / 2.0, spawn_volume.x / 2.0) + var y_range : Vector2 = Vector2(-spawn_volume.y / 2.0, spawn_volume.y / 2.0) + var z_range : Vector2 = Vector2(-spawn_volume.z / 2.0, spawn_volume.z / 2.0) + + return Vector3( + randf_range(x_range.x, x_range.y), + randf_range(y_range.x, y_range.y), + randf_range(z_range.x, z_range.y) + ) + + +func random_vel() -> Vector3: + var speed : float = pow(randf_range(min_speed, max_speed), 2) + var x : float = randf_range(0, speed) + speed -= x + var y : float = randf_range(0, speed) + speed -= y + var z : float = randf_range(0, speed) + return Vector3(sqrt(x), sqrt(y), sqrt(z)) diff --git a/scripts/CameraControl.gd b/scripts/CameraControl.gd new file mode 100644 index 0000000..b521683 --- /dev/null +++ b/scripts/CameraControl.gd @@ -0,0 +1,47 @@ +extends Node3D + +@export var pan_factor : float = 0.1 + +@export var events_label : Label +@export var drag_label : Label + +var events = {} +var last_drag_distance : float = 0 +var min_zoom = 0 +var max_zoom = 20 +var zoom_sensitivity = 10 +var zoom_speed = 0.5 + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +func _process(delta): + events_label.text = "Touch events: {no}".format({"no": events.size()}) + + +func _unhandled_input(event): + if event is InputEventScreenTouch: + if event.pressed: + events[event.index] = event + else: + events.erase(event.index) + + if event is InputEventScreenDrag: + events[event.index] = event + if events.size() == 1: + var relative : Vector2 = event.relative * pan_factor + rotation_degrees.y += relative.x + $Tilt.rotation_degrees.x += relative.y + $Tilt.rotation_degrees.x = clamp($Tilt.rotation_degrees.x, -90, -5) + + elif events.size() == 2: + var drag_distance = events[0].position.distance_to(events[1].position) + 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 + last_drag_distance = drag_distance diff --git a/shaders/FadingFloor.gdshader b/shaders/FadingFloor.gdshader new file mode 100644 index 0000000..1222c5d --- /dev/null +++ b/shaders/FadingFloor.gdshader @@ -0,0 +1,7 @@ +shader_type spatial; + +uniform float max_radius; + +void fragment() { + // Place fragment code here. +}