add pistol item; add equipment handler and switching

This commit is contained in:
Rowan 2025-06-21 14:08:43 -04:00
parent 27bd064c15
commit 42492595df
67 changed files with 3766 additions and 140 deletions

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 DmitriySalnikov
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, andor 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.

View file

@ -0,0 +1,157 @@
![icon](/images/icon_3d_128.png)
# Debug drawing utility for Godot
This is an add-on for debug drawing in 3D and for some 2D overlays, which is written in `C++` and can be used with `GDScript` or `C#`.
Based on my previous addon, which was developed [only for C#](https://github.com/DmitriySalnikov/godot_debug_draw_cs), and which was inspired by [Zylann's GDScript addon](https://github.com/Zylann/godot_debug_draw)
## [Documentation](https://dd3d.dmitriysalnikov.ru/docs/)
## [Godot 3 version](https://github.com/DmitriySalnikov/godot_debug_draw_3d/tree/godot_3)
## Support me
Your support adds motivation to develop my public projects.
<a href="https://boosty.to/dmitriysalnikov/donate"><img src="/docs/images/boosty.png" alt="Boosty" width=150px/></a>
<a href="#"><img src="/docs/images/USDT-TRC20.png" alt="USDT-TRC20" width=150px/></a>
<b>USDT-TRC20 TEw934PrsffHsAn5M63SoHYRuZo984EF6v</b>
## Features
3D:
* Arrow
* Billboard opaque square
* Box
* Camera Frustum
* Cylinder
* Gizmo
* Grid
* Line
* Line Path
* Line with Arrow
* Plane
* Points
* Position 3D (3 crossing axes)
* Sphere
* 3D Text
2D:
* **[Work in progress]**
Overlay:
* Text (with grouping and coloring)
Precompiled for:
* Windows
* Linux (built on Ubuntu 22.04)
* macOS (10.15+)
* Android (5.0+)
* iOS
* Web (Firefox is supported by Godot 4.3+)
This addon supports working with several World3D and different Viewports.
There is also a no depth test mode and other settings that can be changed for each instance.
This library supports double-precision builds, for more information, [see the documentation](https://dd3d.dmitriysalnikov.ru/docs/?page=md_docs_2DoublePrecision.html).
## [Interactive Web Demo](https://dd3d.dmitriysalnikov.ru/demo/)
[![screenshot_web](/images/screenshot_web.png)](https://dd3d.dmitriysalnikov.ru/demo/)
## Download
To download, use the [Godot Asset Library](https://godotengine.org/asset-library/asset/1766) or use one of the stable versions from the [GitHub Releases](https://github.com/DmitriySalnikov/godot_debug_draw_3d/releases) page.
For versions prior to `1.4.5`, just download one of the `source codes` in the assets. For newer versions, download `debug-draw-3d_[version].zip`.
### Installation
* Close editor
* Copy `addons/debug_draw_3d` to your `addons` folder, create it if the folder doesn't exist
* Launch editor
## Examples
More examples can be found in the `examples_dd3d/` folder.
Simple test:
```gdscript
func _process(delta: float) -> void:
var _time = Time.get_ticks_msec() / 1000.0
var box_pos = Vector3(0, sin(_time * 4), 0)
var line_begin = Vector3(-1, sin(_time * 4), 0)
var line_end = Vector3(1, cos(_time * 4), 0)
DebugDraw3D.draw_box(box_pos, Quaternion.IDENTITY, Vector3(1, 2, 1), Color(0, 1, 0))
DebugDraw3D.draw_line(line_begin, line_end, Color(1, 1, 0))
DebugDraw2D.set_text("Time", _time)
DebugDraw2D.set_text("Frames drawn", Engine.get_frames_drawn())
DebugDraw2D.set_text("FPS", Engine.get_frames_per_second())
DebugDraw2D.set_text("delta", delta)
```
![screenshot_1](/images/screenshot_1.png)
An example of using scoped configs:
```gdscript
@tool
extends Node3D
func _ready():
# Set the base scoped_config.
# Each frame will be reset to these scoped values.
DebugDraw3D.scoped_config().set_thickness(0.1).set_center_brightness(0.6)
func _process(delta):
# Draw using the base scoped config.
DebugDraw3D.draw_box(Vector3.ZERO, Quaternion.IDENTITY, Vector3.ONE * 2, Color.CORNFLOWER_BLUE)
if true:
# Create a scoped config that will exist until exiting this if.
var _s = DebugDraw3D.new_scoped_config().set_thickness(0).set_center_brightness(0.1)
# Draw with a thickness of 0
DebugDraw3D.draw_box(Vector3.ZERO, Quaternion.IDENTITY, Vector3.ONE, Color.RED)
# If necessary, the values inside this scope can be changed
# even before each call to draw_*.
_s.set_thickness(0.05)
DebugDraw3D.draw_box(Vector3(1,0,1), Quaternion.IDENTITY, Vector3.ONE * 1, Color.BLUE_VIOLET)
```
![screenshot_5](/images/screenshot_5.png)
> [!TIP]
>
> If you want to use a non-standard Viewport for rendering a 3d scene, then do not forget to specify it in the scoped config!
## API
This project has a separate [documentation](https://dd3d.dmitriysalnikov.ru/docs/) page.
Also, a list of all functions is available in the documentation inside the editor (see `DebugDraw3D` and `DebugDraw2D`).
![screenshot_4](/images/screenshot_4.png)
## Known issues and limitations
The text in the keys and values of a text group cannot contain multi-line strings.
The entire text overlay can only be placed in one corner.
[Frustum of Camera3D does not take into account the window size from ProjectSettings](https://github.com/godotengine/godot/issues/70362).
## More screenshots
`DebugDrawDemoScene.tscn` in editor
![screenshot_2](/images/screenshot_2.png)
`DebugDrawDemoScene.tscn` in play mode
![screenshot_3](/images/screenshot_3.png)

View file

@ -0,0 +1,153 @@
[configuration]
entry_symbol = "debug_draw_3d_library_init"
compatibility_minimum = "4.2.2"
reloadable = false
[dependencies]
; example.x86_64 = { "relative or absolute path to the dependency" : "the path relative to the exported project", }
; -------------------------------------
; debug
macos = { }
windows.x86_64 = { }
linux.x86_64 = { }
; by default godot is using threads
web.wasm32.nothreads = {}
web.wasm32 = {}
android.arm32 = { }
android.arm64 = { }
android.x86_32 = { }
android.x86_64 = { }
ios = {}
; -------------------------------------
; release no debug draw
macos.template_release = { }
windows.template_release.x86_64 = { }
linux.template_release.x86_64 = { }
web.template_release.wasm32.nothreads = { }
web.template_release.wasm32 = { }
android.template_release.arm32 = { }
android.template_release.arm64 = { }
android.template_release.x86_32 = { }
android.template_release.x86_64 = { }
ios.template_release = {}
; -------------------------------------
; release forced debug draw
macos.template_release.forced_dd3d = { }
windows.template_release.x86_64.forced_dd3d = { }
linux.template_release.x86_64.forced_dd3d = { }
web.template_release.wasm32.nothreads.forced_dd3d = { }
web.template_release.wasm32.forced_dd3d = { }
ios.template_release.forced_dd3d = {}
[libraries]
; -------------------------------------
; debug
macos = "libs/libdd3d.macos.editor.universal.framework"
windows.x86_64 = "libs/libdd3d.windows.editor.x86_64.dll"
linux.x86_64 = "libs/libdd3d.linux.editor.x86_64.so"
web.wasm32.nothreads = "libs/libdd3d.web.template_debug.wasm32.wasm"
web.wasm32 = "libs/libdd3d.web.template_debug.wasm32.threads.wasm"
android.arm32 = "libs/libdd3d.android.template_debug.arm32.so"
android.arm64 = "libs/libdd3d.android.template_debug.arm64.so"
android.x86_32 = "libs/libdd3d.android.template_debug.x86_32.so"
android.x86_64 = "libs/libdd3d.android.template_debug.x86_64.so"
ios = "libs/libdd3d.ios.template_debug.universal.dylib"
; -------------------------------------
; release no debug draw
macos.template_release = "libs/libdd3d.macos.template_release.universal.framework"
windows.template_release.x86_64 = "libs/libdd3d.windows.template_release.x86_64.dll"
linux.template_release.x86_64 = "libs/libdd3d.linux.template_release.x86_64.so"
web.template_release.wasm32.nothreads = "libs/libdd3d.web.template_release.wasm32.wasm"
web.template_release.wasm32 = "libs/libdd3d.web.template_release.wasm32.threads.wasm"
android.template_release.arm32 = "libs/libdd3d.android.template_release.arm32.so"
android.template_release.arm64 = "libs/libdd3d.android.template_release.arm64.so"
android.template_release.x86_32 = "libs/libdd3d.android.template_release.x86_32.so"
android.template_release.x86_64 = "libs/libdd3d.android.template_release.x86_64.so"
ios.template_release = "libs/libdd3d.ios.template_release.universal.dylib"
; -------------------------------------
; release forced debug draw
macos.template_release.forced_dd3d = "libs/libdd3d.macos.template_release.universal.enabled.framework"
windows.template_release.x86_64.forced_dd3d = "libs/libdd3d.windows.template_release.x86_64.enabled.dll"
linux.template_release.x86_64.forced_dd3d = "libs/libdd3d.linux.template_release.x86_64.enabled.so"
web.template_release.wasm32.nothreads.forced_dd3d = "libs/libdd3d.web.template_release.wasm32.enabled.wasm"
web.template_release.wasm32.forced_dd3d = "libs/libdd3d.web.template_release.wasm32.threads.enabled.wasm"
ios.template_release.forced_dd3d = "libs/libdd3d.ios.template_release.universal.enabled.dylib"
; -------------------------------------
; DOUBLE PRECISION
; -------------------------------------
; -------------------------------------
; debug
macos.double = "libs/libdd3d.macos.editor.universal.double.framework"
windows.x86_64.double = "libs/libdd3d.windows.editor.x86_64.double.dll"
linux.x86_64.double = "libs/libdd3d.linux.editor.x86_64.double.so"
web.wasm32.nothreads.double = "libs/libdd3d.web.template_debug.wasm32.double.wasm"
web.wasm32.double = "libs/libdd3d.web.template_debug.wasm32.threads.double.wasm"
android.arm32.double = "libs/libdd3d.android.template_debug.arm32.double.so"
android.arm64.double = "libs/libdd3d.android.template_debug.arm64.double.so"
android.x86_32.double = "libs/libdd3d.android.template_debug.x86_32.double.so"
android.x86_64.double = "libs/libdd3d.android.template_debug.x86_64.double.so"
ios.double = "libs/libdd3d.ios.template_debug.universal.dylib"
; -------------------------------------
; release no debug draw
macos.template_release.double = "libs/libdd3d.macos.template_release.universal.double.framework"
windows.template_release.x86_64.double = "libs/libdd3d.windows.template_release.x86_64.double.dll"
linux.template_release.x86_64.double = "libs/libdd3d.linux.template_release.x86_64.double.so"
web.template_release.wasm32.nothreads.double = "libs/libdd3d.web.template_release.wasm32.double.wasm"
web.template_release.wasm32.double = "libs/libdd3d.web.template_release.wasm32.threads.double.wasm"
android.template_release.arm32.double = "libs/libdd3d.android.template_release.arm32.double.so"
android.template_release.arm64.double = "libs/libdd3d.android.template_release.arm64.double.so"
android.template_release.x86_32.double = "libs/libdd3d.android.template_release.x86_32.double.so"
android.template_release.x86_64.double = "libs/libdd3d.android.template_release.x86_64.double.so"
ios.template_release.double = "libs/libdd3d.ios.template_release.universal.double.dylib"
; -------------------------------------
; release forced debug draw
macos.template_release.forced_dd3d.double = "libs/libdd3d.macos.template_release.universal.enabled.double.framework"
windows.template_release.x86_64.forced_dd3d.double = "libs/libdd3d.windows.template_release.x86_64.enabled.double.dll"
linux.template_release.x86_64.forced_dd3d.double = "libs/libdd3d.linux.template_release.x86_64.enabled.double.so"
web.template_release.wasm32.nothreads.forced_dd3d.double = "libs/libdd3d.web.template_release.wasm32.enabled.double.wasm"
web.template_release.wasm32.forced_dd3d.double = "libs/libdd3d.web.template_release.wasm32.threads.enabled.double.wasm"
ios.template_release.forced_dd3d.double = "libs/libdd3d.ios.template_release.universal.enabled.double.dylib"

View file

@ -0,0 +1 @@
uid://svqaxfp5kyrl

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>libdd3d.macos.editor.universal.dylib</string>
<key>CFBundleName</key>
<string>Debug Draw 3D</string>
<key>CFBundleDisplayName</key>
<string>Debug Draw 3D</string>
<key>CFBundleIdentifier</key>
<string>ru.dmitriysalnikov.dd3d</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright (c) Dmitriy Salnikov.</string>
<key>CFBundleVersion</key>
<string>1.5.1</string>
<key>CFBundleShortVersionString</key>
<string>1.5.1</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>DTPlatformName</key>
<string>macosx</string>
<key>LSMinimumSystemVersion</key>
<string>10.14</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
</dict>
</plist>

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>libdd3d.macos.template_release.universal.enabled.dylib</string>
<key>CFBundleName</key>
<string>Debug Draw 3D</string>
<key>CFBundleDisplayName</key>
<string>Debug Draw 3D</string>
<key>CFBundleIdentifier</key>
<string>ru.dmitriysalnikov.dd3d</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright (c) Dmitriy Salnikov.</string>
<key>CFBundleVersion</key>
<string>1.5.1</string>
<key>CFBundleShortVersionString</key>
<string>1.5.1</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>DTPlatformName</key>
<string>macosx</string>
<key>LSMinimumSystemVersion</key>
<string>10.14</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
</dict>
</plist>

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>libdd3d.macos.template_release.universal.dylib</string>
<key>CFBundleName</key>
<string>Debug Draw 3D</string>
<key>CFBundleDisplayName</key>
<string>Debug Draw 3D</string>
<key>CFBundleIdentifier</key>
<string>ru.dmitriysalnikov.dd3d</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright (c) Dmitriy Salnikov.</string>
<key>CFBundleVersion</key>
<string>1.5.1</string>
<key>CFBundleShortVersionString</key>
<string>1.5.1</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>DTPlatformName</key>
<string>macosx</string>
<key>LSMinimumSystemVersion</key>
<string>10.14</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
</dict>
</plist>

View file

@ -0,0 +1,621 @@
@tool
extends Node3D
@export var custom_font : Font
@export var custom_3d_font : Font
@export var zylann_example := false
@export var update_in_physics := false
@export var test_text := true
@export var more_test_cases := true
@export var draw_3d_text := true
@export var draw_array_of_boxes := false
@export var draw_text_with_boxes := false
@export var draw_1m_boxes := false
@export_range(0, 5, 0.001) var debug_thickness := 0.1
@export_range(0, 1, 0.001) var debug_center_brightness := 0.8
@export_range(0, 1) var camera_frustum_scale := 0.9
@export_group("Text groups", "text_groups")
@export var text_groups_show_examples := true
@export var text_groups_show_hints := true
@export var text_groups_show_stats := false
@export var text_groups_show_stats_2d := false
@export var text_groups_position := DebugDraw2DConfig.POSITION_LEFT_TOP
@export var text_groups_offset := Vector2i(8, 8)
@export var text_groups_padding := Vector2i(3, 1)
@export_range(1, 100) var text_groups_default_font_size := 15
@export_range(1, 100) var text_groups_title_font_size := 20
@export_range(1, 100) var text_groups_text_font_size := 17
@export_group("Tests", "tests")
@export var tests_use_threads := false
var test_thread : Thread = null
var test_thread_closing := false
var button_presses := {}
var frame_rendered := false
var physics_tick_processed := false
var timer_1 := 0.0
var timer_cubes := 0.0
var timer_3 := 0.0
var timer_text := 0.0
func _process(delta) -> void:
#print("Label3Ds count: %d" % get_child(0).get_child_count() if Engine.is_editor_hint() else get_tree().root.get_child(0).get_child_count())
$OtherWorld.mesh.material.set_shader_parameter("albedo_texture", $OtherWorld/SubViewport.get_texture())
physics_tick_processed = false
if not update_in_physics:
main_update(delta)
_update_timers(delta)
_call_from_thread()
## Since physics frames may not be called every frame or may be called multiple times in one frame,
## there is an additional check to ensure that a new frame has been drawn before updating the data.
func _physics_process(delta: float) -> void:
if not physics_tick_processed:
physics_tick_processed = true
if update_in_physics:
main_update(delta)
_update_timers(delta)
# Physics specific:
if not zylann_example:
DebugDraw3D.draw_line($"Lines/8".global_position, $Lines/Target.global_position, Color.YELLOW)
if more_test_cases:
_draw_rays_casts()
## Additional drawing in the Viewport
if true:
var _w1 = DebugDraw3D.new_scoped_config().set_viewport(%OtherWorldBox.get_viewport()).set_thickness(0.01).set_center_brightness(1).set_no_depth_test(true)
DebugDraw3D.draw_box_xf(Transform3D(Basis()
.scaled(Vector3.ONE*0.3)
.rotated(Vector3(0,0,1), PI/4)
.rotated(Vector3(0,1,0), wrapf(Time.get_ticks_msec() / -1500.0, 0, TAU) - PI/4), %OtherWorldBox.global_transform.origin),
Color.BROWN, true, 0.4)
func main_update(delta: float) -> void:
DebugDraw3D.scoped_config().set_thickness(debug_thickness).set_center_brightness(debug_center_brightness)
_update_keys_just_press()
if _is_key_just_pressed(KEY_F1):
zylann_example = !zylann_example
# Zylann's example :D
if zylann_example:
var _time = Time.get_ticks_msec() / 1000.0
var box_pos = Vector3(0, sin(_time * 4), 0)
var line_begin = Vector3(-1, sin(_time * 4), 0)
var line_end = Vector3(1, cos(_time * 4), 0)
DebugDraw3D.draw_box(box_pos, Quaternion.IDENTITY, Vector3(1, 2, 1), Color(0, 1, 0))
DebugDraw3D.draw_line(line_begin, line_end, Color(1, 1, 0))
DebugDraw2D.set_text("Time", _time)
DebugDraw2D.set_text("Frames drawn", Engine.get_frames_drawn())
DebugDraw2D.set_text("FPS", Engine.get_frames_per_second())
DebugDraw2D.set_text("delta", delta)
$HitTest.visible = false
$LagTest.visible = false
$PlaneOrigin.visible = false
$OtherWorld.visible = false
%ZDepthTestCube.visible = false
return
$HitTest.visible = true
$LagTest.visible = true
$PlaneOrigin.visible = true
$OtherWorld.visible = true
%ZDepthTestCube.visible = true
# Testing the rendering layers by showing the image from the second camera inside the 2D panel
DebugDraw3D.config.geometry_render_layers = 1 if not Input.is_key_pressed(KEY_ALT) else 0b10010
$Panel.visible = Input.is_key_pressed(KEY_ALT)
DebugDraw2D.custom_canvas = %CustomCanvas if Input.is_key_pressed(KEY_ALT) else null
# More property toggles
DebugDraw3D.config.freeze_3d_render = Input.is_key_pressed(KEY_DOWN)
DebugDraw3D.config.visible_instance_bounds = Input.is_key_pressed(KEY_RIGHT)
# Regenerate meshes
if Input.is_action_just_pressed("ui_end"):
DebugDraw3D.regenerate_geometry_meshes()
# Some property toggles
if _is_key_just_pressed(KEY_LEFT):
DebugDraw3D.config.use_frustum_culling = !DebugDraw3D.config.use_frustum_culling
if _is_key_just_pressed(KEY_UP):
DebugDraw3D.config.force_use_camera_from_scene = !DebugDraw3D.config.force_use_camera_from_scene
if _is_key_just_pressed(KEY_CTRL):
if not Engine.is_editor_hint():
get_viewport().msaa_3d = Viewport.MSAA_DISABLED if get_viewport().msaa_3d == Viewport.MSAA_4X else Viewport.MSAA_4X
if not Engine.is_editor_hint():
if _is_key_just_pressed(KEY_1):
DebugDraw3D.debug_enabled = !DebugDraw3D.debug_enabled
if _is_key_just_pressed(KEY_2):
DebugDraw2D.debug_enabled = !DebugDraw2D.debug_enabled
if _is_key_just_pressed(KEY_3):
DebugDrawManager.debug_enabled = !DebugDrawManager.debug_enabled
DebugDraw3D.config.frustum_length_scale = camera_frustum_scale
# Zones with black borders
for z in $Zones.get_children():
DebugDraw3D.draw_box_xf(z.global_transform, Color.BLACK)
# Spheres
_draw_zone_title(%SpheresBox, "Spheres")
DebugDraw3D.draw_sphere_xf($Spheres/SphereTransform.global_transform, Color.CRIMSON)
if true:
var _shd = DebugDraw3D.new_scoped_config().set_hd_sphere(true)
DebugDraw3D.draw_sphere_xf($Spheres/SphereHDTransform.global_transform, Color.ORANGE_RED)
## Delayed spheres
if timer_1 < 0:
DebugDraw3D.draw_sphere($Spheres/SpherePosition.global_position, 2.0, Color.BLUE_VIOLET, 2.0)
var _shd = DebugDraw3D.new_scoped_config().set_hd_sphere(true)
DebugDraw3D.draw_sphere($Spheres/SpherePosition.global_position + Vector3.FORWARD * 4, 2.0, Color.CORNFLOWER_BLUE, 2.0)
timer_1 = 2
# Cylinders
_draw_zone_title(%CylindersBox, "Cylinders")
DebugDraw3D.draw_cylinder($Cylinders/Cylinder1.global_transform, Color.CRIMSON)
DebugDraw3D.draw_cylinder(Transform3D(Basis.IDENTITY.scaled(Vector3(1,2,1)), $Cylinders/Cylinder2.global_position), Color.RED)
DebugDraw3D.draw_cylinder_ab($"Cylinders/Cylinder3/1".global_position, $"Cylinders/Cylinder3/2".global_position, 0.7)
# Boxes
_draw_zone_title(%BoxesBox, "Boxes")
DebugDraw3D.draw_box_xf($Boxes/Box1.global_transform, Color.MEDIUM_PURPLE)
DebugDraw3D.draw_box($Boxes/Box2.global_position, Quaternion.from_euler(Vector3(0, deg_to_rad(45), deg_to_rad(45))), Vector3.ONE, Color.REBECCA_PURPLE)
DebugDraw3D.draw_box_xf(Transform3D(Basis(Vector3.UP, PI * 0.25).scaled(Vector3.ONE * 2), $Boxes/Box3.global_position), Color.ROSY_BROWN)
DebugDraw3D.draw_aabb(AABB($Boxes/AABB_fixed.global_position, Vector3(2, 1, 2)), Color.AQUA)
DebugDraw3D.draw_aabb_ab($Boxes/AABB/a.global_position, $Boxes/AABB/b.global_position, Color.DEEP_PINK)
# Boxes AB
DebugDraw3D.draw_arrow($Boxes/BoxAB.global_position, $Boxes/BoxAB/o/up.global_position, Color.GOLD, 0.1, true)
DebugDraw3D.draw_box_ab($Boxes/BoxAB/a.global_position, $Boxes/BoxAB/b.global_position, $Boxes/BoxAB/o/up.global_position - $Boxes/BoxAB.global_position, Color.PERU)
DebugDraw3D.draw_arrow($Boxes/BoxABEdge.global_position, $Boxes/BoxABEdge/o/up.global_position, Color.DARK_RED, 0.1, true)
DebugDraw3D.draw_box_ab($Boxes/BoxABEdge/a.global_position, $Boxes/BoxABEdge/b.global_position, $Boxes/BoxABEdge/o/up.global_position - $Boxes/BoxABEdge.global_position, Color.DARK_OLIVE_GREEN, false)
# Lines
_draw_zone_title(%LinesBox, "Lines")
var target = $Lines/Target
DebugDraw3D.draw_square(target.global_position, 0.5, Color.RED)
DebugDraw3D.draw_line($"Lines/1".global_position, target.global_position, Color.FUCHSIA)
DebugDraw3D.draw_ray($"Lines/3".global_position, (target.global_position - $"Lines/3".global_position).normalized(), 3.0, Color.CRIMSON)
if timer_3 < 0:
DebugDraw3D.draw_line($"Lines/6".global_position, target.global_position, Color.FUCHSIA, 2.0)
timer_3 = 2
# Test UP vector
DebugDraw3D.draw_line($"Lines/7".global_position, target.global_position, Color.RED)
# Lines with Arrow
DebugDraw3D.draw_arrow($"Lines/2".global_position, target.global_position, Color.BLUE, 0.5, true)
DebugDraw3D.draw_arrow_ray($"Lines/4".global_position, (target.global_position - $"Lines/4".global_position).normalized(), 8.0, Color.LAVENDER, 0.5, true)
DebugDraw3D.draw_line_hit_offset($"Lines/5".global_position, target.global_position, true, abs(sin(Time.get_ticks_msec() / 1000.0)), 0.25, Color.AQUA)
# Paths
_draw_zone_title(%PathsBox, "Paths")
## preparing data
var points: PackedVector3Array = []
var points_below: PackedVector3Array = []
var points_below2: PackedVector3Array = []
var points_below3: PackedVector3Array = []
var points_below4: PackedVector3Array = []
var lines_above: PackedVector3Array = []
for c in $LinePath.get_children():
if not c is Node3D:
break
points.append(c.global_position)
points_below.append(c.global_position + Vector3.DOWN)
points_below2.append(c.global_position + Vector3.DOWN * 2)
points_below3.append(c.global_position + Vector3.DOWN * 3)
points_below4.append(c.global_position + Vector3.DOWN * 4)
for x in points.size()-1:
lines_above.append(points[x] + Vector3.UP)
lines_above.append(points[x+1] + Vector3.UP)
## drawing lines
DebugDraw3D.draw_lines(lines_above)
DebugDraw3D.draw_line_path(points, Color.BEIGE)
DebugDraw3D.draw_points(points_below, DebugDraw3D.POINT_TYPE_SQUARE, 0.2, Color.DARK_GREEN)
DebugDraw3D.draw_point_path(points_below2, DebugDraw3D.POINT_TYPE_SQUARE, 0.25, Color.BLUE, Color.TOMATO)
DebugDraw3D.draw_arrow_path(points_below3, Color.GOLD, 0.5)
if true:
var _sl = DebugDraw3D.new_scoped_config().set_thickness(0.05)
DebugDraw3D.draw_point_path(points_below4, DebugDraw3D.POINT_TYPE_SPHERE, 0.25, Color.MEDIUM_SEA_GREEN, Color.MEDIUM_VIOLET_RED)
# Misc
_draw_zone_title(%MiscBox, "Misc")
if Engine.is_editor_hint():
#for i in 1000:
var _a11 = DebugDraw3D.new_scoped_config().set_thickness(0)
DebugDraw3D.draw_camera_frustum($Camera, Color.DARK_ORANGE)
if true:
var _s123 = DebugDraw3D.new_scoped_config().set_center_brightness(0.1)
DebugDraw3D.draw_arrowhead($Misc/Arrow.global_transform, Color.YELLOW_GREEN)
DebugDraw3D.draw_square($Misc/Billboard.global_position, 0.5, Color.GREEN)
DebugDraw3D.draw_position($Misc/Position.global_transform, Color.BROWN)
DebugDraw3D.draw_gizmo($Misc/GizmoTransform.global_transform, DebugDraw3D.empty_color, true)
DebugDraw3D.draw_gizmo($Misc/GizmoOneColor.global_transform, Color.BROWN, true)
if true:
var _s123 = DebugDraw3D.new_scoped_config().set_center_brightness(0.5).set_no_depth_test(true)
DebugDraw3D.draw_gizmo($Misc/GizmoNormal.global_transform.orthonormalized(), DebugDraw3D.empty_color, false)
# Grids
_draw_zone_title_pos($Grids/GridCentered.global_position + Vector3(0, 1.5, 0), "Grids", 96, 36)
var tg : Transform3D = $Grids/Grid.global_transform
var tn : Vector3 = $Grids/Grid/Subdivision.transform.origin
DebugDraw3D.draw_grid(tg.origin, tg.basis.x, tg.basis.z, Vector2i(int(tn.x*10), int(tn.z*10)), Color.LIGHT_CORAL, false)
var tn1 = $Grids/GridCentered/Subdivision.transform.origin
DebugDraw3D.draw_grid_xf($Grids/GridCentered.global_transform, Vector2i(tn1.x*10, tn1.z*10))
if true:
var _s32 = DebugDraw3D.new_scoped_config().set_thickness(0.05)
DebugDraw3D.draw_box_xf($PostProcess.global_transform, Color.SEA_GREEN)
# Local transform
_draw_local_xf_box(%LocalTransformRecursiveOrigin.global_transform, 0.05, 10)
# 2D
DebugDraw2D.config.text_default_size = text_groups_default_font_size
DebugDraw2D.config.text_block_offset = text_groups_offset
DebugDraw2D.config.text_block_position = text_groups_position
DebugDraw2D.config.text_padding = text_groups_padding
DebugDraw2D.config.text_custom_font = custom_font
if test_text:
_text_tests()
# Lag Test
var lag_test_pos = $LagTest/RESET.get_animation("RESET").track_get_key_value(0,0)
_draw_zone_title_pos(lag_test_pos, "Lag test")
$LagTest.position = lag_test_pos + Vector3(sin(Time.get_ticks_msec() / 100.0) * 2.5, 0, 0)
DebugDraw3D.draw_box($LagTest.global_position, Quaternion.IDENTITY, Vector3.ONE * 2.01, Color.CHOCOLATE, true)
if more_test_cases:
for ray in $HitTest/RayEmitter.get_children():
ray.set_physics_process_internal(true)
_more_tests()
else:
for ray in $HitTest/RayEmitter.get_children():
ray.set_physics_process_internal(false)
_draw_other_world()
if draw_array_of_boxes:
_draw_array_of_boxes()
func _text_tests():
DebugDraw2D.set_text("FPS", "%.2f" % Engine.get_frames_per_second(), 0, Color.GOLD)
if text_groups_show_examples:
if timer_text < 0:
DebugDraw2D.set_text("Some delayed text", "for 2.5s", -1, Color.BLACK, 2.5) # it's supposed to show text for 2.5 seconds
timer_text = 5
DebugDraw2D.begin_text_group("-- First Group --", 2, Color.LIME_GREEN, true, text_groups_title_font_size, text_groups_text_font_size)
DebugDraw2D.set_text("Simple text")
DebugDraw2D.set_text("Text", "Value", 0, Color.AQUAMARINE)
DebugDraw2D.set_text("Text out of order", null, -1, Color.SILVER)
DebugDraw2D.begin_text_group("-- Second Group --", 1, Color.BEIGE)
DebugDraw2D.set_text("Rendered frames", Engine.get_frames_drawn())
DebugDraw2D.end_text_group()
if text_groups_show_stats or text_groups_show_stats_2d:
DebugDraw2D.begin_text_group("-- Stats --", 3, Color.WHEAT)
var render_stats := DebugDraw3D.get_render_stats()
if render_stats && text_groups_show_stats:
DebugDraw2D.set_text("Total", render_stats.total_geometry)
DebugDraw2D.set_text("Instances", render_stats.instances + render_stats.instances_physics, 1)
DebugDraw2D.set_text("Lines", render_stats.lines + render_stats.lines_physics, 2)
DebugDraw2D.set_text("Total Visible", render_stats.total_visible, 3)
DebugDraw2D.set_text("Visible Instances", render_stats.visible_instances, 4)
DebugDraw2D.set_text("Visible Lines", render_stats.visible_lines, 5)
DebugDraw2D.set_text("---", null, 12)
DebugDraw2D.set_text("Culling time", "%.2f ms" % (render_stats.total_time_culling_usec / 1000.0), 13)
DebugDraw2D.set_text("Filling instances buffer", "%.2f ms" % (render_stats.time_filling_buffers_instances_usec / 1000.0), 14)
DebugDraw2D.set_text("Filling lines buffer", "%.2f ms" % (render_stats.time_filling_buffers_lines_usec / 1000.0), 15)
DebugDraw2D.set_text("Filling time", "%.2f ms" % (render_stats.total_time_filling_buffers_usec / 1000.0), 16)
DebugDraw2D.set_text("Total time", "%.2f ms" % (render_stats.total_time_spent_usec / 1000.0), 17)
DebugDraw2D.set_text("----", null, 32)
DebugDraw2D.set_text("Total Label3D", render_stats.nodes_label3d_exists_total, 33)
DebugDraw2D.set_text("Visible Label3D", render_stats.nodes_label3d_visible + render_stats.nodes_label3d_visible_physics, 34)
DebugDraw2D.set_text("-----", null, 48)
DebugDraw2D.set_text("Created scoped configs", "%d" % render_stats.created_scoped_configs, 49)
if text_groups_show_stats && text_groups_show_stats_2d:
DebugDraw2D.set_text("------", null, 64)
var render_stats_2d := DebugDraw2D.get_render_stats()
if render_stats_2d && text_groups_show_stats_2d:
DebugDraw2D.set_text("Text groups", render_stats_2d.overlay_text_groups, 96)
DebugDraw2D.set_text("Text lines", render_stats_2d.overlay_text_lines, 97)
DebugDraw2D.end_text_group()
if text_groups_show_hints:
DebugDraw2D.begin_text_group("controls", 1024, Color.WHITE, false)
if not Engine.is_editor_hint():
DebugDraw2D.set_text("WASD QE, LMB", "To move", 0)
DebugDraw2D.set_text("Alt: change render layers", DebugDraw3D.config.geometry_render_layers, 1)
if not OS.has_feature("web"):
DebugDraw2D.set_text("Ctrl: toggle anti-aliasing", "MSAA 4x" if get_viewport().msaa_3d == Viewport.MSAA_4X else "Disabled", 2)
DebugDraw2D.set_text("Down: freeze render", DebugDraw3D.config.freeze_3d_render, 3)
if Engine.is_editor_hint():
DebugDraw2D.set_text("Up: use scene camera", DebugDraw3D.config.force_use_camera_from_scene, 4)
DebugDraw2D.set_text("1,2,3: toggle debug", "%s, %s 😐, %s 😏" % [DebugDraw3D.debug_enabled, DebugDraw2D.debug_enabled, DebugDrawManager.debug_enabled], 5)
DebugDraw2D.set_text("Left: toggle frustum culling", DebugDraw3D.config.use_frustum_culling, 6)
DebugDraw2D.set_text("Right: draw bounds for culling", DebugDraw3D.config.visible_instance_bounds, 7)
DebugDraw2D.end_text_group()
func _draw_zone_title(node: Node3D, title: String):
if draw_3d_text:
var _s1 = DebugDraw3D.new_scoped_config().set_text_outline_size(72)
DebugDraw3D.draw_text(node.global_position + node.global_basis.y * 0.85, title, 128)
func _draw_zone_title_pos(pos: Vector3, title: String, font_size: int = 128, outline: int = 72):
if draw_3d_text:
var _s1 = DebugDraw3D.new_scoped_config().set_text_outline_size(outline)
DebugDraw3D.draw_text(pos, title, font_size)
const _local_mul := 0.45
const _local_mul_vec := Vector3(_local_mul, _local_mul, _local_mul)
var __local_lines_cross_recursive = PackedVector3Array([Vector3(-0.5, -0.5, -0.5), Vector3(0.5, -0.5, 0.5), Vector3(-0.5, -0.5, 0.5), Vector3(0.5, -0.5, -0.5)])
var __local_box_recursive = Transform3D.IDENTITY.rotated_local(Vector3.UP, deg_to_rad(30)).translated(Vector3(-0.25, -0.55, 0.25)).scaled(_local_mul_vec)
var __local_sphere_recursive = Transform3D.IDENTITY.translated(Vector3(0.5, 0.55, -0.5)).scaled(_local_mul_vec)
func _draw_local_xf_box(xf: Transform3D, thickness: float, max_depth: int, depth: int = 0):
if depth >= max_depth:
return
var _s1 = DebugDraw3D.new_scoped_config().set_thickness(thickness).set_transform(xf)
# a box with a small offset
DebugDraw3D.draw_box_xf(Transform3D(Basis(), Vector3(0, 0.001, 0)), Color.BROWN)
# a box and a stand for the next depth
DebugDraw3D.draw_box_xf(__local_box_recursive, Color.CHARTREUSE)
# just a sphere and lines
DebugDraw3D.draw_sphere_xf(__local_sphere_recursive, Color.DARK_ORANGE)
_s1.set_thickness(0)
DebugDraw3D.draw_lines(__local_lines_cross_recursive, Color.CRIMSON)
# A simple animation generator with descent into the depth of the scene
if false:
var anim: Animation = %RecursiveTransformTest.get_animation("recursive")
# clear keys
if depth == 0: for i in anim.track_get_key_count(0): anim.track_remove_key(0, 0); anim.track_remove_key(1, 0)
var time = depth * 2
var s_xf = xf * __local_sphere_recursive
var next_s_xf = (xf * __local_box_recursive.translated(__local_box_recursive.basis.y)) * __local_sphere_recursive
var get_sphere_pos = func(l_xf): return l_xf.origin + (l_xf).basis.y
anim.position_track_insert_key(0, time, get_sphere_pos.call(s_xf))
anim.rotation_track_insert_key(1, time, Transform3D(Basis(), get_sphere_pos.call(s_xf)).looking_at(get_sphere_pos.call(next_s_xf), xf.basis.y).basis.get_rotation_quaternion())
_draw_local_xf_box(xf * __local_box_recursive.translated(__local_box_recursive.basis.y), thickness * _local_mul, max_depth, depth + 1)
func _draw_other_world():
var _w1 = DebugDraw3D.new_scoped_config().set_viewport(%OtherWorldBox.get_viewport())
DebugDraw3D.draw_box_xf(%OtherWorldBox.global_transform.rotated_local(Vector3(1,1,-1).normalized(), wrapf(Time.get_ticks_msec() / 1000.0, 0, TAU)), Color.SANDY_BROWN)
DebugDraw3D.draw_box_xf(%OtherWorldBox.global_transform.rotated_local(Vector3(-1,1,-1).normalized(), wrapf(Time.get_ticks_msec() / -1000.0, 0, TAU) - PI/4), Color.SANDY_BROWN)
if draw_3d_text:
var angle = wrapf(Time.get_ticks_msec() / 1000.0, 0, TAU)
if true:
var _w2 = DebugDraw3D.new_scoped_config().set_text_font(custom_3d_font)
DebugDraw3D.draw_text(%OtherWorldBox.global_position + Vector3(cos(angle), -0.25, sin(angle)), "Hello world!", 32, Color.CRIMSON, 0)
if true:
var _w3 = DebugDraw3D.new_scoped_config().set_no_depth_test(true).set_text_outline_color(Color.INDIAN_RED).set_text_outline_size(6)
DebugDraw3D.draw_text(%OtherWorldBox.global_position + Vector3(cos(angle), +0.25, sin(-angle)), "World without depth", 20, Color.PINK, 0)
func _draw_rays_casts():
# Line hits render
_draw_zone_title_pos(%HitTestSphere.global_position, "Line hits", 96, 36)
for ray in $HitTest/RayEmitter.get_children():
if ray is RayCast3D:
ray.force_raycast_update()
DebugDraw3D.draw_line_hit(ray.global_position, ray.to_global(ray.target_position), ray.get_collision_point(), ray.is_colliding(), 0.3)
func _more_tests():
# Delayed line render
if true:
var _a12 = DebugDraw3D.new_scoped_config().set_thickness(0.035)
DebugDraw3D.draw_line($LagTest.global_position + Vector3.UP, $LagTest.global_position + Vector3(0,3,sin(Time.get_ticks_msec() / 50.0)), DebugDraw3D.empty_color, 0.35)
if draw_3d_text:
DebugDraw3D.draw_text($LagTest.global_position + Vector3(0,3,sin(Time.get_ticks_msec() / 50.0)), "%.1f" % sin(Time.get_ticks_msec() / 50.0), 16, DebugDraw3D.empty_color, 0.35)
# Draw plane
if true:
var _s11 = DebugDraw3D.new_scoped_config().set_thickness(0.02).set_plane_size(10)
var pl_node: Node3D = $PlaneOrigin
var xf: Transform3D = pl_node.global_transform
var normal: = xf.basis.y.normalized()
var plane = Plane(normal, xf.origin.dot(normal))
var vp: Viewport = get_viewport()
if Engine.is_editor_hint() and Engine.get_singleton(&"EditorInterface").get_editor_viewport_3d(0):
vp = Engine.get_singleton(&"EditorInterface").get_editor_viewport_3d(0)
var cam = vp.get_camera_3d()
if cam:
var dir = vp.get_camera_3d().project_ray_normal(vp.get_mouse_position())
var intersect = plane.intersects_ray(cam.global_position, dir)
DebugDraw3D.draw_plane(plane, Color.CORAL * Color(1,1,1, 0.4), pl_node.global_position)
if intersect and intersect.distance_to(pl_node.global_position) < _s11.get_plane_size() * 0.5:
# Need to test different colors on both sides of the plane
var col = Color.FIREBRICK if plane.is_point_over(cam.global_position) else Color.AQUAMARINE
DebugDraw3D.draw_sphere(intersect, 0.3, col)
func _draw_array_of_boxes():
# Lots of boxes to check performance..
var x_size := 50
var y_size := 50
var z_size := 3
var mul := 1
var cubes_max_time := 1.25
var show_text := draw_text_with_boxes
var cfg = DebugDraw3D.new_scoped_config()
if draw_1m_boxes:
x_size = 100
y_size = 100
z_size = 100
mul = 4
cubes_max_time = 60
show_text = false
var size := Vector3.ONE
var half_size := size * 0.5
if timer_cubes < 0:
var _start_time = Time.get_ticks_usec()
for x in x_size:
for y in y_size:
for z in z_size:
cfg.set_thickness(randf_range(0, 0.1))
var pos := Vector3(x * mul, (-4-z) * mul, y * mul) + global_position
DebugDraw3D.draw_box(pos, Quaternion.IDENTITY, size, DebugDraw3D.empty_color, false, cubes_max_time)
if show_text and z == 0:
DebugDraw3D.draw_text(pos + half_size, str(pos), 32, DebugDraw3D.empty_color, cubes_max_time)
#print("Draw Cubes: %.3fms" % ((Time.get_ticks_usec() - _start_time) / 1000.0))
timer_cubes = cubes_max_time
func _ready() -> void:
_update_keys_just_press()
await get_tree().process_frame
# this check is required for inherited scenes, because an instance of this
# script is created first, and then overridden by another
if not is_inside_tree():
return
DebugDraw2D.config.text_background_color = Color(0.3, 0.3, 0.3, 0.8)
func _is_key_just_pressed(key):
if (button_presses[key] == 1):
button_presses[key] = 2
return true
return false
func _update_keys_just_press():
var set_key = func (k: Key):
if Input.is_key_pressed(k) and button_presses.has(k):
if button_presses[k] == 0:
return 1
else:
return button_presses[k]
else:
return 0
button_presses[KEY_LEFT] = set_key.call(KEY_LEFT)
button_presses[KEY_UP] = set_key.call(KEY_UP)
button_presses[KEY_CTRL] = set_key.call(KEY_CTRL)
button_presses[KEY_F1] = set_key.call(KEY_F1)
button_presses[KEY_1] = set_key.call(KEY_1)
button_presses[KEY_2] = set_key.call(KEY_2)
button_presses[KEY_3] = set_key.call(KEY_3)
func _update_timers(delta : float):
timer_1 -= delta
timer_cubes -= delta
timer_3 -= delta
timer_text -= delta
func _notification(what: int) -> void:
if what == NOTIFICATION_EDITOR_PRE_SAVE or what == NOTIFICATION_EXIT_TREE:
_thread_stop()
func _call_from_thread():
if tests_use_threads and (not test_thread or not test_thread.is_alive()):
test_thread_closing = false
test_thread = Thread.new()
test_thread.start(_thread_body)
elif not tests_use_threads and (test_thread and test_thread.is_alive()):
_thread_stop()
func _thread_stop():
if test_thread and test_thread.is_alive():
tests_use_threads = false
test_thread_closing = true
test_thread.wait_to_finish()
func _thread_body():
print("Thread started!")
while not test_thread_closing:
DebugDraw3D.draw_box(Vector3(0,-1,0), Quaternion.IDENTITY, Vector3.ONE, Color.BROWN, true, 0.016)
var boxes = 10
for y in boxes:
var offset := sin(TAU/boxes * y + wrapf(Time.get_ticks_msec() / 100.0, 0, TAU))
var pos := Vector3(offset, y, 0)
DebugDraw3D.draw_box(pos, Quaternion.IDENTITY, Vector3.ONE, Color.GREEN_YELLOW, true, 0.016)
DebugDraw3D.draw_text(pos, str(y), 64, Color.WHITE , 0.016)
if y == 0:
DebugDraw2D.set_text("thread. sin", offset)
OS.delay_msec(16)
print("Thread finished!")

View file

@ -0,0 +1 @@
uid://ba2ie81p2x3x7

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,854 @@
using Godot;
using System;
using System.Collections.Generic;
[Tool]
public partial class DebugDrawDemoSceneCS : Node3D
{
Random random = new Random();
[Export] Font custom_font;
[Export] Font custom_3d_font;
[Export] bool zylann_example = false;
[Export] bool update_in_physics = false;
[Export] bool test_text = true;
[Export] bool more_test_cases = true;
[Export] bool draw_3d_text = true;
[Export] bool draw_array_of_boxes = false;
[Export] bool draw_text_with_boxes = false;
[Export] bool draw_1m_boxes = false;
[Export(PropertyHint.Range, "0, 5, 0.001")] float debug_thickness = 0.1f;
[Export(PropertyHint.Range, "0, 1")] float camera_frustum_scale = 0.9f;
[ExportGroup("Text groups", "text_groups")]
[Export] bool text_groups_show_examples = true;
[Export] bool text_groups_show_hints = true;
[Export] bool text_groups_show_stats = true;
[Export] bool text_groups_show_stats_2d = true;
[Export] DebugDraw2DConfig.BlockPosition text_groups_position = DebugDraw2DConfig.BlockPosition.LeftTop;
[Export] Vector2I text_groups_offset = new Vector2I(8, 8);
[Export] Vector2I text_groups_padding = new Vector2I(3, 1);
[Export(PropertyHint.Range, "1, 100")] int text_groups_default_font_size = 15;
[Export(PropertyHint.Range, "1, 100")] int text_groups_title_font_size = 20;
[Export(PropertyHint.Range, "1, 100")] int text_groups_text_font_size = 17;
Dictionary<Key, int> button_presses = new Dictionary<Key, int>() {
{ Key.Left, 0 },
{ Key.Up, 0 },
{ Key.Ctrl, 0 },
{ Key.F1, 0 },
{ Key.Key1, 0 },
{ Key.Key2, 0 },
{ Key.Key3, 0 },
};
double timer_1 = 0.0;
double timer_cubes = 0.0;
double timer_3 = 0.0;
double timer_text = 0.0;
public override async void _Ready()
{
_get_nodes();
_update_keys_just_press();
await new SignalAwaiter(GetTree(), "process_frame", this);
// this check is required for inherited scenes, because an instance of this
// script is created first, and then overridden by another
if (!IsInsideTree())
return;
DebugDraw2D.Config.TextBackgroundColor = new Color(0.3f, 0.3f, 0.3f, 0.8f);
}
bool _is_key_just_pressed(Key key)
{
if (button_presses[key] == 1)
{
button_presses[key] = 2;
return true;
}
return false;
}
void _update_timers(double delta)
{
timer_1 -= delta;
timer_cubes -= delta;
timer_3 -= delta;
timer_text -= delta;
}
void _update_keys_just_press()
{
var set = (Key k) => Input.IsKeyPressed(k) ? (button_presses[k] == 0 ? 1 : button_presses[k]) : 0;
button_presses[Key.Left] = set(Key.Left);
button_presses[Key.Up] = set(Key.Up);
button_presses[Key.Ctrl] = set(Key.Ctrl);
button_presses[Key.F1] = set(Key.F1);
button_presses[Key.Key1] = set(Key.Key1);
button_presses[Key.Key2] = set(Key.Key2);
button_presses[Key.Key3] = set(Key.Key3);
}
bool phys_frame_called = false;
public override void _Process(double delta)
{
((ShaderMaterial)((PrimitiveMesh)dOtherWorld.Mesh).Material).SetShaderParameter("albedo_texture", dOtherWorldViewport.GetTexture());
phys_frame_called = false;
if (!update_in_physics)
{
MainUpdate(delta);
_update_timers(delta);
}
}
public override void _PhysicsProcess(double delta)
{
if (!phys_frame_called)
{
phys_frame_called = true;
if (update_in_physics)
{
MainUpdate(delta);
_update_timers(delta);
}
}
// Physics specific:
if (!zylann_example)
{
DebugDraw3D.DrawLine(dLines_8.GlobalPosition, dLines_Target.GlobalPosition, Colors.Yellow);
if (more_test_cases)
{
_draw_rays_casts();
}
// Additional drawing in the Viewport
using (var _w1 = DebugDraw3D.NewScopedConfig().SetViewport(dOtherWorldBox.GetViewport()).SetThickness(0.01f).SetCenterBrightness(1).SetNoDepthTest(true))
{
DebugDraw3D.DrawBoxXf(new Transform3D(Basis.Identity
.Scaled(Vector3.One * 0.3f)
.Rotated(new Vector3(0, 0, 1), Mathf.Pi / 4)
.Rotated(new Vector3(0, 1, 0), Mathf.Wrap(Time.GetTicksMsec() / -1500.0f, 0, Mathf.Tau) - Mathf.Pi / 4), dOtherWorldBox.GlobalPosition),
Colors.Brown, true, 0.4f);
}
}
}
void MainUpdate(double delta)
{
DebugDraw3D.ScopedConfig().SetThickness(debug_thickness);
_update_keys_just_press();
if (_is_key_just_pressed(Key.F1))
zylann_example = !zylann_example;
// Zylann's example :D
if (zylann_example)
{
var _time = Time.GetTicksMsec() / 1000.0f;
var box_pos = new Vector3(0, Mathf.Sin(_time * 4f), 0);
var line_begin = new Vector3(-1, Mathf.Sin(_time * 4f), 0);
var line_end = new Vector3(1, Mathf.Cos(_time * 4f), 0);
DebugDraw3D.DrawBox(box_pos, Quaternion.Identity, new Vector3(1, 2, 1), new Color(0, 1, 0));
DebugDraw3D.DrawLine(line_begin, line_end, new Color(1, 1, 0));
DebugDraw2D.SetText("Time", _time);
DebugDraw2D.SetText("Frames drawn", Engine.GetFramesDrawn());
DebugDraw2D.SetText("FPS", Engine.GetFramesPerSecond());
DebugDraw2D.SetText("delta", delta);
dHitTest.Visible = false;
dLagTest.Visible = false;
dPlaneOrigin.Visible = false;
pZDepthTestCube.Visible = false;
dOtherWorld.Visible = false;
return;
}
dHitTest.Visible = true;
dLagTest.Visible = true;
dPlaneOrigin.Visible = true;
pZDepthTestCube.Visible = true;
dOtherWorld.Visible = true;
// Testing the rendering layers by showing the image from the second camera inside the 2D panel
DebugDraw3D.Config.GeometryRenderLayers = !Input.IsKeyPressed(Key.Alt) ? 1 : 0b10010;
dPanel.Visible = Input.IsKeyPressed(Key.Alt);
DebugDraw2D.CustomCanvas = Input.IsKeyPressed(Key.Alt) ? dCustomCanvas : null;
// More property toggles
DebugDraw3D.Config.Freeze3dRender = Input.IsKeyPressed(Key.Down);
DebugDraw3D.Config.VisibleInstanceBounds = Input.IsKeyPressed(Key.Right);
// Regenerate meshes
if (Input.IsActionJustPressed("ui_end"))
DebugDraw3D.RegenerateGeometryMeshes();
// Some property toggles
if (_is_key_just_pressed(Key.Left))
DebugDraw3D.Config.UseFrustumCulling = !DebugDraw3D.Config.UseFrustumCulling;
if (_is_key_just_pressed(Key.Up))
DebugDraw3D.Config.ForceUseCameraFromScene = !DebugDraw3D.Config.ForceUseCameraFromScene;
if (_is_key_just_pressed(Key.Ctrl))
if (!Engine.IsEditorHint())
GetViewport().Msaa3D = GetViewport().Msaa3D == Viewport.Msaa.Msaa4X ? Viewport.Msaa.Disabled : Viewport.Msaa.Msaa4X;
if (!Engine.IsEditorHint())
{
if (_is_key_just_pressed(Key.Key1))
DebugDraw3D.DebugEnabled = !DebugDraw3D.DebugEnabled;
if (_is_key_just_pressed(Key.Key2))
DebugDraw2D.DebugEnabled = !DebugDraw2D.DebugEnabled;
if (_is_key_just_pressed(Key.Key3))
DebugDrawManager.DebugEnabled = !DebugDrawManager.DebugEnabled;
}
DebugDraw3D.Config.FrustumLengthScale = camera_frustum_scale;
// Zones with black borders
foreach (var node in dZones.GetChildren())
{
if (node is Node3D z)
{
DebugDraw3D.DrawBoxXf(z.GlobalTransform, Colors.Black);
}
}
// Spheres
_draw_zone_title(pSpheresBox, "Spheres");
DebugDraw3D.DrawSphereXf(dSphereTransform.GlobalTransform, Colors.Crimson);
using (var _s1 = DebugDraw3D.NewScopedConfig().SetHdSphere(true))
DebugDraw3D.DrawSphereXf(dSphereHDTransform.GlobalTransform, Colors.OrangeRed);
/// Delayed spheres
if (timer_1 <= 0)
{
DebugDraw3D.DrawSphere(dSpherePosition.GlobalPosition, 2.0f, Colors.BlueViolet, 2.0f);
using (var _s1 = DebugDraw3D.NewScopedConfig().SetHdSphere(true))
DebugDraw3D.DrawSphere(dSpherePosition.GlobalPosition + Vector3.Forward * 4, 2.0f, Colors.CornflowerBlue, 2.0f);
timer_1 = 2;
}
timer_1 -= delta;
// Cylinders
_draw_zone_title(pCylindersBox, "Cylinders");
DebugDraw3D.DrawCylinder(dCylinder1.GlobalTransform, Colors.Crimson);
DebugDraw3D.DrawCylinder(new Transform3D(Basis.Identity.Scaled(new Vector3(1, 2, 1)), dCylinder2.GlobalPosition), Colors.Red);
DebugDraw3D.DrawCylinderAb(dCylinder3a.GlobalPosition, dCylinder3b.GlobalPosition, 0.7f);
// Boxes
_draw_zone_title(pBoxesBox, "Boxes");
DebugDraw3D.DrawBoxXf(dBox1.GlobalTransform, Colors.MediumPurple);
DebugDraw3D.DrawBox(dBox2.GlobalPosition, Quaternion.FromEuler(new Vector3(0, Mathf.DegToRad(45), Mathf.DegToRad(45))), Vector3.One, Colors.RebeccaPurple);
DebugDraw3D.DrawBoxXf(new Transform3D(new Basis(Vector3.Up, Mathf.Pi * 0.25f).Scaled(Vector3.One * 2), dBox3.GlobalPosition), Colors.RosyBrown);
DebugDraw3D.DrawAabb(new Aabb(dAABB_fixed.GlobalPosition, new Vector3(2, 1, 2)), Colors.Aqua);
DebugDraw3D.DrawAabbAb(dAABB.GetChild<Node3D>(0).GlobalPosition, dAABB.GetChild<Node3D>(1).GlobalPosition, Colors.DeepPink);
// Boxes AB
DebugDraw3D.DrawArrow(dBoxAB.GlobalPosition, dBoxABup.GlobalPosition, Colors.Gold, 0.1f, true);
DebugDraw3D.DrawBoxAb(dBoxABa.GlobalPosition, dBoxABb.GlobalPosition, dBoxABup.GlobalPosition - dBoxAB.GlobalPosition, Colors.Peru);
DebugDraw3D.DrawArrow(dBoxABEdge.GlobalPosition, dBoxABEdgeup.GlobalPosition, Colors.DarkRed, 0.1f, true);
DebugDraw3D.DrawBoxAb(dBoxABEdgea.GlobalPosition, dBoxABEdgeb.GlobalPosition, dBoxABEdgeup.GlobalPosition - dBoxABEdge.GlobalPosition, Colors.DarkOliveGreen, false);
// Lines
_draw_zone_title(pLinesBox, "Lines");
DebugDraw3D.DrawSquare(dLines_Target.GlobalPosition, 0.5f, Colors.Red);
DebugDraw3D.DrawLine(dLines_1.GlobalPosition, dLines_Target.GlobalPosition, Colors.Fuchsia);
DebugDraw3D.DrawRay(dLines_3.GlobalPosition, (dLines_Target.GlobalPosition - dLines_3.GlobalPosition).Normalized(), 3.0f, Colors.Crimson);
if (timer_3 <= 0)
{
DebugDraw3D.DrawLine(dLines_6.GlobalPosition, dLines_Target.GlobalPosition, Colors.Fuchsia, 2.0f);
timer_3 = 2;
}
timer_3 -= delta;
// Test UP vector
DebugDraw3D.DrawLine(dLines_7.GlobalPosition, dLines_Target.GlobalPosition, Colors.Red);
// Lines with Arrow
DebugDraw3D.DrawArrow(dLines_2.GlobalPosition, dLines_Target.GlobalPosition, Colors.Blue, 0.5f, true);
DebugDraw3D.DrawArrowRay(dLines_4.GlobalPosition, (dLines_Target.GlobalPosition - dLines_4.GlobalPosition).Normalized(), 8.0f, Colors.Lavender, 0.5f, true);
DebugDraw3D.DrawLineHitOffset(dLines_5.GlobalPosition, dLines_Target.GlobalPosition, true, Mathf.Abs(Mathf.Sin(Time.GetTicksMsec() / 1000.0f)), 0.25f, Colors.Aqua);
// Paths
_draw_zone_title(pPathsBox, "Paths");
/// preparing data
List<Vector3> points = new List<Vector3>();
List<Vector3> points_below = new List<Vector3>();
List<Vector3> points_below2 = new List<Vector3>();
List<Vector3> points_below3 = new List<Vector3>();
List<Vector3> points_below4 = new List<Vector3>();
List<Vector3> lines_above = new List<Vector3>();
foreach (var node in dLinePath.GetChildren())
{
if (node is Node3D c)
{
points.Add(c.GlobalPosition);
points_below.Add(c.GlobalPosition + Vector3.Down);
points_below2.Add(c.GlobalPosition + Vector3.Down * 2);
points_below3.Add(c.GlobalPosition + Vector3.Down * 3);
points_below4.Add(c.GlobalPosition + Vector3.Down * 4);
}
}
for (int x = 0; x < points.Count - 1; x++)
{
lines_above.Add(points[x] + Vector3.Up);
lines_above.Add(points[x + 1] + Vector3.Up);
}
/// drawing lines
DebugDraw3D.DrawLines(lines_above.ToArray());
DebugDraw3D.DrawLinePath(points.ToArray(), Colors.Beige);
DebugDraw3D.DrawPoints(points_below.ToArray(), DebugDraw3D.PointType.TypeSquare, 0.2f, Colors.DarkGreen);
DebugDraw3D.DrawPointPath(points_below2.ToArray(), DebugDraw3D.PointType.TypeSquare, 0.25f, Colors.Blue, Colors.Tomato);
DebugDraw3D.DrawArrowPath(points_below3.ToArray(), Colors.Gold, 0.5f);
using (var _sl = DebugDraw3D.NewScopedConfig().SetThickness(0.05f))
DebugDraw3D.DrawPointPath(points_below4.ToArray(), DebugDraw3D.PointType.TypeSphere, 0.25f, Colors.MediumSeaGreen, Colors.MediumVioletRed);
// Misc
_draw_zone_title(pMiscBox, "Misc");
if (Engine.IsEditorHint())
{
using var s = DebugDraw3D.NewScopedConfig().SetThickness(0);
DebugDraw3D.DrawCameraFrustum(dCamera, Colors.DarkOrange);
}
using (var s = DebugDraw3D.NewScopedConfig().SetCenterBrightness(0.1f))
{
DebugDraw3D.DrawArrowhead(dMisc_Arrow.GlobalTransform, Colors.YellowGreen);
}
DebugDraw3D.DrawSquare(dMisc_Billboard.GlobalPosition, 0.5f, Colors.Green);
DebugDraw3D.DrawPosition(dMisc_Position.GlobalTransform, Colors.Brown);
DebugDraw3D.DrawGizmo(dMisc_GizmoTransform.GlobalTransform, null, true);
DebugDraw3D.DrawGizmo(dMisc_GizmoOneColor.GlobalTransform, Colors.Brown, true);
using (var s = DebugDraw3D.NewScopedConfig().SetCenterBrightness(0.5f).SetNoDepthTest(true))
{
DebugDraw3D.DrawGizmo(dMisc_GizmoNormal.GlobalTransform.Orthonormalized(), null, false);
}
// Grids
_draw_zone_title_pos(dGrids_GridCentered.GlobalPosition + new Vector3(0, 1.5f, 0), "Grids", 96, 36);
Transform3D tg = dGrids_Grid.GlobalTransform;
Vector3 tn = dGrids_Grid_Subdivision.Transform.Origin;
DebugDraw3D.DrawGrid(tg.Origin, tg.Basis.X, tg.Basis.Z, new Vector2I((int)tn.X * 10, (int)tn.Z * 10), Colors.LightCoral, false);
var tn1 = dGrids_GridCentered_Subdivision.Transform.Origin;
DebugDraw3D.DrawGridXf(dGrids_GridCentered.GlobalTransform, new Vector2I((int)(tn1.X * 10), (int)(tn1.Z * 10)));
using (var s = DebugDraw3D.NewScopedConfig().SetThickness(0.05f))
{
DebugDraw3D.DrawBoxXf(dPostProcess.GlobalTransform, Colors.SeaGreen);
}
// Local transform
_draw_local_xf_box(pLocalTransformRecursiveOrigin.GlobalTransform, 0.05f, 10);
// 2D
DebugDraw2D.Config.TextDefaultSize = text_groups_default_font_size;
DebugDraw2D.Config.TextBlockOffset = text_groups_offset;
DebugDraw2D.Config.TextBlockPosition = text_groups_position;
DebugDraw2D.Config.TextPadding = text_groups_padding;
DebugDraw2D.Config.TextCustomFont = custom_font;
if (test_text)
{
_text_tests();
}
// Lag Test
var lag_test_pos = (Vector3)dLagTest_RESET.GetAnimation("RESET").TrackGetKeyValue(0, 0);
_draw_zone_title_pos(lag_test_pos, "Lag test");
dLagTest.Position = lag_test_pos + new Vector3(Mathf.Sin(Time.GetTicksMsec() / 100.0f) * 2.5f, 0, 0);
DebugDraw3D.DrawBox(dLagTest.GlobalPosition, Quaternion.Identity, Vector3.One * 2.01f, Colors.Chocolate, true);
if (more_test_cases)
{
foreach (var node in dHitTest_RayEmitter.GetChildren())
{
if (node is RayCast3D ray)
ray.SetPhysicsProcessInternal(true);
}
_more_tests();
}
else
{
foreach (var node in dHitTest_RayEmitter.GetChildren())
{
if (node is RayCast3D ray)
ray.SetPhysicsProcessInternal(false);
}
}
_draw_other_world();
if (draw_array_of_boxes)
{
_draw_array_of_boxes();
}
}
void _text_tests()
{
DebugDraw2D.SetText("FPS", $"{Engine.GetFramesPerSecond():F2}", 0, Colors.Gold);
if (text_groups_show_examples)
{
if (timer_text < 0)
{
DebugDraw2D.SetText("Some delayed text", "for 2.5s", -1, Colors.Black, 2.5f); // it's supposed to show text for 2.5 seconds
timer_text += 5;
}
DebugDraw2D.BeginTextGroup("-- First Group --", 2, Colors.LimeGreen, true, text_groups_title_font_size, text_groups_text_font_size);
DebugDraw2D.SetText("Simple text");
DebugDraw2D.SetText("Text", "Value", 0, Colors.Aquamarine);
DebugDraw2D.SetText("Text out of order", null, -1, Colors.Silver);
DebugDraw2D.BeginTextGroup("-- Second Group --", 1, Colors.Beige);
DebugDraw2D.SetText("Rendered frames", Engine.GetFramesDrawn());
DebugDraw2D.EndTextGroup();
}
if (text_groups_show_stats)
{
DebugDraw2D.BeginTextGroup("-- Stats --", 3, Colors.Wheat);
var render_stats = DebugDraw3D.GetRenderStats();
if (render_stats != null && text_groups_show_stats)
{
DebugDraw2D.SetText("Total", render_stats.TotalGeometry);
DebugDraw2D.SetText("Instances", render_stats.Instances, 1);
DebugDraw2D.SetText("Lines", render_stats.Lines, 2);
DebugDraw2D.SetText("Total Visible", render_stats.TotalVisible, 3);
DebugDraw2D.SetText("Visible Instances", render_stats.VisibleInstances, 4);
DebugDraw2D.SetText("Visible Lines", render_stats.VisibleLines, 5);
DebugDraw2D.SetText("---", "", 12);
DebugDraw2D.SetText("Culling time", $"{(render_stats.TotalTimeCullingUsec / 1000.0):F2} ms", 13);
DebugDraw2D.SetText("Filling instances buffer", $"{(render_stats.TimeFillingBuffersInstancesUsec / 1000.0):F2} ms", 14);
DebugDraw2D.SetText("Filling lines buffer", $"{(render_stats.TimeFillingBuffersLinesUsec / 1000.0):F2} ms", 15);
DebugDraw2D.SetText("Filling time", $"{(render_stats.TotalTimeFillingBuffersUsec / 1000.0):F2} ms", 16);
DebugDraw2D.SetText("Total time", $"{(render_stats.TotalTimeSpentUsec / 1000.0):F2} ms", 17);
DebugDraw2D.SetText("----", null, 32);
DebugDraw2D.SetText("Total Label3D", render_stats.NodesLabel3dExistsTotal, 33);
DebugDraw2D.SetText("Visible Label3D", render_stats.NodesLabel3dVisible + render_stats.NodesLabel3dVisiblePhysics, 34);
DebugDraw2D.SetText("-----", null, 48);
DebugDraw2D.SetText("Created scoped configs", $"{render_stats.CreatedScopedConfigs}", 49);
}
if (text_groups_show_stats && text_groups_show_stats_2d)
{
DebugDraw2D.SetText("------", null, 64);
}
var render_stats_2d = DebugDraw2D.GetRenderStats();
if (render_stats_2d != null && text_groups_show_stats_2d)
{
DebugDraw2D.SetText("Text groups", render_stats_2d.OverlayTextGroups, 96);
DebugDraw2D.SetText("Text lines", render_stats_2d.OverlayTextLines, 97);
}
DebugDraw2D.EndTextGroup();
}
if (text_groups_show_hints)
{
DebugDraw2D.BeginTextGroup("controls", 1024, Colors.White, false);
if (!Engine.IsEditorHint())
{
DebugDraw2D.SetText("WASD QE, LMB", "To move", 0);
}
DebugDraw2D.SetText("Alt: change render layers", DebugDraw3D.Config.GeometryRenderLayers, 1);
if (!OS.HasFeature("web"))
{
DebugDraw2D.SetText("Ctrl: toggle anti-aliasing", GetViewport().Msaa3D == Viewport.Msaa.Msaa4X ? "MSAA 4x" : "Disabled", 2);
}
DebugDraw2D.SetText("Down: freeze render", DebugDraw3D.Config.Freeze3dRender, 3);
if (Engine.IsEditorHint())
{
DebugDraw2D.SetText("Up: use scene camera", DebugDraw3D.Config.ForceUseCameraFromScene, 4);
}
DebugDraw2D.SetText("1,2,3: toggle debug", $"{DebugDraw3D.DebugEnabled}, {DebugDraw2D.DebugEnabled} 😐, {DebugDrawManager.DebugEnabled} 😏", 5);
DebugDraw2D.SetText("Left: toggle frustum culling", DebugDraw3D.Config.UseFrustumCulling, 6);
DebugDraw2D.SetText("Right: draw bounds for culling", DebugDraw3D.Config.VisibleInstanceBounds, 7);
}
}
void _draw_zone_title(Node3D node, string title)
{
if (draw_3d_text)
{
using var _s1 = DebugDraw3D.NewScopedConfig().SetTextOutlineSize(72);
DebugDraw3D.DrawText(node.GlobalPosition + node.GlobalBasis.Y * 0.85f, title, 128);
}
}
void _draw_zone_title_pos(Vector3 pos, string title, int font_size = 128, int outline = 72)
{
if (draw_3d_text)
{
using var _s1 = DebugDraw3D.NewScopedConfig().SetTextOutlineSize(outline);
DebugDraw3D.DrawText(pos, title, font_size);
}
}
const float _local_mul = 0.45f;
static readonly Vector3 _local_mul_vec = new(_local_mul, _local_mul, _local_mul);
Vector3[] __local_lines_cross_recursive = [new Vector3(-0.5f, -0.5f, -0.5f), new Vector3(0.5f, -0.5f, 0.5f), new Vector3(-0.5f, -0.5f, 0.5f), new Vector3(0.5f, -0.5f, -0.5f)];
Transform3D __local_box_recursive = Transform3D.Identity.RotatedLocal(Vector3.Up, Mathf.DegToRad(30)).Translated(new Vector3(-0.25f, -0.55f, 0.25f)).Scaled(_local_mul_vec);
Transform3D __local_sphere_recursive = Transform3D.Identity.Translated(new Vector3(0.5f, 0.55f, -0.5f)).Scaled(_local_mul_vec);
void _draw_local_xf_box(Transform3D xf, float thickness, int max_depth, int depth = 0)
{
if (depth >= max_depth)
return;
using var _s1 = DebugDraw3D.NewScopedConfig().SetThickness(thickness).SetTransform(xf);
// a box with a small offset
DebugDraw3D.DrawBoxXf(new Transform3D(Basis.Identity, new Vector3(0, 0.001f, 0)), Colors.Brown);
// a box and a stand for the next depth
DebugDraw3D.DrawBoxXf(__local_box_recursive, Colors.Chartreuse);
// just a sphere and lines
DebugDraw3D.DrawSphereXf(__local_sphere_recursive, Colors.DarkOrange);
_s1.SetThickness(0);
DebugDraw3D.DrawLines(__local_lines_cross_recursive, Colors.Crimson);
// A simple animation generator with descent into the depth of the scene
#if false
{
Animation anim = pRecursiveTransformTest.GetAnimation("recursive");
// clear keys
if (depth == 0)
for (var i = 0; i < anim.TrackGetKeyCount(0); i++)
{
anim.TrackRemoveKey(0, 0);
anim.TrackRemoveKey(1, 0);
}
var time = depth * 2;
var s_xf = xf * __local_sphere_recursive;
var next_s_xf = (xf * __local_box_recursive.Translated(__local_box_recursive.Basis.Y)) * __local_sphere_recursive;
var get_sphere_pos = (Transform3D l_xf) => l_xf.Origin + (l_xf).Basis.Y;
anim.PositionTrackInsertKey(0, time, get_sphere_pos(s_xf));
anim.RotationTrackInsertKey(1, time, new Transform3D(Basis.Identity, get_sphere_pos(s_xf)).LookingAt(get_sphere_pos(next_s_xf), xf.Basis.Y).Basis.GetRotationQuaternion());
}
#endif
_draw_local_xf_box(xf * __local_box_recursive.Translated(__local_box_recursive.Basis.Y), thickness * _local_mul, max_depth, depth + 1);
}
void _draw_other_world()
{
using var s = DebugDraw3D.NewScopedConfig().SetViewport(dOtherWorldBox.GetViewport());
DebugDraw3D.DrawBoxXf(dOtherWorldBox.GlobalTransform.RotatedLocal(new Vector3(1, 1, -1).Normalized(), Mathf.Wrap(Time.GetTicksMsec() / 1000.0f, 0f, Mathf.Tau)), Colors.SandyBrown);
DebugDraw3D.DrawBoxXf(dOtherWorldBox.GlobalTransform.RotatedLocal(new Vector3(-1, 1, -1).Normalized(), Mathf.Wrap(Time.GetTicksMsec() / 1000.0f, 0f, Mathf.Tau) - Mathf.Pi / 4), Colors.SandyBrown);
if (draw_3d_text)
{
var angle = Mathf.Wrap(Time.GetTicksMsec() / 1000.0f, 0, Mathf.Tau);
using (var _w2 = DebugDraw3D.NewScopedConfig().SetTextFont(custom_3d_font))
{
DebugDraw3D.DrawText(dOtherWorldBox.GlobalPosition + new Vector3(Mathf.Cos(angle), -0.25f, Mathf.Sin(angle)), "Hello world!", 32, Colors.Crimson, 0);
}
using (var _w3 = DebugDraw3D.NewScopedConfig().SetNoDepthTest(true).SetTextOutlineColor(Colors.IndianRed).SetTextOutlineSize(6))
{
DebugDraw3D.DrawText(dOtherWorldBox.GlobalPosition + new Vector3(Mathf.Cos(angle), +0.25f, Mathf.Sin(-angle)), "World without depth", 20, Colors.Pink, 0);
}
}
}
void _draw_rays_casts()
{
// Line hits render
_draw_zone_title_pos(pHitTestSphere.GlobalPosition, "Line hits", 96, 36);
foreach (var node in dHitTest_RayEmitter.GetChildren())
{
if (node is RayCast3D ray)
{
ray.ForceRaycastUpdate();
DebugDraw3D.DrawLineHit(ray.GlobalPosition, ray.ToGlobal(ray.TargetPosition), ray.GetCollisionPoint(), ray.IsColliding(), 0.3f);
}
}
}
void _more_tests()
{
// Delayed line render
using (var s = DebugDraw3D.NewScopedConfig().SetThickness(0.035f))
{
DebugDraw3D.DrawLine(dLagTest.GlobalPosition + Vector3.Up, dLagTest.GlobalPosition + new Vector3(0, 3, Mathf.Sin(Time.GetTicksMsec() / 50.0f)), null, 0.35f);
if (draw_3d_text)
{
DebugDraw3D.DrawText(dLagTest.GlobalPosition + new Vector3(0, 3, Mathf.Sin(Time.GetTicksMsec() / 50.0f)), $"{Mathf.Sin(Time.GetTicksMsec() / 50.0f):F1}", 16, null, 0.35f);
}
}
// Draw plane
using (var _s11 = DebugDraw3D.NewScopedConfig().SetThickness(0.02f).SetPlaneSize(10))
{
var pl_node = GetNode<Node3D>("PlaneOrigin");
var xf = pl_node.GlobalTransform;
var normal = xf.Basis.Y.Normalized();
var plane = new Plane(normal, xf.Origin.Dot(normal));
var vp = GetViewport();
if (Engine.IsEditorHint() && (Viewport)Engine.GetSingleton("EditorInterface").Call("get_editor_viewport_3d", 0) != null)
{
vp = (Viewport)Engine.GetSingleton("EditorInterface").Call("get_editor_viewport_3d", 0);
}
var cam = vp.GetCamera3D();
if (cam != null)
{
var dir = vp.GetCamera3D().ProjectRayNormal(vp.GetMousePosition());
Vector3? intersect = plane.IntersectsRay(cam.GlobalPosition, dir);
DebugDraw3D.DrawPlane(plane, Colors.Coral * new Color(1, 1, 1, 0.4f), pl_node.GlobalPosition);
if (intersect.HasValue && intersect.Value.DistanceTo(pl_node.GlobalPosition) < _s11.GetPlaneSize() * 0.5f)
{
// Need to test different colors on both sides of the plane
var col = plane.IsPointOver(cam.GlobalPosition) ? Colors.Firebrick : Colors.Aquamarine;
DebugDraw3D.DrawSphere(intersect.Value, 0.3f, col);
}
}
}
}
void _draw_array_of_boxes()
{
// Lots of boxes to check performance..
var x_size = 50;
var y_size = 50;
var z_size = 3;
var mul = 1.0f;
var cubes_max_time = 1.25f;
var show_text = draw_text_with_boxes;
using var cfg = DebugDraw3D.NewScopedConfig();
if (draw_1m_boxes)
{
x_size = 100;
y_size = 100;
z_size = 100;
mul = 4.0f;
cubes_max_time = 60f;
draw_text_with_boxes = false;
}
var size = Vector3.One;
var half_size = size * 0.5f;
if (timer_cubes <= 0)
{
var start_time = Time.GetTicksUsec();
for (int x = 0; x < x_size; x++)
{
for (int y = 0; y < y_size; y++)
{
for (int z = 0; z < z_size; z++)
{
cfg.SetThickness(Random.Shared.NextSingle() * 0.1f);
var pos = new Vector3(x * mul, (-4 - z) * mul, y * mul) + GlobalPosition;
DebugDraw3D.DrawBox(pos, Quaternion.Identity, size, null, false, cubes_max_time);
if (show_text && z == 0)
{
DebugDraw3D.DrawText(pos + half_size, pos.ToString(), 32, null, cubes_max_time);
}
}
}
}
//GD.Print($"Draw Cubes: {((Time.GetTicksUsec() - start_time) / 1000.0):F3}ms");
timer_cubes = cubes_max_time;
}
}
Node3D dHitTest;
CsgBox3D dLagTest;
PanelContainer dPanel;
Node3D dZones;
Node3D dSpherePosition;
Node3D dSphereTransform;
Node3D dSphereHDTransform;
Node3D dAABB;
Node3D dAABB_fixed;
Node3D dBox1;
Node3D dBox2;
Node3D dBox3;
Node3D dBoxAB;
Node3D dBoxABa;
Node3D dBoxABb;
Node3D dBoxABup;
Node3D dBoxABEdge;
Node3D dBoxABEdgea;
Node3D dBoxABEdgeb;
Node3D dBoxABEdgeup;
Node3D dLines_1;
Node3D dLines_2;
Node3D dLines_3;
Node3D dLines_4;
Node3D dLines_5;
Node3D dLines_6;
Node3D dLines_7;
Node3D dLines_8;
Node3D dLines_Target;
Node3D dLinePath;
Node3D dCylinder1;
Node3D dCylinder2;
Node3D dCylinder3a;
Node3D dCylinder3b;
Node3D pSpheresBox;
Node3D pCylindersBox;
Node3D pBoxesBox;
Node3D pLinesBox;
Node3D pPathsBox;
Node3D pMiscBox;
MeshInstance3D dPlaneOrigin;
MeshInstance3D pZDepthTestCube;
MeshInstance3D dOtherWorld;
SubViewport dOtherWorldViewport;
Node3D dOtherWorldBox;
Control dCustomCanvas;
Node3D dMisc_Arrow;
Camera3D dCamera;
Node3D dMisc_Billboard;
Node3D dMisc_Position;
Node3D dMisc_GizmoTransform;
Node3D dMisc_GizmoNormal;
Node3D dMisc_GizmoOneColor;
Node3D pLocalTransformRecursiveOrigin;
AnimationPlayer pRecursiveTransformTest;
Node3D dGrids_Grid;
Node3D dGrids_Grid_Subdivision;
Node3D dGrids_GridCentered_Subdivision;
Node3D dGrids_GridCentered;
MeshInstance3D dPostProcess;
AnimationPlayer dLagTest_RESET;
Node3D dHitTest_RayEmitter;
Node3D pHitTestSphere;
void _get_nodes()
{
dHitTest = GetNode<Node3D>("HitTest");
dLagTest = GetNode<CsgBox3D>("LagTest");
dPanel = GetNode<PanelContainer>("Panel");
dZones = GetNode<Node3D>("Zones");
dSpherePosition = GetNode<Node3D>("Spheres/SpherePosition");
dSphereTransform = GetNode<Node3D>("Spheres/SphereTransform");
dSphereHDTransform = GetNode<Node3D>("Spheres/SphereHDTransform");
dAABB = GetNode<Node3D>("Boxes/AABB");
dAABB_fixed = GetNode<Node3D>("Boxes/AABB_fixed");
dBox1 = GetNode<Node3D>("Boxes/Box1");
dBox2 = GetNode<Node3D>("Boxes/Box2");
dBox3 = GetNode<Node3D>("Boxes/Box3");
dBoxAB = GetNode<Node3D>("Boxes/BoxAB");
dBoxABa = GetNode<Node3D>("Boxes/BoxAB/a");
dBoxABb = GetNode<Node3D>("Boxes/BoxAB/b");
dBoxABup = GetNode<Node3D>("Boxes/BoxAB/o/up");
dBoxABEdge = GetNode<Node3D>("Boxes/BoxABEdge");
dBoxABEdgea = GetNode<Node3D>("Boxes/BoxABEdge/a");
dBoxABEdgeb = GetNode<Node3D>("Boxes/BoxABEdge/b");
dBoxABEdgeup = GetNode<Node3D>("Boxes/BoxABEdge/o/up");
dLines_1 = GetNode<Node3D>("Lines/1");
dLines_2 = GetNode<Node3D>("Lines/2");
dLines_3 = GetNode<Node3D>("Lines/3");
dLines_4 = GetNode<Node3D>("Lines/4");
dLines_5 = GetNode<Node3D>("Lines/5");
dLines_6 = GetNode<Node3D>("Lines/6");
dLines_7 = GetNode<Node3D>("Lines/7");
dLines_8 = GetNode<Node3D>("Lines/8");
dLines_Target = GetNode<Node3D>("Lines/Target");
dLinePath = GetNode<Node3D>("LinePath");
dCylinder1 = GetNode<Node3D>("Cylinders/Cylinder1");
dCylinder2 = GetNode<Node3D>("Cylinders/Cylinder2");
dCylinder3a = GetNode<Node3D>("Cylinders/Cylinder3/1");
dCylinder3b = GetNode<Node3D>("Cylinders/Cylinder3/2");
pSpheresBox = GetNode<Node3D>("%SpheresBox");
pCylindersBox = GetNode<Node3D>("%CylindersBox");
pBoxesBox = GetNode<Node3D>("%BoxesBox");
pLinesBox = GetNode<Node3D>("%LinesBox");
pPathsBox = GetNode<Node3D>("%PathsBox");
pMiscBox = GetNode<Node3D>("%MiscBox");
dPlaneOrigin = GetNode<MeshInstance3D>("PlaneOrigin");
pZDepthTestCube = GetNode<MeshInstance3D>("%ZDepthTestCube");
dOtherWorld = GetNode<MeshInstance3D>("OtherWorld");
dOtherWorldViewport = GetNode<SubViewport>("OtherWorld/SubViewport");
dOtherWorldBox = GetNode<Node3D>("OtherWorld/SubViewport/SubViewportContainer/SubViewport/OtherWorldBox");
dCustomCanvas = GetNode<Control>("CustomCanvas");
dMisc_Arrow = GetNode<Node3D>("Misc/Arrow");
dCamera = GetNode<Camera3D>("Camera");
dMisc_Billboard = GetNode<Node3D>("Misc/Billboard");
dMisc_Position = GetNode<Node3D>("Misc/Position");
dMisc_GizmoTransform = GetNode<Node3D>("Misc/GizmoTransform");
dMisc_GizmoNormal = GetNode<Node3D>("Misc/GizmoNormal");
dMisc_GizmoOneColor = GetNode<Node3D>("Misc/GizmoOneColor");
pLocalTransformRecursiveOrigin = GetNode<Node3D>("%LocalTransformRecursiveOrigin");
pRecursiveTransformTest = GetNode<AnimationPlayer>("%RecursiveTransformTest");
dGrids_Grid = GetNode<Node3D>("Grids/Grid");
dGrids_Grid_Subdivision = GetNode<Node3D>("Grids/Grid/Subdivision");
dGrids_GridCentered_Subdivision = GetNode<Node3D>("Grids/GridCentered/Subdivision");
dGrids_GridCentered = GetNode<Node3D>("Grids/GridCentered");
dPostProcess = GetNode<MeshInstance3D>("PostProcess");
dLagTest_RESET = GetNode<AnimationPlayer>("LagTest/RESET");
dHitTest_RayEmitter = GetNode<Node3D>("HitTest/RayEmitter");
pHitTestSphere = GetNode<Node3D>("%HitTestSphere");
}
}

View file

@ -0,0 +1 @@
uid://dnf8ejsrnlvxb

View file

@ -0,0 +1,16 @@
[gd_scene load_steps=3 format=3 uid="uid://sxtw8fme7g63"]
[ext_resource type="PackedScene" uid="uid://c3sccy6x0ht5j" path="res://examples_dd3d/DebugDrawDemoScene.tscn" id="2"]
[ext_resource type="Script" path="res://examples_dd3d/DebugDrawDemoSceneCS.cs" id="2_ipqea"]
[node name="DebugDrawDemoSceneCS" instance=ExtResource("2")]
script = ExtResource("2_ipqea")
[node name="Settings" parent="." index="23"]
switch_to_scene = "res://examples_dd3d/DebugDrawDemoScene.tscn"
[node name="Label" parent="Settings/HBox/VBoxContainer" index="1"]
text = "C# example"
[node name="SwitchLang" parent="Settings/HBox/VBox/SettingsPanel/VBox" index="13"]
text = "Switch to GDScript"

View file

@ -0,0 +1,35 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://7am1h57ldd6"
path="res://.godot/imported/PixelatedElegance.ttf-afa66bcfa5f4155ab81c9eb4b7feee72.fontdata"
[deps]
source_file="res://addons/debug_draw_3d/examples_dd3d/PixelatedElegance.ttf"
dest_files=["res://.godot/imported/PixelatedElegance.ttf-afa66bcfa5f4155ab81c9eb4b7feee72.fontdata"]
[params]
Rendering=null
antialiasing=1
generate_mipmaps=false
disable_embedded_bitmaps=true
multichannel_signed_distance_field=false
msdf_pixel_range=8
msdf_size=48
allow_system_fallback=true
force_autohinter=false
hinting=1
subpixel_positioning=1
keep_rounding_remainders=true
oversampling=0.0
Fallbacks=null
fallbacks=[]
Compress=null
compress=true
preload=[]
language_support={}
script_support={}
opentype_features={}

View file

@ -0,0 +1,39 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://erdgllynwqkw"
path="res://.godot/imported/Roboto-Bold.ttf-8898863a4b571640f76579de7e16a7d4.fontdata"
[deps]
source_file="res://addons/debug_draw_3d/examples_dd3d/Roboto-Bold.ttf"
dest_files=["res://.godot/imported/Roboto-Bold.ttf-8898863a4b571640f76579de7e16a7d4.fontdata"]
[params]
Rendering=null
antialiasing=1
generate_mipmaps=false
disable_embedded_bitmaps=true
multichannel_signed_distance_field=false
msdf_pixel_range=8
msdf_size=48
allow_system_fallback=true
force_autohinter=false
hinting=1
subpixel_positioning=1
keep_rounding_remainders=true
oversampling=0.0
Fallbacks=null
fallbacks=[]
Compress=null
compress=true
preload=[{
"chars": [],
"glyphs": [],
"name": "New Configuration"
}]
language_support={}
script_support={}
opentype_features={}

View file

@ -0,0 +1,17 @@
[gd_resource type="AudioBusLayout" load_steps=2 format=3 uid="uid://7sy4h4ibftrk"]
[sub_resource type="AudioEffectSpectrumAnalyzer" id="AudioEffectSpectrumAnalyzer_odciy"]
resource_name = "SpectrumAnalyzer"
fft_size = 3
[resource]
bus/0/mute = true
bus/0/volume_db = -20.0
bus/1/name = &"MusicAnalyzer"
bus/1/solo = false
bus/1/mute = false
bus/1/bypass_fx = false
bus/1/volume_db = 0.0
bus/1/send = &"Master"
bus/1/effect/0/effect = SubResource("AudioEffectSpectrumAnalyzer_odciy")
bus/1/effect/0/enabled = true

View file

@ -0,0 +1,11 @@
@tool
extends Node3D
func _process(delta: float) -> void:
var a = DebugDraw3D.new_scoped_config().set_thickness(0.015)
DebugDraw3D.draw_box_xf($box.global_transform, Color.GREEN)
DebugDraw3D.draw_gizmo($gizmo.global_transform)
DebugDraw3D.draw_grid_xf($gizmo/grid.global_transform, Vector2i(2,2), DebugDraw3D.empty_color, false)
DebugDraw3D.draw_sphere_xf($sphere.global_transform, Color.RED)
DebugDraw3D.draw_cylinder($cylinder.global_transform, Color.BLUE)
DebugDraw3D.draw_line_hit_offset($"line/1".global_transform.origin, $"line/2".global_transform.origin, true, 0.3, 0.1)

View file

@ -0,0 +1 @@
uid://b2lj85riqyno0

View file

@ -0,0 +1,37 @@
[gd_scene load_steps=3 format=3 uid="uid://1lhiwf8tgleh"]
[ext_resource type="Script" path="res://examples_dd3d/addon_icon.gd" id="1_bq18y"]
[sub_resource type="Environment" id="1"]
background_mode = 1
[node name="icon" type="Node3D"]
script = ExtResource("1_bq18y")
[node name="Camera" type="Camera3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 5.39732)
environment = SubResource("1")
current = true
[node name="box" type="Node3D" parent="."]
transform = Transform3D(0.316305, 0.0204714, -0.293415, -0.239575, 0.267896, -0.239575, 0.170631, 0.338191, 0.207538, -0.410294, 0.312541, 0.243199)
[node name="gizmo" type="Node3D" parent="."]
transform = Transform3D(0.707107, 0, -0.707107, -0.294265, 0.909294, -0.294265, 0.642968, 0.416154, 0.642968, 0, 0, 0)
[node name="grid" type="Node3D" parent="gizmo"]
transform = Transform3D(1, -2.98023e-08, 1.19209e-07, 0, 1, 0, 1.19209e-07, -2.98023e-08, 1, -0.0263093, -0.0170284, -0.0263093)
[node name="sphere" type="Node3D" parent="."]
transform = Transform3D(0.401341, 0.207831, -0.437109, -0.449118, 0.371584, -0.235691, 0.180418, 0.46267, 0.385639, 0.466197, 0.322665, 0.200436)
[node name="cylinder" type="Node3D" parent="."]
transform = Transform3D(0.155034, 0.231693, -0.112783, -0.160003, 0.264761, -0.0839674, 0.0232275, 0.277352, 0.174372, -0.0566943, -0.290515, 0.905274)
[node name="line" type="Node3D" parent="."]
[node name="1" type="Node3D" parent="line"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.568458, -0.615948, 0.653444)
[node name="2" type="Node3D" parent="line"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0051975, 0.373791, 0.0974927)

View file

@ -0,0 +1,60 @@
extends Camera3D
@export var mouse_sensitivity := 0.25
@export var camera_speed := 10.0
@export var camera_speed_fast := 30.0
var btn_clicked := false
const hPI := PI/2
var rot_x := 0.0
var rot_y := 0.0
func _ready():
reset_input_rotation()
func _unhandled_input(event) -> void:
if event is InputEventMouseButton:
btn_clicked = event.pressed
func reset_input_rotation():
rot_x = rotation.y
rot_y = rotation.x
func _input(event) -> void:
if btn_clicked:
if event is InputEventMouseMotion:
if event.button_mask == MOUSE_BUTTON_LEFT:
rot_x += -deg_to_rad(event.relative.x * mouse_sensitivity)
rot_y += -deg_to_rad(event.relative.y * mouse_sensitivity)
rot_y = clamp(rot_y, -hPI, hPI)
transform.basis = Basis()
rotate_object_local(Vector3.UP, rot_x)
rotate_object_local(Vector3.RIGHT, rot_y)
func get_axis(neg : Array[Key], pos : Array[Key]) -> float:
var pressed = func (arr: Array[Key]):
var p: float = 0
for k in arr:
if Input.is_physical_key_pressed(k):
p = 1
break
return p
return pressed.call(pos) - pressed.call(neg)
func _process(delta) -> void:
var motion := Vector2(get_axis([KEY_S], [KEY_W]), get_axis([KEY_A], [KEY_D]))
var lift := get_axis([KEY_Q, KEY_CTRL], [KEY_E, KEY_SPACE])
var speed := camera_speed_fast if Input.is_physical_key_pressed(KEY_SHIFT) else camera_speed
motion = motion.limit_length()
var b := global_transform.basis
var v := (-b.z * motion.x) + (b.x * motion.y) + (b.y * lift)
global_position += v.limit_length() * speed * delta

View file

@ -0,0 +1 @@
uid://b5mdrjubj0lg5

View file

@ -0,0 +1,175 @@
@tool
extends VBoxContainer
@export_range(1, 128) var bars_count := 32
var transform: Transform3D:
get:
return %AudioVisualizer.global_transform
@export_exp_easing("inout") var motion_smoothing := 0.025
@export_range(0, 0.5) var bar_thickness := 0.065
@export_range(0, 10) var bars_separation := 0.325
@export_exp_easing("inout") var color_offset_speed := 0.4
@export var colors: Gradient = null
var MusicAnalyzerBus := &"MusicAnalyzer"
var MasterBus := &"Master"
var MAX_HZ := 16000.0
var MIN_HZ := 20.0
var MIN_DB := 60.0
var spectrum: AudioEffectSpectrumAnalyzerInstance = null
var smoothed_energy: Array[float] = []
var color_offset := 0.0
var _on_data_loaded_callback = null
func _ready():
var bus = AudioServer.get_bus_index(MusicAnalyzerBus)
if bus == -1:
print("'MusicVisualizer' audio bus not found.\nSet 'VisualizerAudioBus.tres' as the default bus to use the audio visualizer.")
spectrum = AudioServer.get_bus_effect_instance(bus, 0)
%MuteMaster.button_pressed = AudioServer.is_bus_mute(AudioServer.get_bus_index(MasterBus))
%VolumeSlider.value = db_to_linear(AudioServer.get_bus_volume_db(AudioServer.get_bus_index(MasterBus)))
if OS.has_feature('web'):
motion_smoothing = motion_smoothing * 1.5
_on_data_loaded_callback = JavaScriptBridge.create_callback(_on_data_loaded)
# Retrieve the 'gd_callbacks' object
var gdcallbacks: JavaScriptObject = JavaScriptBridge.get_interface("gd_callbacks")
# Assign the callbacks
gdcallbacks.dataLoaded = _on_data_loaded_callback
func _process(_delta):
if %MusicPlayer.playing:
draw_spectrum()
func _pressed():
var open_file = func(filepath: String):
print("Opening '%s'" % filepath)
var file = FileAccess.open(filepath, FileAccess.READ)
var data = file.get_buffer(file.get_length())
open_stream(filepath.get_extension(), data)
if DisplayServer.has_feature(DisplayServer.FEATURE_NATIVE_DIALOG):
DisplayServer.file_dialog_show("Select audio file", "", "", true, DisplayServer.FILE_DIALOG_MODE_OPEN_FILE, ["*.mp3"],
func (status: bool, selected: PackedStringArray, _fileter: int):
if status and selected.size():
open_file.call(selected[0])
)
elif OS.has_feature('web'):
JavaScriptBridge.eval("loadData()")
else:
var fd := FileDialog.new()
add_child(fd)
fd.title = "Select audio file"
fd.access = FileDialog.ACCESS_FILESYSTEM
fd.file_mode = FileDialog.FILE_MODE_OPEN_FILE
fd.current_dir = OS.get_system_dir(OS.SYSTEM_DIR_DOWNLOADS)
fd.add_filter("*.mp3")
fd.popup_centered_ratio(0.8)
fd.file_selected.connect(func(path: String):
open_file.call(path)
)
fd.visibility_changed.connect(func():
if not fd.visible:
fd.queue_free()
)
func _on_data_loaded(data: Array) -> void:
# Make sure there is something
if (data.size() == 0):
return
var file_name: String = data[0]
print("Opening '%s'" % file_name)
var arr: PackedByteArray = JavaScriptBridge.eval("gd_callbacks.dataLoadedResult;")
open_stream(file_name.get_extension(), arr)
func open_stream(file_ext: String, data: PackedByteArray):
var stream: AudioStream = null
if file_ext == "mp3":
stream = AudioStreamMP3.new()
stream.data = data
if not stream.data:
print("Failed to load MP3!")
return
if not stream:
print("Failed to load music!")
return
%MusicPlayer.stream = stream
%MusicPlayer.bus = MusicAnalyzerBus
%MusicPlayer.play()
# Debugging frequencies
for ih in range(1, bars_count + 1):
var _hz: float = log_freq(ih / float(bars_count), MIN_HZ, MAX_HZ)
#print("%.0f hz %.2f" % [_hz, ih / float(bars_count)])
func draw_spectrum():
var _s1 = DebugDraw3D.scoped_config().set_thickness(bar_thickness).set_center_brightness(0.9)
var prev_hz = MIN_HZ
smoothed_energy.resize(bars_count)
var xf := transform
var y := xf.basis.y
var h := y.length()
var x := xf.basis.x
var z := xf.basis.z
var origin := xf.origin - (x * bars_count + (x * bars_separation) * (bars_count - 1)) * 0.5
var sum := 0.0
for ih in range(1, bars_count + 1):
var i := ih - 1
var hz: float = log_freq(ih / float(bars_count), MIN_HZ, MAX_HZ)
var magnitude: float = spectrum.get_magnitude_for_frequency_range(prev_hz, hz, AudioEffectSpectrumAnalyzerInstance.MAGNITUDE_AVERAGE).length()
var energy: float = clampf((MIN_DB + linear_to_db(magnitude)) / MIN_DB, 0, 1)
var e: float = lerp(smoothed_energy[i], energy, clampf(get_process_delta_time() / motion_smoothing if motion_smoothing else 1.0, 0, 1))
smoothed_energy[i] = e
var height: float = e * h
sum += e
var s := x * bars_separation
var a := origin + x * i + s * i + (z * 0.5)
var b := origin + x * (i + 1) + s * i + (z * -0.5) + xf.basis.y.normalized() * clampf(height, 0.001, h)
var c := Color.HOT_PINK
if colors:
c = colors.sample(wrapf(float(ih) / bars_count + color_offset, 0, 1))
c.s = clamp(c.s - smoothed_energy[i] * 0.3, 0, 1.0)
DebugDraw3D.draw_box_ab(a, b, y, c)
prev_hz = hz
color_offset = wrapf(color_offset + sum / smoothed_energy.size() * clampf(get_process_delta_time() / color_offset_speed if color_offset_speed else 1.0, 0, 1), 0, 1)
func log10(val: float) -> float:
return log(val) / 2.302585
func log_freq(pos: float, min_hz: float, max_hz: float) -> float:
return pow(10, log10(min_hz) + (log10(max_hz) - log10(min_hz)) * pos)
func _on_volume_slider_value_changed(value):
AudioServer.set_bus_volume_db(AudioServer.get_bus_index(MasterBus), linear_to_db(value))
func _on_mute_master_toggled(toggled_on):
AudioServer.set_bus_mute(AudioServer.get_bus_index(MasterBus), toggled_on)

View file

@ -0,0 +1 @@
uid://bebbekatkxaoe

View file

@ -0,0 +1,103 @@
@tool
extends Control
@export var switch_to_scene = ""
var is_ready := false
func _ready():
if Engine.is_editor_hint():
return
if ProjectSettings.has_setting("application/config/no_csharp_support"):
%SwitchLang.visible = false
%SwitchLang.disabled = true
%ThicknessSlider.value = get_parent().debug_thickness
%FrustumScaleSlider.value = get_parent().camera_frustum_scale
%UpdateInPhysics.text = "Update in physics (%d Ticks) *" % ProjectSettings.get_setting("physics/common/physics_ticks_per_second")
%UpdateInPhysics.button_pressed = get_parent().update_in_physics
%ShowText.button_pressed = get_parent().test_text
%ShowExamples.button_pressed = get_parent().text_groups_show_examples
%ShowStats.button_pressed = get_parent().text_groups_show_stats
%ShowHints.button_pressed = get_parent().text_groups_show_hints
%Draw3DText.button_pressed = get_parent().draw_3d_text
%DrawBoxes.button_pressed = get_parent().draw_array_of_boxes
%Draw1MBoxes.button_pressed = get_parent().draw_1m_boxes
%DrawBoxesAddText.button_pressed = get_parent().draw_text_with_boxes
if get_tree():
await get_tree().create_timer(0.2).timeout
%SwitchLang.disabled = false
is_ready = true
func _on_Button_pressed() -> void:
get_tree().call_deferred("change_scene_to_file", switch_to_scene)
func _on_hide_show_panel_pressed():
if %SettingsPanel.visible:
%SettingsPanel.hide()
%HideShowPanelButton.text = "Show panel"
else:
%SettingsPanel.show()
%HideShowPanelButton.text = "Hide panel"
func _on_thickness_slider_value_changed(value):
if not is_ready: return
get_parent().debug_thickness = value
func _on_frustum_scale_slider_value_changed(value):
if not is_ready: return
get_parent().camera_frustum_scale = value
func _on_update_in_physics_toggled(toggled_on):
get_parent().update_in_physics = toggled_on
func _on_show_text_toggled(toggled_on: bool) -> void:
get_parent().test_text = toggled_on
func _on_show_examples_toggled(toggled_on: bool) -> void:
get_parent().text_groups_show_examples = toggled_on
func _on_show_stats_toggled(toggled_on):
get_parent().text_groups_show_stats = toggled_on
func _on_show_hints_toggled(toggled_on: bool) -> void:
get_parent().text_groups_show_hints = toggled_on
func _on_draw_3d_text_toggled(toggled_on: bool) -> void:
get_parent().draw_3d_text = toggled_on
func _on_draw_boxes_toggled(toggled_on):
get_parent().draw_array_of_boxes = toggled_on
DebugDraw3D.clear_all()
get_parent().timer_cubes = 0
func _on_draw_1m_boxes_toggled(toggled_on):
get_parent().draw_1m_boxes = toggled_on
if get_parent().draw_array_of_boxes:
DebugDraw3D.clear_all()
get_parent().timer_cubes = 0
func _on_add_text_to_boxes_toggled(toggled_on: bool) -> void:
get_parent().draw_text_with_boxes = toggled_on

View file

@ -0,0 +1 @@
uid://83dhsep7l725

View file

@ -0,0 +1,42 @@
extends HBoxContainer
var _on_versions_loaded_callback = null
@onready var btn: OptionButton = $OptionButton
func _enter_tree():
hide()
func _ready():
if OS.has_feature('web'):
_on_versions_loaded_callback = JavaScriptBridge.create_callback(_on_versions_loaded)
var versions_callbacks: JavaScriptObject = JavaScriptBridge.get_interface("versions_callbacks")
versions_callbacks.loaded = _on_versions_loaded_callback
JavaScriptBridge.eval("loadVersions()")
func _on_versions_loaded(args: Array) -> void:
if (args.size() == 0):
return
var current_version: String = args[0]
var versions_str: String = JavaScriptBridge.eval("versions_callbacks.versions;")
var version_urls_str: String = JavaScriptBridge.eval("versions_callbacks.version_urls;")
var versions: PackedStringArray = versions_str.split(";", false)
var version_urls: PackedStringArray = version_urls_str.split(";", false)
if versions:
show()
btn.clear()
btn.item_selected.connect(func(idx):
# move to another version
JavaScriptBridge.eval("window.location.href = \"%s\"" % version_urls[idx])
)
for i in range(versions.size()):
btn.add_item(versions[i], i)
if versions[i] == current_version:
btn.select(i)

View file

@ -0,0 +1 @@
uid://hvx3t70syvkm

View file

@ -3,134 +3,134 @@ class_name Option extends RefCounted
static var Unit = Option.some(null) static var Unit = Option.some(null)
static func some(value: Variant) -> Option: static func some(value: Variant) -> Option:
return Some.new(value) return Some.new(value)
static var none: Option.None = None.new() static var none: Option.None = None.new()
static func from(value: Variant) -> Option: static func from(value: Variant) -> Option:
if typeof(value) == TYPE_NIL: if typeof(value) == TYPE_NIL:
return Option.none return Option.none
else: return Option.some(value) else: return Option.some(value)
static func collect_some(options: Array[Option], ignore_none: bool = false) -> Option: static func collect_some(options: Array[Option], ignore_none: bool = false) -> Option:
var result = [] var result = []
for option in options: for option in options:
if option.is_some(): if option.is_some():
result.push_back(option.unwrap()) result.push_back(option.unwrap())
elif not ignore_none: elif not ignore_none:
return Option.none return Option.none
return Option.some(result) return Option.some(result)
class Some extends Option: class Some extends Option:
var value: Variant var value: Variant
func _init(val: Variant) -> void: func _init(val: Variant) -> void:
value = val value = val
func and_then(fn: Callable) -> Option: func and_then(fn: Callable) -> Option:
return fn.call(value) return fn.call(value)
func and_other(other: Option) -> Option: func and_other(other: Option) -> Option:
return other return other
func contains(target_value: Variant) -> bool: func contains(target_value: Variant) -> bool:
return value == target_value return value == target_value
func filter(fn: Callable) -> Option: func filter(fn: Callable) -> Option:
if fn.call(value): return self if fn.call(value): return self
else: return Option.none else: return Option.none
func flatten() -> Option: func flatten() -> Option:
if value is Option: if value is Option:
return value.flatten() return value.flatten()
else: return Option.some(value) else: return Option.some(value)
func map(fn: Callable) -> Option: func map(fn: Callable) -> Option:
return Option.some(fn.call(value)) return Option.some(fn.call(value))
func ok_or(_err: Variant) -> Result: func ok_or(_err: Variant) -> Result:
return Result.ok(value) return Result.ok(value)
func ok_or_else(fn: Callable) -> Result: func ok_or_else(fn: Callable) -> Result:
return Result.ok(value) return Result.ok(value)
func or_other(option: Option) -> Option: func or_other(option: Option) -> Option:
return self return self
func inspect(fn: Callable) -> Option: func inspect(fn: Callable) -> Option:
fn.call(value) fn.call(value)
return self return self
func is_some() -> bool: func is_some() -> bool:
return true return true
func is_none() -> bool: func is_none() -> bool:
return false return false
func unwrap() -> Variant: func unwrap() -> Variant:
return value return value
func unwrap_or(_default_value: Variant) -> Variant: func unwrap_or(_default_value: Variant) -> Variant:
return value return value
func unwrap_or_else(_fn: Callable) -> Variant: func unwrap_or_else(_fn: Callable) -> Variant:
return value return value
func xor_other(other: Option) -> Option: func xor_other(other: Option) -> Option:
if other.is_none(): if other.is_none():
return self return self
else: else:
return Option.none return Option.none
class None extends Option: class None extends Option:
func and_then(_fn: Callable) -> Option: func and_then(_fn: Callable) -> Option:
return self return self
func and_other(other: Option) -> Option: func and_other(other: Option) -> Option:
return self return self
func contains(value: Variant) -> bool: func contains(value: Variant) -> bool:
return false return false
func filter(_f: Callable) -> Option: func filter(_f: Callable) -> Option:
return self return self
func flatten() -> Option: func flatten() -> Option:
return self return self
func map(_fn: Callable) -> Option: func map(_fn: Callable) -> Option:
return self return self
func ok_or(err: Variant) -> Result: func ok_or(err: Variant) -> Result:
return Result.err(err) return Result.err(err)
func ok_or_else(fn: Callable) -> Result: func ok_or_else(fn: Callable) -> Result:
return Result.err(fn.call()) return Result.err(fn.call())
func or_other(option: Option) -> Option: func or_other(option: Option) -> Option:
return option return option
func inspect(_fn: Callable) -> Option: func inspect(_fn: Callable) -> Option:
return self return self
func is_some() -> bool: func is_some() -> bool:
return false return false
func is_none() -> bool: func is_none() -> bool:
return true return true
func unwrap() -> Variant: func unwrap() -> Variant:
assert(false, "Called unwrap() on a None value") assert(false, "Called unwrap() on a None value")
return null return null
func unwrap_or(default_value: Variant) -> Variant: func unwrap_or(default_value: Variant) -> Variant:
return default_value return default_value
func unwrap_or_else(fn: Callable) -> Variant: func unwrap_or_else(fn: Callable) -> Variant:
return fn.call() return fn.call()
func xor_other(other: Option) -> Option: func xor_other(other: Option) -> Option:
if other.is_some(): if other.is_some():
return other return other
else: else:
return self return self

View file

@ -0,0 +1,12 @@
[gd_resource type="Resource" script_class="Equipment" load_steps=3 format=3 uid="uid://crgwey6ibaf2h"]
[ext_resource type="PackedScene" uid="uid://isqkayrtr7t8" path="res://scenes/pistol.tscn" id="1_6ttue"]
[ext_resource type="Script" uid="uid://c710qg683rqbc" path="res://src/equipment.gd" id="1_lqglu"]
[resource]
script = ExtResource("1_lqglu")
scene = ExtResource("1_6ttue")
name = "Pistol"
description = ""
max_stack = 1
metadata/_custom_type_script = "uid://c710qg683rqbc"

View file

@ -1,6 +1,6 @@
[gd_resource type="Resource" script_class="Inventory" load_steps=5 format=3 uid="uid://bllq6ri54q3ne"] [gd_resource type="Resource" script_class="Inventory" load_steps=5 format=3 uid="uid://bllq6ri54q3ne"]
[ext_resource type="Script" uid="uid://db4nrsnmkv3h0" path="res://src/item_instance.gd" id="1_uptie"] [ext_resource type="Script" uid="uid://1rjq1ttxq4nd" path="res://src/item_instance.gd" id="1_uptie"]
[ext_resource type="Script" uid="uid://dh4ytedxidq0x" path="res://src/inventory.gd" id="2_1njko"] [ext_resource type="Script" uid="uid://dh4ytedxidq0x" path="res://src/inventory.gd" id="2_1njko"]
[ext_resource type="Resource" uid="uid://cqfnwpmo4fyv4" path="res://resources/items/key.tres" id="2_85a8j"] [ext_resource type="Resource" uid="uid://cqfnwpmo4fyv4" path="res://resources/items/key.tres" id="2_85a8j"]

View file

@ -1,30 +1,37 @@
[gd_scene load_steps=4 format=3 uid="uid://isqkayrtr7t8"] [gd_scene load_steps=5 format=3 uid="uid://isqkayrtr7t8"]
[ext_resource type="Script" uid="uid://bn7dr8s404qnf" path="res://src/usable.gd" id="1_1e3ry"] [ext_resource type="Script" uid="uid://bn7dr8s404qnf" path="res://src/usable.gd" id="1_1e3ry"]
[ext_resource type="PackedScene" uid="uid://5a023hrws3gx" path="res://assets/Glock 17 Gen 4/Main.glb" id="1_igbvm"] [ext_resource type="PackedScene" uid="uid://5a023hrws3gx" path="res://assets/Glock 17 Gen 4/Main.glb" id="1_igbvm"]
[ext_resource type="Script" uid="uid://ddqif2gmm1ec2" path="res://src/damage_source.gd" id="2_buff3"] [ext_resource type="Script" uid="uid://ddqif2gmm1ec2" path="res://src/damage_source.gd" id="2_buff3"]
[ext_resource type="Script" uid="uid://bgun1u5812uil" path="res://src/raycast.gd" id="4_t6oaa"]
[node name="Pistol" type="Node3D"] [node name="Pistol" type="Node3D"]
script = ExtResource("1_1e3ry") script = ExtResource("1_1e3ry")
[node name="Main" parent="." instance=ExtResource("1_igbvm")]
[node name="RayCast3D" type="RayCast3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, -1.25)
target_position = Vector3(0, 0, -100)
debug_shape_custom_color = Color(1, 0, 0, 1)
debug_shape_thickness = 1
[node name="DamageSource" type="Node" parent="." node_paths=PackedStringArray("raycast")] [node name="DamageSource" type="Node" parent="." node_paths=PackedStringArray("raycast")]
script = ExtResource("2_buff3") script = ExtResource("2_buff3")
damage = 1 damage = 1
raycast = NodePath("../RayCast3D") raycast = NodePath("../Node3D/Raycast")
metadata/_custom_type_script = "uid://ddqif2gmm1ec2" metadata/_custom_type_script = "uid://ddqif2gmm1ec2"
[node name="Timer" type="Timer" parent="."] [node name="Timer" type="Timer" parent="."]
wait_time = 0.5 wait_time = 0.5
one_shot = true one_shot = true
[node name="Node3D" type="Node3D" parent="."]
transform = Transform3D(-0.0948472, 0.981445, -0.166645, -0.538265, -0.191379, -0.820759, -0.837421, 0.0118525, 0.546429, 3.16379, 3.48907, 1.04434)
[node name="Main" parent="Node3D" instance=ExtResource("1_igbvm")]
transform = Transform3D(10, 5.21541e-08, 0, -1.3411e-07, 10, 8.9407e-08, -4.76837e-07, 8.9407e-08, 10, 0, 0, 0)
[node name="Raycast" type="Node3D" parent="Node3D"]
transform = Transform3D(1, 1.02445e-08, 2.98023e-08, -8.3819e-09, 1, -3.25963e-08, -2.98023e-08, -3.58559e-08, 1, -0.35812, -1.98491, -11.4862)
script = ExtResource("4_t6oaa")
length = 1000.0
custom_color = Color(1, 0, 0, 1)
width = 1
metadata/_custom_type_script = "uid://bgun1u5812uil"
[connection signal="used" from="." to="." method="disable"] [connection signal="used" from="." to="." method="disable"]
[connection signal="used" from="." to="DamageSource" method="try_damage"] [connection signal="used" from="." to="DamageSource" method="try_damage"]
[connection signal="used" from="." to="Timer" method="start"] [connection signal="used" from="." to="Timer" method="start"]

View file

@ -5,9 +5,9 @@
[ext_resource type="Script" uid="uid://877g2wvcupw6" path="res://src/player_input.gd" id="3_dqkch"] [ext_resource type="Script" uid="uid://877g2wvcupw6" path="res://src/player_input.gd" id="3_dqkch"]
[ext_resource type="Script" uid="uid://c3wlcxy4vnm2i" path="res://src/interactor.gd" id="4_dqkch"] [ext_resource type="Script" uid="uid://c3wlcxy4vnm2i" path="res://src/interactor.gd" id="4_dqkch"]
[ext_resource type="Script" uid="uid://csjl56hf0fnoy" path="res://src/item_container.gd" id="5_qlg0r"] [ext_resource type="Script" uid="uid://csjl56hf0fnoy" path="res://src/item_container.gd" id="5_qlg0r"]
[ext_resource type="Script" uid="uid://k1ihjmhj7ix" path="res://src/equipment_handler.gd" id="5_smehm"]
[ext_resource type="Resource" uid="uid://crgwey6ibaf2h" path="res://resources/items/pistol.tres" id="6_smehm"]
[ext_resource type="Resource" uid="uid://bllq6ri54q3ne" path="res://resources/player_inventory.tres" id="6_tuyoq"] [ext_resource type="Resource" uid="uid://bllq6ri54q3ne" path="res://resources/player_inventory.tres" id="6_tuyoq"]
[ext_resource type="PackedScene" uid="uid://isqkayrtr7t8" path="res://scenes/pistol.tscn" id="7_fjrip"]
[ext_resource type="Script" uid="uid://c710qg683rqbc" path="res://src/equipment.gd" id="7_ur7pv"]
[sub_resource type="SphereShape3D" id="SphereShape3D_qhqgy"] [sub_resource type="SphereShape3D" id="SphereShape3D_qhqgy"]
@ -206,17 +206,14 @@ script = ExtResource("3_dqkch")
script = ExtResource("5_qlg0r") script = ExtResource("5_qlg0r")
inventory = ExtResource("6_tuyoq") inventory = ExtResource("6_tuyoq")
[node name="Weapon" type="BoneAttachment3D" parent="." node_paths=PackedStringArray("initial_equipment")] [node name="Weapon" type="BoneAttachment3D" parent="."]
transform = Transform3D(0.00876506, 0.0120414, 0.00178277, 0.00882159, -0.00779736, 0.00929411, 0.00838767, -0.00438243, -0.0116379, -0.128585, 1.36723, 0.500051) transform = Transform3D(0.00876506, 0.0120414, 0.00178277, 0.00882159, -0.00779736, 0.00929411, 0.00838767, -0.00438243, -0.0116379, -0.128585, 1.36723, 0.500051)
bone_name = "mixamorigRightHandMiddle1" bone_name = "mixamorigRightHandMiddle1"
bone_idx = 24 bone_idx = 24
use_external_skeleton = true use_external_skeleton = true
external_skeleton = NodePath("../Mesh/AuxScene/Scene/Armature/Skeleton3D") external_skeleton = NodePath("../Mesh/AuxScene/Scene/Armature/Skeleton3D")
script = ExtResource("7_ur7pv") script = ExtResource("5_smehm")
initial_equipment = NodePath("Pistol") initial_equipment = ExtResource("6_smehm")
[node name="Pistol" parent="Weapon" instance=ExtResource("7_fjrip")]
transform = Transform3D(-0.948472, 9.81445, -1.66645, -5.38265, -1.91379, -8.20758, -8.37422, 0.118531, 5.46429, 3.16379, 3.48907, 1.04434)
[node name="Interactor" type="Node3D" parent="." node_paths=PackedStringArray("area", "root_node")] [node name="Interactor" type="Node3D" parent="." node_paths=PackedStringArray("area", "root_node")]
script = ExtResource("4_dqkch") script = ExtResource("4_dqkch")

View file

@ -1,23 +1,21 @@
class_name DamageSource extends Node class_name DamageSource extends Node
@export var damage: int @export var damage: int
@export var raycast: RayCast3D @export var raycast: Raycast
func _ready() -> void: func _ready() -> void:
raycast.enabled = false raycast.enabled = false
func raycast_to_target() -> Option: func raycast_to_target() -> Option:
raycast.force_raycast_update() raycast.force_raycast_update()
if raycast.is_colliding(): return raycast.hit
return Option.some(raycast.get_collider())
else:
return Option.none
func try_damage() -> void: func try_damage() -> void:
match raycast_to_target(): match raycast_to_target():
var option when option.is_some(): var option when option.is_some():
var value = option.unwrap() var hit = option.unwrap()
match NodeExt.find_child_variant(value, Health): var collider = hit.collider
match NodeExt.find_child_variant(collider, Health):
var node when node.is_some(): var node when node.is_some():
var health: Health = node.unwrap() var health: Health = node.unwrap()
health.apply_damage(damage) health.apply_damage(damage)

View file

@ -1,25 +1,9 @@
class_name Equipment extends Node class_name Equipment extends Item
signal unequipped(item: Item) @export var scene: PackedScene
signal equipped(item: Item)
@export var initial_equipment: Usable func create() -> Option:
var current_item: Option = Option.none if scene != null and scene.can_instantiate():
return Option.some(scene.instantiate())
func _ready() -> void: else:
current_item = Option.from(initial_equipment) return Option.none
func unequip():
if current_item.is_some():
var item = current_item.unwrap()
current_item = Option.none
unequipped.emit(item)
func equip(item: Item):
unequip()
if item != null:
current_item = Option.some(item)
equipped.emit(item)
func use():
current_item.inspect(func(x: Variant) -> void: x.use())

View file

@ -0,0 +1,33 @@
class_name EquipmentHandler extends Node3D
signal unequipped(equipment: Equipment)
signal equipped(equipment: Equipment)
@export var initial_equipment: Equipment
var current_equipment: Option = Option.none
var has_equipped_item: bool:
get: return current_equipment.is_some()
func _ready() -> void:
equip(initial_equipment)
func unequip():
if current_equipment.is_some():
var equipment = current_equipment.unwrap()
current_equipment = Option.none
unequipped.emit(equipment)
equipment.queue_free()
func equip(equipment: Equipment):
unequip()
if equipment != null:
match initial_equipment.create():
var opt when opt.is_some():
var item = opt.unwrap()
add_child(item)
current_equipment = Option.from(item)
equipped.emit(equipment)
func use():
current_equipment.inspect(func(x: Variant) -> void: x.use())

View file

@ -0,0 +1 @@
uid://k1ihjmhj7ix

View file

@ -5,12 +5,14 @@ class_name Player extends CharacterBody3D
@export var input: PlayerInput @export var input: PlayerInput
@export var interactor: Interactor @export var interactor: Interactor
@export var equipment: Equipment @export var equipment: EquipmentHandler
var is_running: bool: var is_running: bool:
get: return velocity and input.is_running get: return velocity and input.is_running
var is_carrying_item = true var is_carrying_item: bool:
get: return equipment.has_equipped_item
var is_weapon_ready: bool: var is_weapon_ready: bool:
get: return is_carrying_item and input.is_weapon_ready get: return is_carrying_item and input.is_weapon_ready

90
godot/src/raycast.gd Normal file
View file

@ -0,0 +1,90 @@
class_name Raycast extends Node3D
class RaycastHit extends RefCounted:
var collider: CollisionObject3D
var shape: int
var normal: Vector3
var position: Vector3
var face_index: int
@warning_ignore("shadowed_variable")
func _init(collider: CollisionObject3D, shape: int, normal: Vector3, position: Vector3, index: int) -> void:
self.collider = collider
self.shape = shape
self.normal = normal
self.position = position
self.face_index = index
func get_shape_owner() -> Option:
if typeof(self.collider) == TYPE_NIL or self.shape == 0: return Option.none
var owner_id = self.collider.shape_find_owner(shape)
return Option.some(self.collider.shape_owner_get_owner(owner_id))
static func from_dict(hit: Dictionary) -> Option:
if hit.is_empty(): return Option.none
return Option.some(
RaycastHit.new(
hit['collider'],
hit['shape'],
hit['normal'],
hit['position'],
hit['face_index']
)
)
@export var enabled: bool = true
@export var exclude_parent: bool = true
@export var length: float = 1
@export_flags_3d_physics var collision_mask: int = 1
@export var hit_from_inside: bool = false
@export var hit_backfaces: bool = true
@export_group("Collide With")
@export var areas: bool = false
@export var bodies: bool = true
@export var exclusions: Array[CollisionObject3D] = []
var _exclusions: Array
@export_group("Debug Shape")
@export var custom_color: Color
@export var width: int = 2
var forward: Vector3:
get: return -global_basis.z
var hit: Option = Option.none
func _ready() -> void:
set_physics_process(enabled)
_exclusions = exclusions.map(func(x): return x.get_rid())
if exclude_parent:
match _find_parent_collider():
var x when x.is_some():
_exclusions.append(x.unwrap().get_rid())
func _physics_process(_delta: float) -> void:
force_raycast_update()
func _find_parent_collider(node: Node3D = self) -> Option:
if typeof(node) == TYPE_NIL: return Option.none
if is_instance_of(node, CollisionObject3D):
return Option.some(node)
else:
return _find_parent_collider(node.get_parent())
func force_raycast_update() -> void:
var to = forward * length + global_position
var query = PhysicsRayQueryParameters3D.create(global_position, to, collision_mask, _exclusions)
DebugDraw3D.draw_ray(global_position, forward, length, custom_color, .25)
query.hit_from_inside = hit_from_inside
query.hit_back_faces = hit_backfaces
query.collide_with_areas = areas
query.collide_with_bodies = bodies
var raycast_hit = get_world_3d().direct_space_state.intersect_ray(query)
hit = RaycastHit.from_dict(raycast_hit)
func is_colliding() -> bool:
return hit.is_some()