插件UI更新

This commit is contained in:
RedisTKey 2026-01-05 11:39:42 +08:00
parent a9499e6b27
commit bea2ff4c5c
8 changed files with 194 additions and 29 deletions

9
GameEntry.tscn Normal file
View File

@ -0,0 +1,9 @@
[gd_scene load_steps=2 format=3 uid="uid://bgxnvmxg2jsx2"]
[ext_resource type="PackedScene" uid="uid://b4ojkr2fq8xjm" path="res://_ui/main_menu/main_menu.tscn" id="1_fcou6"]
[node name="GameEntry" type="Node"]
[node name="CanvasLayer" type="CanvasLayer" parent="."]
[node name="MainMenu" parent="CanvasLayer" instance=ExtResource("1_fcou6")]

View File

@ -0,0 +1,60 @@
[gd_scene load_steps=2 format=3 uid="uid://b4ojkr2fq8xjm"]
[ext_resource type="Texture2D" uid="uid://c673bap4b12fx" path="res://icon.svg" id="1_j8fyu"]
[node name="MainMenu" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="TextureRect" type="TextureRect" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
texture = ExtResource("1_j8fyu")
[node name="MC_Title" type="MarginContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="L_Title" type="Label" parent="MC_Title"]
layout_mode = 2
text = "游戏名称"
[node name="MC_Options" type="MarginContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="VBoxContainer" type="VBoxContainer" parent="MC_Options"]
layout_mode = 2
[node name="B_Start" type="Button" parent="MC_Options/VBoxContainer"]
layout_mode = 2
text = "Start"
[node name="B_Continue" type="Button" parent="MC_Options/VBoxContainer"]
layout_mode = 2
text = "Continue
"
[node name="B_Option" type="Button" parent="MC_Options/VBoxContainer"]
layout_mode = 2
text = "Option"
[node name="B_Exit" type="Button" parent="MC_Options/VBoxContainer"]
layout_mode = 2
text = "Exit"

View File

@ -13,7 +13,14 @@ enum SpawnSpace {
TARGET_NODE, TARGET_NODE,
##如果是直接Spawn在World需要提供一个额外的全局坐标 ##如果是直接Spawn在World需要提供一个额外的全局坐标
WORLD_POSITION WORLD_POSITION,
}
## VFX 播放的层级
enum SpawnLayer
{
LOCAL,
GLOBAL
} }
@export var spawn_space := SpawnSpace.TARGET_NODE @export var spawn_space := SpawnSpace.TARGET_NODE

View File

@ -96,6 +96,7 @@ layout_mode = 2
text = "Choose" text = "Choose"
[node name="ClearButton" type="Button" parent="MarginContainer/HBC_Main/VBoxContainer/HBC_Drop/HBC_Option"] [node name="ClearButton" type="Button" parent="MarginContainer/HBC_Main/VBoxContainer/HBC_Drop/HBC_Option"]
unique_name_in_owner = true
layout_mode = 2 layout_mode = 2
text = "Clear" text = "Clear"

View File

@ -11,11 +11,18 @@ const COLOR_CAN_DROP: Color = Color(0.4, 0.7, 1.0, 1.0)
const COLOR_CANNOT_DROP: Color = Color(1.0, 0.35, 0.35, 1.0) const COLOR_CANNOT_DROP: Color = Color(1.0, 0.35, 0.35, 1.0)
const COLOR_CHECKED: Color = Color.GREEN const COLOR_CHECKED: Color = Color.GREEN
## 設置Locker的時候自更新一次State
var vaild: bool = false:
set(value):
_set_state(3)
vaild = value
var _icon: TextureRect var _icon: TextureRect
var _state := 0 # 0 idle, 1 can, 2 cannot var _state := 0 # 0 idle, 1 can, 2 cannot
var _current_drag_data: Variant = null var _current_drag_data: Variant = null
signal node_path_dropped(node_path: NodePath) signal node_path_dropped(node_path: NodePath)
signal state_change(state: int)
# ===================================================== # =====================================================
# Life cycle # Life cycle
@ -81,6 +88,9 @@ func _set_state(s: int) -> void:
match _state: match _state:
0: 0:
if vaild:
_set_state(3)
return
_icon.modulate = COLOR_IDLE _icon.modulate = COLOR_IDLE
1: 1:
_icon.modulate = COLOR_CAN_DROP _icon.modulate = COLOR_CAN_DROP
@ -88,3 +98,5 @@ func _set_state(s: int) -> void:
_icon.modulate = COLOR_CANNOT_DROP _icon.modulate = COLOR_CANNOT_DROP
3: 3:
_icon.modulate = COLOR_CHECKED _icon.modulate = COLOR_CHECKED
state_change.emit(_state)

View File

@ -8,6 +8,7 @@ extends Control
@onready var context: RichTextLabel = %Context @onready var context: RichTextLabel = %Context
@onready var cb_use_trans: CheckBox = %CB_UseTrans @onready var cb_use_trans: CheckBox = %CB_UseTrans
@onready var clear_button: Button = %ClearButton
@onready var index: Label = %Index @onready var index: Label = %Index
@ -15,25 +16,57 @@ var _cached_single_act: SingleAct = null
var _cached_prop_id: int = -1 var _cached_prop_id: int = -1
var _cached_info: Dictionary var _cached_info: Dictionary
var _state: int = 0
const NORMAL_STATE_LABLE: String = "Drag state node to icon." const NORMAL_STATE_LABLE: String = "Drag state node to icon."
const NORMAL_CONTEXT: String = "Information will be show here." const NORMAL_CONTEXT: String = "Information will be show here."
#const ICON_COLOR: Dictionary = {
#"Idle": Color.GRAY,
#""
#}
const COLOR_IDLE: Color = Color.GRAY const COLOR_IDLE: Color = Color.GRAY
const COLOR_CHECKED_1: Color = Color.GREEN const COLOR_CHECKED_1: Color = Color.GREEN
const COLOR_CHECKED_2: Color = Color.YELLOW const COLOR_CHECKED_2: Color = Color.YELLOW
const COLOR_CHECKED_3: Color = Color.ORANGE_RED const COLOR_CHECKED_3: Color = Color.ORANGE_RED
func _ready() -> void: func _ready() -> void:
_reset_to_default() _reset_to_default()
_reset_cb_use_trans() _reset_cb_use_trans()
if drop_area: if drop_area:
drop_area.node_path_dropped.connect(_on_node_path_dropped) drop_area.node_path_dropped.connect(_on_node_path_dropped)
drop_area.state_change.connect(_on_drap_area_state_change)
## 核心函數通過狀態機來控制UI組件的狀態。
func _set_state(new_state: int) -> void:
if _state == new_state:
return
_state = new_state
match _state:
0: ## 初始狀態,什麽都沒有
pass
1: ## vaild 狀態,可以插入了
pass
func _btn_init() -> void:
clear_button.pressed.connect(_on_clear_pressed)
func _on_clear_pressed() -> void:
_clear_cached_act()
func init(index: int) -> void: func init(index: int) -> void:
self.index.text = str(index) self.index.text = str(index)
func _on_node_path_dropped(path: NodePath) -> void: func _on_node_path_dropped(path: NodePath) -> void:
## 如果已經可以插入但是重新被插入了一個State先clear再插入。
if get_ready_to_insert():
_clear_cached_act()
var state := StateResolveUtils.get_state_node_from_path(path) var state := StateResolveUtils.get_state_node_from_path(path)
if state == null: if state == null:
_clear_cached_act() _clear_cached_act()
@ -57,12 +90,12 @@ func _on_node_path_dropped(path: NodePath) -> void:
_cached_prop_id = int(info.prop_id) _cached_prop_id = int(info.prop_id)
## 启用 CheckBox
#cb_use_trans.disabled = false
#cb_use_trans.button_pressed = _cached_single_act.use_trans
# 直接用 info + cached 刷 UI
_update_context(info) _update_context(info)
drop_area.vaild = true
func _on_drap_area_state_change(state:int) -> void:
pass
func _on_use_trans_toggled(pressed: bool) -> void: func _on_use_trans_toggled(pressed: bool) -> void:
# 如果存在就改,不存在無事發生 # 如果存在就改,不存在無事發生
@ -71,7 +104,6 @@ func _on_use_trans_toggled(pressed: bool) -> void:
_update_context() _update_context()
func _resolve_state_from_path(path: NodePath) -> ReedPropState: func _resolve_state_from_path(path: NodePath) -> ReedPropState:
var root := EditorInterface.get_edited_scene_root() var root := EditorInterface.get_edited_scene_root()
if root == null: if root == null:
@ -116,6 +148,10 @@ func _build_cached_act(state: ReedPropState, info: Dictionary) -> void:
func _clear_cached_act() -> void: func _clear_cached_act() -> void:
_cached_single_act = null _cached_single_act = null
_cached_prop_id = -1 _cached_prop_id = -1
_cached_info = {}
drop_area.vaild = false
_update_context()
## 设置文本 ## 设置文本
func _update_context(info:Dictionary = {}) ->void: func _update_context(info:Dictionary = {}) ->void:
@ -174,3 +210,13 @@ func _update_context(info:Dictionary = {}) ->void:
bbcode += "[/cell][/table]" bbcode += "[/cell][/table]"
context.text = bbcode context.text = bbcode
## 外部調用可以返回當前的Slot是否有效懶檢查
func get_ready_to_insert() -> bool:
return (
_cached_single_act != null
and _cached_prop_id >= 0
and _cached_info != null
and _cached_info != {}
)

View File

@ -1,9 +1,20 @@
@tool @tool
extends PanelContainer extends PanelContainer
@onready var spawn_slot_root: VBoxContainer = %SpawnSlotRoot @onready var vbc_spawn_slot_root: VBoxContainer = %VBC_SpawnSlotRoot
@onready var add_button: Button = %AddButton
@onready var remove_button: Button = %RemoveButton @onready var b_insert: Button = %B_Insert
@onready var b_remove: Button = %B_Remove
@onready var b_add: Button = %B_Add
@onready var rtl_context: RichTextLabel = %RTL_Context
const DEFAULT_CONTEXT: Dictionary = {
"default": "Press insert to generate a act.",
"removerr": "Act need at least on single act.",
"adderr": "Single act count cannot over the count of props.",
"inserterr": "Insert act with empty slot."
}
var _inited: bool = false var _inited: bool = false
var _max_length: int = -1 var _max_length: int = -1
@ -16,14 +27,15 @@ func _ready() -> void:
return return
# 连接按钮 # 连接按钮
add_button.pressed.connect(_on_add_pressed) b_add.pressed.connect(_on_add_pressed)
remove_button.pressed.connect(_on_remove_pressed) b_remove.pressed.connect(_on_remove_pressed)
b_insert.pressed.connect(_on_insert_pressed)
# 初始保证至少有一个 Slot # 初始保证至少有一个 Slot
if spawn_slot_root.get_child_count() == 0: if vbc_spawn_slot_root.get_child_count() == 0:
_add_slot() _add_slot()
_update_remove_button_state() _update_b_remove_state()
func init(info:Dictionary) -> void: func init(info:Dictionary) -> void:
_inited = true _inited = true
@ -36,26 +48,42 @@ func _on_add_pressed() -> void:
func _on_remove_pressed() -> void: func _on_remove_pressed() -> void:
_remove_slot() _remove_slot()
func _on_insert_pressed() -> void:
_insert_act()
## 插入一個根據當前的條目生成的Act
func _insert_act()-> void:
var slots = vbc_spawn_slot_root.get_children()
for s in slots:
var vs = s as StateDrapSlot
if not vs:
continue ##後續要有報錯Message
## 添加一個Slot不能超過當前Scene的最大prop數量
func _add_slot() -> void: func _add_slot() -> void:
if spawn_slot_root.get_child_count() >= _max_length: if vbc_spawn_slot_root.get_child_count() >= _max_length:
return return
var slot := SLOT.instantiate() var slot := SLOT.instantiate()
spawn_slot_root.add_child(slot) vbc_spawn_slot_root.add_child(slot)
slot.owner = get_tree().edited_scene_root # 编辑器可保存 slot.owner = get_tree().edited_scene_root # 编辑器可保存
slot.init(spawn_slot_root.get_children().size()) slot.init(vbc_spawn_slot_root.get_children().size())
_update_remove_button_state() _update_b_remove_state()
## 移除一個Slot最少不能為0
func _remove_slot() -> void: func _remove_slot() -> void:
var count := spawn_slot_root.get_child_count() var count := vbc_spawn_slot_root.get_child_count()
if count <= 1: if count <= 1:
return return
var last := spawn_slot_root.get_child(count - 1) var last := vbc_spawn_slot_root.get_child(count - 1)
last.queue_free() last.queue_free()
_update_remove_button_state() _update_b_remove_state()
func _update_remove_button_state() -> void:
remove_button.disabled = spawn_slot_root.get_child_count() <= 1 func _update_b_remove_state() -> void:
b_remove.disabled = vbc_spawn_slot_root.get_child_count() <= 1

View File

@ -25,16 +25,17 @@ layout_mode = 2
text = "State Quick Config Panel" text = "State Quick Config Panel"
[node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer/VBoxContainer"] [node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer/VBoxContainer"]
custom_minimum_size = Vector2(0, 300) custom_minimum_size = Vector2(0, 240)
layout_mode = 2 layout_mode = 2
size_flags_vertical = 3 size_flags_vertical = 3
[node name="SpawnSlotRoot" type="VBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer"] [node name="VBC_SpawnSlotRoot" type="VBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer"]
unique_name_in_owner = true unique_name_in_owner = true
layout_mode = 2 layout_mode = 2
size_flags_horizontal = 3 size_flags_horizontal = 3
[node name="RichTextLabel" type="RichTextLabel" parent="MarginContainer/VBoxContainer"] [node name="RTL_Context" type="RichTextLabel" parent="MarginContainer/VBoxContainer"]
unique_name_in_owner = true
custom_minimum_size = Vector2(0, 32) custom_minimum_size = Vector2(0, 32)
layout_mode = 2 layout_mode = 2
bbcode_enabled = true bbcode_enabled = true
@ -44,21 +45,22 @@ fit_content = true
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"] [node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
layout_mode = 2 layout_mode = 2
[node name="AddButton" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer"] [node name="B_Add" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer"]
unique_name_in_owner = true unique_name_in_owner = true
custom_minimum_size = Vector2(0, 24) custom_minimum_size = Vector2(0, 24)
layout_mode = 2 layout_mode = 2
size_flags_horizontal = 3 size_flags_horizontal = 3
text = "Add" text = "Add"
[node name="RemoveButton" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer"] [node name="B_Remove" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer"]
unique_name_in_owner = true unique_name_in_owner = true
custom_minimum_size = Vector2(24, 24) custom_minimum_size = Vector2(24, 24)
layout_mode = 2 layout_mode = 2
size_flags_horizontal = 3 size_flags_horizontal = 3
disabled = true
text = "Remove" text = "Remove"
[node name="InsertButton" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer"] [node name="B_Insert" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer"]
unique_name_in_owner = true unique_name_in_owner = true
custom_minimum_size = Vector2(24, 24) custom_minimum_size = Vector2(24, 24)
layout_mode = 2 layout_mode = 2