diff --git a/.gitignore b/.gitignore index 49baf96..ecf2dca 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,7 @@ /android/ rust/target /addons/boids/lib/* -/boids-release.zip \ No newline at end of file + +/boids-release.zip +/builds +*.blend1 \ No newline at end of file diff --git a/addons/debug_camera/LICENSE.txt b/addons/debug_camera/LICENSE.txt new file mode 100644 index 0000000..5ec5885 --- /dev/null +++ b/addons/debug_camera/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Kenechukwu Ozoemene + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/addons/debug_camera/LICENSE.txt.uid b/addons/debug_camera/LICENSE.txt.uid new file mode 100644 index 0000000..bae3177 --- /dev/null +++ b/addons/debug_camera/LICENSE.txt.uid @@ -0,0 +1 @@ +uid://2a0qp06gjk6j diff --git a/addons/debug_camera/plugin.cfg b/addons/debug_camera/plugin.cfg new file mode 100644 index 0000000..4272759 --- /dev/null +++ b/addons/debug_camera/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Debug Camera" +description="A debug camera for Godot 4" +author="Kcfresh53" +version="1.2" +script="scripts/plugin.gd" diff --git a/addons/debug_camera/scripts/DebugCamAutoload.gd b/addons/debug_camera/scripts/DebugCamAutoload.gd new file mode 100644 index 0000000..02f7275 --- /dev/null +++ b/addons/debug_camera/scripts/DebugCamAutoload.gd @@ -0,0 +1,14 @@ +extends Node + +var debug_cam_2d = preload("res://addons/debug_camera/scripts/DebugCamera2D.gd") +var debug_cam_3d = preload("res://addons/debug_camera/scripts/DebugCamera3D.gd") + +## call this function after you scene is ready to add the debug camera to it +func add_debug_cam(scene: Node) -> void: + var cam_2d := debug_cam_2d.new() + var cam_3d := debug_cam_3d.new() + + if get_viewport().get_camera_2d() != null: + scene.add_child(cam_2d) + elif get_viewport().get_camera_3d() != null: + scene.add_child(cam_3d) diff --git a/addons/debug_camera/scripts/DebugCamAutoload.gd.uid b/addons/debug_camera/scripts/DebugCamAutoload.gd.uid new file mode 100644 index 0000000..34065af --- /dev/null +++ b/addons/debug_camera/scripts/DebugCamAutoload.gd.uid @@ -0,0 +1 @@ +uid://p51rl4f0njxx diff --git a/addons/debug_camera/scripts/DebugCamera2D.gd b/addons/debug_camera/scripts/DebugCamera2D.gd new file mode 100644 index 0000000..ed9366a --- /dev/null +++ b/addons/debug_camera/scripts/DebugCamera2D.gd @@ -0,0 +1,60 @@ +extends Camera2D +class_name DebugCamera2D + +# Lower cap for the `_zoom_level`. +@export var min_zoom := 0.5 +# Upper cap for the `_zoom_level`. +@export var max_zoom := 2.0 +# Controls how much we increase or decrease the `_zoom_level` on every turn of the scroll wheel. +@export var zoom_factor := 0.1 +# Duration of the zoom's tween animation. +@export var zoom_duration := 0.2 + +# The camera's target zoom level. +var _zoom_level : float = 1.0 : + set(value): + var tween = get_tree().create_tween() + # We limit the value between `min_zoom` and `max_zoom` + _zoom_level = clamp(value, min_zoom, max_zoom) + tween.tween_property(self, "zoom", Vector2(_zoom_level, _zoom_level), zoom_duration).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_OUT) + +var _previousPosition: Vector2 = Vector2(0, 0) +var _moveCamera: bool = false + +var main_cam : Camera2D + + +func _ready() -> void: + enabled = false; name = "DebugCamera2D" + main_cam = get_viewport().get_camera_2d() + + +func _unhandled_input(event: InputEvent) -> void: + # Toggle cameras + if event.is_action_pressed(&"toggle_debug_camera"): + var cam := main_cam + cam.enabled = !cam.enabled + enabled = !cam.enabled + self.global_position = cam.global_position + if enabled: self.make_current() + else: cam.make_current() + + if not enabled: return + + if event is InputEventMouseButton: + # zoom out + if event.pressed && event.button_index == MOUSE_BUTTON_WHEEL_DOWN: + _zoom_level = _zoom_level - zoom_factor * _zoom_level + # zoom in + if event.pressed && event.button_index == MOUSE_BUTTON_WHEEL_UP: + _zoom_level = _zoom_level + zoom_factor * _zoom_level + + if event is InputEventMouseButton && event.button_index == MOUSE_BUTTON_RIGHT: + if event.is_pressed(): + _previousPosition = event.position + _moveCamera = true + else: + _moveCamera = false + elif event is InputEventMouseMotion && _moveCamera: + global_position += (_previousPosition - event.position) / _zoom_level + _previousPosition = event.position diff --git a/addons/debug_camera/scripts/DebugCamera2D.gd.uid b/addons/debug_camera/scripts/DebugCamera2D.gd.uid new file mode 100644 index 0000000..9d8d98c --- /dev/null +++ b/addons/debug_camera/scripts/DebugCamera2D.gd.uid @@ -0,0 +1 @@ +uid://ps1ybwpu8q3x diff --git a/addons/debug_camera/scripts/DebugCamera3D.gd b/addons/debug_camera/scripts/DebugCamera3D.gd new file mode 100644 index 0000000..e713297 --- /dev/null +++ b/addons/debug_camera/scripts/DebugCamera3D.gd @@ -0,0 +1,63 @@ +extends Camera3D +class_name DebugCamera3D + + +@export_range(0, 10, 0.01) var sensitivity : float = 3 +@export_range(0, 1000, 0.1) var default_velocity : float = 5 +@export_range(0, 10, 0.01) var speed_scale : float = 1.17 +@export_range(1, 100, 0.1) var boost_speed_multiplier : float = 3.0 +@export var max_speed : float = 1000 +@export var min_speed : float = 0.2 + +@onready var _velocity = default_velocity + +var main_cam : Camera3D + + +func _ready() -> void: + current = false + name = "DebugCamera3D" + main_cam = get_viewport().get_camera_3d() + + +func _process(delta: float) -> void: + if !current: + position = main_cam.global_position + rotation = main_cam.global_rotation + return + + var direction = Vector3( + float(Input.is_physical_key_pressed(KEY_D)) - float(Input.is_physical_key_pressed(KEY_A)), + float(Input.is_physical_key_pressed(KEY_E)) - float(Input.is_physical_key_pressed(KEY_Q)), + float(Input.is_physical_key_pressed(KEY_S)) - float(Input.is_physical_key_pressed(KEY_W)) + ).normalized() + + if Input.is_physical_key_pressed(KEY_SHIFT): # boost + translate(direction * _velocity * delta * boost_speed_multiplier) + else: + translate(direction * _velocity * delta) + + +func _unhandled_input(event: InputEvent) -> void: + # Toggle cameras + if event.is_action_pressed(&"toggle_debug_camera"): + var cam := main_cam + cam.current = !cam.current + current = !cam.current + + if not current: return + + if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED: + if event is InputEventMouseMotion: + rotation.y -= event.relative.x / 1000 * sensitivity + rotation.x -= event.relative.y / 1000 * sensitivity + rotation.x = clamp(rotation.x, PI/-2, PI/2) + + if event is InputEventMouseButton: + match event.button_index: + MOUSE_BUTTON_RIGHT: + Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED if event.pressed else Input.MOUSE_MODE_VISIBLE) + MOUSE_BUTTON_WHEEL_UP: # increase fly velocity + _velocity = clamp(_velocity * speed_scale, min_speed, max_speed) + MOUSE_BUTTON_WHEEL_DOWN: # decrease fly velocity + _velocity = clamp(_velocity / speed_scale, min_speed, max_speed) diff --git a/addons/debug_camera/scripts/DebugCamera3D.gd.uid b/addons/debug_camera/scripts/DebugCamera3D.gd.uid new file mode 100644 index 0000000..8e8b208 --- /dev/null +++ b/addons/debug_camera/scripts/DebugCamera3D.gd.uid @@ -0,0 +1 @@ +uid://b2fljwxrjfuuh diff --git a/addons/debug_camera/scripts/plugin.gd b/addons/debug_camera/scripts/plugin.gd new file mode 100644 index 0000000..96c2143 --- /dev/null +++ b/addons/debug_camera/scripts/plugin.gd @@ -0,0 +1,12 @@ +@tool +extends EditorPlugin + + +func _enter_tree(): + if not ProjectSettings.has_setting("autoload/DebugCam"): + add_autoload_singleton("DebugCam", "res://addons/debug_camera/scripts/DebugCamAutoload.gd") + + +func _exit_tree(): + if ProjectSettings.has_setting("autoload/DebugCam"): + remove_autoload_singleton("DebugCam") diff --git a/addons/debug_camera/scripts/plugin.gd.uid b/addons/debug_camera/scripts/plugin.gd.uid new file mode 100644 index 0000000..df2133d --- /dev/null +++ b/addons/debug_camera/scripts/plugin.gd.uid @@ -0,0 +1 @@ +uid://gyy0f127lfvc diff --git a/examples/boids/2d/follow/example.gd b/examples/boids/2d/follow/example.gd index 89a37cc..2af546f 100644 --- a/examples/boids/2d/follow/example.gd +++ b/examples/boids/2d/follow/example.gd @@ -5,6 +5,7 @@ func _ready() -> void: if flock is not Flock2D: continue var color = Color(randf_range(0.8, 1.5), randf_range(0.8, 1.5), randf_range(0.2, 1.5), 1) for i in 100: spawnBoid(flock, color) + DebugCam.add_debug_cam(self) func _process(delta: float) -> void: $Path2D/PathFollow2D.progress_ratio += delta * 0.125 diff --git a/examples/boids/2d/follow/example.tscn b/examples/boids/2d/follow/example.tscn index 87788b9..842c79a 100644 --- a/examples/boids/2d/follow/example.tscn +++ b/examples/boids/2d/follow/example.tscn @@ -66,3 +66,6 @@ target = NodePath("../Path2D3/PathFollow2D") [node name="WorldEnvironment" type="WorldEnvironment" parent="."] environment = SubResource("Environment_8ucif") + +[node name="Camera2D" type="Camera2D" parent="."] +position = Vector2(576, 324) diff --git a/examples/boids/2d/simple/example.gd b/examples/boids/2d/simple/example.gd index 46ca14f..344a9b5 100644 --- a/examples/boids/2d/simple/example.gd +++ b/examples/boids/2d/simple/example.gd @@ -5,6 +5,7 @@ func _ready() -> void: if flock is not Flock2D: continue var color = Color(randf(), randf(), randf(), 1) for i in 2000: spawnBoid(flock, color) + DebugCam.add_debug_cam(self) func spawnBoid(flock: Flock2D, color: Color) -> void: var boid: Boid2D = preload("../example_boid.tscn").instantiate() diff --git a/examples/boids/2d/simple/example.tscn b/examples/boids/2d/simple/example.tscn index e3d17a7..7ded31d 100644 --- a/examples/boids/2d/simple/example.tscn +++ b/examples/boids/2d/simple/example.tscn @@ -18,3 +18,6 @@ environment = SubResource("Environment_jxsqf") [node name="Flock" type="Flock2D" parent="."] properties = SubResource("FlockProperties_cvyp0") + +[node name="Camera2D" type="Camera2D" parent="."] +position = Vector2(576, 324) diff --git a/examples/boids/3d/example_boid.blend b/examples/boids/3d/example_boid.blend new file mode 100644 index 0000000..2c9a657 Binary files /dev/null and b/examples/boids/3d/example_boid.blend differ diff --git a/examples/boids/3d/example_boid.blend.import b/examples/boids/3d/example_boid.blend.import new file mode 100644 index 0000000..e960cef --- /dev/null +++ b/examples/boids/3d/example_boid.blend.import @@ -0,0 +1,51 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://bqklv2qo52yic" +path="res://.godot/imported/example_boid.blend-3a150588ea3bbfa9f2a9c36f7077e2dc.scn" + +[deps] + +source_file="res://examples/boids/3d/example_boid.blend" +dest_files=["res://.godot/imported/example_boid.blend-3a150588ea3bbfa9f2a9c36f7077e2dc.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +_subresources={} +blender/nodes/visible=0 +blender/nodes/active_collection_only=false +blender/nodes/punctual_lights=true +blender/nodes/cameras=true +blender/nodes/custom_properties=true +blender/nodes/modifiers=1 +blender/meshes/colors=false +blender/meshes/uvs=true +blender/meshes/normals=true +blender/meshes/tangents=true +blender/meshes/skins=2 +blender/meshes/export_bones_deforming_mesh_only=false +blender/materials/unpack_enabled=true +blender/materials/export_materials=1 +blender/animation/limit_playback=true +blender/animation/always_sample=true +blender/animation/group_tracks=true diff --git a/examples/boids/3d/example_boid.tscn b/examples/boids/3d/example_boid.tscn new file mode 100644 index 0000000..4706cab --- /dev/null +++ b/examples/boids/3d/example_boid.tscn @@ -0,0 +1,25 @@ +[gd_scene load_steps=3 format=3 uid="uid://1pug7bs83oif"] + +[ext_resource type="PackedScene" uid="uid://bqklv2qo52yic" path="res://examples/boids/3d/example_boid.blend" id="1_4juxv"] + +[sub_resource type="GDScript" id="GDScript_i7ix1"] +script/source = "extends Node3D + +@onready var boid: Boid3D = get_parent() +@onready var mesh: MeshInstance3D = get_node(\"Cube\") + +func _ready() -> void: + var mat: StandardMaterial3D = mesh.get_active_material(1).duplicate(true) + mat.albedo_color = Color(randf(), randf(), randf()) + mesh.set_surface_override_material(1, mat) + +func _process(delta: float) -> void: + var dir_target := boid.global_position + boid.get_velocity() + look_at_from_position(boid.global_position, dir_target) +" + +[node name="ExampleBoid" type="Boid3D"] + +[node name="example_boid" parent="." instance=ExtResource("1_4juxv")] +transform = Transform3D(0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0, 0, 0) +script = SubResource("GDScript_i7ix1") diff --git a/examples/boids/3d/simple/example.gd b/examples/boids/3d/simple/example.gd new file mode 100644 index 0000000..f92aa0a --- /dev/null +++ b/examples/boids/3d/simple/example.gd @@ -0,0 +1,14 @@ +extends Node3D + +const area := Vector3(4.0, 4.0, 4.0) + +func _ready() -> void: + for flock in get_children(): + if flock is not Flock3D: continue + for i in 20: spawnBoid(flock) + DebugCam.add_debug_cam(self) + +func spawnBoid(flock: Flock3D) -> void: + var boid: Boid3D = preload("../example_boid.tscn").instantiate() + boid.global_position = Vector3(randf_range(-area.x, area.x), randf_range(-area.y, area.y), randf_range(-area.z, area.z)) + flock.add_child(boid) diff --git a/examples/boids/3d/simple/example.tscn b/examples/boids/3d/simple/example.tscn new file mode 100644 index 0000000..1fb73d7 --- /dev/null +++ b/examples/boids/3d/simple/example.tscn @@ -0,0 +1,30 @@ +[gd_scene load_steps=4 format=3 uid="uid://dmjob0jc7a2qr"] + +[ext_resource type="Script" path="res://examples/boids/3d/simple/example.gd" id="1_um23s"] + +[sub_resource type="Environment" id="Environment_aypca"] +ambient_light_source = 2 +ambient_light_color = Color(0.89059, 0.89059, 0.89059, 1) +glow_enabled = true +glow_bloom = 0.1 +glow_blend_mode = 1 + +[sub_resource type="FlockProperties" id="FlockProperties_1d3ec"] +goal_seperation = 4.0 +goal_alignment = 16.0 +goal_cohesion = 16.0 + +[node name="Example" type="Node3D"] +script = ExtResource("1_um23s") + +[node name="WorldEnvironment" type="WorldEnvironment" parent="."] +environment = SubResource("Environment_aypca") + +[node name="Flock3D" type="Flock3D" parent="." node_paths=PackedStringArray("target")] +properties = SubResource("FlockProperties_1d3ec") +target = NodePath("../Marker3D") + +[node name="Camera3D" type="Camera3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 0.866025, 0.5, 0, -0.5, 0.866025, 0, 6, 10) + +[node name="Marker3D" type="Marker3D" parent="."] diff --git a/justfile b/justfile index 9a1f12e..65c1bc2 100644 --- a/justfile +++ b/justfile @@ -24,4 +24,10 @@ linux: (build-install 'x86_64-unknown-linux-gnu') all: (_just-cmd '--timestamp' 'profile=release' 'linux' 'windows' 'wasm') package: - run-external 'zip' '-r' 'boids-release.zip' 'addons' 'examples' 'README.md' 'LICENSE.txt' \ No newline at end of file + rm -rf boids-release.zip builds + mkdir builds/addons + touch builds/.gdignore + cp -rf addons/boids builds/addons/ + cp -f README.md LICENSE.txt builds/addons/boids/ + cp -rf examples README.md LICENSE.txt builds/ + cd builds; run-external 'zip' '-r' '../boids-release.zip' 'addons' 'examples' 'README.md' 'LICENSE.txt' \ No newline at end of file diff --git a/project.godot b/project.godot index 86e9468..389dfaf 100644 --- a/project.godot +++ b/project.godot @@ -17,10 +17,24 @@ config/features=PackedStringArray("4.3", "GL Compatibility") [autoload] ProcessBoids="*res://addons/boids/process_boids.tscn" +DebugCam="*res://addons/debug_camera/scripts/DebugCamAutoload.gd" [editor_plugins] -enabled=PackedStringArray("res://addons/boids/plugin.cfg") +enabled=PackedStringArray("res://addons/boids/plugin.cfg", "res://addons/debug_camera/plugin.cfg") + +[input] + +toggle_debug_camera={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":true,"shift_pressed":false,"ctrl_pressed":true,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":67,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} + +[physics] + +common/physics_jitter_fix=0.0 +common/physics_interpolation=true [rendering]