godot-turn-system
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTurn System
回合系统
Turn order calculation, action points, phase management, and timeline systems define turn-based combat.
回合顺序计算、行动点数、阶段管理和时间线系统构成了回合制战斗的核心。
Available Scripts
可用脚本
active_time_battle.gd
active_time_battle.gd
Framework for Active Time Battle (ATB) systems with async action support.
支持异步动作的动态时间战斗(ATB)系统框架。
timeline_turn_manager.gd
timeline_turn_manager.gd
Expert timeline-based turn manager with interrupts and simultaneous actions.
专业级基于时间线的回合管理器,支持打断机制和同步动作。
NEVER Do in Turn Systems
回合系统的禁止做法
- NEVER recalculate turn order every action — Sort 50 combatants after every move? O(n log n) × actions = lag. Calculate once per round, update on stat changes only.
- NEVER use speed ties without determinism — Two units same speed, random order? Non-reproducible replays. Break ties with secondary stat (ID, position, etc.).
- NEVER forget to validate action costs — Allow action without checking points? Negative AP = exploits. ALWAYS before deducting.
if can_perform_action(cost) - NEVER hardcode phase transitions — for 10 phases? Unmaintainable. Use enum + match OR array of phase handlers.
if phase == 0: phase = 1 - NEVER skip turn timeout for networked games — Wait forever for player input? Griefing exploit. ALWAYS implement turn timer with default action.
- NEVER emit turn_ended before cleanup — Signal listeners start next turn, previous hasn't cleaned up? State corruption. Cleanup FIRST, then emit.
gdscript
undefined- 绝对不要每次行动后都重新计算回合顺序——每次行动后都给50个战斗单位排序?O(n log n)复杂度 × 行动次数 = 卡顿。每轮仅计算一次,仅在属性变化时更新即可。
- 速度相同的情况下绝对不要使用非确定性排序——两个单位速度相同就随机排序?会导致回放无法复现。使用次要属性(ID、位置等)来打破平局。
- 绝对不要忘记验证行动消耗——不检查点数就允许行动?负AP会导致漏洞。扣除点数前务必先执行判断。
if can_perform_action(cost) - 绝对不要硬编码阶段跳转——10个阶段就写这种代码?完全无法维护。建议使用枚举+match语法,或者阶段处理函数数组。
if phase == 0: phase = 1 - 网络游戏中绝对不要省略回合超时机制——永远等待玩家输入?会导致恶意挂机漏洞。务必实现带有默认行动的回合计时器。
- 清理工作完成前绝对不要发送turn_ended信号——信号监听器会启动下一回合,但上一回合还没完成清理?会导致状态损坏。先完成清理,再发送信号。
gdscript
undefinedturn_manager.gd (AutoLoad)
turn_manager.gd (AutoLoad)
extends Node
signal turn_started(combatant: Node)
signal turn_ended(combatant: Node)
signal round_ended
var combatants: Array[Node] = []
var turn_order: Array[Node] = []
var current_turn_index: int = 0
func start_combat(participants: Array[Node]) -> void:
combatants = participants
calculate_turn_order()
start_next_turn()
func calculate_turn_order() -> void:
turn_order = combatants.duplicate()
turn_order.sort_custom(func(a, b): return a.speed > b.speed)
func start_next_turn() -> void:
if current_turn_index >= turn_order.size():
current_turn_index = 0
round_ended.emit()
calculate_turn_order() # Recalculate each round
var current := turn_order[current_turn_index]
turn_started.emit(current)func end_turn() -> void:
var current := turn_order[current_turn_index]
turn_ended.emit(current)
current_turn_index += 1
start_next_turn()
undefinedextends Node
signal turn_started(combatant: Node)
signal turn_ended(combatant: Node)
signal round_ended
var combatants: Array[Node] = []
var turn_order: Array[Node] = []
var current_turn_index: int = 0
func start_combat(participants: Array[Node]) -> void:
combatants = participants
calculate_turn_order()
start_next_turn()
func calculate_turn_order() -> void:
turn_order = combatants.duplicate()
turn_order.sort_custom(func(a, b): return a.speed > b.speed)
func start_next_turn() -> void:
if current_turn_index >= turn_order.size():
current_turn_index = 0
round_ended.emit()
calculate_turn_order() # Recalculate each round
var current := turn_order[current_turn_index]
turn_started.emit(current)func end_turn() -> void:
var current := turn_order[current_turn_index]
turn_ended.emit(current)
current_turn_index += 1
start_next_turn()
undefinedAction Point System
行动点数系统
gdscript
undefinedgdscript
undefinedcombatant.gd
combatant.gd
extends Node
@export var max_action_points: int = 3
var current_action_points: int = 3
func start_turn() -> void:
current_action_points = max_action_points
func can_perform_action(cost: int) -> bool:
return current_action_points >= cost
func perform_action(cost: int) -> bool:
if not can_perform_action(cost):
return false
current_action_points -= cost
return trueundefinedextends Node
@export var max_action_points: int = 3
var current_action_points: int = 3
func start_turn() -> void:
current_action_points = max_action_points
func can_perform_action(cost: int) -> bool:
return current_action_points >= cost
func perform_action(cost: int) -> bool:
if not can_perform_action(cost):
return false
current_action_points -= cost
return trueundefinedTurn Phases
回合阶段
gdscript
enum Phase { DRAW, MAIN, END }
var current_phase: Phase = Phase.DRAW
func advance_phase() -> void:
match current_phase:
Phase.DRAW:
current_phase = Phase.MAIN
Phase.MAIN:
current_phase = Phase.END
Phase.END:
TurnManager.end_turn()
current_phase = Phase.DRAWgdscript
enum Phase { DRAW, MAIN, END }
var current_phase: Phase = Phase.DRAW
func advance_phase() -> void:
match current_phase:
Phase.DRAW:
current_phase = Phase.MAIN
Phase.MAIN:
current_phase = Phase.END
Phase.END:
TurnManager.end_turn()
current_phase = Phase.DRAWBest Practices
最佳实践
- Speed-Based - Initiative determines order
- Action Points - Limit actions per turn
- Timeout - Add turn timer for online play
- 基于速度——主动权决定回合顺序
- 行动点数——限制每回合可执行的动作数量
- 超时机制——为在线对局添加回合计时器
Reference
参考
- Related: ,
godot-combat-systemgodot-rpg-stats
- 相关内容:、
godot-combat-systemgodot-rpg-stats
Related
相关内容
- Master Skill: godot-master
- 核心技能:godot-master