更新dialogue的相关接口。(主要是输入)
NPC图片更新。 对话框UI的逐字显示逻辑更新。
@ -6,7 +6,7 @@
|
|||||||
"week": 1,
|
"week": 1,
|
||||||
"day": 1
|
"day": 1
|
||||||
},
|
},
|
||||||
"money": 3000,
|
"money": 5000,
|
||||||
"idea":0,
|
"idea":0,
|
||||||
"fans": 0,
|
"fans": 0,
|
||||||
"staff_count": 0,
|
"staff_count": 0,
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
"npc": {
|
"npc": {
|
||||||
"米子三": {
|
"米子三": {
|
||||||
"type": "员工",
|
"type": "员工",
|
||||||
|
"icon": "米子三",
|
||||||
"title": "项目总监",
|
"title": "项目总监",
|
||||||
"level": 1,
|
"level": 1,
|
||||||
"power": 180,
|
"power": 180,
|
||||||
@ -14,6 +15,7 @@
|
|||||||
},
|
},
|
||||||
"塔祺": {
|
"塔祺": {
|
||||||
"type": "员工",
|
"type": "员工",
|
||||||
|
"icon": "塔祺",
|
||||||
"title": "美术设计师",
|
"title": "美术设计师",
|
||||||
"level": 3,
|
"level": 3,
|
||||||
"power": 150,
|
"power": 150,
|
||||||
@ -26,6 +28,7 @@
|
|||||||
},
|
},
|
||||||
"瞎五": {
|
"瞎五": {
|
||||||
"type": "外包",
|
"type": "外包",
|
||||||
|
"icon": "瞎五",
|
||||||
"title": "策划",
|
"title": "策划",
|
||||||
"level": 2,
|
"level": 2,
|
||||||
"power": 160,
|
"power": 160,
|
||||||
@ -34,7 +37,7 @@
|
|||||||
"code": 50,
|
"code": 50,
|
||||||
"art": 70,
|
"art": 70,
|
||||||
"audio": 70,
|
"audio": 70,
|
||||||
"outsourcing": 1000
|
"outsourcing": 2000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 99 KiB |
@ -3,15 +3,15 @@
|
|||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://hdidwixuokxn"
|
uid="uid://hdidwixuokxn"
|
||||||
path="res://.godot/imported/npc_ability_icon.png-bfd6d66f16fe1f985312ee4082b5b29d.ctex"
|
path="res://.godot/imported/npc_ability_icon.png-50cfe5e6f622de28a6626dfe9cf951f8.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"vram_texture": false
|
"vram_texture": false
|
||||||
}
|
}
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://Entity/NPC/npc_ability_icon.png"
|
source_file="res://Entity/NPC/art/npc_ability_icon.png"
|
||||||
dest_files=["res://.godot/imported/npc_ability_icon.png-bfd6d66f16fe1f985312ee4082b5b29d.ctex"]
|
dest_files=["res://.godot/imported/npc_ability_icon.png-50cfe5e6f622de28a6626dfe9cf951f8.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 637 B After Width: | Height: | Size: 637 B |
34
Entity/NPC/art/塔祺.png.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://l10c627dkvqk"
|
||||||
|
path="res://.godot/imported/塔祺.png-b299ce4379c4a1dbc822b8004e91f428.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://Entity/NPC/art/塔祺.png"
|
||||||
|
dest_files=["res://.godot/imported/塔祺.png-b299ce4379c4a1dbc822b8004e91f428.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
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/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
Entity/NPC/art/瞎五.png
Normal file
|
After Width: | Height: | Size: 637 B |
34
Entity/NPC/art/瞎五.png.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://b1yh5gywpavyy"
|
||||||
|
path="res://.godot/imported/瞎五.png-5318b112b2d2eed9a5229dbdc2071b51.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://Entity/NPC/art/瞎五.png"
|
||||||
|
dest_files=["res://.godot/imported/瞎五.png-5318b112b2d2eed9a5229dbdc2071b51.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
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/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
Entity/NPC/art/秘书.png
Normal file
|
After Width: | Height: | Size: 637 B |
@ -3,15 +3,15 @@
|
|||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://bb3kyiufyyj05"
|
uid="uid://bb3kyiufyyj05"
|
||||||
path="res://.godot/imported/NPC_1_UI.png-83ecc50c62455610d5961b891015b3cc.ctex"
|
path="res://.godot/imported/秘书.png-ed96a35be8dbb7f405ac82294c185d80.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"vram_texture": false
|
"vram_texture": false
|
||||||
}
|
}
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://Entity/NPC/NPC_1_UI.png"
|
source_file="res://Entity/NPC/art/秘书.png"
|
||||||
dest_files=["res://.godot/imported/NPC_1_UI.png-83ecc50c62455610d5961b891015b3cc.ctex"]
|
dest_files=["res://.godot/imported/秘书.png-ed96a35be8dbb7f405ac82294c185d80.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
BIN
Entity/NPC/art/米子三.png
Normal file
|
After Width: | Height: | Size: 666 B |
34
Entity/NPC/art/米子三.png.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://b2hovy2llqpgk"
|
||||||
|
path="res://.godot/imported/米子三.png-97aa29879811dabba52f779af04a6ad2.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://Entity/NPC/art/米子三.png"
|
||||||
|
dest_files=["res://.godot/imported/米子三.png-97aa29879811dabba52f779af04a6ad2.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
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/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
|
||||||
@ -5,7 +5,7 @@
|
|||||||
class_name TypewriterLogic # 使用 class_name 使其可以在其他脚本中按类型提示引用
|
class_name TypewriterLogic # 使用 class_name 使其可以在其他脚本中按类型提示引用
|
||||||
|
|
||||||
# --- 信号 ---
|
# --- 信号 ---
|
||||||
signal finished # 当打字动画自然完成时发出
|
signal finished # 当打字动画自然完成时,或在start_typing中因文本为空/速度无效而立即完成时发出
|
||||||
|
|
||||||
# --- 属性 ---
|
# --- 属性 ---
|
||||||
var target_label: Label # 要应用效果的目标 Label 节点
|
var target_label: Label # 要应用效果的目标 Label 节点
|
||||||
@ -23,7 +23,7 @@ func _init(p_target_label: Label, p_typing_speed: float = 20.0):
|
|||||||
|
|
||||||
target_label = p_target_label
|
target_label = p_target_label
|
||||||
typing_speed = p_typing_speed
|
typing_speed = p_typing_speed
|
||||||
print("TypewriterLogic initialized for Label: ", target_label.name)
|
print("TypewriterLogic initialized for Label: ", target_label.name if is_instance_valid(target_label) else "INVALID_LABEL")
|
||||||
|
|
||||||
|
|
||||||
# --- 公共方法 ---
|
# --- 公共方法 ---
|
||||||
@ -43,9 +43,11 @@ func start_typing(full_text: String):
|
|||||||
|
|
||||||
# 3. 如果文本为空或速度<=0,则直接显示完成,不创建动画
|
# 3. 如果文本为空或速度<=0,则直接显示完成,不创建动画
|
||||||
if full_text.length() == 0 or typing_speed <= 0:
|
if full_text.length() == 0 or typing_speed <= 0:
|
||||||
target_label.visible_characters = full_text.length() # 直接显示全部
|
if is_instance_valid(target_label):
|
||||||
|
target_label.visible_characters = full_text.length() # 直接显示全部
|
||||||
_is_typing = false
|
_is_typing = false
|
||||||
finished.emit() # 即使没有动画,也视为完成
|
finished.emit() # 即使没有动画,也视为完成
|
||||||
|
print("TypewriterLogic: Text is empty or speed is non-positive. Displaying all and emitting finished.")
|
||||||
return
|
return
|
||||||
|
|
||||||
# 4. 设置标记,表示正在打字
|
# 4. 设置标记,表示正在打字
|
||||||
@ -53,11 +55,18 @@ func start_typing(full_text: String):
|
|||||||
|
|
||||||
# 5. 创建新的Tween动画 (使用 Label 节点作为 Tween 的宿主)
|
# 5. 创建新的Tween动画 (使用 Label 节点作为 Tween 的宿主)
|
||||||
# 注意:Tween 需要一个 Node 来运行,我们使用 target_label 本身
|
# 注意:Tween 需要一个 Node 来运行,我们使用 target_label 本身
|
||||||
|
# 确保 target_label 仍然有效才创建 Tween
|
||||||
|
if not is_instance_valid(target_label): # 再次检查,以防在 stop_typing 后 target_label 失效
|
||||||
|
printerr("TypewriterLogic: Target Label became invalid before Tween creation.")
|
||||||
|
_is_typing = false
|
||||||
|
return
|
||||||
|
|
||||||
current_tween = target_label.create_tween()
|
current_tween = target_label.create_tween()
|
||||||
|
|
||||||
# 6. 绑定动画完成信号到内部处理函数
|
# 6. 绑定动画完成信号到内部处理函数
|
||||||
# 使用 bind() 来确保 _on_typing_finished 被这个实例调用
|
# 使用 bind() 来确保 _on_typing_finished 被这个实例调用
|
||||||
current_tween.finished.connect(_on_typing_finished)
|
# Callable(self, "_on_typing_finished") 是更现代的写法
|
||||||
|
current_tween.finished.connect(Callable(self, "_on_typing_finished"))
|
||||||
|
|
||||||
# 7. 计算动画时长
|
# 7. 计算动画时长
|
||||||
var duration = float(full_text.length()) / typing_speed
|
var duration = float(full_text.length()) / typing_speed
|
||||||
@ -77,7 +86,11 @@ func skip_typing():
|
|||||||
return
|
return
|
||||||
|
|
||||||
if not is_instance_valid(target_label):
|
if not is_instance_valid(target_label):
|
||||||
printerr("TypewriterLogic: Target Label is not valid.")
|
printerr("TypewriterLogic: Target Label is not valid for skip_typing.")
|
||||||
|
_is_typing = false # 确保状态更新
|
||||||
|
if current_tween != null and current_tween.is_valid(): # 尝试清理 tween
|
||||||
|
current_tween.kill()
|
||||||
|
current_tween = null
|
||||||
return
|
return
|
||||||
|
|
||||||
if current_tween != null and current_tween.is_valid():
|
if current_tween != null and current_tween.is_valid():
|
||||||
@ -87,23 +100,23 @@ func skip_typing():
|
|||||||
target_label.visible_characters = target_label.text.length() # 显示全部字符
|
target_label.visible_characters = target_label.text.length() # 显示全部字符
|
||||||
_is_typing = false # 更新状态
|
_is_typing = false # 更新状态
|
||||||
# 注意:跳过时通常不发出 finished 信号,因为这不是自然完成
|
# 注意:跳过时通常不发出 finished 信号,因为这不是自然完成
|
||||||
# 如果需要,可以在调用 skip_typing 的地方手动处理完成逻辑
|
# 如果需要在跳过时也认为“完成”,调用方应在调用 skip_typing() 后手动处理,
|
||||||
|
# 或在此处添加 finished.emit() 并明确其行为。
|
||||||
print("TypewriterLogic: Skipped typing on Label '", target_label.name, "'")
|
print("TypewriterLogic: Skipped typing on Label '", target_label.name, "'")
|
||||||
|
|
||||||
|
|
||||||
# 停止当前的打字动画 (例如,对话框提前关闭)
|
# 停止当前的打字动画 (例如,对话框提前关闭)
|
||||||
func stop_typing():
|
func stop_typing():
|
||||||
if not is_instance_valid(target_label):
|
# 即使 Label 无效,也要尝试清理 _is_typing 和 current_tween
|
||||||
# 如果 Label 无效,也可能意味着 Tween 已经无效或不存在
|
|
||||||
current_tween = null
|
|
||||||
_is_typing = false
|
|
||||||
return
|
|
||||||
|
|
||||||
if current_tween != null and current_tween.is_valid():
|
if current_tween != null and current_tween.is_valid():
|
||||||
current_tween.kill()
|
current_tween.kill() # 停止动画
|
||||||
current_tween = null
|
current_tween = null
|
||||||
_is_typing = false # 确保状态被重置
|
_is_typing = false # 确保状态被重置
|
||||||
print("TypewriterLogic: Stopped typing on Label '", target_label.name, "'")
|
|
||||||
|
if is_instance_valid(target_label):
|
||||||
|
print("TypewriterLogic: Stopped typing on Label '", target_label.name, "'")
|
||||||
|
else:
|
||||||
|
print("TypewriterLogic: Stopped typing (target Label was invalid).")
|
||||||
|
|
||||||
|
|
||||||
# 返回当前是否正在进行打字动画
|
# 返回当前是否正在进行打字动画
|
||||||
@ -117,5 +130,8 @@ func is_typing() -> bool:
|
|||||||
func _on_typing_finished():
|
func _on_typing_finished():
|
||||||
_is_typing = false
|
_is_typing = false
|
||||||
current_tween = null # 清理 Tween 引用
|
current_tween = null # 清理 Tween 引用
|
||||||
print("TypewriterLogic: Typing finished naturally on Label '", target_label.name, "'")
|
if is_instance_valid(target_label):
|
||||||
|
print("TypewriterLogic: Typing finished naturally on Label '", target_label.name, "'")
|
||||||
|
else:
|
||||||
|
print("TypewriterLogic: Typing finished naturally (target Label was invalid).")
|
||||||
finished.emit() # 发出完成信号
|
finished.emit() # 发出完成信号
|
||||||
|
|||||||
@ -2,70 +2,108 @@
|
|||||||
|
|
||||||
## 1. 目标
|
## 1. 目标
|
||||||
|
|
||||||
`TypewriterLogic` 是一个 GDScript 辅助类,用于给 `Label` 节点添加逐字显示(打字机)效果。它封装了动画逻辑和状态,实现代码复用。
|
`TypewriterLogic` 是一个 GDScript 辅助类,用于给 `Label` 节点添加逐字显示(打字机)效果。它封装了动画逻辑和状态,旨在简化打字机效果的实现和代码复用。该类使用 `class_name TypewriterLogic` 注册,方便在其他脚本中进行类型提示和引用。
|
||||||
|
|
||||||
## 2. 使用方法
|
## 2. 使用方法
|
||||||
|
|
||||||
**a. 引入与实例化:**
|
**a. 引入与实例化:**
|
||||||
|
|
||||||
```gdscript
|
```gdscript
|
||||||
# 预加载类 (确保路径正确)
|
# 预加载类 (如果 TypewriterLogic.gd 在 res://scripts/ 目录下)
|
||||||
const TypewriterLogic = preload("res://path/to/TypewriterLogic.gd")
|
const TypewriterLogicClass = preload("res://scripts/TypewriterLogic.gd") # 确保路径正确
|
||||||
|
|
||||||
# 获取 Label 节点
|
# 获取 Label 节点
|
||||||
@onready var dialogue_label: Label = $Path/To/Label
|
@onready var dialogue_label: Label = $Path/To/Your/LabelNode
|
||||||
|
|
||||||
# 声明实例变量
|
# 声明实例变量
|
||||||
var typewriter: TypewriterLogic
|
var typewriter: TypewriterLogic
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
# 创建实例,传入 Label 和速度
|
# 确保 Label 节点有效
|
||||||
if is_instance_valid(dialogue_label):
|
if not is_instance_valid(dialogue_label):
|
||||||
typewriter = TypewriterLogic.new(dialogue_label, 25.0) # 25.0 是打字速度
|
printerr("Error: Dialogue Label node not found or invalid.")
|
||||||
# (可选) 连接信号
|
return
|
||||||
typewriter.finished.connect(_on_typing_done)
|
|
||||||
|
# 创建实例,传入 Label 和打字速度
|
||||||
|
# TypewriterLogic 是 class_name,可以直接用作类型
|
||||||
|
typewriter = TypewriterLogicClass.new(dialogue_label, 25.0) # 25.0 是打字速度 (字符/秒)
|
||||||
|
|
||||||
|
# (可选) 连接信号,以在打字自然完成时执行操作
|
||||||
|
if typewriter != null and typewriter.has_signal("finished"): # 检查实例和信号是否存在
|
||||||
|
typewriter.finished.connect(_on_typing_naturally_finished)
|
||||||
|
|
||||||
|
func _on_typing_naturally_finished():
|
||||||
|
print("打字效果已自然播放完毕!")
|
||||||
|
# 在这里可以添加例如显示“继续”图标、启用下一页按钮等逻辑
|
||||||
```
|
```
|
||||||
|
|
||||||
**b. 控制效果:**
|
**b. 控制效果:**
|
||||||
|
|
||||||
```gdscript
|
```gdscript
|
||||||
# 开始打字
|
# 开始播放打字效果
|
||||||
func show_message(text: String):
|
func display_message(new_text: String):
|
||||||
if typewriter != null:
|
if typewriter != null:
|
||||||
typewriter.start_typing(text)
|
typewriter.start_typing(new_text)
|
||||||
|
|
||||||
# 跳过打字 (例如,点击时)
|
# 如果正在打字,立即显示全部文本 (跳过动画)
|
||||||
func skip_message():
|
func skip_current_typing_animation():
|
||||||
if typewriter != null and typewriter.is_typing():
|
if typewriter != null and typewriter.is_typing():
|
||||||
typewriter.skip_typing()
|
typewriter.skip_typing()
|
||||||
|
# 注意:skip_typing() 默认不发出 finished 信号。
|
||||||
|
# 如果跳过后需要执行与自然完成相同的逻辑,可以在这里手动调用:
|
||||||
|
# _on_typing_naturally_finished()
|
||||||
|
# 或者根据需求处理不同的逻辑
|
||||||
|
|
||||||
# 停止打字 (例如,关闭UI时)
|
# 强制停止当前的打字效果 (例如,UI关闭或切换时)
|
||||||
func force_stop_typing():
|
func stop_current_typing_immediately():
|
||||||
if typewriter != null:
|
if typewriter != null:
|
||||||
typewriter.stop_typing()
|
typewriter.stop_typing()
|
||||||
|
|
||||||
# (可选) 处理完成信号
|
# 检查是否正在打字
|
||||||
func _on_typing_done():
|
func check_if_typing():
|
||||||
print("打字自然完成")
|
if typewriter != null and typewriter.is_typing():
|
||||||
|
print("打字机正在工作中...")
|
||||||
|
else:
|
||||||
|
print("打字机当前空闲。")
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 3. API
|
## 3. API 详解
|
||||||
|
|
||||||
* **`TypewriterLogic.new(target_label: Label, typing_speed: float = 20.0)`**
|
* **`TypewriterLogic.new(target_label: Label, typing_speed: float = 20.0)`**
|
||||||
* 构造函数。需要目标 `Label` 和可选的打字速度 (字符/秒)。
|
* **构造函数 (`_init`)**: 创建 `TypewriterLogic` 的一个新实例。
|
||||||
|
* `target_label`: (必需) `Label` 类型的节点,打字效果将应用于此节点。如果无效,将打印错误。
|
||||||
|
* `typing_speed`: (可选) `float` 类型,表示打字速度,单位为“字符/秒”。默认值为 `20.0`。如果速度小于或等于0,文本将立即完全显示。
|
||||||
|
|
||||||
* **`start_typing(full_text: String)`**
|
* **`start_typing(full_text: String)`**
|
||||||
* 方法。开始播放指定文本的打字动画。
|
* **方法**: 开始在关联的 `Label` 上播放指定文本的打字动画。
|
||||||
|
* `full_text`: `String` 类型,要显示的完整文本。
|
||||||
|
* 如果先前有动画正在播放,会先停止旧动画。
|
||||||
|
* 如果 `full_text` 为空字符串,或者 `typing_speed` 设置为0或负数,文本会立即完全显示,并发出 `finished` 信号。
|
||||||
|
|
||||||
* **`skip_typing()`**
|
* **`skip_typing()`**
|
||||||
* 方法。立即停止动画并显示全部文本。
|
* **方法**: 如果当前正在进行打字动画,则立即停止动画并将 `Label` 的文本设置为完整内容。
|
||||||
|
* 如果当前没有在打字,则此方法不执行任何操作。
|
||||||
|
* **注意**: 此方法**不会**发出 `finished` 信号,因为它表示的是非自然完成。如果需要在跳过时执行特定逻辑,应在调用此方法后手动处理。
|
||||||
|
|
||||||
* **`stop_typing()`**
|
* **`stop_typing()`**
|
||||||
* 方法。立即停止动画。
|
* **方法**: 立即停止任何正在进行的打字动画。`Label` 的 `visible_characters` 将停留在被停止时的状态。
|
||||||
|
* 此方法主要用于对话框提前关闭或需要中断效果的场景。
|
||||||
|
* **注意**: 此方法**不会**发出 `finished` 信号。
|
||||||
|
|
||||||
* **`is_typing() -> bool`**
|
* **`is_typing() -> bool`**
|
||||||
* 方法。返回 `true` 如果正在打字。
|
* **方法**: 返回一个布尔值,`true` 表示当前正在进行打字动画,`false` 则表示没有。
|
||||||
|
|
||||||
* **`finished`**
|
* **`finished`**
|
||||||
* 信号。当动画**自然**完成时发出。`skip_typing()` 或 `stop_typing()` 不会触发。
|
* **信号**: 当打字动画**自然**完成(即,所有字符都已按设定速度逐个显示完毕)时发出。
|
||||||
|
* 也会在调用 `start_typing` 时,如果提供的文本为空或打字速度无效(≤0),导致文本立即显示完全时发出。
|
||||||
|
* 通过 `skip_typing()` 或 `stop_typing()` 中断动画**不会**触发此信号。
|
||||||
|
|
||||||
## 4. 注意
|
## 4. 注意事项
|
||||||
|
|
||||||
* 必须关联一个有效的 `Label` 节点。
|
* **有效 `Label`**: `TypewriterLogic` 必须与一个有效的 `Label` 节点关联才能工作。构造时会检查 `Label` 的有效性。
|
||||||
* `Tween` 动画由目标 `Label` 节点管理。
|
* **Tween 管理**: 内部使用 `Tween` 来实现动画效果。`Tween` 实例由 `TypewriterLogic` 创建并附加到 `target_label` 节点上运行。`TypewriterLogic` 负责管理这些 `Tween` 的生命周期(创建、停止、清理)。
|
||||||
|
* **`class_name`**: `TypewriterLogic` 使用 `class_name TypewriterLogic` 声明,这意味着你可以在其他 GDScript 文件中直接使用 `TypewriterLogic` 作为类型提示,例如 `var typewriter: TypewriterLogic`。
|
||||||
|
* **信号连接**: 连接到 `finished` 信号时,请确保 `TypewriterLogic` 实例已成功创建。
|
||||||
|
* **错误处理**: 类内部包含对无效 `Label` 的基本错误打印,但更健壮的错误处理(如游戏崩溃或替代行为)应由调用方代码根据具体需求实现。
|
||||||
```
|
```
|
||||||
|
|||||||
@ -72,7 +72,7 @@ func _on_date_changed(new_date: Dictionary) -> void:
|
|||||||
printerr("警告:接收到的 date_changed 信号数据格式不正确。")
|
printerr("警告:接收到的 date_changed 信号数据格式不正确。")
|
||||||
|
|
||||||
func _on_state_value_changed(key: String, new_value: Variant) -> void:
|
func _on_state_value_changed(key: String, new_value: Variant) -> void:
|
||||||
print("接收到 state_value_changed 信号: key=", key, ", value=", new_value)
|
#print("接收到 state_value_changed 信号: key=", key, ", value=", new_value)
|
||||||
match key:
|
match key:
|
||||||
"money":
|
"money":
|
||||||
money_button.text = _format_value_as_int_string(new_value, "0")
|
money_button.text = _format_value_as_int_string(new_value, "0")
|
||||||
|
|||||||
@ -4,139 +4,149 @@ extends UIPage
|
|||||||
const _TypewriterLogic = preload("res://UI/class/TypewriterLogic.gd")
|
const _TypewriterLogic = preload("res://UI/class/TypewriterLogic.gd")
|
||||||
|
|
||||||
@export var dialogues: Array
|
@export var dialogues: Array
|
||||||
|
@export var default_npc_name = '秘书'
|
||||||
|
|
||||||
|
@onready var npc_icon: TextureRect = $Part_2/npc_icon
|
||||||
|
|
||||||
|
var npc_icon_png_folder = "res://Entity/NPC/art/"
|
||||||
var typing_speed: float = 20.0 # 每秒显示的字符数
|
var typing_speed: float = 20.0 # 每秒显示的字符数
|
||||||
var label_node_path: NodePath = "Part_2/Part_3/Label" # Label节点的路径
|
var label_node_path: NodePath = "Part_2/Part_3/Label" # Label节点的路径
|
||||||
|
|
||||||
# --- 基础变量 ---
|
# --- 基础变量 ---
|
||||||
var node_name: String
|
var node_name: String
|
||||||
# var next_ui_node = null # next_ui_node_path 从 UIPage 继承,这里不需要重复定义
|
|
||||||
var dialogue_queue = []
|
var dialogue_queue = []
|
||||||
var current_dialogue_index = 0
|
var current_dialogue_index = -1 # Initialize to -1, so first advance makes it 0
|
||||||
|
|
||||||
# --- 节点和模块引用 ---
|
# --- 节点和模块引用 ---
|
||||||
var label: Label = null # 缓存Label节点引用
|
var label: Label = null
|
||||||
var typewriter: TypewriterLogic = null # 用于存储 TypewriterLogic 实例
|
var typewriter: TypewriterLogic = null
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
super._ready() # 确保调用父类的 _ready 方法
|
super._ready()
|
||||||
node_name = str(self.name)
|
node_name = str(self.name)
|
||||||
print(node_name + ": _ready executed.")
|
print(node_name + ": _ready executed.")
|
||||||
|
|
||||||
# 尝试获取 Label 节点引用
|
|
||||||
label = get_node_or_null(label_node_path)
|
label = get_node_or_null(label_node_path)
|
||||||
if label == null:
|
if label == null:
|
||||||
printerr(node_name + ": Failed to find Label node at path: ", label_node_path)
|
printerr(node_name + ": Failed to find Label node at path: ", label_node_path)
|
||||||
else:
|
else:
|
||||||
# 2. 创建 TypewriterLogic 实例
|
|
||||||
print(node_name + ": Label found. Creating TypewriterLogic instance.")
|
print(node_name + ": Label found. Creating TypewriterLogic instance.")
|
||||||
typewriter = _TypewriterLogic.new(label, typing_speed)
|
typewriter = _TypewriterLogic.new(label, typing_speed)
|
||||||
# 检查实例是否成功创建 (TypewriterLogic 内部会检查 Label 有效性)
|
|
||||||
if typewriter != null:
|
if typewriter != null:
|
||||||
# 3. 连接 TypewriterLogic 的 finished 信号 (如果需要响应)
|
|
||||||
if not typewriter.is_connected("finished", Callable(self, "_on_dialogue_typing_finished")):
|
if not typewriter.is_connected("finished", Callable(self, "_on_dialogue_typing_finished")):
|
||||||
typewriter.finished.connect(_on_dialogue_typing_finished)
|
typewriter.finished.connect(Callable(self, "_on_dialogue_typing_finished"))
|
||||||
print(node_name + ": TypewriterLogic instance created and signal connected.")
|
print(node_name + ": TypewriterLogic instance created and signal connected.")
|
||||||
else:
|
else:
|
||||||
printerr(node_name + ": Failed to create TypewriterLogic instance.")
|
printerr(node_name + ": Failed to create TypewriterLogic instance.")
|
||||||
|
|
||||||
func _on_page_activated():
|
func _on_page_activated():
|
||||||
super._on_page_activated() # 调用父类的方法
|
super._on_page_activated()
|
||||||
|
if GameState.get_value("dialogue_npc"):
|
||||||
|
var npc_name = GameState.get_value("dialogue_npc")
|
||||||
|
npc_icon.texture = load(npc_icon_png_folder+npc_name+'.png')
|
||||||
|
GameState.set_value("dialogue_npc",null)
|
||||||
|
else:
|
||||||
|
npc_icon.texture = load(npc_icon_png_folder+default_npc_name+'.png')
|
||||||
print(node_name + ": Page activated.")
|
print(node_name + ": Page activated.")
|
||||||
_start(dialogues)
|
_start(dialogues)
|
||||||
|
|
||||||
func _on_page_deactivated():
|
func _on_page_deactivated():
|
||||||
super._on_page_deactivated() # 调用父类的方法
|
super._on_page_deactivated()
|
||||||
print(node_name + ": Page deactivated.")
|
print(node_name + ": Page deactivated.")
|
||||||
# 确保在页面停用时也停止输入处理和可能的游戏暂停状态
|
|
||||||
if typewriter != null:
|
if typewriter != null:
|
||||||
typewriter.stop_typing()
|
typewriter.stop_typing()
|
||||||
|
|
||||||
set_process_input(false)
|
set_process_input(false)
|
||||||
|
|
||||||
|
func _start(p_dialogues) -> void:
|
||||||
# 启动对话框显示
|
|
||||||
func _start(p_dialogues) -> void: # Renamed parameter to avoid conflict
|
|
||||||
print(node_name + ": _start function called.")
|
print(node_name + ": _start function called.")
|
||||||
if p_dialogues is String:
|
if p_dialogues is String:
|
||||||
dialogue_queue = [p_dialogues]
|
dialogue_queue = [p_dialogues]
|
||||||
elif p_dialogues is Array:
|
elif p_dialogues is Array:
|
||||||
dialogue_queue = p_dialogues.duplicate() # 使用 duplicate 以免修改原始导出数组
|
dialogue_queue = p_dialogues.duplicate()
|
||||||
else:
|
else:
|
||||||
printerr(node_name + ": Invalid dialogues data type.")
|
printerr(node_name + ": Invalid dialogues data type.")
|
||||||
dialogue_queue = [] # 置空以避免后续错误
|
dialogue_queue = []
|
||||||
|
|
||||||
current_dialogue_index = 0
|
current_dialogue_index = -1 # Reset index
|
||||||
|
|
||||||
_show_current_dialogue()
|
# Advance to the first dialogue automatically when starting
|
||||||
|
_advance_dialogue_or_finish()
|
||||||
|
|
||||||
set_process_input(true) # 在页面激活时启用输入处理
|
set_process_input(true)
|
||||||
|
|
||||||
|
# Renamed and repurposed: Tries to show next dialogue or finishes the page
|
||||||
|
func _advance_dialogue_or_finish() -> void:
|
||||||
|
current_dialogue_index += 1
|
||||||
|
print(node_name + ": Attempting to advance. New index: ", current_dialogue_index)
|
||||||
|
|
||||||
# 使用 TypewriterLogic 显示当前对话
|
|
||||||
func _show_current_dialogue() -> void:
|
|
||||||
if current_dialogue_index < dialogue_queue.size():
|
if current_dialogue_index < dialogue_queue.size():
|
||||||
if typewriter == null:
|
_show_current_dialogue_line()
|
||||||
printerr(node_name + ": TypewriterLogic instance is null. Cannot display text with effect.")
|
|
||||||
if label != null:
|
|
||||||
label.text = dialogue_queue[current_dialogue_index]
|
|
||||||
label.visible_characters = label.text.length()
|
|
||||||
return
|
|
||||||
|
|
||||||
var full_text = dialogue_queue[current_dialogue_index]
|
|
||||||
print(node_name + ": Requesting typewriter to start typing: '", full_text, "'")
|
|
||||||
typewriter.start_typing(full_text)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# 对话队列结束
|
# All dialogues in this page's queue are finished
|
||||||
print(node_name + ": Dialogue queue finished.")
|
print(node_name + ": Dialogue queue for this page finished. Calling go_next().")
|
||||||
_close_dialogue()
|
go_next() # This will eventually call _close_dialogue and hide the page
|
||||||
|
|
||||||
|
# Renamed to reflect it shows a single line
|
||||||
|
func _show_current_dialogue_line() -> void:
|
||||||
|
if not (current_dialogue_index >= 0 and current_dialogue_index < dialogue_queue.size()):
|
||||||
|
printerr(node_name + ": Invalid current_dialogue_index: ", current_dialogue_index)
|
||||||
|
return
|
||||||
|
|
||||||
# 关闭对话框
|
if typewriter == null:
|
||||||
func _close_dialogue():
|
printerr(node_name + ": TypewriterLogic instance is null. Cannot display text with effect.")
|
||||||
|
if label != null:
|
||||||
|
label.text = dialogue_queue[current_dialogue_index]
|
||||||
|
label.visible_characters = label.text.length()
|
||||||
|
# Manually call finished if no typewriter, as there's no typing to finish
|
||||||
|
_on_dialogue_typing_finished()
|
||||||
|
return
|
||||||
|
|
||||||
|
var full_text = dialogue_queue[current_dialogue_index]
|
||||||
|
print(node_name + ": Requesting typewriter to start typing: '", full_text, "'")
|
||||||
|
typewriter.start_typing(full_text)
|
||||||
|
|
||||||
|
func _close_dialogue(): # This is typically called by go_next() via UIPage's hide_page -> _on_page_deactivated
|
||||||
print(node_name + ": Closing dialogue. Stopping typewriter if active.")
|
print(node_name + ": Closing dialogue. Stopping typewriter if active.")
|
||||||
if typewriter != null:
|
if typewriter != null:
|
||||||
typewriter.stop_typing()
|
typewriter.stop_typing()
|
||||||
|
set_process_input(false)
|
||||||
set_process_input(false) # 在关闭时禁用输入处理
|
|
||||||
print(node_name + ": Dialogue UI processing stopped.")
|
print(node_name + ": Dialogue UI processing stopped.")
|
||||||
|
|
||||||
|
|
||||||
# 处理 TypewriterLogic 发出的 finished 信号的回调函数
|
|
||||||
func _on_dialogue_typing_finished():
|
func _on_dialogue_typing_finished():
|
||||||
print(node_name + ": Received 'finished' signal from TypewriterLogic.")
|
print(node_name + ": Received 'finished' signal from TypewriterLogic for line: '", dialogue_queue[current_dialogue_index] if current_dialogue_index < dialogue_queue.size() and current_dialogue_index >=0 else "N/A" , "'")
|
||||||
# 文本自然显示完毕后的逻辑。
|
# Current line finished typing. Ready for next input.
|
||||||
# 例如,可以显示一个“点击继续”的提示图标。
|
# You could show a "continue" prompt icon here if desired.
|
||||||
# 对于当前的“点击任意处继续”逻辑,此函数可能不需要执行太多操作,
|
|
||||||
# 因为 _input 函数会处理点击事件。
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# --- 输入处理 ---
|
|
||||||
# 新增/修改: 处理输入事件,特别是鼠标左键点击
|
|
||||||
func _input(event: InputEvent) -> void:
|
func _input(event: InputEvent) -> void:
|
||||||
# 只有当页面可见且输入处理已启用时才处理输入
|
if not visible: # Only process if page is visible
|
||||||
# (set_process_input(true) 会在 _start 中调用)
|
|
||||||
# (visible 状态由 MainController 和 UIPage 的 show_page/hide_page 管理)
|
|
||||||
if not visible:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if event is InputEventMouseButton:
|
var relevant_click = false
|
||||||
if event.button_index == MOUSE_BUTTON_LEFT and event.is_pressed():
|
if event is InputEventMouseButton and event.is_pressed():
|
||||||
print(node_name + ": Left-click detected.")
|
if event.button_index == MOUSE_BUTTON_LEFT or event.button_index == MOUSE_BUTTON_RIGHT:
|
||||||
|
relevant_click = true
|
||||||
|
|
||||||
# 行为1: 如果打字机正在打字,则立即完成当前行打字 (如果TypewriterLogic支持)
|
if relevant_click:
|
||||||
# 行为2: 如果打字机已完成或未激活,则调用 go_next()
|
get_viewport().set_input_as_handled() # Consume the click event early
|
||||||
# 当前的 TypewriterLogic 没有明确的 is_typing 或 skip_to_end 方法,
|
print(node_name + ": Relevant mouse click detected (Left or Right).")
|
||||||
# 所以我们直接调用 go_next()。
|
|
||||||
# go_next() -> _close_dialogue() -> typewriter.stop_typing() 会停止打字。
|
|
||||||
|
|
||||||
print(node_name + ": Calling go_next() due to left-click.")
|
# Behavior 1: If typewriter is currently typing, skip to the end of the current line.
|
||||||
go_next()
|
# Requires TypewriterLogic to have is_typing() and skip_to_end() methods.
|
||||||
get_viewport().set_input_as_handled() # 消费事件,防止其他节点处理
|
if typewriter != null and typewriter.is_typing():
|
||||||
return # 事件已处理
|
print(node_name + ": Typewriter is typing. Calling skip_typing().")
|
||||||
|
typewriter.skip_typing() # This should make it emit 'finished' signal
|
||||||
|
return # Wait for next click to advance dialogue
|
||||||
|
|
||||||
# 调用父类 (UIPage) 的 _input 方法,以保留其功能 (例如右键返回)
|
# Behavior 2: If typewriter is NOT typing (or no typewriter), advance to the next dialogue or finish.
|
||||||
# 如果此处的左键点击事件被处理并返回,则父类的 _input 不会再收到此特定事件。
|
print(node_name + ": Typewriter not typing or no typewriter. Advancing dialogue or finishing.")
|
||||||
super._input(event)
|
_advance_dialogue_or_finish()
|
||||||
|
return
|
||||||
|
|
||||||
|
# If not a relevant click for dialogue, pass to super class (e.g., for other UI interactions)
|
||||||
|
# Note: If you want right-click to *only* advance dialogue and not trigger parent's go_back,
|
||||||
|
# this structure is correct because we consume the event.
|
||||||
|
# If UIPage's _input handles other specific mouse buttons (e.g. middle mouse) or other event types,
|
||||||
|
# they will still be processed if not handled above.
|
||||||
|
if not relevant_click: # Only call super if we didn't handle it
|
||||||
|
super._input(event)
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
[gd_scene load_steps=8 format=3 uid="uid://dtywh0m5odikx"]
|
[gd_scene load_steps=7 format=3 uid="uid://dtywh0m5odikx"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://dml4o41teef7h" path="res://UI/popup/dialogue.gd" id="1_ilhgc"]
|
[ext_resource type="Script" uid="uid://dml4o41teef7h" path="res://UI/popup/dialogue.gd" id="1_ilhgc"]
|
||||||
[ext_resource type="Texture2D" uid="uid://pucudatqrcrq" path="res://UI/popup/popup_bg_1.png" id="2_ilhgc"]
|
[ext_resource type="Texture2D" uid="uid://pucudatqrcrq" path="res://UI/popup/popup_bg_1.png" id="2_ilhgc"]
|
||||||
[ext_resource type="FontFile" uid="uid://egugs822n8gr" path="res://UI/font/AlimamaFangYuanTiVF-Thin.ttf" id="3_ilhgc"]
|
[ext_resource type="FontFile" uid="uid://egugs822n8gr" path="res://UI/font/AlimamaFangYuanTiVF-Thin.ttf" id="3_ilhgc"]
|
||||||
[ext_resource type="Texture2D" uid="uid://bb3kyiufyyj05" path="res://Entity/NPC/NPC_1_UI.png" id="3_nrcga"]
|
|
||||||
|
|
||||||
[sub_resource type="Animation" id="Animation_ilhgc"]
|
[sub_resource type="Animation" id="Animation_ilhgc"]
|
||||||
length = 0.001
|
length = 0.001
|
||||||
@ -178,7 +177,7 @@ libraries = {
|
|||||||
}
|
}
|
||||||
autoplay = "base"
|
autoplay = "base"
|
||||||
|
|
||||||
[node name="Human" type="TextureRect" parent="Part_2"]
|
[node name="npc_icon" type="TextureRect" parent="Part_2"]
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
anchors_preset = 3
|
anchors_preset = 3
|
||||||
anchor_left = 1.0
|
anchor_left = 1.0
|
||||||
@ -191,4 +190,3 @@ offset_right = -11.0
|
|||||||
offset_bottom = -4.0
|
offset_bottom = -4.0
|
||||||
grow_horizontal = 0
|
grow_horizontal = 0
|
||||||
grow_vertical = 0
|
grow_vertical = 0
|
||||||
texture = ExtResource("3_nrcga")
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
[ext_resource type="Script" uid="uid://by3rdgo6jlbff" path="res://UI/popup/task_development/main_plan/strategy/strategy.gd" id="1_pbd5q"]
|
[ext_resource type="Script" uid="uid://by3rdgo6jlbff" path="res://UI/popup/task_development/main_plan/strategy/strategy.gd" id="1_pbd5q"]
|
||||||
[ext_resource type="Texture2D" uid="uid://pucudatqrcrq" path="res://UI/popup/popup_bg_1.png" id="2_eh5ff"]
|
[ext_resource type="Texture2D" uid="uid://pucudatqrcrq" path="res://UI/popup/popup_bg_1.png" id="2_eh5ff"]
|
||||||
[ext_resource type="Theme" uid="uid://ddq54ba6vwyn0" path="res://UI/popup/task_development/main_plan/gameplay/gameplay_option_button.tres" id="3_rq5uk"]
|
[ext_resource type="Theme" uid="uid://ddq54ba6vwyn0" path="res://UI/popup/task_development/main_plan/gameplay/gameplay_option_button.tres" id="3_rq5uk"]
|
||||||
[ext_resource type="Texture2D" uid="uid://bb3kyiufyyj05" path="res://Entity/NPC/NPC_1_UI.png" id="4_vx267"]
|
[ext_resource type="Texture2D" uid="uid://bb3kyiufyyj05" path="res://Entity/NPC/art/秘书.png" id="4_vx267"]
|
||||||
|
|
||||||
[node name="strategy" type="Control"]
|
[node name="strategy" type="Control"]
|
||||||
visible = false
|
visible = false
|
||||||
|
|||||||
@ -28,10 +28,11 @@ var _power_bar_segments: Array[ColorRect] = [] # 用于存储体力条的各个
|
|||||||
var _all_npcs_data: Dictionary = {} # 存储从 GameState 加载的所有NPC原始数据
|
var _all_npcs_data: Dictionary = {} # 存储从 GameState 加载的所有NPC原始数据
|
||||||
var enabled_npc_keys: Array[String] = [] # 存储所有当前可选的NPC的键 (名字)
|
var enabled_npc_keys: Array[String] = [] # 存储所有当前可选的NPC的键 (名字)
|
||||||
var current_npc_index: int = -1 # 当前在 enabled_npc_keys 数组中选中的NPC的索引
|
var current_npc_index: int = -1 # 当前在 enabled_npc_keys 数组中选中的NPC的索引
|
||||||
|
var temp_next_ui_node_path = ''
|
||||||
|
|
||||||
# --- 常量 ---
|
# --- 常量 ---
|
||||||
const NPC_ICON_BASE_PATH = "res://Entity/NPC/" # NPC 图标的基础路径 (如果后续有 Icon 字段)
|
const NPC_ICON_BASE_PATH = "res://Entity/NPC/art/" # NPC 图标的基础路径 (如果后续有 Icon 字段)
|
||||||
const DEFAULT_NPC_ICON_PATH = "res://Entity/NPC/NPC_1_UI.png" # 默认/占位NPC图标
|
const DEFAULT_NPC_ICON_PATH = "res://Entity/NPC/art/秘书.png" # 默认/占位NPC图标
|
||||||
|
|
||||||
const POWER_CURRENT_COLOR = Color.GREEN_YELLOW # 当前体力颜色
|
const POWER_CURRENT_COLOR = Color.GREEN_YELLOW # 当前体力颜色
|
||||||
const POWER_MAX_POTENTIAL_COLOR = Color(0.2, 0.4, 0.2, 0.8) # 最大潜力槽颜色 (稍暗的绿色)
|
const POWER_MAX_POTENTIAL_COLOR = Color(0.2, 0.4, 0.2, 0.8) # 最大潜力槽颜色 (稍暗的绿色)
|
||||||
@ -43,6 +44,8 @@ func _ready() -> void:
|
|||||||
var node_name = str(self.name)
|
var node_name = str(self.name)
|
||||||
add_to_group(node_name) # 方便父节点或其他系统查找
|
add_to_group(node_name) # 方便父节点或其他系统查找
|
||||||
|
|
||||||
|
temp_next_ui_node_path = next_ui_node_path
|
||||||
|
|
||||||
# 收集体力条的片段
|
# 收集体力条的片段
|
||||||
for child in power_bar_segments_container.get_children():
|
for child in power_bar_segments_container.get_children():
|
||||||
if child is ColorRect:
|
if child is ColorRect:
|
||||||
@ -184,7 +187,7 @@ func _display_current_npc() -> void:
|
|||||||
npc_level_label.text = "Lv" + str(int(npc_info.get("level", 1)))
|
npc_level_label.text = "Lv" + str(int(npc_info.get("level", 1)))
|
||||||
|
|
||||||
# 更新图标 (后续会从npc_info.Icon获取)
|
# 更新图标 (后续会从npc_info.Icon获取)
|
||||||
var icon_name_from_data = npc_info.get("Icon", "") # 假设后续会有这个字段
|
var icon_name_from_data = npc_info.get("icon", "") # 假设后续会有这个字段
|
||||||
if not icon_name_from_data.is_empty():
|
if not icon_name_from_data.is_empty():
|
||||||
var dynamic_icon_path = NPC_ICON_BASE_PATH + icon_name_from_data + ".png" # 假设文件名规则
|
var dynamic_icon_path = NPC_ICON_BASE_PATH + icon_name_from_data + ".png" # 假设文件名规则
|
||||||
if ResourceLoader.exists(dynamic_icon_path):
|
if ResourceLoader.exists(dynamic_icon_path):
|
||||||
@ -251,13 +254,14 @@ func _on_confirm_pressed() -> void:
|
|||||||
var selected_npc_key = enabled_npc_keys[current_npc_index]
|
var selected_npc_key = enabled_npc_keys[current_npc_index]
|
||||||
|
|
||||||
# 导航到下一个页面或结束工作流
|
# 导航到下一个页面或结束工作流
|
||||||
|
next_ui_node_path = temp_next_ui_node_path
|
||||||
if GameState.get_value("money") < int(cost_label.text):
|
if GameState.get_value("money") < int(cost_label.text):
|
||||||
next_ui_node_path = "../notice_2"
|
next_ui_node_path = "../notice_2"
|
||||||
go_next()
|
go_next()
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
next_ui_node_path = ""
|
|
||||||
var new_money = GameState.get_value("money")-get_main_data("预算")
|
var new_money = GameState.get_value("money")-get_main_data("预算")
|
||||||
GameState.set_value("money",new_money)
|
GameState.set_value("money",new_money)
|
||||||
|
#GameState.set_value("dialogue_npc",selected_npc_key)
|
||||||
set_main_data("关键环节负责人", selected_npc_key)
|
set_main_data("关键环节负责人", selected_npc_key)
|
||||||
go_next()
|
go_next()
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
[ext_resource type="Texture2D" uid="uid://pucudatqrcrq" path="res://UI/popup/popup_bg_1.png" id="2_oyv27"]
|
[ext_resource type="Texture2D" uid="uid://pucudatqrcrq" path="res://UI/popup/popup_bg_1.png" id="2_oyv27"]
|
||||||
[ext_resource type="Texture2D" uid="uid://dgcugleiv7sfw" path="res://UI/popup/task_development/arrow.png" id="3_qga8r"]
|
[ext_resource type="Texture2D" uid="uid://dgcugleiv7sfw" path="res://UI/popup/task_development/arrow.png" id="3_qga8r"]
|
||||||
[ext_resource type="FontFile" uid="uid://egugs822n8gr" path="res://UI/font/AlimamaFangYuanTiVF-Thin.ttf" id="4_mk7go"]
|
[ext_resource type="FontFile" uid="uid://egugs822n8gr" path="res://UI/font/AlimamaFangYuanTiVF-Thin.ttf" id="4_mk7go"]
|
||||||
[ext_resource type="Texture2D" uid="uid://hdidwixuokxn" path="res://Entity/NPC/npc_ability_icon.png" id="5_8ts75"]
|
[ext_resource type="Texture2D" uid="uid://hdidwixuokxn" path="res://Entity/NPC/art/npc_ability_icon.png" id="5_8ts75"]
|
||||||
[ext_resource type="LabelSettings" uid="uid://qcn0aduvrgvw" path="res://UI/tres/task_development_platform_label_settings.tres" id="6_3iojh"]
|
[ext_resource type="LabelSettings" uid="uid://qcn0aduvrgvw" path="res://UI/tres/task_development_platform_label_settings.tres" id="6_3iojh"]
|
||||||
[ext_resource type="Theme" uid="uid://bau80ps6kx783" path="res://UI/tres/Bottom_Info_button_theme.tres" id="7_mchvh"]
|
[ext_resource type="Theme" uid="uid://bau80ps6kx783" path="res://UI/tres/Bottom_Info_button_theme.tres" id="7_mchvh"]
|
||||||
|
|
||||||
|
|||||||
@ -5,9 +5,9 @@
|
|||||||
[ext_resource type="Texture2D" uid="uid://dgcugleiv7sfw" path="res://UI/popup/task_development/arrow.png" id="3_uudne"]
|
[ext_resource type="Texture2D" uid="uid://dgcugleiv7sfw" path="res://UI/popup/task_development/arrow.png" id="3_uudne"]
|
||||||
[ext_resource type="FontFile" uid="uid://egugs822n8gr" path="res://UI/font/AlimamaFangYuanTiVF-Thin.ttf" id="4_csatq"]
|
[ext_resource type="FontFile" uid="uid://egugs822n8gr" path="res://UI/font/AlimamaFangYuanTiVF-Thin.ttf" id="4_csatq"]
|
||||||
[ext_resource type="LabelSettings" uid="uid://qcn0aduvrgvw" path="res://UI/tres/task_development_platform_label_settings.tres" id="5_l6j0s"]
|
[ext_resource type="LabelSettings" uid="uid://qcn0aduvrgvw" path="res://UI/tres/task_development_platform_label_settings.tres" id="5_l6j0s"]
|
||||||
[ext_resource type="Texture2D" uid="uid://bb3kyiufyyj05" path="res://Entity/NPC/NPC_1_UI.png" id="5_uudne"]
|
[ext_resource type="Texture2D" uid="uid://bb3kyiufyyj05" path="res://Entity/NPC/art/秘书.png" id="5_uudne"]
|
||||||
[ext_resource type="Theme" uid="uid://bau80ps6kx783" path="res://UI/tres/Bottom_Info_button_theme.tres" id="6_6v1sj"]
|
[ext_resource type="Theme" uid="uid://bau80ps6kx783" path="res://UI/tres/Bottom_Info_button_theme.tres" id="6_6v1sj"]
|
||||||
[ext_resource type="Texture2D" uid="uid://hdidwixuokxn" path="res://Entity/NPC/npc_ability_icon.png" id="6_ybd2x"]
|
[ext_resource type="Texture2D" uid="uid://hdidwixuokxn" path="res://Entity/NPC/art/npc_ability_icon.png" id="6_ybd2x"]
|
||||||
|
|
||||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_6a8uh"]
|
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_6a8uh"]
|
||||||
|
|
||||||
|
|||||||
@ -63,13 +63,13 @@ parent_page_node_path = NodePath("..")
|
|||||||
[node name="product_focus" parent="." instance=ExtResource("7_l1sf4")]
|
[node name="product_focus" parent="." instance=ExtResource("7_l1sf4")]
|
||||||
visible = false
|
visible = false
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
next_ui_node_path = NodePath("../dialogue")
|
next_ui_node_path = NodePath("../dialogue_secretary")
|
||||||
back_ui_node_path = NodePath("../main_plan")
|
back_ui_node_path = NodePath("../main_plan")
|
||||||
|
|
||||||
[node name="dialogue" parent="." instance=ExtResource("8_6il88")]
|
[node name="dialogue_secretary" parent="." instance=ExtResource("8_6il88")]
|
||||||
visible = false
|
visible = false
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
dialogues = ["谁来写立项书呢?"]
|
dialogues = ["由谁来写立项书呢?", "立项书只能由公司员工完成。"]
|
||||||
next_ui_node_path = NodePath("../npc_select_1")
|
next_ui_node_path = NodePath("../npc_select_1")
|
||||||
back_ui_node_path = NodePath("../npc_select_1")
|
back_ui_node_path = NodePath("../npc_select_1")
|
||||||
|
|
||||||
@ -77,8 +77,14 @@ back_ui_node_path = NodePath("../npc_select_1")
|
|||||||
visible = false
|
visible = false
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
Suitable_position = ["项目总监", "策划", "美术设计师"]
|
Suitable_position = ["项目总监", "策划", "美术设计师"]
|
||||||
|
next_ui_node_path = NodePath("../dialogue_npc")
|
||||||
back_ui_node_path = NodePath("../main_plan")
|
back_ui_node_path = NodePath("../main_plan")
|
||||||
|
|
||||||
|
[node name="dialogue_npc" parent="." instance=ExtResource("8_6il88")]
|
||||||
|
visible = false
|
||||||
|
layout_mode = 1
|
||||||
|
dialogues = ["感谢给我这个机会,我会尽力!"]
|
||||||
|
|
||||||
[node name="notice_1" parent="." instance=ExtResource("10_5pged")]
|
[node name="notice_1" parent="." instance=ExtResource("10_5pged")]
|
||||||
visible = false
|
visible = false
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
|
|||||||