Files
whale-town-front/scenes/ui/NoticeDialog.gd
xiangwang 75eb227b18 feat: 增加通知板场景
- 增加通知板与用户交互,点击E,弹出通知消息
- 预留前端调用后端获取通知的接口,当不可用时,使用mock data
2026-01-11 01:55:19 +08:00

157 lines
4.9 KiB
GDScript

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()