├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── addons
└── DebugGUI
│ ├── Attributes
│ ├── DebugGUIGraphAttribute.cs
│ └── DebugGUIPrintAttribute.cs
│ ├── DebugGUI.cs
│ ├── DebugGUISettingsInitializer.cs
│ ├── Examples
│ ├── DebugGUIExamples.cs
│ ├── DebugGUIExamples.tscn
│ └── debugGUI_examples.gd
│ ├── Windows
│ ├── DebugGUIWindow.cs
│ ├── GraphWindow.cs
│ └── LogWindow.cs
│ └── plugin.cfg
└── project.godot
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Normalize EOL for all files that Git considers text files.
2 | * text=auto eol=lf
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Godot 4+ specific ignores
2 | .godot/
3 |
4 | # Godot-specific ignores
5 | .import/
6 |
7 | .vs/
8 |
9 | # Imported translations (automatically generated from CSV files)
10 | *.translation
11 |
12 | # Mono-specific ignores
13 | .mono/
14 | data_*/
15 | mono_crash.*.json
16 | Godot Projects.csproj.old*
17 | *.csproj*
18 | *.sln
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2023 Isar Arason (WeaverDev)
4 |
5 | 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:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | 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.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
Debug GUI Graph (C#)
3 |
4 |
5 |
6 |
7 |
8 | Simple and easy to use graphing debug utility.
9 |
10 |
11 |
12 |
13 | ## Description
14 | This is an upgraded port of the [DebugGUI Graph](https://assetstore.unity.com/packages/tools/gui/debuggui-graph-139275) asset for [Godot 4.x](https://godotengine.org/ "Godot") .NET (C#).
15 |
16 | DebugGUI Graph provides a way to debug continuous systems by providing an inspectable graphing GUI and logging overlay. It also provides an optional attribute-based abstraction for a one line injection into your existing code.
17 |
18 |
19 |
20 | ```csharp
21 | // Works with regular fields
22 | [DebugGUIGraph(min: -1, max: 1, r: 0, g: 1, b: 0, autoScale: true)]
23 | float SinField;
24 |
25 | // As well as properties
26 | [DebugGUIGraph(min: -1, max: 1, r: 0, g: 1, b: 1, autoScale: true)]
27 | float CosProperty { get { return Mathf.Cos(time * 6); } }
28 |
29 | // Also works for expression-bodied properties
30 | [DebugGUIGraph(min: -1, max: 1, r: 1, g: 0.3f, b: 1)]
31 | float SinProperty => Mathf.Sin((time + Mathf.Pi / 2) * 6);
32 |
33 | // User inputs, print and graph in one!
34 | [DebugGUIPrint, DebugGUIGraph(group: 1, r: 1, g: 0.3f, b: 0.3f)]
35 | float mouseX;
36 | [DebugGUIPrint, DebugGUIGraph(group: 1, r: 0, g: 1, b: 0)]
37 | float mouseY;
38 | ```
39 |
40 |
41 |
42 |
43 |
44 | ## Installation
45 | 1. Download the latest commit or the stable Release version.
46 | 2. Place the `addons` folder into your project root.
47 | 3. **!! Build the project solution !!** under `MSBuild > Build > Build Project` on the bottom of the editor.
48 |
49 | * *Failing to do this will prevent the plugin settings from being generated and won't auto-add DebugGUI to AutoLoad*
50 | 4. Enable the plugin by going to `Project > Project Settings > Plugins` and checking `Enable` next to `DebugGUI`
51 |
52 | ## Overview
53 |
54 | ### UI Interaction
55 |
56 | - **Dragging** - Windows can be dragged with middle mouse button.
57 | - **Scrubbing** - You can check the values at any point on the graph by hovering over it with the mouse.
58 | - **Freezing** - Holding left mouse button on the graph window stops graph updates for easier scrubbing.
59 | - **Disabling** - Graphs can be toggled on/off by clicking their names.
60 |
61 | Settings for changing colors and graph sizes are available in the project settings under `DebugGui > Settings`.
62 |
63 | ### Graphing
64 |
65 | A graph can be generated by adding the `DebugGUIGraph` attribute above any property or variable castable to `float`. Here you can specify the range of the graph (i.e. values at the top and bottom), the RGB color, and whether it should expand its range if a variable goes outside the range.
66 |
67 | ```cs
68 | [DebugGUIGraph(group: 2, min: -200, max: 200, r: 0, g: 1, b: 0, autoScale: true)]
69 | float playerXVelocity => LinearVelocity.X;
70 | ```
71 |
72 |
73 |
74 | Alternatively, for more control, you can define and manage a graph manually. Graphs are referenced via an `object` key, which you then use to push new values to the graph.
75 |
76 | ```cs
77 | object myGraphKey = new object();
78 |
79 | public override void _Ready()
80 | {
81 | // Graph using this node as the key
82 | DebugGUI.SetGraphProperties(this, "My Graph", 0, 1, 0, Colors.Red, false);
83 |
84 | // Another graph with an arbitrary object key
85 | DebugGUI.SetGraphProperties(myGraphKey, "My Other Graph", 0, 1, 0, Colors.Blue, false);
86 |
87 | // Strings also work as keys
88 | DebugGUI.SetGraphProperties("my graph", "My Other Graph", 0, 1, 0, Colors.Green, false);
89 | }
90 |
91 | public override void _Process(double delta)
92 | {
93 | DebugGUI.Graph(this, (float)delta);
94 | DebugGUI.Graph(myGraphKey, (float)delta);
95 | DebugGUI.Graph("my graph", (float)delta);
96 | }
97 | ```
98 |
99 |
100 |
101 | Graphs can be exported to json via `DebugGUI.ExportGraphs()`.
102 |
103 | ### Logging
104 |
105 | Similar to the graphs, a persistent logged value can be generated by adding the `DebugGUIPrint` attribute above any property or variable. This attribute has no configurable settings. Attribute-derived logs will include the object and field name in its output.
106 |
107 | ```cs
108 | [DebugGUIPrint]
109 | float playerXVelocity => LinearVelocity.X;
110 | ```
111 |
112 |
113 |
114 | Persistent logs may also be managed manually in the same way as graphs using arbitrary keys.
115 |
116 | ```cs
117 | public override void _Process(double delta)
118 | {
119 | DebugGUI.LogPersistent(this, $"Velocity: {LinearVelocity}");
120 | DebugGUI.LogPersistent("deltatime", $"Last delta: {delta}");
121 | DebugGUI.Log("This is a temporary log entry!");
122 | }
123 | ```
124 |
125 | ## GDScript Support
126 |
127 | Using DebugGUI Graph from GDScript requires Godot 4.2. GDScript does not support C#-style attribues, however the static methods of `DebugGUI` can be used manually from GDScript.
128 |
129 | ```python
130 | func _ready():
131 | DebugGUI.SetGraphProperties(self, "MyObject", 0.0, 10.0, 1, Color.WHITE, true)
132 |
133 | func _process(_delta):
134 | DebugGUI.Graph(self, self.linear_velocity.length())
135 | ```
136 |
137 | ## Contribution
138 | If you spot a bug while using this, please create an [Issue](https://github.com/WeaverDev/DebugGUIGraph/issues).
139 |
140 | ## License
141 |
142 | [MIT License](LICENSE)
143 |
--------------------------------------------------------------------------------
/addons/DebugGUI/Attributes/DebugGUIGraphAttribute.cs:
--------------------------------------------------------------------------------
1 | using Godot;
2 | using System;
3 |
4 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
5 | public class DebugGUIGraphAttribute : Attribute
6 | {
7 | public float min { get; private set; }
8 | public float max { get; private set; }
9 | public Color color { get; private set; }
10 | public int group { get; private set; }
11 | public bool autoScale { get; private set; }
12 |
13 | public DebugGUIGraphAttribute(
14 | // Line color
15 | float r = 1,
16 | float g = 1,
17 | float b = 1,
18 | // Values at top/bottom of graph
19 | float min = 0,
20 | float max = 1,
21 | // Offset position on screen
22 | int group = 0,
23 | // Auto-adjust min/max to fit the values
24 | bool autoScale = true
25 | )
26 | {
27 | color = new Color(r, g, b, 0.9f);
28 | this.min = min;
29 | this.max = max;
30 | this.group = group;
31 | this.autoScale = autoScale;
32 | }
33 | }
--------------------------------------------------------------------------------
/addons/DebugGUI/Attributes/DebugGUIPrintAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
4 | public class DebugGUIPrintAttribute : Attribute { }
--------------------------------------------------------------------------------
/addons/DebugGUI/DebugGUI.cs:
--------------------------------------------------------------------------------
1 | using Godot;
2 | using System.IO;
3 | using WeavUtils;
4 |
5 | public partial class DebugGUI : Control
6 | {
7 | // Other scripts may use us right off the bat, so we make sure we initialize first
8 | public DebugGUI()
9 | {
10 | ProcessPhysicsPriority = int.MinValue;
11 | }
12 |
13 | static DebugGUI Instance;
14 |
15 | #region Settings
16 |
17 | public static class Settings
18 | {
19 | const string DEBUGGUI_SETTINGS_DIR = "DebugGUI/Settings/";
20 |
21 | public static void Init()
22 | {
23 | if (!Engine.IsEditorHint()) return;
24 |
25 | // Inits defaults or load current if present
26 | Load();
27 |
28 | ProjectSettings.SetSetting($"{DEBUGGUI_SETTINGS_DIR}{nameof(enableGraphs)}", enableGraphs);
29 | ProjectSettings.SetSetting($"{DEBUGGUI_SETTINGS_DIR}{nameof(enableLogs)}", enableLogs);
30 |
31 | ProjectSettings.SetSetting($"{DEBUGGUI_SETTINGS_DIR}{nameof(backgroundColor)}", backgroundColor);
32 | ProjectSettings.SetSetting($"{DEBUGGUI_SETTINGS_DIR}{nameof(scrubberColor)}", scrubberColor);
33 | ProjectSettings.SetSetting($"{DEBUGGUI_SETTINGS_DIR}{nameof(graphWidth)}", graphWidth);
34 | ProjectSettings.SetSetting($"{DEBUGGUI_SETTINGS_DIR}{nameof(graphHeight)}", graphHeight);
35 | ProjectSettings.SetSetting($"{DEBUGGUI_SETTINGS_DIR}{nameof(temporaryLogLifetime)}", temporaryLogLifetime);
36 |
37 | ProjectSettings.SetAsBasic($"{DEBUGGUI_SETTINGS_DIR}{nameof(enableGraphs)}", true);
38 | ProjectSettings.SetAsBasic($"{DEBUGGUI_SETTINGS_DIR}{nameof(enableLogs)}", true);
39 |
40 | ProjectSettings.SetAsBasic($"{DEBUGGUI_SETTINGS_DIR}{nameof(backgroundColor)}", true);
41 | ProjectSettings.SetAsBasic($"{DEBUGGUI_SETTINGS_DIR}{nameof(scrubberColor)}", true);
42 | ProjectSettings.SetAsBasic($"{DEBUGGUI_SETTINGS_DIR}{nameof(graphWidth)}", true);
43 | ProjectSettings.SetAsBasic($"{DEBUGGUI_SETTINGS_DIR}{nameof(graphHeight)}", true);
44 | ProjectSettings.SetAsBasic($"{DEBUGGUI_SETTINGS_DIR}{nameof(temporaryLogLifetime)}", true);
45 |
46 | var err = ProjectSettings.Save();
47 | if(err != Error.Ok)
48 | {
49 | GD.PrintErr(err);
50 | }
51 | }
52 |
53 | public static void Load()
54 | {
55 | textFont = ThemeDB.FallbackFont;
56 |
57 | enableGraphs = ProjectSettings.GetSetting(
58 | $"{DEBUGGUI_SETTINGS_DIR}{nameof(enableGraphs)}",
59 | true
60 | ).AsBool();
61 | enableLogs = ProjectSettings.GetSetting(
62 | $"{DEBUGGUI_SETTINGS_DIR}{nameof(enableLogs)}",
63 | true
64 | ).AsBool();
65 |
66 | backgroundColor = ProjectSettings.GetSetting(
67 | $"{DEBUGGUI_SETTINGS_DIR}{nameof(backgroundColor)}",
68 | new Color(0f, 0f, 0f, 0.7f)
69 | ).AsColor();
70 | scrubberColor = ProjectSettings.GetSetting(
71 | $"{DEBUGGUI_SETTINGS_DIR}{nameof(scrubberColor)}",
72 | new Color(1f, 1f, 0f, 0.7f)
73 | ).AsColor();
74 | graphWidth = ProjectSettings.GetSetting(
75 | $"{DEBUGGUI_SETTINGS_DIR}{nameof(graphWidth)}",
76 | 300
77 | ).AsInt32();
78 | graphHeight = ProjectSettings.GetSetting(
79 | $"{DEBUGGUI_SETTINGS_DIR}{nameof(graphHeight)}",
80 | 100
81 | ).AsInt32();
82 | temporaryLogLifetime = ProjectSettings.GetSetting(
83 | $"{DEBUGGUI_SETTINGS_DIR}{nameof(temporaryLogLifetime)}",
84 | 5
85 | ).AsDouble();
86 | }
87 |
88 | public static bool enableGraphs;
89 | public static bool enableLogs;
90 |
91 | public static Color backgroundColor;
92 | public static Color scrubberColor;
93 | public static int graphWidth;
94 | public static int graphHeight;
95 | public static double temporaryLogLifetime;
96 |
97 | public static Font textFont;
98 | }
99 |
100 | #endregion
101 |
102 | #region Graph
103 |
104 | ///
105 | /// Set the properties of a graph.
106 | ///
107 | /// The graph's key
108 | /// The graph's label
109 | /// Value at the bottom of the graph box
110 | /// Value at the top of the graph box
111 | /// The graph's ordinal position on screen
112 | /// The graph's color
113 | public static void SetGraphProperties(object key, string label, float min, float max, int group, Color color, bool autoScale)
114 | {
115 | if (Settings.enableGraphs)
116 | Instance?.graphWindow.SetGraphProperties(key, label, min, max, group, color, autoScale);
117 | }
118 |
119 | ///
120 | /// Set the properties of a graph.
121 | ///
122 | /// The graph's key
123 | /// The graph's label
124 | /// Value at the bottom of the graph box
125 | /// Value at the top of the graph box
126 | /// The graph's ordinal position on screen
127 | /// The graph's color
128 | public static void SetGraphProperties(GodotObject key, string label, float min, float max, int group, Color color, bool autoScale)
129 | {
130 | SetGraphProperties((object)key, label, min, max, group, color, autoScale);
131 | }
132 |
133 | ///
134 | /// Add a data point to a graph.
135 | ///
136 | /// The graph's key
137 | /// Value to be added
138 | public static void Graph(object key, float val)
139 | {
140 | if (Settings.enableGraphs)
141 | Instance?.graphWindow.Graph(key, val);
142 | }
143 |
144 | ///
145 | /// Add a data point to a graph.
146 | ///
147 | /// The graph's key
148 | /// Value to be added
149 | public static void Graph(GodotObject key, float val)
150 | {
151 | Graph((object)key, val);
152 | }
153 |
154 | ///
155 | /// Remove an existing graph.
156 | ///
157 | /// The graph's key
158 | public static void RemoveGraph(object key)
159 | {
160 | if (Settings.enableGraphs)
161 | Instance?.graphWindow.RemoveGraph(key);
162 | }
163 |
164 | ///
165 | /// Remove an existing graph.
166 | ///
167 | /// The graph's key
168 | public static void RemoveGraph(GodotObject key)
169 | {
170 | RemoveGraph((object)key);
171 | }
172 |
173 | ///
174 | /// Resets a graph's data.
175 | ///
176 | /// The graph's key
177 | public static void ClearGraph(object key)
178 | {
179 | if (Settings.enableGraphs)
180 | Instance?.graphWindow.ClearGraph(key);
181 | }
182 |
183 | ///
184 | /// Resets a graph's data.
185 | ///
186 | /// The graph's key
187 | public static void ClearGraph(GodotObject key)
188 | {
189 | ClearGraph((object)key);
190 | }
191 |
192 | ///
193 | /// Export graphs to a json file. See path in log.
194 | ///
195 | public static void ExportGraphs()
196 | {
197 | if (Instance == null || !Settings.enableGraphs)
198 | return;
199 |
200 | string dateTimeStr = Time.GetDatetimeStringFromSystem().Replace(':', '-');
201 | string filename = $"debuggui_graph_export_{dateTimeStr}.json";
202 |
203 | using var file = Godot.FileAccess.Open(
204 | "user://" + filename,
205 | Godot.FileAccess.ModeFlags.Write
206 | );
207 |
208 | if (file == null)
209 | {
210 | GD.Print("DebugGUI graph export failed: " + Godot.FileAccess.GetOpenError());
211 | }
212 | else
213 | {
214 | file.StoreString(Instance.graphWindow.ToJson());
215 | GD.Print($"Wrote graph data to {Path.Combine(OS.GetUserDataDir(), filename)}");
216 | }
217 | }
218 |
219 | #endregion
220 |
221 | #region Log
222 |
223 | ///
224 | /// Create or update an existing message with the same key.
225 | ///
226 | public static void LogPersistent(object key, string message)
227 | {
228 | if (Settings.enableLogs)
229 | Instance?.logWindow.LogPersistent(key, message);
230 | }
231 |
232 | ///
233 | /// Create or update an existing message with the same key.
234 | ///
235 | public static void LogPersistent(GodotObject key, string message)
236 | {
237 | LogPersistent((object)key, message);
238 | }
239 |
240 | ///
241 | /// Remove an existing persistent message.
242 | ///
243 | public static void RemovePersistent(object key)
244 | {
245 | if (Settings.enableLogs)
246 | Instance?.logWindow.RemovePersistent(key);
247 | }
248 |
249 | ///
250 | /// Remove an existing persistent message.
251 | ///
252 | public static void RemovePersistent(GodotObject key)
253 | {
254 | RemovePersistent((object)key);
255 | }
256 |
257 | ///
258 | /// Clears all persistent logs.
259 | ///
260 | public static void ClearPersistent()
261 | {
262 | if (Settings.enableLogs)
263 | Instance?.logWindow.ClearPersistent();
264 | }
265 |
266 | ///
267 | /// Print a temporary message.
268 | ///
269 | public static void Log(object message)
270 | {
271 | Log(message.ToString());
272 | }
273 |
274 | ///
275 | /// Print a temporary message.
276 | ///
277 | public static void Log(string message)
278 | {
279 | if (Settings.enableLogs)
280 | Instance?.logWindow.Log(message);
281 | }
282 |
283 | #endregion
284 |
285 | ///
286 | /// Re-scans for DebugGUI attribute holders (i.e. [DebugGUIGraph] and [DebugGUIPrint])
287 | ///
288 | public static void ForceReinitializeAttributes()
289 | {
290 | if (Instance == null) return;
291 |
292 | Instance.graphWindow.ReinitializeAttributes();
293 | Instance.logWindow.ReinitializeAttributes();
294 | }
295 |
296 | GraphWindow graphWindow;
297 | LogWindow logWindow;
298 |
299 | public override void _Ready()
300 | {
301 | Instance = this;
302 | Settings.Load();
303 |
304 | if (Settings.enableGraphs)
305 | {
306 | AddChild(graphWindow = new());
307 | }
308 | if (Settings.enableGraphs)
309 | {
310 | AddChild(logWindow = new());
311 | }
312 | }
313 | }
314 |
--------------------------------------------------------------------------------
/addons/DebugGUI/DebugGUISettingsInitializer.cs:
--------------------------------------------------------------------------------
1 | #if TOOLS
2 | using Godot;
3 |
4 | [Tool]
5 | public partial class DebugGUISettingsInitializer : EditorPlugin
6 | {
7 | const string DEBUGGUI_RES_PATH = "res://addons/DebugGUI/DebugGUI.cs";
8 |
9 | public override void _EnterTree()
10 | {
11 | DebugGUI.Settings.Init();
12 | AddAutoloadSingleton(nameof(DebugGUI), DEBUGGUI_RES_PATH);
13 | }
14 |
15 | public override void _ExitTree()
16 | {
17 | RemoveAutoloadSingleton(nameof(DebugGUI));
18 | }
19 | }
20 | #endif
21 |
--------------------------------------------------------------------------------
/addons/DebugGUI/Examples/DebugGUIExamples.cs:
--------------------------------------------------------------------------------
1 | using Godot;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | public partial class DebugGUIExamples : Node
6 | {
7 | /* * * *
8 | *
9 | * [DebugGUIGraph]
10 | * Renders the variable in a graph on-screen. Attribute based graphs will updates every _Process.
11 | * Lets you optionally define:
12 | * max, min - The range of displayed values
13 | * r, g, b - The RGB color of the graph (0~1)
14 | * group - Graphs can be grouped into the same window and overlaid
15 | * autoScale - If true the graph will readjust min/max to fit the data
16 | *
17 | * [DebugGUIPrint]
18 | * Draws the current variable continuously on-screen as
19 | * $"{GameObject name} {variable name}: {value}"
20 | *
21 | * For more control, these features can be accessed manually.
22 | * DebugGUI.SetGraphProperties(key, ...) - Set the properties of the graph with the provided key
23 | * DebugGUI.Graph(key, value) - Push a value to the graph
24 | * DebugGUI.LogPersistent(key, value) - Print a persistent log entry on screen
25 | * DebugGUI.Log(value) - Print a temporary log entry on screen
26 | *
27 | * See DebugGUI.cs for more info
28 | *
29 | * * * */
30 |
31 | // Disable Field Unused warning
32 | #pragma warning disable 0414
33 |
34 | // Works with regular fields
35 | [DebugGUIGraph(min: -1, max: 1, r: 0, g: 1, b: 0, autoScale: true)]
36 | float SinField;
37 |
38 | // As well as properties
39 | [DebugGUIGraph(min: -1, max: 1, r: 0, g: 1, b: 1, autoScale: true)]
40 | float CosProperty { get { return Mathf.Cos(time * 6); } }
41 |
42 | // Also works for expression-bodied properties
43 | [DebugGUIGraph(min: -1, max: 1, r: 1, g: 0.3f, b: 1)]
44 | float SinProperty => Mathf.Sin((time + Mathf.Pi / 2) * 6);
45 |
46 | // User inputs, print and graph in one!
47 | [DebugGUIPrint, DebugGUIGraph(group: 1, r: 1, g: 0.3f, b: 0.3f)]
48 | float mouseX;
49 | [DebugGUIPrint, DebugGUIGraph(group: 1, r: 0, g: 1, b: 0)]
50 | float mouseY;
51 |
52 | Queue deltaTimeBuffer = new();
53 | double smoothDeltaTime => deltaTimeBuffer.Sum() / deltaTimeBuffer.Count;
54 | float time;
55 | float physicsTime;
56 | bool wasMouseDown;
57 |
58 | public override void _Ready()
59 | {
60 |
61 | // Init smooth DT
62 | for (int i = 0; i < 10; i++)
63 | {
64 | deltaTimeBuffer.Enqueue(0);
65 | }
66 |
67 | // Log (as opposed to LogPersistent) will disappear automatically after some time.
68 | DebugGUI.Log("Hello! I will disappear after some time!");
69 |
70 | // Set up graph properties using our graph keys
71 | DebugGUI.SetGraphProperties("smoothFrameRate", "SmoothFPS", 0, 200, 2, new Color(0, 1, 1), false);
72 | DebugGUI.SetGraphProperties("frameRate", "FPS", 0, 200, 2, new Color(1, 0.5f, 1), false);
73 | DebugGUI.SetGraphProperties("fixedFrameRateSin", "FixedSin", -1, 1, 3, new Color(1, 1, 0), true);
74 | }
75 |
76 | public override void _Process(double delta)
77 | {
78 | time += (float)delta;
79 |
80 | // Update smooth delta time queue
81 | deltaTimeBuffer.Dequeue();
82 | deltaTimeBuffer.Enqueue(delta);
83 |
84 | // Update the fields our attributes are graphing
85 | SinField = Mathf.Sin(time * 6);
86 |
87 | // Update graphed mouse XY values
88 | var mousePos = GetViewport().GetMousePosition();
89 | var viewportRect = GetViewport().GetVisibleRect();
90 | mouseX = Mathf.Clamp(mousePos.X, 0, viewportRect.Size.X);
91 | mouseY = Mathf.Clamp(mousePos.Y, 0, viewportRect.Size.Y);
92 |
93 | // Manual persistent logging
94 | DebugGUI.LogPersistent("smoothFrameRate", "SmoothFPS: " + (1 / smoothDeltaTime).ToString("F3"));
95 | DebugGUI.LogPersistent("frameRate", "FPS: " + (1 / delta).ToString("F3"));
96 |
97 | // Manual logging of mouse clicks
98 | if (Input.IsMouseButtonPressed(MouseButton.Left))
99 | {
100 | if (!wasMouseDown)
101 | {
102 | wasMouseDown = true;
103 | DebugGUI.Log(string.Format(
104 | "Mouse down ({0}, {1})",
105 | mouseX.ToString("F3"),
106 | mouseY.ToString("F3")
107 | ));
108 | }
109 | }
110 | else
111 | {
112 | wasMouseDown = false;
113 | }
114 |
115 | if (smoothDeltaTime != 0)
116 | {
117 | DebugGUI.Graph("smoothFrameRate", 1 / (float)smoothDeltaTime);
118 | }
119 | if (delta != 0)
120 | {
121 | DebugGUI.Graph("frameRate", 1 / (float)delta);
122 | }
123 |
124 | if (Input.IsKeyPressed(Key.Space))
125 | {
126 | QueueFree();
127 | }
128 | }
129 |
130 | public override void _PhysicsProcess(double delta)
131 | {
132 | physicsTime += (float)delta;
133 |
134 | // Manual graphing
135 | DebugGUI.Graph("fixedFrameRateSin", Mathf.Sin(physicsTime * 6));
136 | }
137 |
138 | public override void _ExitTree()
139 | {
140 | // Clean up our logs and graphs when this object leaves tree
141 | DebugGUI.RemoveGraph("frameRate");
142 | DebugGUI.RemoveGraph("fixedFrameRateSin");
143 | DebugGUI.RemoveGraph("smoothFrameRate");
144 |
145 | DebugGUI.RemovePersistent("frameRate");
146 | DebugGUI.RemovePersistent("smoothFrameRate");
147 | }
148 | }
--------------------------------------------------------------------------------
/addons/DebugGUI/Examples/DebugGUIExamples.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://cwxrep5n7yml0"]
2 |
3 | [ext_resource type="Script" path="res://addons/DebugGUI/Examples/DebugGUIExamples.cs" id="1_herxx"]
4 | [ext_resource type="Script" path="res://addons/DebugGUI/Examples/debugGUI_examples.gd" id="2_acgyp"]
5 |
6 | [node name="C# Example" type="Control"]
7 | layout_mode = 3
8 | anchors_preset = 15
9 | anchor_right = 1.0
10 | anchor_bottom = 1.0
11 | grow_horizontal = 2
12 | grow_vertical = 2
13 | script = ExtResource("1_herxx")
14 |
15 | [node name="gdscript example" type="Node" parent="."]
16 | script = ExtResource("2_acgyp")
17 |
--------------------------------------------------------------------------------
/addons/DebugGUI/Examples/debugGUI_examples.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | func _ready():
4 | DebugGUI.SetGraphProperties(self, "from gdscript", 0.0, 10.0, 1, Color.WHITE, true)
5 | DebugGUI.Log(self)
6 | DebugGUI.Log("This can be done from gdscript too!")
7 |
8 | func _process(_delta):
9 | DebugGUI.Graph(self, sin(Time.get_ticks_msec() / 100.0))
10 |
--------------------------------------------------------------------------------
/addons/DebugGUI/Windows/DebugGUIWindow.cs:
--------------------------------------------------------------------------------
1 | using Godot;
2 | using System;
3 |
4 | namespace WeavUtils
5 | {
6 | // Draggable window clamped to the corners
7 | public abstract partial class DebugGUIWindow : Control
8 | {
9 | protected const int outOfScreenClampPadding = 30;
10 |
11 | static bool dragInProgress;
12 | bool dragged;
13 |
14 | new public virtual Rect2 GetRect()
15 | {
16 | return base.GetRect();
17 | }
18 |
19 | public override void _Input(InputEvent @event)
20 | {
21 | if (@event is InputEventMouseButton mb)
22 | {
23 | if (!dragInProgress && mb.Pressed && mb.ButtonIndex == MouseButton.Middle)
24 | {
25 | if (GetRect().HasPoint(mb.Position))
26 | {
27 | dragged = true;
28 | dragInProgress = true;
29 | }
30 | }
31 | if (mb.IsReleased() && mb.ButtonIndex == MouseButton.Middle)
32 | {
33 | if (dragged) dragInProgress = false;
34 | dragged = false;
35 | }
36 | }
37 |
38 | if (@event is InputEventMouseMotion motion)
39 | {
40 | if (dragged)
41 | {
42 | Move(motion.Relative);
43 | }
44 | }
45 | }
46 |
47 | protected void Move(Vector2 delta = default)
48 | {
49 | Position += delta;
50 |
51 | var viewportRect = GetViewportRect();
52 |
53 | // Limit graph window offset so we can't get lost off screen
54 | Position = Position.Clamp(
55 | -GetRect().Size + Vector2.One * outOfScreenClampPadding,
56 | viewportRect.Size - Vector2.One * outOfScreenClampPadding
57 | );
58 | }
59 |
60 | }
61 | }
--------------------------------------------------------------------------------
/addons/DebugGUI/Windows/GraphWindow.cs:
--------------------------------------------------------------------------------
1 | using Godot;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Reflection;
5 | using static DebugGUI.Settings;
6 |
7 | namespace WeavUtils
8 | {
9 | public partial class GraphWindow : DebugGUIWindow
10 | {
11 | const int graphLabelFontSize = 12;
12 | const int graphLabelPadding = 5;
13 | const int graphBlockPadding = 3;
14 | const int scrubberBackgroundWidth = 55;
15 | const int windowOutOfScreenPadding = 30;
16 |
17 | List graphs = new();
18 | HashSet attributeContainers = new();
19 | Dictionary typeInstanceCounts = new();
20 | Dictionary