diff --git a/splunk/addons/freecam_3D/freecam.gd b/splunk/addons/freecam_3D/freecam.gd new file mode 100644 index 0000000..b019470 --- /dev/null +++ b/splunk/addons/freecam_3D/freecam.gd @@ -0,0 +1,145 @@ +extends Camera3D + +## Camera with flying script attached to it. +class_name Freecam3D + +## +## Camera with toggleable freecam mode for prototyping when creating levels, shaders, lighting, etc. +## +## Usage: Run your game, press and fly around freely. Uses Minecraft-like controls. +## + +## Customize your own toggle key to avoid collisions with your current mappings. +@export var toggle_key: Key = KEY_TAB +## Speed up / down by scrolling the mouse whell down / up +@export var invert_speed_controls: bool = false + +@export var overlay_text: bool = true + +## Pivot node for camera looking around +@onready var pivot := Node3D.new() +## Main parent for camera overlay. +@onready var screen_overlay := VBoxContainer.new() +## Container for the chat-like event log. +@onready var event_log := VBoxContainer.new() + +const MAX_SPEED := 4 +const MIN_SPEED := 0.1 +const ACCELERATION := 0.1 +const MOUSE_SENSITIVITY := 0.002 + +## Whether or not the camera can move. +var movement_active := false: + set(val): + movement_active = val + Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED if movement_active else Input.MOUSE_MODE_VISIBLE) + display_message("[Movement ON]" if movement_active else "[Movement OFF]") + +## The current maximum speed. Lower or higher it by scrolling the mouse wheel. +var target_speed := MIN_SPEED +## Movement velocity. +var velocity := Vector3.ZERO + + +## Sets up pivot and UI overlay elements. +func _setup_nodes() -> void: + self.add_sibling(pivot) + pivot.position = position + pivot.rotation = rotation + pivot.name = "FreecamPivot" + self.reparent(pivot) + self.position = Vector3.ZERO + self.rotation = Vector3.ZERO + # UI stuff + screen_overlay.add_theme_constant_override("Separation", 8) + self.add_child(screen_overlay) + screen_overlay.add_child(_make_label("Debug Camera")) + screen_overlay.add_spacer(false) + + screen_overlay.add_child(event_log) + screen_overlay.visible = overlay_text + + +func _ready() -> void: + _setup_nodes.call_deferred() + _add_keybindings() + + +func _process(delta: float) -> void: + + if Input.is_action_just_released("__debug_camera_toggle"): + movement_active = not movement_active + + if movement_active: + var dir = Vector3.ZERO + if Input.is_action_pressed("__debug_camera_forward"): dir.z -= 1 + if Input.is_action_pressed("__debug_camera_back"): dir.z += 1 + if Input.is_action_pressed("__debug_camera_left"): dir.x -= 1 + if Input.is_action_pressed("__debug_camera_right"): dir.x += 1 + if Input.is_action_pressed("__debug_camera_up"): dir.y += 1 + if Input.is_action_pressed("__debug_camera_down"): dir.y -= 1 + + dir = dir.normalized() + dir = dir.rotated(Vector3.UP, pivot.rotation.y) + + velocity = lerp(velocity, dir * target_speed, ACCELERATION) + pivot.position += velocity + + +func _input(event: InputEvent) -> void: + if movement_active: + # Turn around + if event is InputEventMouseMotion: + pivot.rotate_y(-event.relative.x * MOUSE_SENSITIVITY) + rotate_x(-event.relative.y * MOUSE_SENSITIVITY) + rotation.x = clamp(rotation.x, -PI/2, PI/2) + + var speed_up = func(): + target_speed = clamp(target_speed + 0.15, MIN_SPEED, MAX_SPEED) + display_message("[Speed up] " + str(target_speed)) + + var slow_down = func(): + target_speed = clamp(target_speed - 0.15, MIN_SPEED, MAX_SPEED) + display_message("[Slow down] " + str(target_speed)) + + # Speed up and down with the mouse wheel + if event is InputEventMouseButton: + if event.button_index == MOUSE_BUTTON_WHEEL_UP and event.pressed: + slow_down.call() if invert_speed_controls else speed_up.call() + + if event.button_index == MOUSE_BUTTON_WHEEL_DOWN and event.pressed: + speed_up.call() if invert_speed_controls else slow_down.call() + + +## Pushes new message label into "chat" and removes the old ones if necessary +func display_message(text: String) -> void: + while event_log.get_child_count() >= 3: + event_log.remove_child(event_log.get_child(0)) + + event_log.add_child(_make_label(text)) + + +func _make_label(text: String) -> Label: + var l = Label.new() + l.text = text + return l + + +func _add_keybindings() -> void: + var actions = InputMap.get_actions() + if "__debug_camera_forward" not in actions: _add_key_input_action("__debug_camera_forward", KEY_W) + if "__debug_camera_back" not in actions: _add_key_input_action("__debug_camera_back", KEY_S) + if "__debug_camera_left" not in actions: _add_key_input_action("__debug_camera_left", KEY_A) + if "__debug_camera_right" not in actions: _add_key_input_action("__debug_camera_right", KEY_D) + if "__debug_camera_up" not in actions: _add_key_input_action("__debug_camera_up", KEY_SPACE) + if "__debug_camera_down" not in actions: _add_key_input_action("__debug_camera_down", KEY_SHIFT) + if "__debug_camera_toggle" not in actions: _add_key_input_action("__debug_camera_toggle", toggle_key) + + +func _add_key_input_action(name: String, key: Key) -> void: + var ev = InputEventKey.new() + ev.physical_keycode = key + + InputMap.add_action(name) + InputMap.action_add_event(name, ev) + diff --git a/splunk/addons/freecam_3D/freecam.gd.uid b/splunk/addons/freecam_3D/freecam.gd.uid new file mode 100644 index 0000000..1f58977 --- /dev/null +++ b/splunk/addons/freecam_3D/freecam.gd.uid @@ -0,0 +1 @@ +uid://8vyuhyx0xogt diff --git a/splunk/addons/freecam_3D/mc-camera2.png b/splunk/addons/freecam_3D/mc-camera2.png new file mode 100644 index 0000000..62f31b3 Binary files /dev/null and b/splunk/addons/freecam_3D/mc-camera2.png differ diff --git a/splunk/addons/freecam_3D/mc-camera2.png.import b/splunk/addons/freecam_3D/mc-camera2.png.import new file mode 100644 index 0000000..4f5aa2c --- /dev/null +++ b/splunk/addons/freecam_3D/mc-camera2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c4kitg6s5bcqu" +path="res://.godot/imported/mc-camera2.png-fe60f555c5ea92c0796267cd654ef834.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/freecam_3D/mc-camera2.png" +dest_files=["res://.godot/imported/mc-camera2.png-fe60f555c5ea92c0796267cd654ef834.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 diff --git a/splunk/addons/freecam_3D/plugin.cfg b/splunk/addons/freecam_3D/plugin.cfg new file mode 100644 index 0000000..db0b562 --- /dev/null +++ b/splunk/addons/freecam_3D/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Freecam3D" +description="A flying freecam with Minecraft-like controls." +author="Vojtech Struhar" +version="1.2.0" +script="plugin.gd" diff --git a/splunk/addons/freecam_3D/plugin.gd b/splunk/addons/freecam_3D/plugin.gd new file mode 100644 index 0000000..a576db8 --- /dev/null +++ b/splunk/addons/freecam_3D/plugin.gd @@ -0,0 +1,20 @@ +@tool +extends EditorPlugin + +## +## Bootstraps the Freecam3D node. +## + +func _enter_tree() -> void: + print("[Freecam3D Plugin] Loaded.") + + add_custom_type( + "Freecam3D", + "Camera3D", + preload("freecam.gd"), + preload("mc-camera2.png")) + + +func _exit_tree() -> void: + remove_custom_type("Freecam3D") + diff --git a/splunk/addons/freecam_3D/plugin.gd.uid b/splunk/addons/freecam_3D/plugin.gd.uid new file mode 100644 index 0000000..cf140d6 --- /dev/null +++ b/splunk/addons/freecam_3D/plugin.gd.uid @@ -0,0 +1 @@ +uid://1c16mfvgbate diff --git a/splunk/levels/lobby-scene/lobby.tscn b/splunk/levels/lobby-scene/lobby.tscn new file mode 100644 index 0000000..4cddcfc --- /dev/null +++ b/splunk/levels/lobby-scene/lobby.tscn @@ -0,0 +1,32 @@ +[gd_scene load_steps=6 format=3 uid="uid://bj52j4ew2lfr6"] + +[ext_resource type="PackedScene" uid="uid://5vggmy1srgxb" path="res://tools/human-height-reference.tscn" id="1_yyu2g"] +[ext_resource type="PackedScene" uid="uid://daq1prwl8aaia" path="res://tools/debug.tscn" id="2_72fkp"] + +[sub_resource type="Environment" id="Environment_72fkp"] +background_mode = 2 + +[sub_resource type="PlaneMesh" id="PlaneMesh_fnh6i"] +size = Vector2(20, 20) + +[sub_resource type="BoxShape3D" id="BoxShape3D_yyu2g"] +size = Vector3(20, 0.4, 20) + +[node name="Lobby" type="Node3D"] + +[node name="WorldEnvironment" type="WorldEnvironment" parent="."] +environment = SubResource("Environment_72fkp") + +[node name="TempFloor" type="StaticBody3D" parent="."] + +[node name="MeshInstance3D" type="MeshInstance3D" parent="TempFloor"] +mesh = SubResource("PlaneMesh_fnh6i") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="TempFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.2, 0) +shape = SubResource("BoxShape3D_yyu2g") + +[node name="Human-height-reference" parent="." instance=ExtResource("1_yyu2g")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3.33741, 0.953, -5.00694) + +[node name="Debug" parent="." instance=ExtResource("2_72fkp")] diff --git a/splunk/project.godot b/splunk/project.godot index 0c5cf34..b3374d2 100644 --- a/splunk/project.godot +++ b/splunk/project.godot @@ -11,15 +11,21 @@ config_version=5 [application] config/name="Splunk" +run/main_scene="uid://bj52j4ew2lfr6" config/features=PackedStringArray("4.4", "Forward Plus") config/icon="res://icon.svg" +[editor_plugins] + +enabled=PackedStringArray("res://addons/freecam_3D/plugin.cfg") + [file_customization] folder_colors={ "res://items/": "yellow", "res://levels/": "green", -"res://player/": "purple" +"res://player/": "purple", +"res://tools/": "gray" } [physics] diff --git a/splunk/tools/debug.tscn b/splunk/tools/debug.tscn new file mode 100644 index 0000000..96f87f8 --- /dev/null +++ b/splunk/tools/debug.tscn @@ -0,0 +1,10 @@ +[gd_scene load_steps=2 format=3 uid="uid://daq1prwl8aaia"] + +[ext_resource type="Script" uid="uid://8vyuhyx0xogt" path="res://addons/freecam_3D/freecam.gd" id="1_m8a7k"] + +[node name="Debug" type="Node3D"] + +[node name="Freecam3D" type="Camera3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0, 5, 0) +script = ExtResource("1_m8a7k") +metadata/_custom_type_script = "uid://8vyuhyx0xogt" diff --git a/splunk/tools/human-height-reference.tscn b/splunk/tools/human-height-reference.tscn new file mode 100644 index 0000000..1025596 --- /dev/null +++ b/splunk/tools/human-height-reference.tscn @@ -0,0 +1,15 @@ +[gd_scene load_steps=3 format=3 uid="uid://5vggmy1srgxb"] + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_q0jr2"] +albedo_color = Color(0.901217, 0.295359, 0.23356, 1) + +[sub_resource type="CylinderMesh" id="CylinderMesh_q0jr2"] +material = SubResource("StandardMaterial3D_q0jr2") +top_radius = 0.35 +bottom_radius = 0.35 +height = 1.905 + +[node name="Human-height-reference" type="Node3D"] + +[node name="MeshInstance3D" type="MeshInstance3D" parent="."] +mesh = SubResource("CylinderMesh_q0jr2")