Initial commit
This commit is contained in:
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Normalize EOL for all files that Git considers text files.
|
||||
* text=auto eol=lf
|
||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Godot 4+ specific ignores
|
||||
.godot/
|
||||
21
addons/debug_menu/LICENSE.md
Normal file
21
addons/debug_menu/LICENSE.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# MIT License
|
||||
|
||||
Copyright © 2023-present Hugo Locurcio and contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
462
addons/debug_menu/debug_menu.gd
Normal file
462
addons/debug_menu/debug_menu.gd
Normal file
@@ -0,0 +1,462 @@
|
||||
extends Control
|
||||
|
||||
@export var fps: Label
|
||||
@export var frame_time: Label
|
||||
@export var frame_number: Label
|
||||
@export var frame_history_total_avg: Label
|
||||
@export var frame_history_total_min: Label
|
||||
@export var frame_history_total_max: Label
|
||||
@export var frame_history_total_last: Label
|
||||
@export var frame_history_cpu_avg: Label
|
||||
@export var frame_history_cpu_min: Label
|
||||
@export var frame_history_cpu_max: Label
|
||||
@export var frame_history_cpu_last: Label
|
||||
@export var frame_history_gpu_avg: Label
|
||||
@export var frame_history_gpu_min: Label
|
||||
@export var frame_history_gpu_max: Label
|
||||
@export var frame_history_gpu_last: Label
|
||||
@export var fps_graph: Panel
|
||||
@export var total_graph: Panel
|
||||
@export var cpu_graph: Panel
|
||||
@export var gpu_graph: Panel
|
||||
@export var information: Label
|
||||
@export var settings: Label
|
||||
|
||||
## The number of frames to keep in history for graph drawing and best/worst calculations.
|
||||
## Currently, this also affects how FPS is measured.
|
||||
const HISTORY_NUM_FRAMES = 150
|
||||
|
||||
const GRAPH_SIZE = Vector2(150, 25)
|
||||
const GRAPH_MIN_FPS = 10
|
||||
const GRAPH_MAX_FPS = 160
|
||||
const GRAPH_MIN_FRAMETIME = 1.0 / GRAPH_MIN_FPS
|
||||
const GRAPH_MAX_FRAMETIME = 1.0 / GRAPH_MAX_FPS
|
||||
|
||||
## Debug menu display style.
|
||||
enum Style {
|
||||
HIDDEN, ## Debug menu is hidden.
|
||||
VISIBLE_COMPACT, ## Debug menu is visible, with only the FPS, FPS cap (if any) and time taken to render the last frame.
|
||||
VISIBLE_DETAILED, ## Debug menu is visible with full information, including graphs.
|
||||
MAX, ## Represents the size of the Style enum.
|
||||
}
|
||||
|
||||
## The style to use when drawing the debug menu.
|
||||
var style := Style.HIDDEN:
|
||||
set(value):
|
||||
style = value
|
||||
match style:
|
||||
Style.HIDDEN:
|
||||
visible = false
|
||||
Style.VISIBLE_COMPACT, Style.VISIBLE_DETAILED:
|
||||
visible = true
|
||||
frame_number.visible = style == Style.VISIBLE_DETAILED
|
||||
$VBoxContainer/FrameTimeHistory.visible = style == Style.VISIBLE_DETAILED
|
||||
$VBoxContainer/FPSGraph.visible = style == Style.VISIBLE_DETAILED
|
||||
$VBoxContainer/TotalGraph.visible = style == Style.VISIBLE_DETAILED
|
||||
$VBoxContainer/CPUGraph.visible = style == Style.VISIBLE_DETAILED
|
||||
$VBoxContainer/GPUGraph.visible = style == Style.VISIBLE_DETAILED
|
||||
information.visible = style == Style.VISIBLE_DETAILED
|
||||
settings.visible = style == Style.VISIBLE_DETAILED
|
||||
|
||||
# Value of `Time.get_ticks_usec()` on the previous frame.
|
||||
var last_tick := 0
|
||||
|
||||
var thread := Thread.new()
|
||||
|
||||
## Returns the sum of all values of an array (use as a parameter to `Array.reduce()`).
|
||||
var sum_func := func avg(accum: float, number: float) -> float: return accum + number
|
||||
|
||||
# History of the last `HISTORY_NUM_FRAMES` rendered frames.
|
||||
var frame_history_total: Array[float] = []
|
||||
var frame_history_cpu: Array[float] = []
|
||||
var frame_history_gpu: Array[float] = []
|
||||
var fps_history: Array[float] = [] # Only used for graphs.
|
||||
|
||||
var frametime_avg := GRAPH_MIN_FRAMETIME
|
||||
var frametime_cpu_avg := GRAPH_MAX_FRAMETIME
|
||||
var frametime_gpu_avg := GRAPH_MIN_FRAMETIME
|
||||
var frames_per_second := float(GRAPH_MIN_FPS)
|
||||
var frame_time_gradient := Gradient.new()
|
||||
|
||||
func _init() -> void:
|
||||
# This must be done here instead of `_ready()` to avoid having `visibility_changed` be emitted immediately.
|
||||
visible = false
|
||||
|
||||
if not InputMap.has_action("cycle_debug_menu"):
|
||||
# Create default input action if no user-defined override exists.
|
||||
# We can't do it in the editor plugin's activation code as it doesn't seem to work there.
|
||||
InputMap.add_action("cycle_debug_menu")
|
||||
var event := InputEventKey.new()
|
||||
event.keycode = KEY_F3
|
||||
InputMap.action_add_event("cycle_debug_menu", event)
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
fps_graph.draw.connect(_fps_graph_draw)
|
||||
total_graph.draw.connect(_total_graph_draw)
|
||||
cpu_graph.draw.connect(_cpu_graph_draw)
|
||||
gpu_graph.draw.connect(_gpu_graph_draw)
|
||||
|
||||
fps_history.resize(HISTORY_NUM_FRAMES)
|
||||
frame_history_total.resize(HISTORY_NUM_FRAMES)
|
||||
frame_history_cpu.resize(HISTORY_NUM_FRAMES)
|
||||
frame_history_gpu.resize(HISTORY_NUM_FRAMES)
|
||||
|
||||
# NOTE: Both FPS and frametimes are colored following FPS logic
|
||||
# (red = 10 FPS, yellow = 60 FPS, green = 110 FPS, cyan = 160 FPS).
|
||||
# This makes the color gradient non-linear.
|
||||
# Colors are taken from <https://tailwindcolor.com/>.
|
||||
frame_time_gradient.set_color(0, Color8(239, 68, 68)) # red-500
|
||||
frame_time_gradient.set_color(1, Color8(56, 189, 248)) # light-blue-400
|
||||
frame_time_gradient.add_point(0.3333, Color8(250, 204, 21)) # yellow-400
|
||||
frame_time_gradient.add_point(0.6667, Color8(128, 226, 95)) # 50-50 mix of lime-400 and green-400
|
||||
|
||||
get_viewport().size_changed.connect(update_settings_label)
|
||||
|
||||
# Display loading text while information is being queried,
|
||||
# in case the user toggles the full debug menu just after starting the project.
|
||||
information.text = "Loading hardware information...\n\n "
|
||||
settings.text = "Loading project information..."
|
||||
thread.start(
|
||||
func():
|
||||
# Disable thread safety checks as they interfere with this add-on.
|
||||
# This only affects this particular thread, not other thread instances in the project.
|
||||
# See <https://github.com/godotengine/godot/pull/78000> for details.
|
||||
# Use a Callable so that this can be ignored on Godot 4.0 without causing a script error
|
||||
# (thread safety checks were added in Godot 4.1).
|
||||
if Engine.get_version_info()["hex"] >= 0x040100:
|
||||
Callable(Thread, "set_thread_safety_checks_enabled").call(false)
|
||||
|
||||
# Enable required time measurements to display CPU/GPU frame time information.
|
||||
# These lines are time-consuming operations, so run them in a separate thread.
|
||||
RenderingServer.viewport_set_measure_render_time(get_viewport().get_viewport_rid(), true)
|
||||
update_information_label()
|
||||
update_settings_label()
|
||||
)
|
||||
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if event.is_action_pressed("cycle_debug_menu"):
|
||||
style = wrapi(style + 1, 0, Style.MAX) as Style
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
thread.wait_to_finish()
|
||||
|
||||
|
||||
## Update hardware information label (this can change at runtime based on window
|
||||
## size and graphics settings). This is only called when the window is resized.
|
||||
## To update when graphics settings are changed, the function must be called manually
|
||||
## using `DebugMenu.update_settings_label()`.
|
||||
func update_settings_label() -> void:
|
||||
settings.text = ""
|
||||
if ProjectSettings.has_setting("application/config/version"):
|
||||
settings.text += "Project Version: %s\n" % ProjectSettings.get_setting("application/config/version")
|
||||
|
||||
var rendering_method_string := ""
|
||||
match str(ProjectSettings.get_setting("rendering/renderer/rendering_method")):
|
||||
"forward_plus":
|
||||
rendering_method_string = "Forward+"
|
||||
"mobile":
|
||||
rendering_method_string = "Forward Mobile"
|
||||
"gl_compatibility":
|
||||
rendering_method_string = "Compatibility"
|
||||
settings.text += "Rendering Method: %s\n" % rendering_method_string
|
||||
|
||||
var viewport := get_viewport()
|
||||
|
||||
# The size of the viewport rendering, which determines which resolution 3D is rendered at.
|
||||
var viewport_render_size := Vector2i()
|
||||
|
||||
if viewport.content_scale_mode == Window.CONTENT_SCALE_MODE_VIEWPORT:
|
||||
viewport_render_size = viewport.get_visible_rect().size
|
||||
settings.text += "Viewport: %d×%d, Window: %d×%d\n" % [viewport.get_visible_rect().size.x, viewport.get_visible_rect().size.y, viewport.size.x, viewport.size.y]
|
||||
else:
|
||||
# Window size matches viewport size.
|
||||
viewport_render_size = viewport.size
|
||||
settings.text += "Viewport: %d×%d\n" % [viewport.size.x, viewport.size.y]
|
||||
|
||||
# Display 3D settings only if relevant.
|
||||
if viewport.get_camera_3d():
|
||||
var antialiasing_3d_string := ""
|
||||
if viewport.use_taa:
|
||||
antialiasing_3d_string += (" + " if not antialiasing_3d_string.is_empty() else "") + "TAA"
|
||||
if viewport.msaa_3d >= Viewport.MSAA_2X:
|
||||
antialiasing_3d_string += (" + " if not antialiasing_3d_string.is_empty() else "") + "%d× MSAA" % pow(2, viewport.msaa_3d)
|
||||
if viewport.screen_space_aa == Viewport.SCREEN_SPACE_AA_FXAA:
|
||||
antialiasing_3d_string += (" + " if not antialiasing_3d_string.is_empty() else "") + "FXAA"
|
||||
|
||||
var scaling_mode = "Unknown"
|
||||
match viewport.scaling_3d_mode:
|
||||
Viewport.SCALING_3D_MODE_BILINEAR:
|
||||
scaling_mode = "Bilinear"
|
||||
Viewport.SCALING_3D_MODE_FSR:
|
||||
scaling_mode = "FSR 1.0"
|
||||
Viewport.SCALING_3D_MODE_FSR2:
|
||||
scaling_mode = "FSR 2.2"
|
||||
|
||||
settings.text += "3D scale (%s): %d%% = %d×%d" % [
|
||||
scaling_mode,
|
||||
viewport.scaling_3d_scale * 100,
|
||||
viewport_render_size.x * viewport.scaling_3d_scale,
|
||||
viewport_render_size.y * viewport.scaling_3d_scale,
|
||||
]
|
||||
|
||||
if not antialiasing_3d_string.is_empty():
|
||||
settings.text += "\n3D Antialiasing: %s" % antialiasing_3d_string
|
||||
|
||||
var environment := viewport.get_camera_3d().get_world_3d().environment
|
||||
if environment:
|
||||
if environment.ssr_enabled:
|
||||
settings.text += "\nSSR: %d Steps" % environment.ssr_max_steps
|
||||
|
||||
if environment.ssao_enabled:
|
||||
settings.text += "\nSSAO: On"
|
||||
if environment.ssil_enabled:
|
||||
settings.text += "\nSSIL: On"
|
||||
|
||||
if environment.sdfgi_enabled:
|
||||
settings.text += "\nSDFGI: %d Cascades" % environment.sdfgi_cascades
|
||||
|
||||
if environment.glow_enabled:
|
||||
settings.text += "\nGlow: On"
|
||||
|
||||
if environment.volumetric_fog_enabled:
|
||||
settings.text += "\nVolumetric Fog: On"
|
||||
var antialiasing_2d_string := ""
|
||||
if viewport.msaa_2d >= Viewport.MSAA_2X:
|
||||
antialiasing_2d_string = "%d× MSAA" % pow(2, viewport.msaa_2d)
|
||||
|
||||
if not antialiasing_2d_string.is_empty():
|
||||
settings.text += "\n2D Antialiasing: %s" % antialiasing_2d_string
|
||||
|
||||
|
||||
## Update hardware/software information label (this never changes at runtime).
|
||||
func update_information_label() -> void:
|
||||
var adapter_string := ""
|
||||
# Make "NVIDIA Corporation" and "NVIDIA" be considered identical (required when using OpenGL to avoid redundancy).
|
||||
if RenderingServer.get_video_adapter_vendor().trim_suffix(" Corporation") in RenderingServer.get_video_adapter_name():
|
||||
# Avoid repeating vendor name before adapter name.
|
||||
# Trim redundant suffix sometimes reported by NVIDIA graphics cards when using OpenGL.
|
||||
adapter_string = RenderingServer.get_video_adapter_name().trim_suffix("/PCIe/SSE2")
|
||||
else:
|
||||
adapter_string = RenderingServer.get_video_adapter_vendor() + " - " + RenderingServer.get_video_adapter_name().trim_suffix("/PCIe/SSE2")
|
||||
|
||||
# Graphics driver version information isn't always availble.
|
||||
var driver_info := OS.get_video_adapter_driver_info()
|
||||
var driver_info_string := ""
|
||||
if driver_info.size() >= 2:
|
||||
driver_info_string = driver_info[1]
|
||||
else:
|
||||
driver_info_string = "(unknown)"
|
||||
|
||||
var release_string := ""
|
||||
if OS.has_feature("editor"):
|
||||
# Editor build (implies `debug`).
|
||||
release_string = "editor"
|
||||
elif OS.has_feature("debug"):
|
||||
# Debug export template build.
|
||||
release_string = "debug"
|
||||
else:
|
||||
# Release export template build.
|
||||
release_string = "release"
|
||||
|
||||
var graphics_api_string := ""
|
||||
if str(ProjectSettings.get_setting("rendering/renderer/rendering_method")) != "gl_compatibility":
|
||||
graphics_api_string = "Vulkan"
|
||||
else:
|
||||
if OS.has_feature("web"):
|
||||
graphics_api_string = "WebGL"
|
||||
elif OS.has_feature("mobile"):
|
||||
graphics_api_string = "OpenGL ES"
|
||||
else:
|
||||
graphics_api_string = "OpenGL"
|
||||
|
||||
information.text = (
|
||||
"%s, %d threads\n" % [OS.get_processor_name().replace("(R)", "").replace("(TM)", ""), OS.get_processor_count()]
|
||||
+ "%s %s (%s %s), %s %s\n" % [OS.get_name(), "64-bit" if OS.has_feature("64") else "32-bit", release_string, "double" if OS.has_feature("double") else "single", graphics_api_string, RenderingServer.get_video_adapter_api_version()]
|
||||
+ "%s, %s" % [adapter_string, driver_info_string]
|
||||
)
|
||||
|
||||
|
||||
func _fps_graph_draw() -> void:
|
||||
var fps_polyline := PackedVector2Array()
|
||||
fps_polyline.resize(HISTORY_NUM_FRAMES)
|
||||
for fps_index in fps_history.size():
|
||||
fps_polyline[fps_index] = Vector2(
|
||||
remap(fps_index, 0, fps_history.size(), 0, GRAPH_SIZE.x),
|
||||
remap(clampf(fps_history[fps_index], GRAPH_MIN_FPS, GRAPH_MAX_FPS), GRAPH_MIN_FPS, GRAPH_MAX_FPS, GRAPH_SIZE.y, 0.0)
|
||||
)
|
||||
# Don't use antialiasing to speed up line drawing, but use a width that scales with
|
||||
# viewport scale to keep the line easily readable on hiDPI displays.
|
||||
fps_graph.draw_polyline(fps_polyline, frame_time_gradient.sample(remap(frames_per_second, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0)), 1.0)
|
||||
|
||||
|
||||
func _total_graph_draw() -> void:
|
||||
var total_polyline := PackedVector2Array()
|
||||
total_polyline.resize(HISTORY_NUM_FRAMES)
|
||||
for total_index in frame_history_total.size():
|
||||
total_polyline[total_index] = Vector2(
|
||||
remap(total_index, 0, frame_history_total.size(), 0, GRAPH_SIZE.x),
|
||||
remap(clampf(frame_history_total[total_index], GRAPH_MIN_FPS, GRAPH_MAX_FPS), GRAPH_MIN_FPS, GRAPH_MAX_FPS, GRAPH_SIZE.y, 0.0)
|
||||
)
|
||||
# Don't use antialiasing to speed up line drawing, but use a width that scales with
|
||||
# viewport scale to keep the line easily readable on hiDPI displays.
|
||||
total_graph.draw_polyline(total_polyline, frame_time_gradient.sample(remap(1000.0 / frametime_avg, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0)), 1.0)
|
||||
|
||||
|
||||
func _cpu_graph_draw() -> void:
|
||||
var cpu_polyline := PackedVector2Array()
|
||||
cpu_polyline.resize(HISTORY_NUM_FRAMES)
|
||||
for cpu_index in frame_history_cpu.size():
|
||||
cpu_polyline[cpu_index] = Vector2(
|
||||
remap(cpu_index, 0, frame_history_cpu.size(), 0, GRAPH_SIZE.x),
|
||||
remap(clampf(frame_history_cpu[cpu_index], GRAPH_MIN_FPS, GRAPH_MAX_FPS), GRAPH_MIN_FPS, GRAPH_MAX_FPS, GRAPH_SIZE.y, 0.0)
|
||||
)
|
||||
# Don't use antialiasing to speed up line drawing, but use a width that scales with
|
||||
# viewport scale to keep the line easily readable on hiDPI displays.
|
||||
cpu_graph.draw_polyline(cpu_polyline, frame_time_gradient.sample(remap(1000.0 / frametime_cpu_avg, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0)), 1.0)
|
||||
|
||||
|
||||
func _gpu_graph_draw() -> void:
|
||||
var gpu_polyline := PackedVector2Array()
|
||||
gpu_polyline.resize(HISTORY_NUM_FRAMES)
|
||||
for gpu_index in frame_history_gpu.size():
|
||||
gpu_polyline[gpu_index] = Vector2(
|
||||
remap(gpu_index, 0, frame_history_gpu.size(), 0, GRAPH_SIZE.x),
|
||||
remap(clampf(frame_history_gpu[gpu_index], GRAPH_MIN_FPS, GRAPH_MAX_FPS), GRAPH_MIN_FPS, GRAPH_MAX_FPS, GRAPH_SIZE.y, 0.0)
|
||||
)
|
||||
# Don't use antialiasing to speed up line drawing, but use a width that scales with
|
||||
# viewport scale to keep the line easily readable on hiDPI displays.
|
||||
gpu_graph.draw_polyline(gpu_polyline, frame_time_gradient.sample(remap(1000.0 / frametime_gpu_avg, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0)), 1.0)
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if visible:
|
||||
fps_graph.queue_redraw()
|
||||
total_graph.queue_redraw()
|
||||
cpu_graph.queue_redraw()
|
||||
gpu_graph.queue_redraw()
|
||||
|
||||
# Difference between the last two rendered frames in milliseconds.
|
||||
var frametime := (Time.get_ticks_usec() - last_tick) * 0.001
|
||||
|
||||
frame_history_total.push_back(frametime)
|
||||
if frame_history_total.size() > HISTORY_NUM_FRAMES:
|
||||
frame_history_total.pop_front()
|
||||
|
||||
# Frametimes are colored following FPS logic (red = 10 FPS, yellow = 60 FPS, green = 110 FPS, cyan = 160 FPS).
|
||||
# This makes the color gradient non-linear.
|
||||
frametime_avg = frame_history_total.reduce(sum_func) / frame_history_total.size()
|
||||
frame_history_total_avg.text = str(frametime_avg).pad_decimals(2)
|
||||
frame_history_total_avg.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_avg, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
|
||||
|
||||
var frametime_min: float = frame_history_total.min()
|
||||
frame_history_total_min.text = str(frametime_min).pad_decimals(2)
|
||||
frame_history_total_min.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_min, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
|
||||
|
||||
var frametime_max: float = frame_history_total.max()
|
||||
frame_history_total_max.text = str(frametime_max).pad_decimals(2)
|
||||
frame_history_total_max.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_max, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
|
||||
|
||||
frame_history_total_last.text = str(frametime).pad_decimals(2)
|
||||
frame_history_total_last.modulate = frame_time_gradient.sample(remap(1000.0 / frametime, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
|
||||
|
||||
var viewport_rid := get_viewport().get_viewport_rid()
|
||||
var frametime_cpu := RenderingServer.viewport_get_measured_render_time_cpu(viewport_rid) + RenderingServer.get_frame_setup_time_cpu()
|
||||
frame_history_cpu.push_back(frametime_cpu)
|
||||
if frame_history_cpu.size() > HISTORY_NUM_FRAMES:
|
||||
frame_history_cpu.pop_front()
|
||||
|
||||
frametime_cpu_avg = frame_history_cpu.reduce(sum_func) / frame_history_cpu.size()
|
||||
frame_history_cpu_avg.text = str(frametime_cpu_avg).pad_decimals(2)
|
||||
frame_history_cpu_avg.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_cpu_avg, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
|
||||
|
||||
var frametime_cpu_min: float = frame_history_cpu.min()
|
||||
frame_history_cpu_min.text = str(frametime_cpu_min).pad_decimals(2)
|
||||
frame_history_cpu_min.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_cpu_min, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
|
||||
|
||||
var frametime_cpu_max: float = frame_history_cpu.max()
|
||||
frame_history_cpu_max.text = str(frametime_cpu_max).pad_decimals(2)
|
||||
frame_history_cpu_max.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_cpu_max, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
|
||||
|
||||
frame_history_cpu_last.text = str(frametime_cpu).pad_decimals(2)
|
||||
frame_history_cpu_last.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_cpu, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
|
||||
|
||||
var frametime_gpu := RenderingServer.viewport_get_measured_render_time_gpu(viewport_rid)
|
||||
frame_history_gpu.push_back(frametime_gpu)
|
||||
if frame_history_gpu.size() > HISTORY_NUM_FRAMES:
|
||||
frame_history_gpu.pop_front()
|
||||
|
||||
frametime_gpu_avg = frame_history_gpu.reduce(sum_func) / frame_history_gpu.size()
|
||||
frame_history_gpu_avg.text = str(frametime_gpu_avg).pad_decimals(2)
|
||||
frame_history_gpu_avg.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_gpu_avg, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
|
||||
|
||||
var frametime_gpu_min: float = frame_history_gpu.min()
|
||||
frame_history_gpu_min.text = str(frametime_gpu_min).pad_decimals(2)
|
||||
frame_history_gpu_min.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_gpu_min, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
|
||||
|
||||
var frametime_gpu_max: float = frame_history_gpu.max()
|
||||
frame_history_gpu_max.text = str(frametime_gpu_max).pad_decimals(2)
|
||||
frame_history_gpu_max.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_gpu_max, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
|
||||
|
||||
frame_history_gpu_last.text = str(frametime_gpu).pad_decimals(2)
|
||||
frame_history_gpu_last.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_gpu, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
|
||||
|
||||
frames_per_second = 1000.0 / frametime_avg
|
||||
fps_history.push_back(frames_per_second)
|
||||
if fps_history.size() > HISTORY_NUM_FRAMES:
|
||||
fps_history.pop_front()
|
||||
|
||||
fps.text = str(floor(frames_per_second)) + " FPS"
|
||||
var frame_time_color := frame_time_gradient.sample(remap(frames_per_second, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
|
||||
fps.modulate = frame_time_color
|
||||
|
||||
frame_time.text = str(frametime).pad_decimals(2) + " mspf"
|
||||
frame_time.modulate = frame_time_color
|
||||
|
||||
var vsync_string := ""
|
||||
match DisplayServer.window_get_vsync_mode():
|
||||
DisplayServer.VSYNC_ENABLED:
|
||||
vsync_string = "V-Sync"
|
||||
DisplayServer.VSYNC_ADAPTIVE:
|
||||
vsync_string = "Adaptive V-Sync"
|
||||
DisplayServer.VSYNC_MAILBOX:
|
||||
vsync_string = "Mailbox V-Sync"
|
||||
|
||||
if Engine.max_fps > 0 or OS.low_processor_usage_mode:
|
||||
# Display FPS cap determined by `Engine.max_fps` or low-processor usage mode sleep duration
|
||||
# (the lowest FPS cap is used).
|
||||
var low_processor_max_fps := roundi(1000000.0 / OS.low_processor_usage_mode_sleep_usec)
|
||||
var fps_cap := low_processor_max_fps
|
||||
if Engine.max_fps > 0:
|
||||
fps_cap = mini(Engine.max_fps, low_processor_max_fps)
|
||||
frame_time.text += " (cap: " + str(fps_cap) + " FPS"
|
||||
|
||||
if not vsync_string.is_empty():
|
||||
frame_time.text += " + " + vsync_string
|
||||
|
||||
frame_time.text += ")"
|
||||
else:
|
||||
if not vsync_string.is_empty():
|
||||
frame_time.text += " (" + vsync_string + ")"
|
||||
|
||||
frame_number.text = "Frame: " + str(Engine.get_frames_drawn())
|
||||
|
||||
last_tick = Time.get_ticks_usec()
|
||||
|
||||
|
||||
func _on_visibility_changed() -> void:
|
||||
if visible:
|
||||
# Reset graphs to prevent them from looking strange before `HISTORY_NUM_FRAMES` frames
|
||||
# have been drawn.
|
||||
var frametime_last := (Time.get_ticks_usec() - last_tick) * 0.001
|
||||
fps_history.resize(HISTORY_NUM_FRAMES)
|
||||
fps_history.fill(1000.0 / frametime_last)
|
||||
frame_history_total.resize(HISTORY_NUM_FRAMES)
|
||||
frame_history_total.fill(frametime_last)
|
||||
frame_history_cpu.resize(HISTORY_NUM_FRAMES)
|
||||
var viewport_rid := get_viewport().get_viewport_rid()
|
||||
frame_history_cpu.fill(RenderingServer.viewport_get_measured_render_time_cpu(viewport_rid) + RenderingServer.get_frame_setup_time_cpu())
|
||||
frame_history_gpu.resize(HISTORY_NUM_FRAMES)
|
||||
frame_history_gpu.fill(RenderingServer.viewport_get_measured_render_time_gpu(viewport_rid))
|
||||
402
addons/debug_menu/debug_menu.tscn
Normal file
402
addons/debug_menu/debug_menu.tscn
Normal file
@@ -0,0 +1,402 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://cggqb75a8w8r"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/debug_menu/debug_menu.gd" id="1_p440y"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ki0n8"]
|
||||
bg_color = Color(0, 0, 0, 0.25098)
|
||||
|
||||
[node name="CanvasLayer" type="CanvasLayer"]
|
||||
process_mode = 3
|
||||
layer = 128
|
||||
|
||||
[node name="DebugMenu" type="Control" parent="." node_paths=PackedStringArray("fps", "frame_time", "frame_number", "frame_history_total_avg", "frame_history_total_min", "frame_history_total_max", "frame_history_total_last", "frame_history_cpu_avg", "frame_history_cpu_min", "frame_history_cpu_max", "frame_history_cpu_last", "frame_history_gpu_avg", "frame_history_gpu_min", "frame_history_gpu_max", "frame_history_gpu_last", "fps_graph", "total_graph", "cpu_graph", "gpu_graph", "information", "settings")]
|
||||
custom_minimum_size = Vector2(400, 400)
|
||||
layout_mode = 3
|
||||
anchors_preset = 1
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
offset_left = -416.0
|
||||
offset_top = 8.0
|
||||
offset_right = -16.0
|
||||
offset_bottom = 408.0
|
||||
grow_horizontal = 0
|
||||
size_flags_horizontal = 8
|
||||
size_flags_vertical = 4
|
||||
mouse_filter = 2
|
||||
script = ExtResource("1_p440y")
|
||||
fps = NodePath("VBoxContainer/FPS")
|
||||
frame_time = NodePath("VBoxContainer/FrameTime")
|
||||
frame_number = NodePath("VBoxContainer/FrameNumber")
|
||||
frame_history_total_avg = NodePath("VBoxContainer/FrameTimeHistory/TotalAvg")
|
||||
frame_history_total_min = NodePath("VBoxContainer/FrameTimeHistory/TotalMin")
|
||||
frame_history_total_max = NodePath("VBoxContainer/FrameTimeHistory/TotalMax")
|
||||
frame_history_total_last = NodePath("VBoxContainer/FrameTimeHistory/TotalLast")
|
||||
frame_history_cpu_avg = NodePath("VBoxContainer/FrameTimeHistory/CPUAvg")
|
||||
frame_history_cpu_min = NodePath("VBoxContainer/FrameTimeHistory/CPUMin")
|
||||
frame_history_cpu_max = NodePath("VBoxContainer/FrameTimeHistory/CPUMax")
|
||||
frame_history_cpu_last = NodePath("VBoxContainer/FrameTimeHistory/CPULast")
|
||||
frame_history_gpu_avg = NodePath("VBoxContainer/FrameTimeHistory/GPUAvg")
|
||||
frame_history_gpu_min = NodePath("VBoxContainer/FrameTimeHistory/GPUMin")
|
||||
frame_history_gpu_max = NodePath("VBoxContainer/FrameTimeHistory/GPUMax")
|
||||
frame_history_gpu_last = NodePath("VBoxContainer/FrameTimeHistory/GPULast")
|
||||
fps_graph = NodePath("VBoxContainer/FPSGraph/Graph")
|
||||
total_graph = NodePath("VBoxContainer/TotalGraph/Graph")
|
||||
cpu_graph = NodePath("VBoxContainer/CPUGraph/Graph")
|
||||
gpu_graph = NodePath("VBoxContainer/GPUGraph/Graph")
|
||||
information = NodePath("VBoxContainer/Information")
|
||||
settings = NodePath("VBoxContainer/Settings")
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="DebugMenu"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 1
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
offset_left = -300.0
|
||||
offset_bottom = 374.0
|
||||
grow_horizontal = 0
|
||||
mouse_filter = 2
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="FPS" type="Label" parent="DebugMenu/VBoxContainer"]
|
||||
modulate = Color(0, 1, 0, 1)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 5
|
||||
theme_override_constants/line_spacing = 0
|
||||
theme_override_font_sizes/font_size = 18
|
||||
text = "60 FPS"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="FrameTime" type="Label" parent="DebugMenu/VBoxContainer"]
|
||||
modulate = Color(0, 1, 0, 1)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "16.67 mspf (cap: 123 FPS + Adaptive V-Sync)"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="FrameNumber" type="Label" parent="DebugMenu/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "Frame: 1234"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="FrameTimeHistory" type="GridContainer" parent="DebugMenu/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 8
|
||||
mouse_filter = 2
|
||||
theme_override_constants/h_separation = 0
|
||||
theme_override_constants/v_separation = 0
|
||||
columns = 5
|
||||
|
||||
[node name="Spacer" type="Control" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
|
||||
custom_minimum_size = Vector2(60, 0)
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="AvgHeader" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "Average"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="MinHeader" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "Best"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="MaxHeader" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "Worst"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="LastHeader" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "Last"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="TotalHeader" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "Total:"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="TotalAvg" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
|
||||
modulate = Color(0, 1, 0, 1)
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "123.45"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="TotalMin" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
|
||||
modulate = Color(0, 1, 0, 1)
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "123.45"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="TotalMax" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
|
||||
modulate = Color(0, 1, 0, 1)
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "123.45"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="TotalLast" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
|
||||
modulate = Color(0, 1, 0, 1)
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "123.45"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="CPUHeader" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "CPU:"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="CPUAvg" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
|
||||
modulate = Color(0, 1, 0, 1)
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "123.45"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="CPUMin" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
|
||||
modulate = Color(0, 1, 0, 1)
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "12.34"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="CPUMax" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
|
||||
modulate = Color(0, 1, 0, 1)
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "123.45"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="CPULast" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
|
||||
modulate = Color(0, 1, 0, 1)
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "123.45"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="GPUHeader" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "GPU:"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="GPUAvg" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
|
||||
modulate = Color(0, 1, 0, 1)
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "123.45"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="GPUMin" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
|
||||
modulate = Color(0, 1, 0, 1)
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "1.23"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="GPUMax" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
|
||||
modulate = Color(0, 1, 0, 1)
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "123.45"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="GPULast" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
|
||||
modulate = Color(0, 1, 0, 1)
|
||||
custom_minimum_size = Vector2(50, 0)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "123.45"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="FPSGraph" type="HBoxContainer" parent="DebugMenu/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
alignment = 2
|
||||
|
||||
[node name="Title" type="Label" parent="DebugMenu/VBoxContainer/FPSGraph"]
|
||||
custom_minimum_size = Vector2(0, 27)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 8
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "FPS: ↑"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="Graph" type="Panel" parent="DebugMenu/VBoxContainer/FPSGraph"]
|
||||
custom_minimum_size = Vector2(150, 25)
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 0
|
||||
mouse_filter = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_ki0n8")
|
||||
|
||||
[node name="TotalGraph" type="HBoxContainer" parent="DebugMenu/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
alignment = 2
|
||||
|
||||
[node name="Title" type="Label" parent="DebugMenu/VBoxContainer/TotalGraph"]
|
||||
custom_minimum_size = Vector2(0, 27)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 8
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "Total: ↓"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="Graph" type="Panel" parent="DebugMenu/VBoxContainer/TotalGraph"]
|
||||
custom_minimum_size = Vector2(150, 25)
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 0
|
||||
mouse_filter = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_ki0n8")
|
||||
|
||||
[node name="CPUGraph" type="HBoxContainer" parent="DebugMenu/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
alignment = 2
|
||||
|
||||
[node name="Title" type="Label" parent="DebugMenu/VBoxContainer/CPUGraph"]
|
||||
custom_minimum_size = Vector2(0, 27)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 8
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "CPU: ↓"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="Graph" type="Panel" parent="DebugMenu/VBoxContainer/CPUGraph"]
|
||||
custom_minimum_size = Vector2(150, 25)
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 0
|
||||
mouse_filter = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_ki0n8")
|
||||
|
||||
[node name="GPUGraph" type="HBoxContainer" parent="DebugMenu/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
alignment = 2
|
||||
|
||||
[node name="Title" type="Label" parent="DebugMenu/VBoxContainer/GPUGraph"]
|
||||
custom_minimum_size = Vector2(0, 27)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 8
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "GPU: ↓"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="Graph" type="Panel" parent="DebugMenu/VBoxContainer/GPUGraph"]
|
||||
custom_minimum_size = Vector2(150, 25)
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 0
|
||||
mouse_filter = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_ki0n8")
|
||||
|
||||
[node name="Information" type="Label" parent="DebugMenu/VBoxContainer"]
|
||||
modulate = Color(1, 1, 1, 0.752941)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "12th Gen Intel(R) Core(TM) i0-1234K
|
||||
Windows 12 64-bit (double precision), Vulkan 1.2.34
|
||||
NVIDIA GeForce RTX 1234, 123.45.67"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Settings" type="Label" parent="DebugMenu/VBoxContainer"]
|
||||
modulate = Color(0.8, 0.84, 1, 0.752941)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 12
|
||||
text = "Project Version: 1.2.3
|
||||
Rendering Method: Forward+
|
||||
Window: 1234×567, Viewport: 1234×567
|
||||
3D Scale (FSR 1.0): 100% = 1234×567
|
||||
3D Antialiasing: TAA + 2× MSAA + FXAA
|
||||
SSR: 123 Steps
|
||||
SSAO: On
|
||||
SSIL: On
|
||||
SDFGI: 1 Cascades
|
||||
Glow: On
|
||||
Volumetric Fog: On
|
||||
2D Antialiasing: 2× MSAA"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[connection signal="visibility_changed" from="DebugMenu" to="DebugMenu" method="_on_visibility_changed"]
|
||||
7
addons/debug_menu/plugin.cfg
Normal file
7
addons/debug_menu/plugin.cfg
Normal file
@@ -0,0 +1,7 @@
|
||||
[plugin]
|
||||
|
||||
name="Debug Menu"
|
||||
description="In-game debug menu displaying performance metrics and hardware information"
|
||||
author="Calinou"
|
||||
version="1.1.2"
|
||||
script="plugin.gd"
|
||||
29
addons/debug_menu/plugin.gd
Normal file
29
addons/debug_menu/plugin.gd
Normal file
@@ -0,0 +1,29 @@
|
||||
@tool
|
||||
extends EditorPlugin
|
||||
|
||||
func _enter_tree() -> void:
|
||||
add_autoload_singleton("DebugMenu", "res://addons/debug_menu/debug_menu.tscn")
|
||||
|
||||
# FIXME: This appears to do nothing.
|
||||
# if not ProjectSettings.has_setting("application/config/version"):
|
||||
# ProjectSettings.set_setting("application/config/version", "1.0.0")
|
||||
#
|
||||
# ProjectSettings.set_initial_value("application/config/version", "1.0.0")
|
||||
# ProjectSettings.add_property_info({
|
||||
# name = "application/config/version",
|
||||
# type = TYPE_STRING,
|
||||
# })
|
||||
#
|
||||
# if not InputMap.has_action("cycle_debug_menu"):
|
||||
# InputMap.add_action("cycle_debug_menu")
|
||||
# var event := InputEventKey.new()
|
||||
# event.keycode = KEY_F3
|
||||
# InputMap.action_add_event("cycle_debug_menu", event)
|
||||
#
|
||||
# ProjectSettings.save()
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
remove_autoload_singleton("DebugMenu")
|
||||
# Don't remove the project setting's value and input map action,
|
||||
# as the plugin may be re-enabled in the future.
|
||||
102
export_presets.cfg
Normal file
102
export_presets.cfg
Normal file
@@ -0,0 +1,102 @@
|
||||
[preset.0]
|
||||
|
||||
name="Windows Desktop"
|
||||
platform="Windows Desktop"
|
||||
runnable=true
|
||||
dedicated_server=false
|
||||
custom_features=""
|
||||
export_filter="all_resources"
|
||||
include_filter=""
|
||||
exclude_filter=""
|
||||
export_path="C:/Users/Midnight/Desktop/export2/not_bar.exe"
|
||||
encryption_include_filters=""
|
||||
encryption_exclude_filters=""
|
||||
encrypt_pck=false
|
||||
encrypt_directory=false
|
||||
|
||||
[preset.0.options]
|
||||
|
||||
custom_template/debug=""
|
||||
custom_template/release=""
|
||||
debug/export_console_wrapper=1
|
||||
binary_format/embed_pck=false
|
||||
texture_format/bptc=true
|
||||
texture_format/s3tc=true
|
||||
texture_format/etc=false
|
||||
texture_format/etc2=false
|
||||
binary_format/architecture="x86_64"
|
||||
codesign/enable=false
|
||||
codesign/timestamp=true
|
||||
codesign/timestamp_server_url=""
|
||||
codesign/digest_algorithm=1
|
||||
codesign/description=""
|
||||
codesign/custom_options=PackedStringArray()
|
||||
application/modify_resources=true
|
||||
application/icon=""
|
||||
application/console_wrapper_icon=""
|
||||
application/icon_interpolation=4
|
||||
application/file_version=""
|
||||
application/product_version=""
|
||||
application/company_name=""
|
||||
application/product_name=""
|
||||
application/file_description=""
|
||||
application/copyright=""
|
||||
application/trademarks=""
|
||||
application/export_angle=0
|
||||
ssh_remote_deploy/enabled=false
|
||||
ssh_remote_deploy/host="user@host_ip"
|
||||
ssh_remote_deploy/port="22"
|
||||
ssh_remote_deploy/extra_args_ssh=""
|
||||
ssh_remote_deploy/extra_args_scp=""
|
||||
ssh_remote_deploy/run_script="Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}'
|
||||
$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}'
|
||||
$trigger = New-ScheduledTaskTrigger -Once -At 00:00
|
||||
$settings = New-ScheduledTaskSettingsSet
|
||||
$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings
|
||||
Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true
|
||||
Start-ScheduledTask -TaskName godot_remote_debug
|
||||
while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 }
|
||||
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue"
|
||||
ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue
|
||||
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue
|
||||
Remove-Item -Recurse -Force '{temp_dir}'"
|
||||
|
||||
[preset.1]
|
||||
|
||||
name="Linux/X11"
|
||||
platform="Linux/X11"
|
||||
runnable=true
|
||||
dedicated_server=false
|
||||
custom_features=""
|
||||
export_filter="all_resources"
|
||||
include_filter=""
|
||||
exclude_filter=""
|
||||
export_path="C:/Users/Midnight/Desktop/export2/not_bar.x86_64"
|
||||
encryption_include_filters=""
|
||||
encryption_exclude_filters=""
|
||||
encrypt_pck=false
|
||||
encrypt_directory=false
|
||||
|
||||
[preset.1.options]
|
||||
|
||||
custom_template/debug=""
|
||||
custom_template/release=""
|
||||
debug/export_console_wrapper=1
|
||||
binary_format/embed_pck=false
|
||||
texture_format/bptc=true
|
||||
texture_format/s3tc=true
|
||||
texture_format/etc=false
|
||||
texture_format/etc2=false
|
||||
binary_format/architecture="x86_64"
|
||||
ssh_remote_deploy/enabled=false
|
||||
ssh_remote_deploy/host="user@host_ip"
|
||||
ssh_remote_deploy/port="22"
|
||||
ssh_remote_deploy/extra_args_ssh=""
|
||||
ssh_remote_deploy/extra_args_scp=""
|
||||
ssh_remote_deploy/run_script="#!/usr/bin/env bash
|
||||
export DISPLAY=:0
|
||||
unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"
|
||||
\"{temp_dir}/{exe_name}\" {cmd_args}"
|
||||
ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash
|
||||
kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\")
|
||||
rm -rf \"{temp_dir}\""
|
||||
1
icon.svg
Normal file
1
icon.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg height="128" width="128" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="2" width="124" height="124" rx="14" fill="#363d52" stroke="#212532" stroke-width="4"/><g transform="scale(.101) translate(122 122)"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 813 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H447l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c3 34 55 34 58 0v-86c-3-34-55-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 950 B |
37
icon.svg.import
Normal file
37
icon.svg.import
Normal file
@@ -0,0 +1,37 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b8fqumed5vu5w"
|
||||
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://icon.svg"
|
||||
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
BIN
luts/lut_saturated.png
Normal file
BIN
luts/lut_saturated.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 104 KiB |
26
luts/lut_saturated.png.import
Normal file
26
luts/lut_saturated.png.import
Normal file
@@ -0,0 +1,26 @@
|
||||
[remap]
|
||||
|
||||
importer="3d_texture"
|
||||
type="CompressedTexture3D"
|
||||
uid="uid://bus418i6c6y3w"
|
||||
path="res://.godot/imported/lut_saturated.png-bf0a35cafccb1516d07adffb4e04f5f3.ctex3d"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://luts/lut_saturated.png"
|
||||
dest_files=["res://.godot/imported/lut_saturated.png-bf0a35cafccb1516d07adffb4e04f5f3.ctex3d"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
slices/horizontal=8
|
||||
slices/vertical=8
|
||||
41
prefabs/character.tscn
Normal file
41
prefabs/character.tscn
Normal file
@@ -0,0 +1,41 @@
|
||||
[gd_scene load_steps=6 format=3 uid="uid://c4orppao35wg6"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/character/character_controller.gd" id="1_2yciu"]
|
||||
[ext_resource type="Script" path="res://src/character/physics_interpolate.gd" id="2_jbufo"]
|
||||
[ext_resource type="Script" path="res://src/character/camera_controller.gd" id="3_i1tod"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_m1ch2"]
|
||||
radius = 0.4
|
||||
height = 1.8
|
||||
|
||||
[sub_resource type="CapsuleMesh" id="CapsuleMesh_64ysj"]
|
||||
radius = 0.4
|
||||
height = 1.8
|
||||
|
||||
[node name="Character" type="Node"]
|
||||
|
||||
[node name="Physics" type="CharacterBody3D" parent="."]
|
||||
script = ExtResource("1_2yciu")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Physics"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.9, 0)
|
||||
shape = SubResource("CapsuleShape3D_m1ch2")
|
||||
|
||||
[node name="Visual" type="Node3D" parent="." node_paths=PackedStringArray("physicsObject")]
|
||||
script = ExtResource("2_jbufo")
|
||||
physicsObject = NodePath("../Physics")
|
||||
|
||||
[node name="CameraTarget" type="Node3D" parent="Visual"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.28439, 0)
|
||||
|
||||
[node name="CSGMesh3D" type="CSGMesh3D" parent="Visual"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.9, 0)
|
||||
gi_mode = 0
|
||||
mesh = SubResource("CapsuleMesh_64ysj")
|
||||
|
||||
[node name="CameraArm" type="Node3D" parent="." node_paths=PackedStringArray("target")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.6, 0)
|
||||
script = ExtResource("3_i1tod")
|
||||
target = NodePath("../Visual/CameraTarget")
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="CameraArm"]
|
||||
108
project.godot
Normal file
108
project.godot
Normal file
@@ -0,0 +1,108 @@
|
||||
; Engine configuration file.
|
||||
; It's best edited using the editor UI and not directly,
|
||||
; since the parameters that go here are not all obvious.
|
||||
;
|
||||
; Format:
|
||||
; [section] ; section goes between []
|
||||
; param=value ; assign values to parameters
|
||||
|
||||
config_version=5
|
||||
|
||||
[application]
|
||||
|
||||
config/name="3D Character Controller Template"
|
||||
config/version="0.0.2"
|
||||
config/tags=PackedStringArray("3d")
|
||||
run/main_scene="res://scenes/main.tscn"
|
||||
config/features=PackedStringArray("4.2", "Forward Plus")
|
||||
boot_splash/bg_color=Color(0, 0, 0, 1)
|
||||
config/icon="res://icon.svg"
|
||||
|
||||
[autoload]
|
||||
|
||||
DebugMenu="*res://addons/debug_menu/debug_menu.tscn"
|
||||
GameManager="*res://src/game_manager.gd"
|
||||
|
||||
[display]
|
||||
|
||||
window/size/mode=4
|
||||
|
||||
[editor_plugins]
|
||||
|
||||
enabled=PackedStringArray("res://addons/debug_menu/plugin.cfg")
|
||||
|
||||
[input]
|
||||
|
||||
move_left={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":-1.0,"script":null)
|
||||
]
|
||||
}
|
||||
move_right={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":1.0,"script":null)
|
||||
]
|
||||
}
|
||||
move_up={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":-1.0,"script":null)
|
||||
]
|
||||
}
|
||||
move_down={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":1.0,"script":null)
|
||||
]
|
||||
}
|
||||
jump={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":32,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":0,"pressure":0.0,"pressed":true,"script":null)
|
||||
]
|
||||
}
|
||||
sprint={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194325,"key_label":0,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":4,"axis_value":1.0,"script":null)
|
||||
]
|
||||
}
|
||||
zoom_in={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":4,"canceled":false,"pressed":false,"double_click":false,"script":null)
|
||||
]
|
||||
}
|
||||
zoom_out={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":5,"canceled":false,"pressed":false,"double_click":false,"script":null)
|
||||
]
|
||||
}
|
||||
look_left={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":2,"axis_value":-1.0,"script":null)
|
||||
]
|
||||
}
|
||||
look_right={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":2,"axis_value":1.0,"script":null)
|
||||
]
|
||||
}
|
||||
look_up={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":3,"axis_value":-1.0,"script":null)
|
||||
]
|
||||
}
|
||||
look_down={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":3,"axis_value":1.0,"script":null)
|
||||
]
|
||||
}
|
||||
|
||||
[rendering]
|
||||
|
||||
lights_and_shadows/directional_shadow/16_bits=false
|
||||
scaling_3d/mode=2
|
||||
environment/defaults/default_clear_color=Color(0, 0, 0, 1)
|
||||
environment/defaults/default_environment="res://scenes/main/main_environment.tres"
|
||||
8
readme.md
Normal file
8
readme.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# 3D Character Controller Template
|
||||
|
||||
A simple template to get started with 3D
|
||||
|
||||
## Features
|
||||
|
||||
- Performance menu addon (`F3`)
|
||||
- First/Third person character controller with basic input maps
|
||||
64
scenes/main.tscn
Normal file
64
scenes/main.tscn
Normal file
@@ -0,0 +1,64 @@
|
||||
[gd_scene load_steps=7 format=3 uid="uid://dgfh1lgxud87u"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://c4orppao35wg6" path="res://prefabs/character.tscn" id="2_v34ds"]
|
||||
[ext_resource type="Script" path="res://src/spawner.gd" id="3_xxi2i"]
|
||||
|
||||
[sub_resource type="GDScript" id="GDScript_12xd3"]
|
||||
script/source = "extends Node3D
|
||||
|
||||
func _ready() -> void:
|
||||
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||
"
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_xxbnc"]
|
||||
albedo_color = Color(0.266667, 0.145098, 0.0823529, 1)
|
||||
|
||||
[sub_resource type="PlaneMesh" id="PlaneMesh_uelfv"]
|
||||
material = SubResource("StandardMaterial3D_xxbnc")
|
||||
size = Vector2(50, 50)
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_vbj2x"]
|
||||
size = Vector3(50, 1, 50)
|
||||
|
||||
[node name="Main" type="Node3D"]
|
||||
script = SubResource("GDScript_12xd3")
|
||||
|
||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
|
||||
transform = Transform3D(0.276457, -0.764665, 0.582116, 0.11662, 0.62794, 0.769474, -0.953924, -0.14484, 0.262774, 0, 0, 0)
|
||||
light_energy = 2.0
|
||||
shadow_enabled = true
|
||||
directional_shadow_fade_start = 1.0
|
||||
directional_shadow_max_distance = 50.0
|
||||
|
||||
[node name="Spawner" type="Node3D" parent="."]
|
||||
script = ExtResource("3_xxi2i")
|
||||
object_to_spawn = ExtResource("2_v34ds")
|
||||
|
||||
[node name="CSGMesh3D" type="CSGMesh3D" parent="."]
|
||||
mesh = SubResource("PlaneMesh_uelfv")
|
||||
|
||||
[node name="StaticBody3D" type="StaticBody3D" parent="CSGMesh3D"]
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="CSGMesh3D/StaticBody3D"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.5, 0)
|
||||
shape = SubResource("BoxShape3D_vbj2x")
|
||||
|
||||
[node name="CSGCombiner3D" type="CSGCombiner3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
|
||||
use_collision = true
|
||||
|
||||
[node name="Box" type="CSGBox3D" parent="CSGCombiner3D"]
|
||||
|
||||
[node name="Box5" type="CSGBox3D" parent="CSGCombiner3D"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4.37539, 1.21157, -5.02753)
|
||||
|
||||
[node name="Box2" type="CSGBox3D" parent="CSGCombiner3D"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.5, 0.5, 0.5)
|
||||
|
||||
[node name="Box4" type="CSGBox3D" parent="CSGCombiner3D"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4.06635, 1.17009, -1.15682)
|
||||
size = Vector3(1, 1, 4.31364)
|
||||
|
||||
[node name="Box3" type="CSGBox3D" parent="CSGCombiner3D"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.15636, 1.09924, 0.824171)
|
||||
size = Vector3(3.28895, 0.716575, 1)
|
||||
34
scenes/main/main_environment.tres
Normal file
34
scenes/main/main_environment.tres
Normal file
@@ -0,0 +1,34 @@
|
||||
[gd_resource type="Environment" load_steps=4 format=3 uid="uid://b8fqed8jo6yqj"]
|
||||
|
||||
[ext_resource type="CompressedTexture3D" uid="uid://bus418i6c6y3w" path="res://luts/lut_saturated.png" id="1_3f5y7"]
|
||||
|
||||
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_rxwic"]
|
||||
sky_top_color = Color(0.317647, 0.415686, 0.643137, 1)
|
||||
sky_horizon_color = Color(0.878431, 0.929412, 1, 1)
|
||||
ground_bottom_color = Color(0.439216, 0.290196, 0.239216, 1)
|
||||
ground_horizon_color = Color(0.988235, 0.890196, 0.823529, 1)
|
||||
sun_angle_max = 0.0
|
||||
sun_curve = 1e-05
|
||||
|
||||
[sub_resource type="Sky" id="Sky_wbc5y"]
|
||||
sky_material = SubResource("ProceduralSkyMaterial_rxwic")
|
||||
|
||||
[resource]
|
||||
background_mode = 2
|
||||
sky = SubResource("Sky_wbc5y")
|
||||
tonemap_mode = 2
|
||||
tonemap_white = 6.0
|
||||
ssao_enabled = true
|
||||
ssao_ao_channel_affect = 1.0
|
||||
sdfgi_use_occlusion = true
|
||||
sdfgi_bounce_feedback = 0.9
|
||||
glow_enabled = true
|
||||
glow_levels/4 = 1.0
|
||||
glow_levels/6 = 1.0
|
||||
glow_levels/7 = 1.0
|
||||
glow_blend_mode = 4
|
||||
fog_sun_scatter = 0.5
|
||||
fog_aerial_perspective = 0.9
|
||||
volumetric_fog_albedo = Color(0.960784, 0.984314, 1, 1)
|
||||
adjustment_enabled = true
|
||||
adjustment_color_correction = ExtResource("1_3f5y7")
|
||||
29
src/character/camera_controller.gd
Normal file
29
src/character/camera_controller.gd
Normal file
@@ -0,0 +1,29 @@
|
||||
extends Node3D
|
||||
|
||||
@export var target : Node3D
|
||||
@onready var camera = $Camera3D
|
||||
var lookInput : Vector2 = Vector2.ZERO
|
||||
|
||||
func _input(event):
|
||||
if event is InputEventMouseMotion:
|
||||
lookInput.x += event.relative.y
|
||||
lookInput.y += event.relative.x
|
||||
return
|
||||
|
||||
var zoom = .0
|
||||
if event.is_action_released("zoom_in"):
|
||||
zoom -= .2
|
||||
if event.is_action_released("zoom_out"):
|
||||
zoom += .2
|
||||
|
||||
camera.position.z = clamp(camera.position.z + zoom, 0, 4)
|
||||
|
||||
func _process(delta):
|
||||
lookInput += Input.get_vector('look_left','look_right', 'look_down', 'look_up')
|
||||
|
||||
global_position = target.global_position
|
||||
|
||||
rotation.x = clamp(rotation.x - lookInput.x * delta * 0.3, PI*-0.48, PI*0.2)
|
||||
rotation.y -= lookInput.y * delta * 0.3
|
||||
|
||||
lookInput = Vector2.ZERO
|
||||
52
src/character/character_controller.gd
Normal file
52
src/character/character_controller.gd
Normal file
@@ -0,0 +1,52 @@
|
||||
extends CharacterBody3D
|
||||
|
||||
var input3D : Vector3
|
||||
|
||||
@export var SPEED = 1.4
|
||||
@export var SPRINT_SPEED = 3.0
|
||||
@export var JUMP_VELOCITY = 4.5
|
||||
|
||||
var speed = .0
|
||||
|
||||
@onready var camera : Camera3D = get_viewport().get_camera_3d()
|
||||
|
||||
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
|
||||
|
||||
func _ready():
|
||||
process_priority = 2
|
||||
|
||||
func getCameraRelativeInput() -> Vector3 :
|
||||
var cam_basis = camera.global_transform.basis
|
||||
cam_basis.x.y = 0
|
||||
cam_basis.x = cam_basis.x.normalized()
|
||||
cam_basis.z.y = 0
|
||||
cam_basis.z = cam_basis.z.normalized()
|
||||
|
||||
var input = Input.get_vector("move_left", "move_right", "move_up", "move_down")
|
||||
var relativeInput = Vector3.ZERO
|
||||
relativeInput += input.x * cam_basis.x
|
||||
relativeInput += input.y * cam_basis.z
|
||||
|
||||
return relativeInput
|
||||
|
||||
func _physics_process(delta):
|
||||
if not is_on_floor():
|
||||
velocity.y -= gravity * delta
|
||||
|
||||
if Input.is_action_just_pressed("jump") and is_on_floor():
|
||||
velocity.y = JUMP_VELOCITY
|
||||
|
||||
input3D = getCameraRelativeInput()
|
||||
|
||||
speed = SPEED + Input.get_action_strength("sprint") * SPRINT_SPEED
|
||||
|
||||
var direction = input3D.normalized()
|
||||
if direction:
|
||||
velocity.x = direction.x * speed
|
||||
velocity.z = direction.z * speed
|
||||
look_at(direction + global_position)
|
||||
else:
|
||||
velocity.x = move_toward(velocity.x, 0, speed)
|
||||
velocity.z = move_toward(velocity.z, 0, speed)
|
||||
|
||||
move_and_slide()
|
||||
28
src/character/physics_interpolate.gd
Normal file
28
src/character/physics_interpolate.gd
Normal file
@@ -0,0 +1,28 @@
|
||||
extends Node3D
|
||||
|
||||
@export var physicsObject : PhysicsBody3D
|
||||
|
||||
var physics_delta : float = 1
|
||||
|
||||
var target : Transform3D
|
||||
var prev : Transform3D
|
||||
|
||||
func _ready():
|
||||
target = physicsObject.global_transform
|
||||
prev = physicsObject.global_transform
|
||||
|
||||
var d = 0
|
||||
func _process(delta):
|
||||
d += delta
|
||||
|
||||
var t = d / physics_delta
|
||||
|
||||
global_transform = prev.interpolate_with(target, t)
|
||||
|
||||
func _physics_process(delta):
|
||||
physics_delta = delta
|
||||
d = 0
|
||||
|
||||
global_transform = target
|
||||
prev = target
|
||||
target = physicsObject.global_transform
|
||||
20
src/game_manager.gd
Normal file
20
src/game_manager.gd
Normal file
@@ -0,0 +1,20 @@
|
||||
extends Node
|
||||
|
||||
var pause_menu_res = preload('res://ui/pause_menu.tscn')
|
||||
var pause_menu: PauseMenu
|
||||
|
||||
func _ready() -> void:
|
||||
pause_menu = pause_menu_res.instantiate()
|
||||
get_tree().root.add_child.call_deferred(pause_menu)
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if event.is_action_pressed('ui_cancel'):
|
||||
pause_game(not get_tree().paused)
|
||||
|
||||
func quit_game():
|
||||
get_tree().quit()
|
||||
|
||||
func pause_game(pause = true):
|
||||
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE if pause else Input.MOUSE_MODE_CAPTURED
|
||||
get_tree().paused = pause
|
||||
pause_menu.visible = pause
|
||||
10
src/shaders/ui/blur.gdshader
Normal file
10
src/shaders/ui/blur.gdshader
Normal file
@@ -0,0 +1,10 @@
|
||||
shader_type canvas_item;
|
||||
render_mode blend_disabled;
|
||||
|
||||
uniform float blur_amount : hint_range(0,5) = 5.0;
|
||||
uniform vec4 tint : source_color = vec4(.5, .5, .5, 1.0);
|
||||
uniform sampler2D screen_texture : hint_screen_texture, filter_linear_mipmap;
|
||||
|
||||
void fragment() {
|
||||
COLOR = textureLod(screen_texture, SCREEN_UV, blur_amount) * tint;
|
||||
}
|
||||
12
src/spawner.gd
Normal file
12
src/spawner.gd
Normal file
@@ -0,0 +1,12 @@
|
||||
class_name Spawner extends Node3D
|
||||
|
||||
@export var object_to_spawn: PackedScene
|
||||
@export var auto_spawn: bool = true
|
||||
|
||||
func _ready() -> void:
|
||||
if auto_spawn:
|
||||
spawn.call_deferred()
|
||||
|
||||
func spawn() -> void:
|
||||
var object = object_to_spawn.instantiate()
|
||||
get_parent_node_3d().add_child(object)
|
||||
61
ui/pause_menu.tscn
Normal file
61
ui/pause_menu.tscn
Normal file
@@ -0,0 +1,61 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://dilbjuywlv0mc"]
|
||||
|
||||
[ext_resource type="Shader" path="res://src/shaders/ui/blur.gdshader" id="1_q1q1u"]
|
||||
[ext_resource type="Script" path="res://ui/src/pause_menu.gd" id="1_qw2fh"]
|
||||
|
||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_dcwl4"]
|
||||
shader = ExtResource("1_q1q1u")
|
||||
shader_parameter/blur_amount = 3.0
|
||||
shader_parameter/tint = Color(0.5, 0.5, 0.5, 1)
|
||||
|
||||
[node name="PauseMenu" type="Control"]
|
||||
process_mode = 2
|
||||
visible = false
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_qw2fh")
|
||||
|
||||
[node name="MainPanel" type="PanelContainer" parent="."]
|
||||
material = SubResource("ShaderMaterial_dcwl4")
|
||||
layout_mode = 1
|
||||
anchors_preset = 13
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="MainPanel"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 30
|
||||
theme_override_constants/margin_top = 10
|
||||
theme_override_constants/margin_right = 30
|
||||
theme_override_constants/margin_bottom = 10
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="MainPanel/MarginContainer"]
|
||||
custom_minimum_size = Vector2(300, 0)
|
||||
layout_mode = 2
|
||||
alignment = 1
|
||||
|
||||
[node name="Label" type="Label" parent="MainPanel/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_type_variation = &"HeaderLarge"
|
||||
text = "Paused"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="ContinueButton" type="Button" parent="MainPanel/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Continue"
|
||||
|
||||
[node name="QuitButton" type="Button" parent="MainPanel/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Quit
|
||||
"
|
||||
|
||||
[connection signal="pressed" from="MainPanel/MarginContainer/VBoxContainer/ContinueButton" to="." method="_on_continue"]
|
||||
[connection signal="pressed" from="MainPanel/MarginContainer/VBoxContainer/QuitButton" to="." method="_on_quit"]
|
||||
7
ui/src/pause_menu.gd
Normal file
7
ui/src/pause_menu.gd
Normal file
@@ -0,0 +1,7 @@
|
||||
class_name PauseMenu extends Node
|
||||
|
||||
func _on_continue() -> void:
|
||||
GameManager.pause_game(false)
|
||||
|
||||
func _on_quit() -> void:
|
||||
GameManager.quit_game()
|
||||
Reference in New Issue
Block a user