如何在Godot中循环补间动画且避免重复代码段?
问题
需要让角色在两个位置间循环移动,流程为:Idle→奔跑并右移→Idle→奔跑并左移→(重复)。目前原代码可正常运行,但Idle和Run代码段重复编写,十分繁琐。尝试简化代码后,发现循环时变量传递的是初始字面量而非更新后的值,请问该如何解决?
原实现代码
extends Sprite func _ready(): var tween = get_tree().create_tween().set_loops() ## Idle 1 ## tween.tween_callback(animation_player,"play",["Idle"]) # plays idle animation tween.tween_interval(2) ## ## Running 1 ## tween.tween_callback(animation_player,"play",["Running"]) # starts running animation tween.tween_property(self,"flip_h", false, 0) tween.tween_property(self,"position:x", 500.0, 2) # move position to 1000 ## ## Idle 2 ## tween.tween_callback(animation_player,"play",["Idle"]) # plays idle animation tween.tween_interval(2) ## ## Running 2 ## tween.tween_callback(animation_player,"play",["Running"]) # starts running animation tween.tween_property(self,"flip_h", true, 0) tween.tween_property(self,"position:x", -500.0, 2) # move position to 1000 ##
尝试简化的代码
func _ready(): var tween = get_tree().create_tween().set_loops() ## Idle ## tween.tween_callback(animation_player,"play",["Idle"]) # plays idle animation tween.tween_interval(2) # pause for 2 seconds ## ## Running ## tween.tween_callback(animation_player,"play",["Running"]) # starts running animation tween.tween_property(self,"flip_h", !flip_h, 0) tween.tween_property(self,"position:x", position.x*-1, 2) # move position to 1000 ##
解决方案
核心问题是:_ready中初始化Tween时,!flip_h和position.x*-1会被直接计算为初始值,后续循环不会重新读取当前属性状态,导致无法动态更新。
解决思路是用回调函数封装动态逻辑,让Tween每次循环时调用自定义方法,在方法内实时获取当前属性值并计算目标状态。
优化后代码(通用相反数位置)
extends Sprite func _ready(): var tween = get_tree().create_tween().set_loops() # 构建循环序列:Idle → 奔跑移动 → 重复 while true: # Idle阶段 tween.tween_callback(animation_player, "play", ["Idle"]) tween.tween_interval(2) # 调用自定义奔跑移动方法 tween.tween_callback(self, "run_to_opposite") func run_to_opposite(): # 播放奔跑动画 animation_player.play("Running") # 实时翻转朝向 flip_h = !flip_h # 实时计算目标X位置(当前位置的相反数) var target_x = position.x * -1 # 创建子Tween处理移动,避免干扰主序列 get_tree().create_tween().tween_property(self, "position:x", target_x, 2)
优化后代码(固定目标位置)
如果两个目标位置是固定值(比如-500和500),可以提前定义常量,逻辑更清晰:
extends Sprite const LEFT_POS = -500.0 const RIGHT_POS = 500.0 func _ready(): var tween = get_tree().create_tween().set_loops() while true: tween.tween_callback(animation_player, "play", ["Idle"]) tween.tween_interval(2) tween.tween_callback(self, "run_to_target") func run_to_target(): animation_player.play("Running") # 实时判断目标位置 var target_x = position.x == LEFT_POS ? RIGHT_POS : LEFT_POS # 根据目标位置翻转朝向 flip_h = target_x < position.x get_tree().create_tween().tween_property(self, "position:x", target_x, 2)
关键说明
- 自定义方法
run_to_opposite/run_to_target会在每次循环时被调用,实时读取当前的flip_h和position状态,解决了字面量不更新的问题。 - 用
while true在主Tween中构建重复序列,彻底避免代码重复。 - 在回调方法内创建子Tween处理移动,确保动画和主序列同步执行。
内容的提问来源于stack exchange,提问作者cak3_lover
相关产品推荐
相关产品推荐

