222 lines
8.6 KiB
GDScript
222 lines
8.6 KiB
GDScript
class_name StudioHelpDialog
|
|
extends PanelContainer
|
|
## Interactive Welcome, Quick Start Guide & Controls Cheatsheet for ModBison Studio.
|
|
|
|
signal closed
|
|
|
|
const SETTINGS_PATH := "user://studio_settings.json"
|
|
|
|
var _check_show_on_start: CheckBox
|
|
|
|
|
|
func _init() -> void:
|
|
name = "StudioHelpDialog"
|
|
custom_minimum_size = Vector2(720, 520)
|
|
_build_ui()
|
|
|
|
|
|
static func should_show_on_startup() -> bool:
|
|
if not FileAccess.file_exists(SETTINGS_PATH):
|
|
return true
|
|
var fa := FileAccess.open(SETTINGS_PATH, FileAccess.READ)
|
|
if fa == null:
|
|
return true
|
|
var parsed = JSON.parse_string(fa.get_as_text())
|
|
fa.close()
|
|
if parsed is Dictionary and parsed.has("show_help_on_startup"):
|
|
return bool(parsed["show_help_on_startup"])
|
|
return true
|
|
|
|
|
|
static func save_show_on_startup(show_help: bool) -> void:
|
|
var data := {"show_help_on_startup": show_help}
|
|
var fa := FileAccess.open(SETTINGS_PATH, FileAccess.WRITE)
|
|
if fa != null:
|
|
fa.store_string(JSON.stringify(data))
|
|
fa.close()
|
|
|
|
|
|
func _build_ui() -> void:
|
|
# Style panel
|
|
var style := StyleBoxFlat.new()
|
|
style.bg_color = Color(0.14, 0.16, 0.20, 0.98)
|
|
style.border_color = Color(0.9, 0.75, 0.25)
|
|
style.set_border_width_all(2)
|
|
style.set_corner_radius_all(8)
|
|
style.content_margin_left = 24
|
|
style.content_margin_top = 20
|
|
style.content_margin_right = 24
|
|
style.content_margin_bottom = 20
|
|
add_theme_stylebox_override("panel", style)
|
|
|
|
var root_vbox := VBoxContainer.new()
|
|
root_vbox.add_theme_constant_override("separation", 14)
|
|
add_child(root_vbox)
|
|
|
|
# Header Row
|
|
var header_hbox := HBoxContainer.new()
|
|
var title_lbl := Label.new()
|
|
title_lbl.text = "🦬 Welcome to ModBison Studio!"
|
|
title_lbl.add_theme_font_size_override("font_size", 20)
|
|
title_lbl.add_theme_color_override("font_color", Color(1.0, 0.88, 0.35))
|
|
header_hbox.add_child(title_lbl)
|
|
|
|
var spacer := Control.new()
|
|
spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
header_hbox.add_child(spacer)
|
|
|
|
var close_x := Button.new()
|
|
close_x.text = "✕"
|
|
close_x.custom_minimum_size = Vector2(32, 28)
|
|
close_x.pressed.connect(_on_close_pressed)
|
|
header_hbox.add_child(close_x)
|
|
root_vbox.add_child(header_hbox)
|
|
|
|
var subtitle := Label.new()
|
|
subtitle.text = "Your creator workbench for designing 3D worlds, placing interactive props, and playtesting in real-time."
|
|
subtitle.add_theme_font_size_override("font_size", 12)
|
|
subtitle.add_theme_color_override("font_color", Color(0.75, 0.78, 0.82))
|
|
root_vbox.add_child(subtitle)
|
|
|
|
# Tab Container for Guide & Shortcuts
|
|
var tabs := TabContainer.new()
|
|
tabs.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
|
|
# Tab 1: Quick Start Guide
|
|
var guide_scroll := ScrollContainer.new()
|
|
guide_scroll.name = "Quick Start Guide"
|
|
guide_scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
var guide_content := VBoxContainer.new()
|
|
guide_content.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
guide_content.add_theme_constant_override("separation", 14)
|
|
|
|
_add_guide_step(guide_content, "🎥 1. Navigate the 3D World",
|
|
"• Fly Camera: Hold Right Mouse Button (RMB) + W, A, S, D, Q, E\n" +
|
|
"• Orbit Camera: Hold Middle Mouse Button (MMB) and move mouse\n" +
|
|
"• Zoom: Scroll mouse wheel up/down\n" +
|
|
"• Focus View: Press [F] to instantly center and zoom onto the selected object")
|
|
|
|
_add_guide_step(guide_content, "🖱️ 2. Select & Transform Props",
|
|
"• Click any 3D model directly in the viewport (or in the Scene Hierarchy on the left)\n" +
|
|
"• Switch transformation tools via top Toolbar or hotkeys:\n" +
|
|
" [1] ↖ Select Mode [2] ✛ Move (drag arrows) [3] ↻ Rotate [4] ⤢ Scale\n" +
|
|
"• Snapping: Set grid snap step (0.5m, 1.0m, etc.) from the Toolbar snap box\n" +
|
|
"• Duplicate: Press [Ctrl + D] to duplicate, [Delete] to remove")
|
|
|
|
_add_guide_step(guide_content, "📦 3. Add Models & Stacking",
|
|
"• Quick Insert: Click [+ Bison], [+ Crate], [+ Tree], or [+ Lamp] on the top toolbar\n" +
|
|
"• Collections Dock: Open the Collections tab on the right to browse theme packs and drag & drop models directly onto the ground!\n" +
|
|
"• Object Stacking: Place items directly on top of other items — Studio automatically snaps surfaces so they stick together!")
|
|
|
|
_add_guide_step(guide_content, "▶️ 4. Playtest Your World (F5)",
|
|
"• Hit [F5] or click the green '▶ Play' button on the toolbar\n" +
|
|
"• Your player avatar spawns immediately with full walking, jumping, and riding physics!\n" +
|
|
"• Hit [F5] again or click '⏹ Stop' to cleanly return to Edit mode (all objects roll back to their original positions)")
|
|
|
|
_add_guide_step(guide_content, "💾 5. Save & Return to Game",
|
|
"• Save: Press [Ctrl + S] or File -> Save Project\n" +
|
|
"• Return: Click '🏠 Main Menu' in the top-right corner to return to the game menu anytime")
|
|
|
|
guide_scroll.add_child(guide_content)
|
|
tabs.add_child(guide_scroll)
|
|
|
|
# Tab 2: Keyboard & Mouse Reference
|
|
var keys_scroll := ScrollContainer.new()
|
|
keys_scroll.name = "Shortcuts & Controls"
|
|
keys_scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
var keys_vbox := VBoxContainer.new()
|
|
keys_vbox.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
keys_vbox.add_theme_constant_override("separation", 10)
|
|
|
|
_add_shortcut_row(keys_vbox, "RMB + WASDQE", "Fly camera through scene (Hold Shift to fly faster, Ctrl for precision)")
|
|
_add_shortcut_row(keys_vbox, "MMB + Drag", "Pan camera across scene")
|
|
_add_shortcut_row(keys_vbox, "Mouse Wheel", "Zoom camera in / out")
|
|
_add_shortcut_row(keys_vbox, "LMB (Left Click)", "Select object in 3D viewport or click gizmo handles")
|
|
_add_shortcut_row(keys_vbox, "F Key", "Focus camera on selected object")
|
|
_add_shortcut_row(keys_vbox, "1, 2, 3, 4 Keys", "Switch tool: [1] Select, [2] Move, [3] Rotate, [4] Scale")
|
|
_add_shortcut_row(keys_vbox, "7, 1, 3 Keys", "View Presets: [7] Top Ortho, [1] Front Ortho, [3] Side Ortho")
|
|
_add_shortcut_row(keys_vbox, "5 Key", "Toggle Perspective / Orthographic projection")
|
|
_add_shortcut_row(keys_vbox, "F5 Key", "Toggle Playtest (Play Solo / Stop Playtest)")
|
|
_add_shortcut_row(keys_vbox, "Ctrl + Z / Ctrl + Y", "Undo / Redo world modifications")
|
|
_add_shortcut_row(keys_vbox, "Ctrl + D", "Duplicate selected object")
|
|
_add_shortcut_row(keys_vbox, "Delete / Backspace", "Delete selected object")
|
|
_add_shortcut_row(keys_vbox, "Ctrl + S", "Save project to disk (.mbworld)")
|
|
_add_shortcut_row(keys_vbox, "F1 Key", "Toggle this Help & Controls guide")
|
|
|
|
keys_scroll.add_child(keys_vbox)
|
|
tabs.add_child(keys_scroll)
|
|
|
|
root_vbox.add_child(tabs)
|
|
|
|
# Footer Row
|
|
var footer_hbox := HBoxContainer.new()
|
|
_check_show_on_start = CheckBox.new()
|
|
_check_show_on_start.text = "Show this guide when opening Studio"
|
|
_check_show_on_start.button_pressed = should_show_on_startup()
|
|
_check_show_on_start.toggled.connect(func(val): save_show_on_startup(val))
|
|
footer_hbox.add_child(_check_show_on_start)
|
|
|
|
var f_spacer := Control.new()
|
|
f_spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
footer_hbox.add_child(f_spacer)
|
|
|
|
var btn_close := Button.new()
|
|
btn_close.text = "✨ Let's Build! (Close)"
|
|
btn_close.add_theme_color_override("font_color", Color(1.0, 0.9, 0.35))
|
|
btn_close.custom_minimum_size = Vector2(160, 34)
|
|
btn_close.pressed.connect(_on_close_pressed)
|
|
footer_hbox.add_child(btn_close)
|
|
|
|
root_vbox.add_child(footer_hbox)
|
|
|
|
|
|
func _add_guide_step(parent: VBoxContainer, title: String, text: String) -> void:
|
|
var box := VBoxContainer.new()
|
|
var t := Label.new()
|
|
t.text = title
|
|
t.add_theme_font_size_override("font_size", 13)
|
|
t.add_theme_color_override("font_color", Color(0.35, 0.85, 1.0))
|
|
box.add_child(t)
|
|
|
|
var b := Label.new()
|
|
b.text = text
|
|
b.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
|
b.add_theme_font_size_override("font_size", 11)
|
|
b.add_theme_color_override("font_color", Color(0.85, 0.87, 0.9))
|
|
box.add_child(b)
|
|
parent.add_child(box)
|
|
|
|
|
|
func _add_shortcut_row(parent: VBoxContainer, key: String, desc: String) -> void:
|
|
var row := HBoxContainer.new()
|
|
var k_lbl := Label.new()
|
|
k_lbl.text = key
|
|
k_lbl.custom_minimum_size = Vector2(180, 0)
|
|
k_lbl.add_theme_font_size_override("font_size", 11)
|
|
k_lbl.add_theme_color_override("font_color", Color(1.0, 0.85, 0.4))
|
|
row.add_child(k_lbl)
|
|
|
|
var d_lbl := Label.new()
|
|
d_lbl.text = desc
|
|
d_lbl.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
d_lbl.add_theme_font_size_override("font_size", 11)
|
|
d_lbl.add_theme_color_override("font_color", Color(0.82, 0.85, 0.88))
|
|
row.add_child(d_lbl)
|
|
parent.add_child(row)
|
|
|
|
|
|
func _on_close_pressed() -> void:
|
|
visible = false
|
|
closed.emit()
|
|
|
|
|
|
func _unhandled_input(event: InputEvent) -> void:
|
|
if not visible:
|
|
return
|
|
if event is InputEventKey:
|
|
var k := event as InputEventKey
|
|
if k.pressed and not k.echo:
|
|
if k.keycode == KEY_ESCAPE or k.keycode == KEY_F1:
|
|
_on_close_pressed()
|
|
get_viewport().set_input_as_handled()
|