using UnityEngine; namespace BugReporter { /// /// The floating "🐞 Report" button and its one-field form. Drawn with OnGUI so a game needs zero prefabs, /// zero canvases and zero scene edits to adopt the SDK — the same zero-setup rule as the rest of the package. /// Replace with your own UI by setting ShowReportButton = false and calling . /// internal sealed class ReportOverlay : MonoBehaviour { private bool _formOpen; private string _note = ""; // the tester's optional note → travels as the report's description private bool _justSent; private float _sentAt; private GUIStyle _btn, _label, _field; // One-tap categories: the tester has no time to type mid-game, so tapping a tag files the report // immediately with a sensible severity. The category is the title; the note (if any) is the description. private static readonly (string label, Severity sev)[] QuickTags = { ("💥 Crash", Severity.Crash), ("🧊 Freeze / Stuck", Severity.High), ("❌ Wrong result", Severity.High), ("🎨 Visual bug", Severity.Normal), ("📶 Lag / Network", Severity.Normal), ("❓ Other", Severity.Normal), }; private void SendReport(string title, Severity severity) { // Close first: the screenshot is taken at end-of-frame, and the form must not be in it. _formOpen = false; _justSent = true; _sentAt = Time.unscaledTime; BugReporter.ReportFromOverlay(title, _note.Trim(), severity); // the note becomes the description _note = ""; } public static void Create() { var go = new GameObject("[BugReporter.Overlay]"); DontDestroyOnLoad(go); go.hideFlags = HideFlags.HideInHierarchy; go.AddComponent(); } private void EnsureStyles() { if (_btn != null) return; int fs = Mathf.Max(12, Screen.height / 48); _btn = new GUIStyle(GUI.skin.button) { fontSize = fs, fontStyle = FontStyle.Bold }; _label = new GUIStyle(GUI.skin.label) { fontSize = fs, wordWrap = true }; _field = new GUIStyle(GUI.skin.textField) { fontSize = fs }; } private void OnGUI() { EnsureStyles(); if (_justSent && Time.unscaledTime - _sentAt < 2.5f) { float w = Screen.width * 0.5f; GUI.Label(new Rect((Screen.width - w) / 2f, Screen.height * 0.06f, w, 40f), "✓ Bug report sent", _label); return; } _justSent = false; if (!_formOpen) { // Top-left, clear of the usual bottom HUD and the top-right pause/settings cluster. float bw = Screen.width * 0.13f, bh = Screen.height * 0.07f; if (GUI.Button(new Rect(12f, Screen.height * 0.18f, bw, bh), "🐞 Report", _btn)) { _formOpen = true; _note = ""; } return; } DrawForm(); } private void DrawForm() { float w = Screen.width * 0.62f, h = Screen.height * 0.6f; var box = new Rect((Screen.width - w) / 2f, (Screen.height - h) / 2f, w, h); // Modal scrim: swallow clicks behind the form so tapping the field can't also swing the bat. GUI.Box(new Rect(0, 0, Screen.width, Screen.height), GUIContent.none); GUI.Box(box, GUIContent.none); GUILayout.BeginArea(new Rect(box.x + 16f, box.y + 16f, box.width - 32f, box.height - 32f)); // Note FIRST — whatever the tester types here rides along as the description on WHICHEVER category // they then tap. (The old form threw the note away when a quick tag was tapped.) GUILayout.Label("Note (optional) — what happened, in your words:", _label); GUI.SetNextControlName("bugNote"); _note = GUILayout.TextField(_note, 300, _field, GUILayout.Height(Screen.height * 0.10f)); GUILayout.Space(12f); GUILayout.Label("Tap a category to send:", _label); float th = Screen.height * 0.09f; for (int i = 0; i < QuickTags.Length; i += 2) { GUILayout.BeginHorizontal(); for (int j = i; j < i + 2 && j < QuickTags.Length; j++) if (GUILayout.Button(QuickTags[j].label, _btn, GUILayout.Height(th))) SendReport(QuickTags[j].label, QuickTags[j].sev); // title = category, description = note GUILayout.EndHorizontal(); } GUILayout.FlexibleSpace(); if (GUILayout.Button("Cancel", _btn, GUILayout.Height(Screen.height * 0.07f))) { _formOpen = false; _note = ""; } GUILayout.EndArea(); } } }