From 9b9592764b569d7ed34715223aa2baaa9969cb3c Mon Sep 17 00:00:00 2001 From: francis Date: Fri, 6 Mar 2026 23:00:20 +0100 Subject: [PATCH] added flyCamera --- addons/sk_fly_camera/LICENSE | 21 ++ addons/sk_fly_camera/README.md | 11 + addons/sk_fly_camera/icons/fly_camera.png | Bin 0 -> 3661 bytes .../sk_fly_camera/icons/fly_camera.png.import | 40 +++ addons/sk_fly_camera/icons/fly_camera.svg | 64 ++++ .../sk_fly_camera/icons/fly_camera.svg.import | 43 +++ addons/sk_fly_camera/plugin.cfg | 7 + addons/sk_fly_camera/plugin.gd | 5 + addons/sk_fly_camera/plugin.gd.uid | 1 + addons/sk_fly_camera/src/fly_camera.gd | 314 ++++++++++++++++++ addons/sk_fly_camera/src/fly_camera.gd.uid | 1 + 11 files changed, 507 insertions(+) create mode 100644 addons/sk_fly_camera/LICENSE create mode 100644 addons/sk_fly_camera/README.md create mode 100644 addons/sk_fly_camera/icons/fly_camera.png create mode 100644 addons/sk_fly_camera/icons/fly_camera.png.import create mode 100644 addons/sk_fly_camera/icons/fly_camera.svg create mode 100644 addons/sk_fly_camera/icons/fly_camera.svg.import create mode 100644 addons/sk_fly_camera/plugin.cfg create mode 100644 addons/sk_fly_camera/plugin.gd create mode 100644 addons/sk_fly_camera/plugin.gd.uid create mode 100644 addons/sk_fly_camera/src/fly_camera.gd create mode 100644 addons/sk_fly_camera/src/fly_camera.gd.uid diff --git a/addons/sk_fly_camera/LICENSE b/addons/sk_fly_camera/LICENSE new file mode 100644 index 0000000..f626ecf --- /dev/null +++ b/addons/sk_fly_camera/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Skaruts + +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/sk_fly_camera/README.md b/addons/sk_fly_camera/README.md new file mode 100644 index 0000000..363c1de --- /dev/null +++ b/addons/sk_fly_camera/README.md @@ -0,0 +1,11 @@ +# Fly Camera Addon for Godot 4 + +A camera addon for flying around scenes at runtime, which can be handy during the prototyping phase of a project, for example. + +The camera is easy to use. You can just drop it in a scene, and run the game. +Optionally you can also tweek the camera node settings in the inspector (speed, mouse sensitivity, etc). + +By default the camera uses `WASD` keys for movement, `Shift` to move faster, `Ctrl` to move slower, +and `Right Mouse Button` to activate/deactivate the camera's mouse controls. + +Please refer to the documentation for more information. diff --git a/addons/sk_fly_camera/icons/fly_camera.png b/addons/sk_fly_camera/icons/fly_camera.png new file mode 100644 index 0000000000000000000000000000000000000000..bcc6ab8cb6ce51e0f763221b75ea9078023b2a31 GIT binary patch literal 3661 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 literal 0 HcmV?d00001 diff --git a/addons/sk_fly_camera/icons/fly_camera.png.import b/addons/sk_fly_camera/icons/fly_camera.png.import new file mode 100644 index 0000000..713935a --- /dev/null +++ b/addons/sk_fly_camera/icons/fly_camera.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b42t3486jwfud" +path="res://.godot/imported/fly_camera.png-f981b86d63a5d3aa84ae2448e297f41a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/sk_fly_camera/icons/fly_camera.png" +dest_files=["res://.godot/imported/fly_camera.png-f981b86d63a5d3aa84ae2448e297f41a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/addons/sk_fly_camera/icons/fly_camera.svg b/addons/sk_fly_camera/icons/fly_camera.svg new file mode 100644 index 0000000..3eb4a44 --- /dev/null +++ b/addons/sk_fly_camera/icons/fly_camera.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + diff --git a/addons/sk_fly_camera/icons/fly_camera.svg.import b/addons/sk_fly_camera/icons/fly_camera.svg.import new file mode 100644 index 0000000..ef227e0 --- /dev/null +++ b/addons/sk_fly_camera/icons/fly_camera.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dma1meqanq6lr" +path="res://.godot/imported/fly_camera.svg-197f6cff73611fb9b2753ae8bc3c4adb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/sk_fly_camera/icons/fly_camera.svg" +dest_files=["res://.godot/imported/fly_camera.svg-197f6cff73611fb9b2753ae8bc3c4adb.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/addons/sk_fly_camera/plugin.cfg b/addons/sk_fly_camera/plugin.cfg new file mode 100644 index 0000000..4c9ba04 --- /dev/null +++ b/addons/sk_fly_camera/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Fly Camera" +description="A camera for when you need to quickly fly around while prototyping games." +author="Skaruts" +version="0.1" +script="plugin.gd" diff --git a/addons/sk_fly_camera/plugin.gd b/addons/sk_fly_camera/plugin.gd new file mode 100644 index 0000000..81b6b1d --- /dev/null +++ b/addons/sk_fly_camera/plugin.gd @@ -0,0 +1,5 @@ +@tool +extends EditorPlugin + + +# nothing to see here diff --git a/addons/sk_fly_camera/plugin.gd.uid b/addons/sk_fly_camera/plugin.gd.uid new file mode 100644 index 0000000..8a2265c --- /dev/null +++ b/addons/sk_fly_camera/plugin.gd.uid @@ -0,0 +1 @@ +uid://ctjbk1djxsko6 diff --git a/addons/sk_fly_camera/src/fly_camera.gd b/addons/sk_fly_camera/src/fly_camera.gd new file mode 100644 index 0000000..6bf122b --- /dev/null +++ b/addons/sk_fly_camera/src/fly_camera.gd @@ -0,0 +1,314 @@ +@icon("../icons/fly_camera.svg") +class_name FlyCamera +extends CharacterBody3D + +## +## A free flying camera, handy for prototyping. +## [br][br] +## +## +## This camera allows to quickly be able to fly around at runtime. +## Just put it in a scene and it should be good to go. You can optionally +## tweak its settings in the inspector. +## [br][br] +## +## The camera node itself is not an actual camera, but a [CharacterBody3D], so +## it has no visual preview in the inspector. You can still align it to the +## camera in the 3D View, by clicking [param Perspective > Align Transform With View]. +## [br][br] +## +## You will also see a warning in the [param Scene] tree about the [CharacterBody3D] +## not having a shape. Normally a flying camera doesn't need any collisions, +## and you can ignore the warning. The camera still supports collisions, though, +## either by turning on [param Use Collisions] in the inspector, or by +## manually adding a [CollisionShape3D] node with a shape of your choice. +## [br][br] +##[color=white][b]Note:[/b][/color] the collisions are added at runtime, so +## turning on [param Use Collisions] will not suppress the warning. +## [br][br] +## +## The camera controls can be changed. By default it uses the [param WASD] +## keys for movement, [param Shift] to move faster, [param Ctrl] to move slower, and +## the [param Right Mouse Button] to activate/deactivate the mouse controls +## (capturing/uncapturing the mouse pointer). +## [br][br] +## +## This camera was intended for quick use, so the default controls are easy to +## change in the camera script by hand (in the [param _actions_to_key] dictionary). +## However, if you prefer, you can also set the following input actions in +## your project settings, and the camera will automatically use them instead: +## [codeblock] +##cam_forward +##cam_backward +##cam_left +##cam_right +##cam_faster +##cam_slower +##cam_activate +## [/codeblock] +## [color=white][b]Note:[/b][/color] the mouse button used to activate the +## camera can easily be changed in the inspector, so for that end you don't +## need to use [param cam_activate] input action. +## This action is provided in case you'd like to use a keyboard key instead. +## +## + + +## How to activate mouse controls. +enum ActivationMode { + ON_CLICK, ## Click to activate, click again to deactivate. + ON_HOLD, ## Hold mouse button to activate, release to deactivate. +} + +## Where to revert the mouse pointer when releasing mouse controls. +enum RevertMouseOption { + CLICK_POSITION, ## The position where the mouse was initially clicked. + VIEWPORT_CENTER, ## The center of the viewport. +} + +enum MouseButton { + LEFT = 1, + RIGHT, + MIDDLE, +} + + +#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#= + +# User Properties / Settings + +#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#= +#region user_settings +@export_group("Mouse Settings") + +## How to activate the mouse controls. +@export var activation_mode := ActivationMode.ON_CLICK + +## Where the mouse pointer should be at when releasing mouse controls. +@export var revert_mouse_to := RevertMouseOption.CLICK_POSITION + +## Which mouse button activates mouse control. +@export var mouse_button := MouseButton.RIGHT + + +## The mouse sensitivity in each axis. +@export var mouse_sensitivity := Vector2(2.2, 2.2) + +## If true the mouse's vertical axis will be inverted. +@export var invert_y := false + +## If true, the key controls will still work when the mouse controls +## are inactive. +@export var keep_key_controls := true + + +@export_group("Camera Settings") +## The camera's movement speed. +@export var fly_speed := 20.0 + +## The camera's acceleration. +## [br][br] +## For simplicity, this also doubles as friction. +@export var acceleration : int = 10 + +## The factor by which to multiply or divide the camera speed in order to +## move faster or slower. +@export var speed_factor : int = 3 + +## Adds a sphere collision shape to the camera. You can setup +## the collision layers as you please. +@export var use_collision := false: + set(enable): + use_collision = enable + _set_collisions(enable) + +## If true, the camera will use the default controls and ignore any +## input actions defined in the project settings. +@export var use_default_controls := false + + +#endregion + + + +#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#= + +# Internals + +#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#= +#region internal_Stuff +const _ACTION_FORWARD := "cam_forward" +const _ACTION_BACKWARD := "cam_backward" +const _ACTION_LEFT := "cam_left" +const _ACTION_RIGHT := "cam_right" +const _ACTION_FASTER := "cam_faster" +const _ACTION_SLOWER := "cam_slower" +const _ACTION_ACTIVATE := "cam_activate" + +var _actions_to_key := { + _ACTION_FORWARD : KEY_W, + _ACTION_BACKWARD : KEY_S, + _ACTION_LEFT : KEY_A, + _ACTION_RIGHT : KEY_D, + _ACTION_FASTER : KEY_SHIFT, + _ACTION_SLOWER : KEY_CTRL, + _ACTION_ACTIVATE : mouse_button, +} + +const _PITCH_LIMIT : int = 90 + + +var _mouse_click_pos : Vector2 +var _mouse_hidden : bool + +var _coll : CollisionShape3D +var _camera : Camera3D # The actual, internal camera node. +var _cam_pivot: Node3D # The Y rotation pivot node + +var _yaw : float = 0 +var _pitch : float = 0 + + + +func _ready() -> void: + _cam_pivot = Node3D.new() + add_child(_cam_pivot) + + _camera = Camera3D.new() + _cam_pivot.add_child(_camera) + _camera.current = true + + # if this node was rotated in the editor, use that as default rotation + var rot := rotation_degrees + rotation = Vector3.ZERO + set_rot(rot) + + +func _unhandled_input(event: InputEvent) -> void: + _check_mouse_capture(event) + + if not _mouse_hidden: + return + + ## Camera motion + if event is InputEventMouseMotion: + _yaw = fmod(_yaw - event.relative.x * mouse_sensitivity.x/10, 360) + + if not invert_y: _pitch = max(min(_pitch - event.relative.y * mouse_sensitivity.y/10.0, _PITCH_LIMIT), -_PITCH_LIMIT) + else: _pitch = max(min(_pitch + event.relative.y * mouse_sensitivity.y/10.0, _PITCH_LIMIT), -_PITCH_LIMIT) + + _cam_pivot.rotation.y = deg_to_rad(_yaw) + _camera.rotation.x = deg_to_rad(_pitch) + + +func _physics_process(delta: float) -> void: + var aim : Basis = _camera.get_camera_transform().basis + + var dir := Vector3() + var spd := fly_speed + + if _mouse_hidden or keep_key_controls: + if _is_cam_action_pressed(_ACTION_FORWARD): dir -= aim[2] + if _is_cam_action_pressed(_ACTION_BACKWARD): dir += aim[2] + if _is_cam_action_pressed(_ACTION_LEFT): dir -= aim[0] + if _is_cam_action_pressed(_ACTION_RIGHT): dir += aim[0] + if _is_cam_action_pressed(_ACTION_FASTER): spd *= speed_factor + if _is_cam_action_pressed(_ACTION_SLOWER): spd /= speed_factor + + dir = dir.normalized() + + var target := dir * spd + velocity = velocity.lerp( target, acceleration*delta ) + move_and_slide() + + if is_zero_approx(velocity.length()): + velocity = Vector3.ZERO + + +func _is_cam_action_pressed(action:String) -> bool: + if not use_default_controls and InputMap.has_action(action): + return Input.is_action_pressed(action) + return Input.is_key_pressed(_actions_to_key[action]) + + +func _set_collisions(enable:bool) -> void: + if enable: + _coll = CollisionShape3D.new() + _coll.shape = SphereShape3D.new() + add_child(_coll) + else: + _coll.queue_free() + _coll = null + + +func _check_mouse_capture(event:InputEvent) -> void: + var button_state := 0 # 0- unchaged, 1- pressed, 2- released + + if not use_default_controls and InputMap.has_action(_ACTION_ACTIVATE): + if event.is_action_pressed(_ACTION_ACTIVATE): button_state = 1 + elif event.is_action_released(_ACTION_ACTIVATE): button_state = 2 + elif event is InputEventMouseButton and event.button_index == mouse_button: + button_state = 1 if event.pressed else 2 + + if button_state == 0: return + + match activation_mode: + ActivationMode.ON_HOLD: + set_active(button_state == 1) + ActivationMode.ON_CLICK: + if button_state == 1: + set_active(not _mouse_hidden) + + +func _revert_mouse_pos() -> void: + var vp := get_viewport() + match revert_mouse_to: + RevertMouseOption.CLICK_POSITION: + vp.warp_mouse( _mouse_click_pos ) + RevertMouseOption.VIEWPORT_CENTER: + vp.warp_mouse(vp.get_visible_rect().size/2) + + +#endregion + + + +#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#= + +# Public API + +#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#= +## Returns the actual camera that is used internally. +func get_camera() -> Camera3D: + return _camera + + +## Sets the FlyCamera's rotation to [param rot]. +## [br][br] +## [color=white][b]Note:[/b][/color] don't set the rotation directly, as the +## rotation of the root node doesn't represent the rotation of the actual camera. +func set_rot(rot:Vector3) -> void: + _yaw = rot.y + _pitch = rot.x + _cam_pivot.rotation_degrees.y = _yaw + _camera.rotation_degrees.x = _pitch + + +## Returns the rotation of the camera. +## [br][br] +## [color=white][b]Note:[/b][/color] don't get the rotation directly, as the +## rotation of the root node doesn't represent the rotation of the actual camera. +func get_rot() -> Vector3: + return Vector3(_camera.rotation.x, _cam_pivot.rotation.y, 0) + + +## Activate or deactivate the mouse controls +func set_active(enable:bool) -> void: + if enable: + _mouse_click_pos = get_viewport().get_mouse_position() + _mouse_hidden = true + Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) + else: + Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) + _mouse_hidden = false + _revert_mouse_pos() diff --git a/addons/sk_fly_camera/src/fly_camera.gd.uid b/addons/sk_fly_camera/src/fly_camera.gd.uid new file mode 100644 index 0000000..695dd32 --- /dev/null +++ b/addons/sk_fly_camera/src/fly_camera.gd.uid @@ -0,0 +1 @@ +uid://cte4jalives85