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

SceneKit动画播放后停留在最后帧及反向动画问题求助

解决SceneKit动画播放后复位、反向动画无效问题

核心修改点

要实现动画停留在最后帧、支持反向播放且可重复执行,需调整以下关键属性:

  • 设置animation.isRemovedOnCompletion = false:避免动画完成后被自动移除
  • 设置animation.fillMode = .forwards:让节点保持动画最后一帧的状态
  • 避免动画播放器状态丢失,确保每次播放时正确控制进度
  • 修复代码中变量名冲突问题(循环内的animation与参数重名)

修改后的正向播放代码

private func playAnimation(with targetAnimation: ARAnimation) {
    for object in virtualObjectLoader.loadedObjects {
        guard object.hash == targetAnimation.objectSystemHash else { continue }
        
        object.enumerateChildNodes { (child, stop) in
            guard !child.animationKeys.isEmpty else { return }
            
            for key in targetAnimation.animationKeys {
                guard let animationPlayer = child.animationPlayer(forKey: key) else { continue }
                
                // 重置播放器状态,确保从起始位置播放
                animationPlayer.stop()
                animationPlayer.currentTime = 0
                
                // 配置动画属性
                let animation = animationPlayer.animation
                animation.repeatCount = 0
                animation.isRemovedOnCompletion = false
                animation.fillMode = .forwards
                
                // 正向播放
                animationPlayer.speed = 1
                animationPlayer.play()
            }
        }
    }
    reserveAnimationButton.isHidden = false
    playedAnimation = targetAnimation
}

修改后的反向播放代码

private func reverseAnimation() {
    guard let targetAnimation = playedAnimation else { return }
    
    for object in virtualObjectLoader.loadedObjects {
        guard object.hash == targetAnimation.objectSystemHash else { continue }
        
        object.enumerateChildNodes { (child, stop) in
            guard !child.animationKeys.isEmpty else { return }
            
            for key in targetAnimation.animationKeys {
                guard let animationPlayer = child.animationPlayer(forKey: key) else { continue }
                
                // 确保动画停留在当前帧,配置反向播放属性
                let animation = animationPlayer.animation
                animation.isRemovedOnCompletion = false
                animation.fillMode = .forwards
                
                // 反向播放:如果当前已在起始位置,先跳转到结束位置
                if animationPlayer.currentTime <= 0 {
                    animationPlayer.currentTime = animation.duration
                }
                
                animationPlayer.speed = -1
                animationPlayer.play()
            }
        }
    }
    reserveAnimationButton.isHidden = true
}

关键修改说明

  1. 变量名冲突修复:将参数animation改为targetAnimation,避免与循环内的动画变量重名,防止逻辑混乱。
  2. 动画保留与状态保持:正反向播放时都设置isRemovedOnCompletion = false和fillMode = .forwards,确保动画完成后节点不会回到初始状态。
  3. 正向播放重置:每次正向播放前停止播放器并重置currentTime到0,保证每次都从动画开头播放。
  4. 反向播放处理:检查播放器当前时间,若已在起始位置则将currentTime设为动画总时长,确保反向播放从最后一帧回到起始帧;设置speed = -1实现反向播放。
  5. 效率优化:遍历对象时先判断hash是否匹配,减少不必要的节点遍历。

修改后,动画播放完成会停留在最后帧,反向动画可正常从最后帧回到初始帧,且整个流程可重复执行(正向→反向→正向循环),动画不会被移除。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 11:57:26