forked from datawhale/whale-town-front
refactor: 移除SocketIOClient并更新认证场景
- 移除SocketIOClient.gd及.uid文件 - 更新ChatManager以适配新的架构 - 添加认证UI图片资源和背景音乐 - 优化AuthScene布局和配置 - 更新MainScene和项目配置
This commit is contained in:
@@ -233,7 +233,7 @@ func send_chat_message(content: String, scope: String = "local") -> void:
|
||||
|
||||
# 构建消息数据
|
||||
var message_data := {
|
||||
"t": "chat",
|
||||
"type": "chat",
|
||||
"content": content,
|
||||
"scope": scope
|
||||
}
|
||||
@@ -284,7 +284,7 @@ func update_player_position(x: float, y: float, map_id: String) -> void:
|
||||
return
|
||||
|
||||
var position_data := {
|
||||
"t": "position",
|
||||
"type": "position",
|
||||
"x": x,
|
||||
"y": y,
|
||||
"mapId": map_id
|
||||
|
||||
@@ -1,304 +0,0 @@
|
||||
extends Node
|
||||
|
||||
# ============================================================================
|
||||
# SocketIOClient.gd - Socket.IO 协议封装
|
||||
# ============================================================================
|
||||
# 封装 Godot 的 WebSocketPeer,实现简化的 Socket.IO 协议
|
||||
#
|
||||
# 核心职责:
|
||||
# - WebSocket 连接管理
|
||||
# - Socket.IO 消息协议(简化版 JSON 格式)
|
||||
# - 事件监听器管理
|
||||
# - 消息发送/接收
|
||||
#
|
||||
# 注意事项:
|
||||
# - 后端使用简化版 Socket.IO(纯 JSON,无二进制协议)
|
||||
# - 发送消息使用 "t" 字段标识事件类型
|
||||
# - 所有消息通过 JSON 序列化
|
||||
# ============================================================================
|
||||
|
||||
class_name SocketIOClient
|
||||
|
||||
# ============================================================================
|
||||
# 信号定义
|
||||
# ============================================================================
|
||||
|
||||
# 连接成功信号
|
||||
signal connected()
|
||||
|
||||
# 连接断开信号
|
||||
# 参数:
|
||||
# clean_close: bool - 是否为正常关闭
|
||||
signal disconnected(clean_close: bool)
|
||||
|
||||
# 事件接收信号
|
||||
# 参数:
|
||||
# event_name: String - 事件名称(从 "t" 字段提取)
|
||||
# data: Dictionary - 事件数据
|
||||
signal event_received(event_name: String, data: Dictionary)
|
||||
|
||||
# 错误发生信号
|
||||
# 参数:
|
||||
# error: String - 错误信息
|
||||
signal error_occurred(error: String)
|
||||
|
||||
# ============================================================================
|
||||
# 常量定义
|
||||
# ============================================================================
|
||||
|
||||
# 连接状态枚举
|
||||
enum ConnectionState {
|
||||
DISCONNECTED, # 未连接
|
||||
CONNECTING, # 连接中
|
||||
CONNECTED # 已连接
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 成员变量
|
||||
# ============================================================================
|
||||
|
||||
# WebSocket 客户端
|
||||
var _websocket_peer: WebSocketPeer = WebSocketPeer.new()
|
||||
|
||||
# 连接状态
|
||||
var _connection_state: ConnectionState = ConnectionState.DISCONNECTED
|
||||
|
||||
# 服务器 URL
|
||||
var _server_url: String = ""
|
||||
|
||||
# 事件监听器: {event_name: [Callable, ...]}
|
||||
var _event_listeners: Dictionary = {}
|
||||
|
||||
# ============================================================================
|
||||
# 生命周期方法
|
||||
# ============================================================================
|
||||
|
||||
# 初始化
|
||||
func _ready() -> void:
|
||||
print("SocketIOClient 初始化完成")
|
||||
|
||||
# 处理进程 - 轮询 WebSocket 消息
|
||||
func _process(_delta: float) -> void:
|
||||
# 轮询 WebSocket 状态
|
||||
_websocket_peer.poll()
|
||||
|
||||
# 检查连接状态变化
|
||||
var new_state: ConnectionState = _get_connection_state()
|
||||
if new_state != _connection_state:
|
||||
_connection_state = new_state
|
||||
_on_state_changed(_connection_state)
|
||||
|
||||
# 处理接收到的消息
|
||||
_process_incoming_messages()
|
||||
|
||||
# ============================================================================
|
||||
# 公共 API - 连接管理
|
||||
# ============================================================================
|
||||
|
||||
# 连接到服务器
|
||||
#
|
||||
# 参数:
|
||||
# url: String - WebSocket 服务器 URL (ws:// 或 wss://)
|
||||
#
|
||||
# 使用示例:
|
||||
# socket_client.connect_to_server("wss://example.com/game")
|
||||
func connect_to_server(url: String) -> void:
|
||||
if _connection_state == ConnectionState.CONNECTED:
|
||||
push_warning("已经连接到服务器,无需重复连接")
|
||||
return
|
||||
|
||||
_server_url = url
|
||||
print("=== SocketIOClient 开始连接 ===")
|
||||
print("服务器 URL: ", _server_url)
|
||||
|
||||
# 创建 WebSocket 客户端
|
||||
_websocket_peer = WebSocketPeer.new()
|
||||
|
||||
# 发起连接
|
||||
var error := _websocket_peer.connect_to_url(url)
|
||||
if error != OK:
|
||||
push_error("WebSocket 连接失败: %s" % error)
|
||||
error_occurred.emit("WebSocket 连接失败")
|
||||
return
|
||||
|
||||
_connection_state = ConnectionState.CONNECTING
|
||||
print("WebSocket 连接中...")
|
||||
|
||||
# 断开连接
|
||||
func disconnect_from_server() -> void:
|
||||
if _connection_state == ConnectionState.DISCONNECTED:
|
||||
return
|
||||
|
||||
print("=== SocketIOClient 断开连接 ===")
|
||||
_websocket_peer.close()
|
||||
_connection_state = ConnectionState.DISCONNECTED
|
||||
disconnected.emit(true)
|
||||
|
||||
# 检查 Socket 是否已连接
|
||||
#
|
||||
# 返回值:
|
||||
# bool - 是否已连接
|
||||
func is_socket_connected() -> bool:
|
||||
return _connection_state == ConnectionState.CONNECTED
|
||||
|
||||
# ============================================================================
|
||||
# 公共 API - 事件发送
|
||||
# ============================================================================
|
||||
|
||||
# 发送事件(对应 socket.emit)
|
||||
#
|
||||
# 参数:
|
||||
# event_name: String - 事件名称(如 "login", "chat")
|
||||
# data: Dictionary - 事件数据
|
||||
#
|
||||
# 使用示例:
|
||||
# socket_client.emit("login", {"type": "login", "token": "abc123"})
|
||||
# socket_client.emit("chat", {"t": "chat", "content": "Hello", "scope": "local"})
|
||||
func emit(event_name: String, data: Dictionary) -> void:
|
||||
if not is_socket_connected():
|
||||
push_error("无法发送事件: 未连接到服务器")
|
||||
error_occurred.emit("未连接到服务器")
|
||||
return
|
||||
|
||||
# 序列化为 JSON
|
||||
var json_string := JSON.stringify(data)
|
||||
if json_string.is_empty():
|
||||
push_error("JSON 序列化失败")
|
||||
error_occurred.emit("JSON 序列化失败")
|
||||
return
|
||||
|
||||
# 发送数据包
|
||||
var packet := json_string.to_utf8_buffer()
|
||||
var error := _websocket_peer.send(packet)
|
||||
|
||||
if error != OK:
|
||||
push_error("发送数据包失败: %s" % error)
|
||||
error_occurred.emit("发送数据包失败")
|
||||
return
|
||||
|
||||
print("📤 发送事件: ", event_name)
|
||||
print(" 数据: ", json_string if json_string.length() < 200 else json_string.substr(0, 200) + "...")
|
||||
|
||||
# ============================================================================
|
||||
# 公共 API - 事件监听
|
||||
# ============================================================================
|
||||
|
||||
# 添加事件监听器(对应 socket.on)
|
||||
#
|
||||
# 参数:
|
||||
# event_name: String - 事件名称
|
||||
# callback: Callable - 回调函数,接收 data: Dictionary 参数
|
||||
#
|
||||
# 使用示例:
|
||||
# socket_client.add_event_listener("chat_render", func(data):
|
||||
# print("收到消息: ", data.txt)
|
||||
# )
|
||||
func add_event_listener(event_name: String, callback: Callable) -> void:
|
||||
if not _event_listeners.has(event_name):
|
||||
_event_listeners[event_name] = []
|
||||
|
||||
_event_listeners[event_name].append(callback)
|
||||
print("注册事件监听器: ", event_name, " -> ", callback)
|
||||
|
||||
# 移除事件监听器
|
||||
#
|
||||
# 参数:
|
||||
# event_name: String - 事件名称
|
||||
# callback: Callable - 要移除的回调函数
|
||||
func remove_event_listener(event_name: String, callback: Callable) -> void:
|
||||
if not _event_listeners.has(event_name):
|
||||
return
|
||||
|
||||
var listeners: Array = _event_listeners[event_name]
|
||||
listeners.erase(callback)
|
||||
|
||||
if listeners.is_empty():
|
||||
_event_listeners.erase(event_name)
|
||||
|
||||
print("移除事件监听器: ", event_name, " -> ", callback)
|
||||
|
||||
# ============================================================================
|
||||
# 内部方法 - 消息处理
|
||||
# ============================================================================
|
||||
|
||||
# 处理接收到的消息
|
||||
func _process_incoming_messages() -> void:
|
||||
# 检查是否有可用数据包
|
||||
while _websocket_peer.get_available_packet_count() > 0:
|
||||
# 接收数据包
|
||||
var packet: PackedByteArray = _websocket_peer.get_packet()
|
||||
|
||||
# 解析为字符串
|
||||
var json_string: String = packet.get_string_from_utf8()
|
||||
|
||||
# 解析 JSON
|
||||
var json := JSON.new()
|
||||
var parse_result := json.parse(json_string)
|
||||
|
||||
if parse_result != OK:
|
||||
push_error("JSON 解析失败: " + json_string)
|
||||
error_occurred.emit("JSON 解析失败")
|
||||
continue
|
||||
|
||||
var data: Dictionary = json.data
|
||||
|
||||
# 提取事件类型(从 "t" 字段)
|
||||
var event_name: String = data.get("t", "")
|
||||
if event_name.is_empty():
|
||||
# 如果没有 "t" 字段,尝试其他方式识别
|
||||
if data.has("type"):
|
||||
event_name = data["type"]
|
||||
elif data.has("code"):
|
||||
event_name = "error"
|
||||
else:
|
||||
push_warning("收到未知格式消息: " + json_string)
|
||||
continue
|
||||
|
||||
print("📨 收到事件: ", event_name)
|
||||
print(" 数据: ", json_string if json_string.length() < 200 else json_string.substr(0, 200) + "...")
|
||||
|
||||
# 调用事件监听器
|
||||
_notify_event_listeners(event_name, data)
|
||||
|
||||
# 发射通用信号
|
||||
event_received.emit(event_name, data)
|
||||
|
||||
# 通知事件监听器
|
||||
func _notify_event_listeners(event_name: String, data: Dictionary) -> void:
|
||||
if not _event_listeners.has(event_name):
|
||||
return
|
||||
|
||||
var listeners: Array = _event_listeners[event_name]
|
||||
for callback in listeners:
|
||||
if callback.is_valid():
|
||||
callback.call(data)
|
||||
|
||||
# ============================================================================
|
||||
# 内部方法 - 状态管理
|
||||
# ============================================================================
|
||||
|
||||
# 获取当前连接状态
|
||||
func _get_connection_state() -> ConnectionState:
|
||||
match _websocket_peer.get_ready_state():
|
||||
WebSocketPeer.STATE_CONNECTING:
|
||||
return ConnectionState.CONNECTING
|
||||
WebSocketPeer.STATE_OPEN:
|
||||
return ConnectionState.CONNECTED
|
||||
WebSocketPeer.STATE_CLOSING:
|
||||
return ConnectionState.CONNECTING
|
||||
WebSocketPeer.STATE_CLOSED:
|
||||
return ConnectionState.DISCONNECTED
|
||||
_:
|
||||
return ConnectionState.DISCONNECTED
|
||||
|
||||
# 连接状态变化处理
|
||||
func _on_state_changed(new_state: ConnectionState) -> void:
|
||||
match new_state:
|
||||
ConnectionState.CONNECTED:
|
||||
print("✅ WebSocket 连接成功")
|
||||
connected.emit()
|
||||
ConnectionState.DISCONNECTED:
|
||||
print("🔌 WebSocket 连接断开")
|
||||
disconnected.emit(false)
|
||||
ConnectionState.CONNECTING:
|
||||
print("⏳ WebSocket 连接中...")
|
||||
@@ -1 +0,0 @@
|
||||
uid://d0b3aiagnuhxx
|
||||
BIN
assets/audio/music/Spawn Fixed.mp3
Normal file
BIN
assets/audio/music/Spawn Fixed.mp3
Normal file
Binary file not shown.
19
assets/audio/music/Spawn Fixed.mp3.import
Normal file
19
assets/audio/music/Spawn Fixed.mp3.import
Normal file
@@ -0,0 +1,19 @@
|
||||
[remap]
|
||||
|
||||
importer="mp3"
|
||||
type="AudioStreamMP3"
|
||||
uid="uid://c5ujr1fj14n58"
|
||||
path="res://.godot/imported/Spawn Fixed.mp3-cdebcc11ab16736c9b4a0906adccb431.mp3str"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/audio/music/Spawn Fixed.mp3"
|
||||
dest_files=["res://.godot/imported/Spawn Fixed.mp3-cdebcc11ab16736c9b4a0906adccb431.mp3str"]
|
||||
|
||||
[params]
|
||||
|
||||
loop=false
|
||||
loop_offset=0
|
||||
bpm=0
|
||||
beat_count=0
|
||||
bar_beats=4
|
||||
BIN
assets/ui/auth/微信图片_20251218232924_983_1425.png
Normal file
BIN
assets/ui/auth/微信图片_20251218232924_983_1425.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 992 KiB |
40
assets/ui/auth/微信图片_20251218232924_983_1425.png.import
Normal file
40
assets/ui/auth/微信图片_20251218232924_983_1425.png.import
Normal file
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://0pt270gaevbk"
|
||||
path="res://.godot/imported/微信图片_20251218232924_983_1425.png-0163d5f3fcf9765f1d8d0ec22851e7b0.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/ui/auth/微信图片_20251218232924_983_1425.png"
|
||||
dest_files=["res://.godot/imported/微信图片_20251218232924_983_1425.png-0163d5f3fcf9765f1d8d0ec22851e7b0.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
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/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
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
|
||||
BIN
assets/ui/auth/登录背景.png
Normal file
BIN
assets/ui/auth/登录背景.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 206 KiB |
40
assets/ui/auth/登录背景.png.import
Normal file
40
assets/ui/auth/登录背景.png.import
Normal file
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dyma4hpodhdxi"
|
||||
path="res://.godot/imported/登录背景.png-89ec90e6b5b2b96eba5cf8e1b1d50ed8.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/ui/auth/登录背景.png"
|
||||
dest_files=["res://.godot/imported/登录背景.png-89ec90e6b5b2b96eba5cf8e1b1d50ed8.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
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/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
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
|
||||
BIN
assets/ui/auth/输入框.png
Normal file
BIN
assets/ui/auth/输入框.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 104 KiB |
40
assets/ui/auth/输入框.png.import
Normal file
40
assets/ui/auth/输入框.png.import
Normal file
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cnrffaqbtw8f5"
|
||||
path="res://.godot/imported/输入框.png-74076fbd98c6a5dee8485c2e25f4d583.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/ui/auth/输入框.png"
|
||||
dest_files=["res://.godot/imported/输入框.png-74076fbd98c6a5dee8485c2e25f4d583.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
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/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
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
|
||||
@@ -33,7 +33,7 @@ gdscript/warnings/treat_warnings_as_errors=false
|
||||
window/size/viewport_width=1920
|
||||
window/size/viewport_height=1080
|
||||
window/size/mode=2
|
||||
window/stretch/mode="viewport"
|
||||
window/stretch/mode="canvas_items"
|
||||
window/stretch/aspect="expand"
|
||||
|
||||
[gui]
|
||||
|
||||
@@ -90,6 +90,7 @@ func _on_login_success(username: String):
|
||||
print("用户 ", username, " 登录成功!")
|
||||
|
||||
# 连接到聊天服务器(在进入游戏界面之前)
|
||||
# 注意:token 已在 AuthScene._on_controller_login_success 中设置
|
||||
print("🔌 开始连接聊天服务器...")
|
||||
ChatManager.connect_to_chat_server()
|
||||
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
[gd_scene load_steps=10 format=3 uid="uid://by7m8snb4xllf"]
|
||||
[gd_scene load_steps=13 format=3 uid="uid://by7m8snb4xllf"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://bx17oy8lvaca4" path="res://assets/ui/auth/bg_auth_scene.png" id="1_background"]
|
||||
[ext_resource type="Texture2D" uid="uid://b6wlro1vixo8a" path="res://assets/ui/auth/清空内部组件的登录框架 (1).png" id="3_26vyf"]
|
||||
[ext_resource type="Script" uid="uid://b514h2wuido0h" path="res://scenes/ui/AuthScene.gd" id="3_script"]
|
||||
[ext_resource type="Texture2D" uid="uid://dyma4hpodhdxi" path="res://assets/ui/auth/登录背景.png" id="3_wh4n4"]
|
||||
[ext_resource type="Texture2D" uid="uid://cnrffaqbtw8f5" path="res://assets/ui/auth/输入框.png" id="4_lnw07"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_1"]
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_26vyf"]
|
||||
|
||||
[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_cjyup"]
|
||||
texture = ExtResource("4_lnw07")
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_hover"]
|
||||
bg_color = Color(0.3, 0.6, 0.9, 1)
|
||||
@@ -59,6 +63,8 @@ Button/styles/hover = SubResource("StyleBoxFlat_hover")
|
||||
Button/styles/normal = SubResource("StyleBoxFlat_normal")
|
||||
Button/styles/pressed = SubResource("StyleBoxFlat_pressed")
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_1"]
|
||||
|
||||
[node name="AuthScene" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
@@ -81,22 +87,14 @@ texture = ExtResource("1_background")
|
||||
expand_mode = 1
|
||||
stretch_mode = 6
|
||||
|
||||
[node name="WhaleFrame" type="TextureRect" parent="."]
|
||||
[node name="ColorRect" type="ColorRect" parent="."]
|
||||
modulate = Color(0.84313726, 0.92941177, 0.98039216, 0.47058824)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -300.0
|
||||
offset_top = -300.0
|
||||
offset_right = 300.0
|
||||
offset_bottom = 300.0
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("3_26vyf")
|
||||
expand_mode = 1
|
||||
stretch_mode = 5
|
||||
|
||||
[node name="CenterContainer" type="CenterContainer" parent="."]
|
||||
layout_mode = 1
|
||||
@@ -112,35 +110,45 @@ offset_bottom = 236.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="LoginPanel" type="Panel" parent="CenterContainer"]
|
||||
custom_minimum_size = Vector2(350, 400)
|
||||
[node name="WhaleFrame" type="TextureRect" parent="CenterContainer"]
|
||||
custom_minimum_size = Vector2(500, 0)
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxEmpty_1")
|
||||
texture = ExtResource("3_wh4n4")
|
||||
expand_mode = 4
|
||||
stretch_mode = 5
|
||||
|
||||
[node name="LoginPanel" type="Panel" parent="CenterContainer"]
|
||||
custom_minimum_size = Vector2(300, 0)
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxEmpty_26vyf")
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer/LoginPanel"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 30.0
|
||||
offset_top = 30.0
|
||||
offset_right = -30.0
|
||||
offset_bottom = -30.0
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -140.0
|
||||
offset_top = -185.5
|
||||
offset_right = 140.0
|
||||
offset_bottom = 185.5
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="TitleLabel" type="Label" parent="CenterContainer/LoginPanel/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 24
|
||||
theme_override_colors/font_shadow_color = Color(0.011764706, 0.12156863, 0.101960786, 0)
|
||||
theme_override_font_sizes/font_size = 32
|
||||
text = "Whaletown"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="SubtitleLabel" type="Label" parent="CenterContainer/LoginPanel/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_font_sizes/font_size = 14
|
||||
theme_override_colors/font_color = Color(0.53333336, 0.53333336, 0.53333336, 1)
|
||||
theme_override_font_sizes/font_size = 16
|
||||
text = "开始你的小镇之旅!"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
@@ -180,10 +188,13 @@ theme_override_font_sizes/font_size = 12
|
||||
text = "用户名不能为空"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="UsernameInput" type="LineEdit" parent="CenterContainer/LoginPanel/VBoxContainer/LoginForm/UsernameContainer"]
|
||||
[node name="UsernameInput" type="LineEdit" parent="CenterContainer/LoginPanel/VBoxContainer/LoginForm"]
|
||||
custom_minimum_size = Vector2(0, 48)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
theme_override_colors/font_placeholder_color = Color(0.5, 0.5, 0.5, 1)
|
||||
theme_override_colors/selection_color = Color(0.5, 0.5, 0.5, 1)
|
||||
theme_override_styles/normal = SubResource("StyleBoxTexture_cjyup")
|
||||
placeholder_text = "用户名/手机/邮箱"
|
||||
|
||||
[node name="PasswordContainer" type="VBoxContainer" parent="CenterContainer/LoginPanel/VBoxContainer/LoginForm"]
|
||||
@@ -552,6 +563,8 @@ theme = SubResource("Theme_button")
|
||||
text = "返回登录"
|
||||
|
||||
[node name="ToastContainer" type="Control" parent="."]
|
||||
modulate = Color(0.84313726, 0.92941177, 0.98039216, 1)
|
||||
self_modulate = Color(0.84313726, 0.92941177, 0.9843137, 1)
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
|
||||
Reference in New Issue
Block a user