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

如何绕非原点(质心)正确旋转SKSpriteNode?

解决SpriteKit节点绕质心旋转并同步朝向的问题

需求背景

在GameScene中存在一组排列规整的SKSpriteNode,位置按固定间隔分布(例如(0, 0)、(0, 150)、(0, 300)),需要实现以下效果:

  • 所有节点围绕它们的位置质心进行旋转
  • 每个节点的朝向与旋转方向保持一致

初始方案与问题

最初尝试将所有节点放入一个容器SKNode,通过旋转容器实现整体旋转。这种方式虽然能完成旋转,但无法单独控制每个节点的zRotation和position,因此改用2D旋转矩阵实现。但最初的矩阵应用代码存在以下问题:

  • 节点顺时针旋转至约180度后会出现原地抖动
  • 反向旋转时无法回到初始位置
  • 多次拖动控制滑块后,节点会逐渐向质心收敛

修正后的实现方案

核心思路是先将节点的位置平移至以质心为原点的坐标系,再应用旋转矩阵计算新位置,同时根据滑块的当前值直接设置节点的zRotation,确保朝向与旋转方向同步。

核心代码

@objc func sliderValueDidChange(_ sender: UISlider) {
    guard let scene = view.scene as? GameScene else { return }
    let nodes = scene.nodes
    let angleChange = (prevSliderVal - CGFloat(sender.value)) / 180 * .pi
    var cenX = CGFloat.zero
    var cenY = CGFloat.zero
    for node in nodes {
        cenX += node.position.x
        cenY += node.position.y
    }
    cenX = cenX / CGFloat(nodes.count)
    cenY = cenY / CGFloat(nodes.count)
    for node in nodes {
        let translatedPos = CGPoint(x: node.position.x - cenX,
                                    y: node.position.y - cenY)
        let newX = translatedPos.x * cos(angleChange) - translatedPos.y * sin(angleChange)
        let newY = translatedPos.x * sin(angleChange) + translatedPos.y * cos(angleChange)
        node.position = CGPoint(x: newX, y: newY)
        let a = CGFloat(sender.value) / 180 * .pi
        node.zRotation = -a
    }
    prevSliderVal = CGFloat(sender.value)
}

内容的提问来源于stack exchange,提问作者michael.yql

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 16:35:10