You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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)

关键说明

  1. 自定义方法run_to_opposite/run_to_target会在每次循环时被调用,实时读取当前的flip_h和position状态,解决了字面量不更新的问题。
  2. 用while true在主Tween中构建重复序列,彻底避免代码重复。
  3. 在回调方法内创建子Tween处理移动,确保动画和主序列同步执行。

内容的提问来源于stack exchange,提问作者cak3_lover

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 22:01:17