feature updates

This commit is contained in:
2026-02-02 16:28:53 -05:00
parent bf9aa3fa23
commit 44c06530ac
83 changed files with 282641 additions and 11251 deletions

View File

@@ -0,0 +1,431 @@
class_name RegisterScreen
extends CanvasLayer
## RegisterScreen - Account creation form for online play
signal registration_successful(message: String)
signal login_requested
signal back_pressed
const WINDOW_SIZE := Vector2(400, 600)
# Validation constants
const USERNAME_MIN_LENGTH = 3
const USERNAME_MAX_LENGTH = 32
const PASSWORD_MIN_LENGTH = 8
# UI Components
var background: PanelContainer
var main_vbox: VBoxContainer
var title_label: Label
var email_input: LineEdit
var username_input: LineEdit
var password_input: LineEdit
var confirm_password_input: LineEdit
var register_button: Button
var login_link: Button
var back_button: Button
var error_label: Label
var success_label: Label
# State
var _is_loading: bool = false
func _ready() -> void:
layer = 100
_create_ui()
func _create_ui() -> void:
# Background panel
background = PanelContainer.new()
add_child(background)
background.position = Vector2.ZERO
background.size = WINDOW_SIZE
background.add_theme_stylebox_override("panel", _create_panel_style())
# Main layout with margin
var margin = MarginContainer.new()
background.add_child(margin)
margin.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
margin.add_theme_constant_override("margin_left", 40)
margin.add_theme_constant_override("margin_right", 40)
margin.add_theme_constant_override("margin_top", 25)
margin.add_theme_constant_override("margin_bottom", 25)
main_vbox = VBoxContainer.new()
margin.add_child(main_vbox)
main_vbox.add_theme_constant_override("separation", 10)
# Title
_create_title()
# Registration form
_create_form()
# Messages
_create_message_labels()
# Spacer
var spacer = Control.new()
spacer.size_flags_vertical = Control.SIZE_EXPAND_FILL
main_vbox.add_child(spacer)
# Links
_create_links()
# Back button
_create_back_button()
func _create_title() -> void:
title_label = Label.new()
title_label.text = "CREATE ACCOUNT"
title_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
title_label.add_theme_font_size_override("font_size", 28)
title_label.add_theme_color_override("font_color", Color(1.0, 0.95, 0.8))
main_vbox.add_child(title_label)
# Separator
var separator = HSeparator.new()
separator.add_theme_stylebox_override("separator", _create_separator_style())
main_vbox.add_child(separator)
# Small spacer
var spacer = Control.new()
spacer.custom_minimum_size.y = 10
main_vbox.add_child(spacer)
func _create_form() -> void:
# Email field
var email_label = Label.new()
email_label.text = "Email"
email_label.add_theme_font_size_override("font_size", 15)
email_label.add_theme_color_override("font_color", Color(0.9, 0.85, 0.7))
main_vbox.add_child(email_label)
email_input = LineEdit.new()
email_input.placeholder_text = "Enter your email"
email_input.custom_minimum_size = Vector2(0, 38)
_style_input(email_input)
main_vbox.add_child(email_input)
# Username field
var username_label = Label.new()
username_label.text = "Username"
username_label.add_theme_font_size_override("font_size", 15)
username_label.add_theme_color_override("font_color", Color(0.9, 0.85, 0.7))
main_vbox.add_child(username_label)
username_input = LineEdit.new()
username_input.placeholder_text = "3-32 characters"
username_input.custom_minimum_size = Vector2(0, 38)
username_input.max_length = USERNAME_MAX_LENGTH
_style_input(username_input)
main_vbox.add_child(username_input)
# Password field
var password_label = Label.new()
password_label.text = "Password"
password_label.add_theme_font_size_override("font_size", 15)
password_label.add_theme_color_override("font_color", Color(0.9, 0.85, 0.7))
main_vbox.add_child(password_label)
password_input = LineEdit.new()
password_input.placeholder_text = "At least 8 characters"
password_input.secret = true
password_input.custom_minimum_size = Vector2(0, 38)
_style_input(password_input)
main_vbox.add_child(password_input)
# Confirm password field
var confirm_label = Label.new()
confirm_label.text = "Confirm Password"
confirm_label.add_theme_font_size_override("font_size", 15)
confirm_label.add_theme_color_override("font_color", Color(0.9, 0.85, 0.7))
main_vbox.add_child(confirm_label)
confirm_password_input = LineEdit.new()
confirm_password_input.placeholder_text = "Re-enter your password"
confirm_password_input.secret = true
confirm_password_input.custom_minimum_size = Vector2(0, 38)
_style_input(confirm_password_input)
confirm_password_input.text_submitted.connect(_on_input_submitted)
main_vbox.add_child(confirm_password_input)
# Register button
var button_spacer = Control.new()
button_spacer.custom_minimum_size.y = 10
main_vbox.add_child(button_spacer)
register_button = Button.new()
register_button.text = "Create Account"
register_button.custom_minimum_size = Vector2(0, 45)
_style_button(register_button, true)
register_button.pressed.connect(_on_register_pressed)
main_vbox.add_child(register_button)
func _create_message_labels() -> void:
# Error label
error_label = Label.new()
error_label.text = ""
error_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
error_label.add_theme_font_size_override("font_size", 13)
error_label.add_theme_color_override("font_color", Color(1.0, 0.4, 0.4))
error_label.autowrap_mode = TextServer.AUTOWRAP_WORD
error_label.visible = false
main_vbox.add_child(error_label)
# Success label
success_label = Label.new()
success_label.text = ""
success_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
success_label.add_theme_font_size_override("font_size", 13)
success_label.add_theme_color_override("font_color", Color(0.4, 1.0, 0.5))
success_label.autowrap_mode = TextServer.AUTOWRAP_WORD
success_label.visible = false
main_vbox.add_child(success_label)
func _create_links() -> void:
# Login link
login_link = Button.new()
login_link.text = "Already have an account? Login"
login_link.flat = true
login_link.add_theme_font_size_override("font_size", 14)
login_link.add_theme_color_override("font_color", Color(0.6, 0.7, 1.0))
login_link.add_theme_color_override("font_hover_color", Color(0.8, 0.85, 1.0))
login_link.pressed.connect(_on_login_pressed)
main_vbox.add_child(login_link)
func _create_back_button() -> void:
var button_container = HBoxContainer.new()
button_container.alignment = BoxContainer.ALIGNMENT_CENTER
main_vbox.add_child(button_container)
back_button = Button.new()
back_button.text = "Back"
back_button.custom_minimum_size = Vector2(100, 38)
_style_button(back_button, false)
back_button.pressed.connect(_on_back_pressed)
button_container.add_child(back_button)
# ======= STYLING =======
func _create_panel_style() -> StyleBoxFlat:
var style = StyleBoxFlat.new()
style.bg_color = Color(0.08, 0.08, 0.12, 1.0)
style.set_border_width_all(0)
style.set_corner_radius_all(0)
return style
func _create_separator_style() -> StyleBoxFlat:
var style = StyleBoxFlat.new()
style.bg_color = Color(0.5, 0.4, 0.2, 0.5)
style.content_margin_top = 1
return style
func _style_input(input: LineEdit) -> void:
var style = StyleBoxFlat.new()
style.bg_color = Color(0.12, 0.12, 0.16)
style.border_color = Color(0.4, 0.35, 0.25)
style.set_border_width_all(1)
style.set_corner_radius_all(4)
style.content_margin_left = 12
style.content_margin_right = 12
style.content_margin_top = 6
style.content_margin_bottom = 6
input.add_theme_stylebox_override("normal", style)
var focus_style = style.duplicate()
focus_style.border_color = Color(0.7, 0.6, 0.3)
input.add_theme_stylebox_override("focus", focus_style)
input.add_theme_color_override("font_color", Color(0.95, 0.9, 0.8))
input.add_theme_color_override("font_placeholder_color", Color(0.5, 0.5, 0.55))
input.add_theme_font_size_override("font_size", 15)
func _style_button(button: Button, is_primary: bool) -> void:
var style = StyleBoxFlat.new()
if is_primary:
style.bg_color = Color(0.3, 0.25, 0.15)
style.border_color = Color(0.6, 0.5, 0.3)
else:
style.bg_color = Color(0.15, 0.15, 0.2)
style.border_color = Color(0.4, 0.35, 0.25)
style.set_border_width_all(2)
style.set_corner_radius_all(6)
style.content_margin_left = 20
style.content_margin_right = 20
style.content_margin_top = 8
style.content_margin_bottom = 8
button.add_theme_stylebox_override("normal", style)
var hover_style = style.duplicate()
if is_primary:
hover_style.bg_color = Color(0.4, 0.35, 0.2)
hover_style.border_color = Color(0.8, 0.7, 0.4)
else:
hover_style.bg_color = Color(0.2, 0.2, 0.25)
hover_style.border_color = Color(0.5, 0.45, 0.35)
button.add_theme_stylebox_override("hover", hover_style)
var pressed_style = style.duplicate()
pressed_style.bg_color = Color(0.1, 0.1, 0.12)
button.add_theme_stylebox_override("pressed", pressed_style)
var disabled_style = style.duplicate()
disabled_style.bg_color = Color(0.1, 0.1, 0.12)
disabled_style.border_color = Color(0.25, 0.25, 0.3)
button.add_theme_stylebox_override("disabled", disabled_style)
button.add_theme_color_override("font_color", Color(0.9, 0.85, 0.7))
button.add_theme_color_override("font_hover_color", Color(1.0, 0.95, 0.8))
button.add_theme_color_override("font_pressed_color", Color(0.7, 0.65, 0.55))
button.add_theme_color_override("font_disabled_color", Color(0.45, 0.42, 0.38))
button.add_theme_font_size_override("font_size", 16)
# ======= EVENT HANDLERS =======
func _on_input_submitted(_text: String) -> void:
_on_register_pressed()
func _on_register_pressed() -> void:
if _is_loading:
return
var email = email_input.text.strip_edges()
var username = username_input.text.strip_edges()
var password = password_input.text
var confirm_password = confirm_password_input.text
# Validate inputs
var validation_error = _validate_inputs(email, username, password, confirm_password)
if validation_error != "":
_show_error(validation_error)
return
# Start registration
_set_loading(true)
_hide_messages()
var result = await NetworkManager.register(email, password, username)
_set_loading(false)
if result.success:
_show_success(result.message)
registration_successful.emit(result.message)
else:
_show_error(result.message)
func _on_login_pressed() -> void:
login_requested.emit()
func _on_back_pressed() -> void:
back_pressed.emit()
# ======= VALIDATION =======
func _validate_inputs(email: String, username: String, password: String, confirm_password: String) -> String:
# Email validation
if email.is_empty():
return "Please enter your email"
if not _is_valid_email(email):
return "Please enter a valid email address"
# Username validation
if username.is_empty():
return "Please enter a username"
if username.length() < USERNAME_MIN_LENGTH:
return "Username must be at least %d characters" % USERNAME_MIN_LENGTH
if username.length() > USERNAME_MAX_LENGTH:
return "Username must be at most %d characters" % USERNAME_MAX_LENGTH
if not _is_valid_username(username):
return "Username can only contain letters, numbers, underscores, and hyphens"
# Password validation
if password.is_empty():
return "Please enter a password"
if password.length() < PASSWORD_MIN_LENGTH:
return "Password must be at least %d characters" % PASSWORD_MIN_LENGTH
# Confirm password
if confirm_password != password:
return "Passwords do not match"
return ""
func _is_valid_email(email: String) -> bool:
var regex = RegEx.new()
regex.compile("^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$")
return regex.search(email) != null
func _is_valid_username(username: String) -> bool:
var regex = RegEx.new()
regex.compile("^[a-zA-Z0-9_-]+$")
return regex.search(username) != null
# ======= HELPERS =======
func _show_error(message: String) -> void:
error_label.text = message
error_label.visible = true
success_label.visible = false
func _show_success(message: String) -> void:
success_label.text = message
success_label.visible = true
error_label.visible = false
func _hide_messages() -> void:
error_label.visible = false
success_label.visible = false
func _set_loading(loading: bool) -> void:
_is_loading = loading
register_button.disabled = loading
register_button.text = "Creating Account..." if loading else "Create Account"
email_input.editable = not loading
username_input.editable = not loading
password_input.editable = not loading
confirm_password_input.editable = not loading
func clear_form() -> void:
email_input.text = ""
username_input.text = ""
password_input.text = ""
confirm_password_input.text = ""
_hide_messages()
_set_loading(false)
func focus_email() -> void:
email_input.grab_focus()