Merge branch 'dev_UI' into dev

This commit is contained in:
2026-09-10 00:28:58 +08:00
12 changed files with 147 additions and 91 deletions
+6
View File
@@ -116,3 +116,9 @@ func load_from_dict(d) -> void
graph TD
A[分配属性总量,按正正态分布] --> B[随机分配5种属性,属性之和为1] --> C[分配灵气利用率]
```
## 修炼说明
每个小境界修炼需要的经验 = 基础经验值 * 属性总量
经验获取量 = 基础经验 * 灵气吸收效率
-1
View File
@@ -18,7 +18,6 @@ config/icon="res://icon.svg"
[autoload]
GameState="*res://src/Core/GameState.gd"
TimeSystem="*res://src/Core/TimeSystem.gd"
Settings="*res://src/Core/Settings.gd"
SaveSystem="*res://src/Core/SaveSystem.gd"
+13 -12
View File
@@ -1,6 +1,4 @@
# 初始版本不提供添加弟子的接口
class_name DiscipleManager
extends Node
@@ -14,6 +12,7 @@ const INITIAL_ROSTER := [
# 1 玄真(宗主):修士·炼气9层,五行全高,炼丹3级
{
"name": "玄真",
"id" : 1,
"metal": 45, "wood": 38, "water": 22, "fire": 31, "earth": 19,
"efficiency": 85,
"realm_level": 1, "sub_realm_level": 9,
@@ -23,6 +22,7 @@ const INITIAL_ROSTER := [
# 2 凌霄:修士·炼气4层,金火旺
{
"name": "凌霄",
"id" : 2,
"metal": 62, "wood": 12, "water": 15, "fire": 44, "earth": 20,
"efficiency": 76,
"realm_level": 1, "sub_realm_level": 4,
@@ -32,6 +32,7 @@ const INITIAL_ROSTER := [
# 3 青禾:凡人带灵根(木47≥20 可修炼破境),药草天赋
{
"name": "青禾",
"id" : 3,
"metal": 8, "wood": 47, "water": 25, "fire": 12, "earth": 10,
"efficiency": 68,
"realm_level": 0, "sub_realm_level": 1,
@@ -41,6 +42,7 @@ const INITIAL_ROSTER := [
# 4 阿福:凡人杂役(无灵根,五行均<20)
{
"name": "阿福",
"id" : 4,
"metal": 5, "wood": 12, "water": 8, "fire": 9, "earth": 10,
"efficiency": 41,
"realm_level": 0, "sub_realm_level": 1,
@@ -50,6 +52,7 @@ const INITIAL_ROSTER := [
# 5 阿禄:凡人杂役(无灵根)
{
"name": "阿禄",
"id" : 5,
"metal": 3, "wood": 6, "water": 5, "fire": 8, "earth": 15,
"efficiency": 35,
"realm_level": 0, "sub_realm_level": 1,
@@ -61,16 +64,16 @@ const INITIAL_ROSTER := [
var _disciples: Array[Disciple] = [] # 弟子列表
var _master_id: int = 0 # 管理器的发号计数,id 的唯一来源
# ---- 工厂 ----
func _enter_tree() -> void:
pass
# ---- 工厂 ----
# 初始编队(复用 _create_from_data
func spawn_initial_roster() -> Array[Disciple]:
func spawn_initial_roster() -> void:
for data in INITIAL_ROSTER:
var disciple = _create_from_data(data)
if disciple != null:
add_disciple(disciple)
# _disciples.append(disciple)
# emit_signal("disciple_added", disciple)
else:
push_error("Failed to spawn disciple from data: %s" % data)
pass
@@ -78,14 +81,14 @@ func spawn_initial_roster() -> Array[Disciple]:
# 补 id → Disciple.create()
# 从数据字典创建 Disciple 实例,若失败返回 null
func _create_from_data(data: Dictionary) -> Disciple:
var disciple := Disciple.create(data)
var copy := data.duplicate() # 可写副本(浅拷贝,顶层加键足够)
copy["id"] = _master_id
_master_id += 1
var disciple := Disciple.create(copy)
if disciple == null:
push_error("Failed to create disciple from data: %s" % data)
return null
disciple.id = _master_id
_master_id += 1
return disciple
pass
# ---- 仓储 ----
@@ -159,5 +162,3 @@ func to_dict():
func load_from_dict():
pass
+1
View File
@@ -0,0 +1 @@
uid://bstiea1nx61b8
+22
View File
@@ -1,5 +1,17 @@
extends Node
var cnt := 0;
func _ready() -> void:
%DiscipleManager.spawn_initial_roster()
pass
func _process(delta: float) -> void:
if cnt >= 1000:
var d : Disciple= %DiscipleManager.get_disciple(2);
%DiscipleManager.remove_disciple(d);
else:
cnt = cnt + 1;
pass
func _on_top_bar_hud_sign_return_mainmenu() -> void:
if GameState.mode == GameState.GameMode.NEW_GAME:
@@ -8,3 +20,13 @@ func _on_top_bar_hud_sign_return_mainmenu() -> void:
SaveSystem.save(GameState.profile_id) # 进游戏立即存首档,防开局就丢
get_tree().change_scene_to_file("res://src/UI/Panels/MainMenu/MainMenu.tscn")
pass # Replace with function body.
func _on_disciple_manager_disciple_added(disciple: Disciple) -> void:
$PanelContainer/Manager.add_disciple_card(disciple)
pass # Replace with function body.
func _on_disciple_manager_disciple_removed(disciple: Disciple) -> void:
$PanelContainer/Manager.remove_disciple_card(disciple.id)
pass # Replace with function body.
+16 -2
View File
@@ -1,12 +1,14 @@
[gd_scene format=3 uid="uid://c1exffg84ojqx"]
[ext_resource type="Script" uid="uid://cr4by5k8vgkcq" path="res://src/Core/MainGame.gd" id="1_8bu23"]
[ext_resource type="Script" uid="uid://cr4by5k8vgkcq" path="res://src/Core/MainGame.gd" id="1_2atgf"]
[ext_resource type="Script" uid="uid://bstiea1nx61b8" path="res://src/Character/DiscipleManager.gd" id="1_dl5bp"]
[ext_resource type="PackedScene" uid="uid://d3njijtx7ws1m" path="res://src/UI/HUD/MainSceneHud.tscn" id="2_8bu23"]
[ext_resource type="StyleBox" uid="uid://e86yw57h4v2s" path="res://resources/manager_style_box_flat.tres" id="3_dl5bp"]
[ext_resource type="PackedScene" uid="uid://d1mbwdtarjqof" path="res://src/UI/Panels/Manager/Manager.tscn" id="4_58g0x"]
[ext_resource type="Script" uid="uid://b8f8t2phmhq2e" path="res://src/Core/TimeSystem.gd" id="5_58g0x"]
[node name="MainGame" type="Node" unique_id=42551660]
script = ExtResource("1_8bu23")
script = ExtResource("1_2atgf")
[node name="MainHud" parent="." unique_id=836125968 instance=ExtResource("2_8bu23")]
size_flags_horizontal = 3
@@ -23,4 +25,16 @@ theme_override_styles/panel = ExtResource("3_dl5bp")
[node name="Manager" parent="PanelContainer" unique_id=360636457 instance=ExtResource("4_58g0x")]
layout_mode = 2
[node name="DiscipleManager" type="Node" parent="." unique_id=1485476702]
unique_name_in_owner = true
script = ExtResource("1_dl5bp")
metadata/_custom_type_script = "uid://bstiea1nx61b8"
[node name="TimeSystem" type="Node" parent="." unique_id=1280036358]
unique_name_in_owner = true
script = ExtResource("5_58g0x")
metadata/_custom_type_script = "uid://b8f8t2phmhq2e"
[connection signal="disciple_added" from="DiscipleManager" to="." method="_on_disciple_manager_disciple_added"]
[connection signal="disciple_removed" from="DiscipleManager" to="." method="_on_disciple_manager_disciple_removed"]
[connection signal="sign_return_mainmenu" from="MainHud" to="." method="_on_top_bar_hud_sign_return_mainmenu"]
+1
View File
@@ -1,6 +1,7 @@
## 全局时间系统(Autoload 单例)。
## 负责游戏时间的推进与播报,仅在世界场景中运行。
## 历法:12 月 × 30 日 = 360 日/年。
class_name TimeSystem
extends Node
const MONTHS_PER_YEAR := 12
+3 -3
View File
@@ -137,7 +137,7 @@ var total_amount: int:
## 构造:按 data 覆盖属性,数值属性经 RANGES 夹取;缺键保留字段默认值。
## @param data: 键名与属性名一致,如 {"id": 1, "name": "玄真", "metal": 60}
func _init(data: Dictionary[String, Variant] = {}) -> void:
func _init(data: Dictionary = {}) -> void:
if data.has("id"):
id = int(data["id"])
if data.has("name"):
@@ -187,12 +187,12 @@ func set_attr(key: String, value: int) -> bool:
if key == "realm_level":
# 大境界变化后,小境界不得超过新境界的上限(如落入凡人则强制 1)
set("realm_level", v)
var max_sub := SUB_MAX_BY_REALM[v]
var max_sub : int = SUB_MAX_BY_REALM[v]
if int(get("sub_realm_level")) > max_sub:
set("sub_realm_level", max_sub)
elif key == "sub_realm_level":
# 小境界写入时按当前大境界上限夹取(凡人上限 1 / 练气 13 / 其余 4)
var max_sub := SUB_MAX_BY_REALM[int(get("realm_level"))]
var max_sub : int = SUB_MAX_BY_REALM[int(get("realm_level"))]
set("sub_realm_level", clampi(v, 1, max_sub))
else:
set(key, v)
+3 -3
View File
@@ -6,8 +6,8 @@ extends Control
signal sign_return_mainmenu
func _ready() -> void:
time_label.text = TimeSystem.get_date_text()
TimeSystem.month_passed.connect(_on_TimeMonthPassed)
time_label.text = %TimeSystem.get_date_text()
%TimeSystem.month_passed.connect(_on_TimeMonthPassed)
pass
func _on_ButtonEsc_ButtonUp() -> void:
@@ -20,5 +20,5 @@ func _on_TimeMonthPassed(_year: int, _month: int) -> void:
func _on_button_continue_button_up() -> void:
TimeSystem.advance_month()
%TimeSystem.advance_month()
pass # Replace with function body.
@@ -1,11 +1,14 @@
extends Control
var disciple_id: int;
func _ready() -> void:
custom_maximum_size = Vector2(180, 320);
custom_minimum_size = Vector2(180, 240);
pass;
func set_info(info: Dictionary):
disciple_id = info['id'];
$VBoxContainer/HBoxContainer/Name.text = info['name'];
$VBoxContainer/HBoxContainer2/Level.text = info['level']
$VBoxContainer/HBoxContainer3/GridContainer/MetalVal.text = str(info['metal'])
@@ -13,4 +16,6 @@ func set_info(info: Dictionary):
$VBoxContainer/HBoxContainer3/GridContainer/WaterVal.text = str(info['water'])
$VBoxContainer/HBoxContainer3/GridContainer/FireVal.text = str(info['fire'])
$VBoxContainer/HBoxContainer3/GridContainer/EarthVal.text = str(info['earth'])
#print(info)
pass
@@ -15,6 +15,7 @@ grow_vertical = 2
size_flags_horizontal = 3
theme_override_styles/panel = ExtResource("1_po3i5")
script = ExtResource("2_6fig8")
metadata/discipleId = 0
[node name="VBoxContainer" type="VBoxContainer" parent="." unique_id=1066350214]
layout_mode = 2
+27 -21
View File
@@ -1,6 +1,5 @@
extends Control
var test_disciple_table : Array[Dictionary] = [] # 弟子
var test_field_table : Array[Dictionary] = [] # 建筑
var test_order_table : Array[Dictionary] = [] # 订单
var test_alchemy_table : Array[Dictionary] = [] # 炼丹配方
@@ -22,7 +21,6 @@ func _ready() -> void:
var manager_panel_scene := load("res://src/UI/Panels/Manager/ManagerPanel.tscn") as PackedScene
var inventory_panel_scene := load("res://src/UI/Panels/Manager/InventoryPanel/InventoryPanel.tscn") as PackedScene
sect_resources["弟子"] = manager_panel_scene.instantiate();
sect_resources["弟子"].name = "弟子";
$TabContainer.add_child(sect_resources["弟子"]);
@@ -43,12 +41,6 @@ func _ready() -> void:
sect_resources["库房"].name = "库房";
$TabContainer.add_child(sect_resources["库房"]);
for e in test_disciple_table:
var d := disciple_info_scene.instantiate()
d.set_info(e)
sect_resources["弟子"].add_info_card(d)
pass
for e in test_field_table:
var d := field_info_scene.instantiate()
d.set_field_info(e)
@@ -66,25 +58,12 @@ func _ready() -> void:
d.set_alchemy_info(e)
sect_resources['炼丹'].add_info_card(d)
pass
pass
func init_test_data() -> void:
test_disciple_table.append_array([
{"name": "赵一", "gender": "", "level": "练气一层", "metal": 0.5, "wood": 0.9, "water": 0.1, "fire": 0.2, "earth": 0.15},
{"name": "钱二", "gender": "", "level": "练气一层", "metal": 0.5, "wood": 0.9, "water": 0.1, "fire": 0.2, "earth": 0.15},
{"name": "孙三", "gender": "", "level": "练气一层", "metal": 0.5, "wood": 0.9, "water": 0.1, "fire": 0.2, "earth": 0.15},
{"name": "李四", "gender": "", "level": "练气一层", "metal": 0.5, "wood": 0.9, "water": 0.1, "fire": 0.2, "earth": 0.15},
{"name": "周五", "gender": "", "level": "练气一层", "metal": 0.5, "wood": 0.9, "water": 0.1, "fire": 0.2, "earth": 0.15},
{"name": "吴六", "gender": "", "level": "练气一层", "metal": 0.5, "wood": 0.9, "water": 0.1, "fire": 0.2, "earth": 0.15},
{"name": "郑七", "gender": "", "level": "练气一层", "metal": 0.5, "wood": 0.9, "water": 0.1, "fire": 0.2, "earth": 0.15}
])
test_field_table.append_array([
{"name": "灵田", "弟子": 0},
{"name": "灵田", "弟子": 1},
@@ -129,3 +108,30 @@ func init_test_data() -> void:
test_inventory.append_array([{"草药": test_sub_inventory1}, {"粮食": test_sub_inventory2}, {"丹药": test_sub_inventory3}]);
pass
func add_disciple_card(d : Disciple) -> void:
var ds := disciple_info_scene.instantiate()
var info := {
"id": d.id,
"name": d.name,
"gender" : "x",
"level" : d.realm_name(),
"metal" : int(d.get_attr("metal")),
"wood" : int(d.get_attr("wood")),
"water" : int(d.get_attr("water")),
"fire" : int(d.get_attr("fire")),
"earth" : int(d.get_attr("earth"))
}
ds.set_info(info)
sect_resources["弟子"].add_info_card(ds)
pass
func remove_disciple_card(id: int) -> void:
var panel: Control = sect_resources["弟子"] # ManagerPanel 页
var flow: Node = panel.get_node("ScrollContainer/HFlowContainer")
for child in flow.get_children():
if child.disciple_id == id: # 指定项匹配
flow.remove_child(child) # 1. 先从树摘除
child.queue_free() # 2. 再排队销毁
return # 匹配唯一,删完即走