Compare commits
5 Commits
ed7d89e39d
...
feature/wh
| Author | SHA1 | Date | |
|---|---|---|---|
| 14bd5e1b29 | |||
| fecebbc4c1 | |||
| 75eb227b18 | |||
| 449cd1e8f3 | |||
| 8a5a4a0005 |
@@ -38,15 +38,17 @@ signal request_completed(request_id: String, success: bool, data: Dictionary)
|
|||||||
# message: String - 错误消息
|
# message: String - 错误消息
|
||||||
signal request_failed(request_id: String, error_type: String, message: String)
|
signal request_failed(request_id: String, error_type: String, message: String)
|
||||||
|
|
||||||
|
# 公告列表接收信号
|
||||||
|
signal notices_received(data: Array)
|
||||||
|
|
||||||
# ============ 常量定义 ============
|
# ============ 常量定义 ============
|
||||||
|
|
||||||
# API基础URL - 所有请求的根地址
|
# API基础URL - 所有请求的根地址
|
||||||
# [Remote] 正式环境地址 (实际正式项目用此地址)
|
# [Remote] 正式环境地址 (实际正式项目用此地址)
|
||||||
# [Remote] 正式环境地址 (实际正式项目用此地址)
|
# const API_BASE_URL = "https://whaletownend.xinghangee.icu"
|
||||||
const API_BASE_URL = "https://whaletownend.xinghangee.icu"
|
|
||||||
|
|
||||||
# [Local] 本地调试地址 (本地调试用此地址)
|
# [Local] 本地调试地址 (本地调试用此地址)
|
||||||
# const API_BASE_URL = "http://localhost:3000"
|
const API_BASE_URL = "http://localhost:3000"
|
||||||
|
|
||||||
# 默认请求超时时间(秒)
|
# 默认请求超时时间(秒)
|
||||||
const DEFAULT_TIMEOUT = 30.0
|
const DEFAULT_TIMEOUT = 30.0
|
||||||
@@ -119,6 +121,7 @@ var request_counter: int = 0 # 请求计数器,用于
|
|||||||
# 初始化网络管理器
|
# 初始化网络管理器
|
||||||
# 在节点准备就绪时调用
|
# 在节点准备就绪时调用
|
||||||
func _ready():
|
func _ready():
|
||||||
|
process_mode = Node.PROCESS_MODE_ALWAYS
|
||||||
print("NetworkManager 已初始化")
|
print("NetworkManager 已初始化")
|
||||||
|
|
||||||
# ============ 公共API接口 ============
|
# ============ 公共API接口 ============
|
||||||
@@ -441,6 +444,18 @@ func github_login(github_id: String, username: String, nickname: String, email:
|
|||||||
|
|
||||||
return post_request("/auth/github", data, callback)
|
return post_request("/auth/github", data, callback)
|
||||||
|
|
||||||
|
# TODO: 获取公告列表
|
||||||
|
func request_notices():
|
||||||
|
# 发送 GET 请求到 /notices 接口
|
||||||
|
get_request("/notices", _on_notices_response)
|
||||||
|
|
||||||
|
func _on_notices_response(success: bool, data: Dictionary, error_info: Dictionary):
|
||||||
|
if success and data.has("data"):
|
||||||
|
notices_received.emit(data["data"])
|
||||||
|
else:
|
||||||
|
# 失败或无数据时发送空数组
|
||||||
|
notices_received.emit([])
|
||||||
|
|
||||||
# ============ 核心请求处理 ============
|
# ============ 核心请求处理 ============
|
||||||
|
|
||||||
# 发送请求的核心方法
|
# 发送请求的核心方法
|
||||||
|
|||||||
BIN
assets/characters/npc_286_241.png
Normal file
BIN
assets/characters/npc_286_241.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 96 KiB |
40
assets/characters/npc_286_241.png.import
Normal file
40
assets/characters/npc_286_241.png.import
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://brko2ik6t6ib5"
|
||||||
|
path="res://.godot/imported/npc_286_241.png-dfe6daef11d0f27f7902e69d6057828f.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/characters/npc_286_241.png"
|
||||||
|
dest_files=["res://.godot/imported/npc_286_241.png-dfe6daef11d0f27f7902e69d6057828f.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/materials/NoticeBoard.png
Normal file
BIN
assets/materials/NoticeBoard.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 142 KiB |
40
assets/materials/NoticeBoard.png.import
Normal file
40
assets/materials/NoticeBoard.png.import
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://b4aildrnhbpl4"
|
||||||
|
path="res://.godot/imported/NoticeBoard.png-038eefee12f116fb9502ed755594cede.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/materials/NoticeBoard.png"
|
||||||
|
dest_files=["res://.godot/imported/NoticeBoard.png-038eefee12f116fb9502ed755594cede.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/materials/WelcomeBoard.png
Normal file
BIN
assets/materials/WelcomeBoard.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 179 KiB |
40
assets/materials/WelcomeBoard.png.import
Normal file
40
assets/materials/WelcomeBoard.png.import
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://v7loa3smfkrd"
|
||||||
|
path="res://.godot/imported/WelcomeBoard.png-bcff7f9bf968cb5d7630e2ad47f2fb42.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/materials/WelcomeBoard.png"
|
||||||
|
dest_files=["res://.godot/imported/WelcomeBoard.png-bcff7f9bf968cb5d7630e2ad47f2fb42.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
|
||||||
File diff suppressed because one or more lines are too long
29
scenes/characters/NPCController.gd
Normal file
29
scenes/characters/NPCController.gd
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
extends CharacterBody2D
|
||||||
|
|
||||||
|
signal interaction_happened(text)
|
||||||
|
|
||||||
|
@export var npc_name: String = "NPC"
|
||||||
|
@export var dialogue: String = "欢迎来到WhaleTown,我是镇长范鲸晶"
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
$Sprite2D.texture = preload("res://assets/characters/npc_286_241.png")
|
||||||
|
$Sprite2D.hframes = 4
|
||||||
|
$Sprite2D.vframes = 4
|
||||||
|
|
||||||
|
# Start Idle Animation
|
||||||
|
if has_node("AnimationPlayer"):
|
||||||
|
$AnimationPlayer.play("idle")
|
||||||
|
|
||||||
|
# Ensure interaction layer
|
||||||
|
collision_layer = 3 # Layer 1 & 2 (Blocking)
|
||||||
|
collision_mask = 3
|
||||||
|
|
||||||
|
func interact():
|
||||||
|
show_bubble(dialogue)
|
||||||
|
interaction_happened.emit(dialogue)
|
||||||
|
return null
|
||||||
|
|
||||||
|
func show_bubble(text):
|
||||||
|
var bubble = preload("res://scenes/ui/ChatBubble.tscn").instantiate()
|
||||||
|
add_child(bubble)
|
||||||
|
bubble.set_text(text)
|
||||||
1
scenes/characters/NPCController.gd.uid
Normal file
1
scenes/characters/NPCController.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dy3uf1rlu4h1u
|
||||||
@@ -9,6 +9,7 @@ const MOVE_SPEED = 200.0
|
|||||||
# 节点引用
|
# 节点引用
|
||||||
@onready var animation_player: AnimationPlayer = $AnimationPlayer
|
@onready var animation_player: AnimationPlayer = $AnimationPlayer
|
||||||
@onready var sprite: Sprite2D = $Sprite2D
|
@onready var sprite: Sprite2D = $Sprite2D
|
||||||
|
@onready var ray_cast: RayCast2D = $RayCast2D
|
||||||
|
|
||||||
var last_direction := "down"
|
var last_direction := "down"
|
||||||
|
|
||||||
@@ -20,6 +21,11 @@ func _ready() -> void:
|
|||||||
if animation_player.has_animation("idle"):
|
if animation_player.has_animation("idle"):
|
||||||
animation_player.play("idle")
|
animation_player.play("idle")
|
||||||
|
|
||||||
|
# Initialize RayCast
|
||||||
|
ray_cast.add_exception(self) # Ignore local player
|
||||||
|
ray_cast.enabled = true
|
||||||
|
ray_cast.target_position = Vector2(0, 60)
|
||||||
|
|
||||||
func _check_spawn_position() -> void:
|
func _check_spawn_position() -> void:
|
||||||
var spawn_pos = SceneManager.get_next_scene_position()
|
var spawn_pos = SceneManager.get_next_scene_position()
|
||||||
if spawn_pos != null:
|
if spawn_pos != null:
|
||||||
@@ -27,6 +33,14 @@ func _check_spawn_position() -> void:
|
|||||||
|
|
||||||
func _physics_process(delta: float) -> void:
|
func _physics_process(delta: float) -> void:
|
||||||
_handle_movement(delta)
|
_handle_movement(delta)
|
||||||
|
_handle_interaction()
|
||||||
|
|
||||||
|
func _handle_interaction() -> void:
|
||||||
|
if Input.is_action_just_pressed("interact"):
|
||||||
|
if ray_cast.is_colliding():
|
||||||
|
var collider = ray_cast.get_collider()
|
||||||
|
if collider and collider.has_method("interact"):
|
||||||
|
collider.interact()
|
||||||
|
|
||||||
func _handle_movement(_delta: float) -> void:
|
func _handle_movement(_delta: float) -> void:
|
||||||
# 获取移动向量 (参考 docs/02-开发规范/输入映射配置.md)
|
# 获取移动向量 (参考 docs/02-开发规范/输入映射配置.md)
|
||||||
@@ -59,13 +73,17 @@ func _update_animation_state(direction: Vector2) -> void:
|
|||||||
if abs(direction.x) > abs(direction.y):
|
if abs(direction.x) > abs(direction.y):
|
||||||
if direction.x > 0:
|
if direction.x > 0:
|
||||||
last_direction = "right"
|
last_direction = "right"
|
||||||
|
ray_cast.target_position = Vector2(60, 0)
|
||||||
else:
|
else:
|
||||||
last_direction = "left"
|
last_direction = "left"
|
||||||
|
ray_cast.target_position = Vector2(-60, 0)
|
||||||
else:
|
else:
|
||||||
if direction.y > 0:
|
if direction.y > 0:
|
||||||
last_direction = "down"
|
last_direction = "down"
|
||||||
|
ray_cast.target_position = Vector2(0, 60)
|
||||||
else:
|
else:
|
||||||
last_direction = "up"
|
last_direction = "up"
|
||||||
|
ray_cast.target_position = Vector2(0, -60)
|
||||||
|
|
||||||
animation_player.play("walk_" + last_direction)
|
animation_player.play("walk_" + last_direction)
|
||||||
|
|
||||||
|
|||||||
64
scenes/characters/npc.tscn
Normal file
64
scenes/characters/npc.tscn
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
[gd_scene load_steps=7 format=3 uid="uid://npc2282a2new"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" uid="uid://brko2ik6t6ib5" path="res://assets/characters/npc_286_241.png" id="1_2r34a"]
|
||||||
|
[ext_resource type="Script" uid="uid://dy3uf1rlu4h1u" path="res://scenes/characters/NPCController.gd" id="1_script"]
|
||||||
|
|
||||||
|
[sub_resource type="RectangleShape2D" id="RectangleShape2D_npc"]
|
||||||
|
size = Vector2(48, 24)
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_2r34a"]
|
||||||
|
length = 0.001
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("Sprite2D:frame")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"update": 1,
|
||||||
|
"values": [0]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_idle"]
|
||||||
|
resource_name = "idle"
|
||||||
|
length = 1.2
|
||||||
|
loop_mode = 1
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("Sprite2D:frame")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0.0333333, 0.26666665, 0.4666667, 0.8, 1),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
|
||||||
|
"update": 1,
|
||||||
|
"values": [2, 1, 0, 4, 5]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="AnimationLibrary" id="AnimationLibrary_npc"]
|
||||||
|
_data = {
|
||||||
|
&"RESET": SubResource("Animation_2r34a"),
|
||||||
|
&"idle": SubResource("Animation_idle")
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="NPC" type="CharacterBody2D"]
|
||||||
|
position = Vector2(-8, 0)
|
||||||
|
script = ExtResource("1_script")
|
||||||
|
|
||||||
|
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||||
|
texture = ExtResource("1_2r34a")
|
||||||
|
hframes = 4
|
||||||
|
vframes = 4
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
|
light_mask = 5
|
||||||
|
visibility_layer = 5
|
||||||
|
shape = SubResource("RectangleShape2D_npc")
|
||||||
|
|
||||||
|
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
||||||
|
libraries = {
|
||||||
|
&"": SubResource("AnimationLibrary_npc")
|
||||||
|
}
|
||||||
@@ -175,3 +175,5 @@ libraries = {
|
|||||||
|
|
||||||
[node name="Camera2D" type="Camera2D" parent="."]
|
[node name="Camera2D" type="Camera2D" parent="."]
|
||||||
zoom = Vector2(2, 2)
|
zoom = Vector2(2, 2)
|
||||||
|
|
||||||
|
[node name="RayCast2D" type="RayCast2D" parent="."]
|
||||||
|
|||||||
13
scenes/prefabs/items/NoticeBoard.gd
Normal file
13
scenes/prefabs/items/NoticeBoard.gd
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
extends StaticBody2D
|
||||||
|
|
||||||
|
func interact():
|
||||||
|
print("Interacted with Notice Board")
|
||||||
|
|
||||||
|
# Check if dialog already exists
|
||||||
|
if get_tree().root.has_node("NoticeDialog"):
|
||||||
|
return
|
||||||
|
|
||||||
|
var dialog = preload("res://scenes/ui/notice_dialog.tscn").instantiate()
|
||||||
|
dialog.name = "NoticeDialog"
|
||||||
|
get_tree().root.add_child(dialog)
|
||||||
|
return null # No bubble text needed
|
||||||
1
scenes/prefabs/items/NoticeBoard.gd.uid
Normal file
1
scenes/prefabs/items/NoticeBoard.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://pnlgf420wktn
|
||||||
13
scenes/prefabs/items/WelcomeBoard.gd
Normal file
13
scenes/prefabs/items/WelcomeBoard.gd
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
extends StaticBody2D
|
||||||
|
|
||||||
|
func interact():
|
||||||
|
# Prevent multiple dialogs
|
||||||
|
if get_tree().root.has_node("WelcomeDialog"):
|
||||||
|
return null
|
||||||
|
|
||||||
|
# Spawn the Welcome Dialog
|
||||||
|
var dialog = preload("res://scenes/ui/welcome_dialog.tscn").instantiate()
|
||||||
|
dialog.name = "WelcomeDialog"
|
||||||
|
# Add to the Scene Root (World) or CanvasLayer if it has one
|
||||||
|
get_tree().root.add_child(dialog)
|
||||||
|
return null # Return null prevents Player from showing a bubble
|
||||||
1
scenes/prefabs/items/WelcomeBoard.gd.uid
Normal file
1
scenes/prefabs/items/WelcomeBoard.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://d2od22agputjt
|
||||||
20
scenes/prefabs/items/notice_board.tscn
Normal file
20
scenes/prefabs/items/notice_board.tscn
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
[gd_scene load_steps=4 format=3 uid="uid://rdmrm7j4iokr"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://pnlgf420wktn" path="res://scenes/prefabs/items/NoticeBoard.gd" id="1_script"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://b4aildrnhbpl4" path="res://assets/materials/NoticeBoard.png" id="2_sprite"]
|
||||||
|
|
||||||
|
[sub_resource type="RectangleShape2D" id="RectangleShape2D_nb"]
|
||||||
|
size = Vector2(160, 53.333332)
|
||||||
|
|
||||||
|
[node name="NoticeBoard" type="StaticBody2D"]
|
||||||
|
scale = Vector2(0.6, 0.6)
|
||||||
|
script = ExtResource("1_script")
|
||||||
|
|
||||||
|
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||||
|
position = Vector2(0, -16)
|
||||||
|
scale = Vector2(0.5, 0.5)
|
||||||
|
texture = ExtResource("2_sprite")
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
|
position = Vector2(0, 13.333335)
|
||||||
|
shape = SubResource("RectangleShape2D_nb")
|
||||||
19
scenes/prefabs/items/welcome_board.tscn
Normal file
19
scenes/prefabs/items/welcome_board.tscn
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
[gd_scene load_steps=4 format=3 uid="uid://c7k8yay002w4"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://d2od22agputjt" path="res://scenes/prefabs/items/WelcomeBoard.gd" id="1_script"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://v7loa3smfkrd" path="res://assets/materials/WelcomeBoard.png" id="2_sprite"]
|
||||||
|
|
||||||
|
[sub_resource type="RectangleShape2D" id="RectangleShape2D_board"]
|
||||||
|
size = Vector2(112, 26.5)
|
||||||
|
|
||||||
|
[node name="WelcomeBoard" type="StaticBody2D"]
|
||||||
|
collision_layer = 3
|
||||||
|
script = ExtResource("1_script")
|
||||||
|
|
||||||
|
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||||
|
scale = Vector2(0.25, 0.25)
|
||||||
|
texture = ExtResource("2_sprite")
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
|
position = Vector2(0, 18.75)
|
||||||
|
shape = SubResource("RectangleShape2D_board")
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
[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://bx17oy8lvaca4" path="res://assets/ui/auth/bg_auth_scene.png" id="1_background"]
|
||||||
[ext_resource type="Texture2D" uid="uid://de4q4s1gxivtf" path="res://assets/ui/auth/login_frame_smart_transparent.png" id="2_frame"]
|
[ext_resource type="Texture2D" uid="uid://de4q4s1gxivtf" path="res://assets/ui/auth/login_frame_smart_transparent.png" id="2_frame"]
|
||||||
[ext_resource type="Script" path="res://scenes/ui/AuthScene.gd" id="3_script"]
|
[ext_resource type="Script" uid="uid://b514h2wuido0h" path="res://scenes/ui/AuthScene.gd" id="3_script"]
|
||||||
|
|
||||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_1"]
|
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_1"]
|
||||||
|
|
||||||
|
|||||||
9
scenes/ui/ChatBubble.gd
Normal file
9
scenes/ui/ChatBubble.gd
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
@onready var label = $PanelContainer/Label
|
||||||
|
|
||||||
|
func set_text(text):
|
||||||
|
label.text = text
|
||||||
|
# Destroy after 5 seconds
|
||||||
|
await get_tree().create_timer(5.0).timeout
|
||||||
|
queue_free()
|
||||||
1
scenes/ui/ChatBubble.gd.uid
Normal file
1
scenes/ui/ChatBubble.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://b4aorojcbwkmb
|
||||||
42
scenes/ui/ChatBubble.tscn
Normal file
42
scenes/ui/ChatBubble.tscn
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
[gd_scene load_steps=3 format=3]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://b4aorojcbwkmb" path="res://scenes/ui/ChatBubble.gd" id="1_script"]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_bubble_modern"]
|
||||||
|
bg_color = Color(1, 1, 1, 0.9)
|
||||||
|
corner_radius_top_left = 5
|
||||||
|
corner_radius_top_right = 5
|
||||||
|
corner_radius_bottom_right = 5
|
||||||
|
corner_radius_bottom_left = 5
|
||||||
|
shadow_color = Color(0, 0, 0, 0.2)
|
||||||
|
shadow_size = 2
|
||||||
|
|
||||||
|
[node name="ChatBubble" type="Control"]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 0
|
||||||
|
script = ExtResource("1_script")
|
||||||
|
|
||||||
|
[node name="PanelContainer" type="PanelContainer" parent="."]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 7
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 1.0
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_left = -75.0
|
||||||
|
offset_top = -60.0
|
||||||
|
offset_right = 75.0
|
||||||
|
offset_bottom = -20.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 0
|
||||||
|
theme_override_styles/panel = SubResource("StyleBoxFlat_bubble_modern")
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="PanelContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_colors/font_color = Color(0.1, 0.1, 0.1, 1)
|
||||||
|
theme_override_font_sizes/font_size = 8
|
||||||
|
text = "..."
|
||||||
|
horizontal_alignment = 1
|
||||||
|
vertical_alignment = 1
|
||||||
|
autowrap_mode = 3
|
||||||
|
custom_minimum_size = Vector2(150, 0)
|
||||||
156
scenes/ui/NoticeDialog.gd
Normal file
156
scenes/ui/NoticeDialog.gd
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
extends CanvasLayer
|
||||||
|
|
||||||
|
@onready var content_label = $CenterContainer/PanelContainer/VBoxContainer/ContentContainer/TextPanel/ContentLabel
|
||||||
|
@onready var prev_btn = $CenterContainer/PanelContainer/VBoxContainer/Footer/PrevButton
|
||||||
|
@onready var next_btn = $CenterContainer/PanelContainer/VBoxContainer/Footer/NextButton
|
||||||
|
@onready var dots_container = $CenterContainer/PanelContainer/VBoxContainer/Footer/DotsContainer
|
||||||
|
@onready var content_container = $CenterContainer/PanelContainer/VBoxContainer/ContentContainer
|
||||||
|
|
||||||
|
# Mock Data
|
||||||
|
var pages = [
|
||||||
|
{
|
||||||
|
"text": "欢迎来到 [color=#3399ff]Datawhale Town[/color]!\n\n这里是开源学习者的家园。在这里,我们一同探索知识,分享成长。\n\n[center]🐋[/center]",
|
||||||
|
# 使用社区图片作为封面
|
||||||
|
"image_path": "res://assets/sprites/environment/community_512_512.png",
|
||||||
|
"image_color": Color(0.9, 0.9, 0.9) # 保留作为后备选项
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "最新活动:\n\n- 镇长刚刚搬进来了,就在喷泉左边。\n- 欢迎板已经设立,查看最新动态。\n- 玩家名字现在显示在头顶了!",
|
||||||
|
# 使用喷泉图片对应"喷泉左边"的描述
|
||||||
|
"image_path": "res://assets/sprites/environment/fountain_256_192.png",
|
||||||
|
"image_color": Color(0.8, 0.9, 0.8)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "操作提示:\n\n- 按 [color=#ffaa00]F[/color] 键可以与物体互动。\n- 在下方输入框输入文字并在气泡中显示。\n- 点击右下角按钮发送聊天。",
|
||||||
|
# 使用公告板图片对应"操作提示"
|
||||||
|
"image_path": "res://assets/sprites/environment/board.png",
|
||||||
|
"image_color": Color(0.9, 0.8, 0.8)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
var current_page = 0
|
||||||
|
var tween: Tween
|
||||||
|
var mock_pages = []
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
# Pause the game
|
||||||
|
get_tree().paused = true
|
||||||
|
|
||||||
|
$CenterContainer/PanelContainer/VBoxContainer/Header/RightContainer/CloseButton.pressed.connect(_on_close_pressed)
|
||||||
|
prev_btn.pressed.connect(_on_prev_pressed)
|
||||||
|
next_btn.pressed.connect(_on_next_pressed)
|
||||||
|
|
||||||
|
# Network Integration - Use direct callback for better error handling
|
||||||
|
# Short timeout (2.0s) so mock data appears quickly if server is down
|
||||||
|
NetworkManager.get_request("/notices", _on_notices_response, 2.0)
|
||||||
|
|
||||||
|
# Initial Setup (with generic "Loading" state)
|
||||||
|
mock_pages = pages.duplicate(true)
|
||||||
|
pages = [{"text": "[center]Loading notices...[/center]", "image_color": Color(0.9, 0.9, 0.9)}]
|
||||||
|
_setup_dots()
|
||||||
|
_update_ui(false)
|
||||||
|
|
||||||
|
func _on_notices_response(success: bool, data: Dictionary, _error_info: Dictionary):
|
||||||
|
var new_pages = []
|
||||||
|
if success and data.has("data") and data["data"] is Array:
|
||||||
|
new_pages = data["data"]
|
||||||
|
|
||||||
|
if new_pages.is_empty():
|
||||||
|
pages = mock_pages
|
||||||
|
else:
|
||||||
|
pages = new_pages
|
||||||
|
# Handle color strings from JSON if necessary
|
||||||
|
for p in pages:
|
||||||
|
if p.has("image_color") and p["image_color"] is String:
|
||||||
|
p["image_color"] = Color(p["image_color"])
|
||||||
|
|
||||||
|
current_page = 0
|
||||||
|
_setup_dots()
|
||||||
|
_update_ui(true)
|
||||||
|
|
||||||
|
|
||||||
|
func _setup_dots():
|
||||||
|
for child in dots_container.get_children():
|
||||||
|
child.queue_free()
|
||||||
|
|
||||||
|
for i in range(pages.size()):
|
||||||
|
var dot = ColorRect.new()
|
||||||
|
dot.custom_minimum_size = Vector2(10, 10) # Base size
|
||||||
|
dots_container.add_child(dot)
|
||||||
|
|
||||||
|
func _update_ui(animate: bool = true):
|
||||||
|
if pages.is_empty():
|
||||||
|
return
|
||||||
|
|
||||||
|
# Update Buttons
|
||||||
|
prev_btn.disabled = (current_page == 0)
|
||||||
|
next_btn.disabled = (current_page == pages.size() - 1)
|
||||||
|
|
||||||
|
# Update Dots Logic
|
||||||
|
var dots = dots_container.get_children()
|
||||||
|
for i in range(dots.size()):
|
||||||
|
if i == current_page:
|
||||||
|
dots[i].color = Color(0.2, 0.2, 0.2, 1) # Dark Active
|
||||||
|
dots[i].custom_minimum_size = Vector2(12, 12) # Active Slightly Larger
|
||||||
|
else:
|
||||||
|
dots[i].color = Color(0.8, 0.8, 0.8, 1) # Light Inactive
|
||||||
|
dots[i].custom_minimum_size = Vector2(10, 10)
|
||||||
|
|
||||||
|
# Update Content
|
||||||
|
if animate:
|
||||||
|
_animate_content_change()
|
||||||
|
else:
|
||||||
|
_set_content_immediate()
|
||||||
|
|
||||||
|
@onready var image_rect = $CenterContainer/PanelContainer/VBoxContainer/ContentContainer/ImagePanel/ImageRect
|
||||||
|
@onready var image_label = $CenterContainer/PanelContainer/VBoxContainer/ContentContainer/ImagePanel/ImageLabel
|
||||||
|
|
||||||
|
func _set_content_immediate():
|
||||||
|
var page = pages[current_page]
|
||||||
|
content_label.text = page.get("text", "")
|
||||||
|
|
||||||
|
if page.has("image_path") and page["image_path"] != "":
|
||||||
|
var path = page["image_path"]
|
||||||
|
if ResourceLoader.exists(path):
|
||||||
|
image_rect.texture = load(path)
|
||||||
|
image_label.visible = false
|
||||||
|
else:
|
||||||
|
image_rect.texture = null
|
||||||
|
image_label.visible = true
|
||||||
|
image_label.text = "Image Not Found"
|
||||||
|
else:
|
||||||
|
image_rect.texture = null
|
||||||
|
image_label.visible = true
|
||||||
|
image_label.text = "No Image"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func _animate_content_change():
|
||||||
|
if tween and tween.is_valid():
|
||||||
|
tween.kill()
|
||||||
|
|
||||||
|
tween = create_tween()
|
||||||
|
|
||||||
|
# Fade Out
|
||||||
|
tween.tween_property(content_container, "modulate:a", 0.0, 0.15)
|
||||||
|
|
||||||
|
# Callback to change text
|
||||||
|
tween.tween_callback(self._set_content_immediate)
|
||||||
|
|
||||||
|
# Fade In
|
||||||
|
tween.tween_property(content_container, "modulate:a", 1.0, 0.15)
|
||||||
|
|
||||||
|
func _on_prev_pressed():
|
||||||
|
if current_page > 0:
|
||||||
|
current_page -= 1
|
||||||
|
_update_ui()
|
||||||
|
|
||||||
|
func _on_next_pressed():
|
||||||
|
if current_page < pages.size() - 1:
|
||||||
|
current_page += 1
|
||||||
|
_update_ui()
|
||||||
|
|
||||||
|
func _on_close_pressed():
|
||||||
|
# Unpause the game
|
||||||
|
get_tree().paused = false
|
||||||
|
queue_free()
|
||||||
1
scenes/ui/NoticeDialog.gd.uid
Normal file
1
scenes/ui/NoticeDialog.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://cxi5rchnmk07p
|
||||||
20
scenes/ui/WelcomeDialog.gd
Normal file
20
scenes/ui/WelcomeDialog.gd
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
extends CanvasLayer
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
# Connect close button (X)
|
||||||
|
var header_close = find_child("CloseButton", true, false)
|
||||||
|
if header_close:
|
||||||
|
header_close.pressed.connect(_on_close_pressed)
|
||||||
|
|
||||||
|
# Connect Start button
|
||||||
|
var start_btn = find_child("StartButton", true, false)
|
||||||
|
if start_btn:
|
||||||
|
start_btn.pressed.connect(_on_close_pressed)
|
||||||
|
|
||||||
|
func _on_close_pressed():
|
||||||
|
queue_free()
|
||||||
|
|
||||||
|
func _input(event):
|
||||||
|
# Allow ESC to close
|
||||||
|
if event.is_action_pressed("ui_cancel"):
|
||||||
|
queue_free()
|
||||||
1
scenes/ui/WelcomeDialog.gd.uid
Normal file
1
scenes/ui/WelcomeDialog.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://cu6x4dxhsylw2
|
||||||
132
scenes/ui/notice_dialog.tscn
Normal file
132
scenes/ui/notice_dialog.tscn
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
[gd_scene load_steps=3 format=3 uid="uid://rdmro1jxs6ga"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://cxi5rchnmk07p" path="res://scenes/ui/NoticeDialog.gd" id="1_script"]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_rounded"]
|
||||||
|
bg_color = Color(0.95, 0.95, 0.95, 1)
|
||||||
|
corner_radius_top_left = 16
|
||||||
|
corner_radius_top_right = 16
|
||||||
|
corner_radius_bottom_right = 16
|
||||||
|
corner_radius_bottom_left = 16
|
||||||
|
shadow_color = Color(0, 0, 0, 0.2)
|
||||||
|
shadow_size = 8
|
||||||
|
|
||||||
|
[node name="NoticeDialog" type="CanvasLayer"]
|
||||||
|
process_mode = 3
|
||||||
|
script = ExtResource("1_script")
|
||||||
|
|
||||||
|
[node name="Dimmer" type="ColorRect" parent="."]
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
color = Color(0, 0, 0, 0.5)
|
||||||
|
|
||||||
|
[node name="CenterContainer" type="CenterContainer" parent="."]
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="PanelContainer" type="PanelContainer" parent="CenterContainer"]
|
||||||
|
custom_minimum_size = Vector2(480, 420)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_styles/panel = SubResource("StyleBoxFlat_rounded")
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer/PanelContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 12
|
||||||
|
|
||||||
|
[node name="HeaderSpacer" type="Control" parent="CenterContainer/PanelContainer/VBoxContainer"]
|
||||||
|
custom_minimum_size = Vector2(0, 4)
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Header" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="LeftSpacer" type="Control" parent="CenterContainer/PanelContainer/VBoxContainer/Header"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
|
[node name="Title" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/Header"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_colors/font_color = Color(0.2, 0.2, 0.2, 1)
|
||||||
|
theme_override_font_sizes/font_size = 22
|
||||||
|
text = "公告板"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="RightContainer" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/Header"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
alignment = 2
|
||||||
|
|
||||||
|
[node name="CloseButton" type="Button" parent="CenterContainer/PanelContainer/VBoxContainer/Header/RightContainer"]
|
||||||
|
custom_minimum_size = Vector2(32, 32)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "X"
|
||||||
|
flat = true
|
||||||
|
|
||||||
|
[node name="RightMargin" type="Control" parent="CenterContainer/PanelContainer/VBoxContainer/Header/RightContainer"]
|
||||||
|
custom_minimum_size = Vector2(8, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="ContentContainer" type="VBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
theme_override_constants/separation = 10
|
||||||
|
|
||||||
|
[node name="ImagePanel" type="PanelContainer" parent="CenterContainer/PanelContainer/VBoxContainer/ContentContainer"]
|
||||||
|
custom_minimum_size = Vector2(0, 200)
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="ImageRect" type="TextureRect" parent="CenterContainer/PanelContainer/VBoxContainer/ContentContainer/ImagePanel"]
|
||||||
|
layout_mode = 2
|
||||||
|
expand_mode = 1
|
||||||
|
stretch_mode = 5
|
||||||
|
|
||||||
|
[node name="ImageLabel" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/ContentContainer/ImagePanel"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_colors/font_color = Color(0.6, 0.6, 0.6, 1)
|
||||||
|
text = "Image Placeholder"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
vertical_alignment = 1
|
||||||
|
|
||||||
|
[node name="TextPanel" type="MarginContainer" parent="CenterContainer/PanelContainer/VBoxContainer/ContentContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
theme_override_constants/margin_left = 16
|
||||||
|
theme_override_constants/margin_right = 16
|
||||||
|
|
||||||
|
[node name="ContentLabel" type="RichTextLabel" parent="CenterContainer/PanelContainer/VBoxContainer/ContentContainer/TextPanel"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_colors/default_color = Color(0.3, 0.3, 0.3, 1)
|
||||||
|
theme_override_font_sizes/normal_font_size = 16
|
||||||
|
bbcode_enabled = true
|
||||||
|
text = "Announcement Content..."
|
||||||
|
|
||||||
|
[node name="Footer" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer"]
|
||||||
|
custom_minimum_size = Vector2(0, 48)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 20
|
||||||
|
alignment = 1
|
||||||
|
|
||||||
|
[node name="PrevButton" type="Button" parent="CenterContainer/PanelContainer/VBoxContainer/Footer"]
|
||||||
|
custom_minimum_size = Vector2(40, 40)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "<"
|
||||||
|
|
||||||
|
[node name="DotsContainer" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/Footer"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 8
|
||||||
|
alignment = 1
|
||||||
|
|
||||||
|
[node name="NextButton" type="Button" parent="CenterContainer/PanelContainer/VBoxContainer/Footer"]
|
||||||
|
custom_minimum_size = Vector2(40, 40)
|
||||||
|
layout_mode = 2
|
||||||
|
text = ">"
|
||||||
|
|
||||||
|
[node name="BottomSpacer" type="Control" parent="CenterContainer/PanelContainer/VBoxContainer"]
|
||||||
|
custom_minimum_size = Vector2(0, 4)
|
||||||
|
layout_mode = 2
|
||||||
117
scenes/ui/welcome_dialog.tscn
Normal file
117
scenes/ui/welcome_dialog.tscn
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
[gd_scene load_steps=5 format=3 uid="uid://d8mam0n1a3b5"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://cu6x4dxhsylw2" path="res://scenes/ui/WelcomeDialog.gd" id="1_vs5b1"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://v7loa3smfkrd" path="res://assets/materials/WelcomeBoard.png" id="2_dy5hw"]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_card"]
|
||||||
|
bg_color = Color(1, 1, 1, 1)
|
||||||
|
corner_radius_top_left = 10
|
||||||
|
corner_radius_top_right = 10
|
||||||
|
corner_radius_bottom_right = 10
|
||||||
|
corner_radius_bottom_left = 10
|
||||||
|
shadow_color = Color(0, 0, 0, 0.2)
|
||||||
|
shadow_size = 10
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_btn_rounded"]
|
||||||
|
bg_color = Color(0.95, 0.95, 0.95, 1)
|
||||||
|
border_width_left = 1
|
||||||
|
border_width_top = 1
|
||||||
|
border_width_right = 1
|
||||||
|
border_width_bottom = 1
|
||||||
|
corner_radius_top_left = 20
|
||||||
|
corner_radius_top_right = 20
|
||||||
|
corner_radius_bottom_right = 20
|
||||||
|
corner_radius_bottom_left = 20
|
||||||
|
|
||||||
|
[node name="WelcomeDialog" type="CanvasLayer"]
|
||||||
|
script = ExtResource("1_vs5b1")
|
||||||
|
|
||||||
|
[node name="ColorRect" type="ColorRect" parent="."]
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
color = Color(0, 0, 0, 0.4)
|
||||||
|
|
||||||
|
[node name="CenterContainer" type="CenterContainer" parent="."]
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="PanelContainer" type="PanelContainer" parent="CenterContainer"]
|
||||||
|
custom_minimum_size = Vector2(400, 350)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_styles/panel = SubResource("StyleBoxFlat_card")
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer/PanelContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 10
|
||||||
|
|
||||||
|
[node name="Header" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
alignment = 1
|
||||||
|
|
||||||
|
[node name="Spacer" type="Control" parent="CenterContainer/PanelContainer/VBoxContainer/Header"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
|
[node name="Title" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/Header"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||||
|
theme_override_font_sizes/font_size = 18
|
||||||
|
text = "欢迎来到 Datawhale Town!"
|
||||||
|
|
||||||
|
[node name="Spacer2" type="Control" parent="CenterContainer/PanelContainer/VBoxContainer/Header"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
|
[node name="CloseButton" type="Button" parent="CenterContainer/PanelContainer/VBoxContainer/Header"]
|
||||||
|
custom_minimum_size = Vector2(30, 30)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "X"
|
||||||
|
flat = true
|
||||||
|
|
||||||
|
[node name="HSeparator" type="HSeparator" parent="CenterContainer/PanelContainer/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="LogoContainer" type="CenterContainer" parent="CenterContainer/PanelContainer/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="TextureRect" type="TextureRect" parent="CenterContainer/PanelContainer/VBoxContainer/LogoContainer"]
|
||||||
|
custom_minimum_size = Vector2(300, 100)
|
||||||
|
layout_mode = 2
|
||||||
|
texture = ExtResource("2_dy5hw")
|
||||||
|
expand_mode = 1
|
||||||
|
stretch_mode = 5
|
||||||
|
|
||||||
|
[node name="BodyText" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_colors/font_color = Color(0.3, 0.3, 0.3, 1)
|
||||||
|
theme_override_font_sizes/font_size = 14
|
||||||
|
text = "连接·共生·见证
|
||||||
|
Datawhale Town —— 学习者的赛博家园与精神坐标。
|
||||||
|
✨ 实时广场:看大家都在学什么。
|
||||||
|
🏠 个人空间:展示你的学习笔记与作品。
|
||||||
|
🤝 开源营地:更有氛围的组队学习体验。"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
autowrap_mode = 3
|
||||||
|
|
||||||
|
[node name="Spacer3" type="Control" parent="CenterContainer/PanelContainer/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="ActionContainer" type="CenterContainer" parent="CenterContainer/PanelContainer/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="StartButton" type="Button" parent="CenterContainer/PanelContainer/VBoxContainer/ActionContainer"]
|
||||||
|
custom_minimum_size = Vector2(150, 40)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||||
|
theme_override_styles/normal = SubResource("StyleBoxFlat_btn_rounded")
|
||||||
|
text = "开始探索"
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="CenterContainer/PanelContainer/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
Reference in New Issue
Block a user