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

能否让SKCameraNode的setScale()排除特定子节点不参与缩放?

实现SKScene部分子节点的缩放控制

你当前通过缩放SKCameraNode实现的是整个场景的视觉缩放,要只让部分子节点参与缩放,可以用以下两种方案:

方案一:用容器节点分组管理(推荐)

核心思路是把需要缩放的节点统一放到一个容器节点里,捏合手势时只缩放这个容器,而非相机。不需要缩放的节点直接添加到场景根节点,完全不受容器缩放影响。

修改后的代码示例:

class GameScene: SKScene {
    // 定义缩放容器
    private let scaleContainer = SKNode()
    // 记录上一次的容器缩放值
    private var previousContainerScale: CGFloat = 1.0

    override func didMove(to view: SKView) {
        // 添加缩放容器到场景
        self.addChild(scaleContainer)
        
        // ---- 把需要缩放的子节点添加到scaleContainer里 ----
        let scalableSprite = SKSpriteNode(color: .red, size: CGSize(width: 100, height: 100))
        scalableSprite.position = self.midPoint
        scaleContainer.addChild(scalableSprite)
        
        // ---- 不需要缩放的节点直接添加到场景 ----
        let fixedSprite = SKSpriteNode(color: .blue, size: CGSize(width: 50, height: 50))
        fixedSprite.position = CGPoint(x: self.midPoint.x + 200, y: self.midPoint.y)
        self.addChild(fixedSprite)
        
        // 添加捏合手势
        let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(scaleContainer(_:)))
        view.addGestureRecognizer(pinchGesture)
    }

    @objc func scaleContainer(_ sender: UIPinchGestureRecognizer) {
        guard sender.state == .began || sender.state == .changed else { return }
        
        let scaleFactor = 1 / sender.scale
        let newScale = max(0.5, min(1.0, previousContainerScale * scaleFactor))
        previousContainerScale = newScale
        // 缩放容器节点
        scaleContainer.setScale(newScale)
        
        // 重置手势的scale,避免累积影响
        sender.scale = 1.0
    }
}

方案二:抵消相机缩放对特定节点的影响(适合必须用相机的场景)

如果你仍需要使用SKCameraNode(比如还要做相机平移),可以对不需要缩放的节点做反向缩放,抵消相机的缩放效果。

修改后的代码示例:

class GameScene: SKScene {
    private var previousCameraScale: CGFloat = 1.0
    // 存储不需要缩放的节点数组
    private var fixedNodes: [SKNode] = []

    override func didMove(to view: SKView) {
        let cameraNode = SKCameraNode()
        cameraNode.position = self.midPoint
        self.addChild(cameraNode)
        self.camera = cameraNode
        
        // ---- 添加需要缩放的节点(直接加场景,受相机影响) ----
        let scalableSprite = SKSpriteNode(color: .red, size: CGSize(width: 100, height: 100))
        scalableSprite.position = self.midPoint
        self.addChild(scalableSprite)
        
        // ---- 添加不需要缩放的节点,存入fixedNodes数组 ----
        let fixedSprite = SKSpriteNode(color: .blue, size: CGSize(width: 50, height: 50))
        fixedSprite.position = CGPoint(x: self.midPoint.x + 200, y: self.midPoint.y)
        self.addChild(fixedSprite)
        fixedNodes.append(fixedSprite)
        
        let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(scaleCamera(_:)))
        view.addGestureRecognizer(pinchGesture)
    }

    @objc func scaleCamera(_ sender: UIPinchGestureRecognizer) {
        guard let camera = self.camera, (sender.state == .began || sender.state == .changed) else {
            print("GameScene - Pinch Gesture Action - No camera for scene")
            return
        }
        
        let scaleFactor = 1 / sender.scale
        let newScale = max(0.5, min(1.0, previousCameraScale * scaleFactor))
        previousCameraScale = newScale
        camera.setScale(newScale)
        
        // 对固定节点做反向缩放,抵消相机的缩放效果
        fixedNodes.forEach { node in
            node.setScale(1 / newScale)
        }
        
        sender.scale = 1.0
    }
}

注意事项

  • 方案一逻辑更清晰,性能也更好,优先推荐;
  • 方案二中要确保固定节点的初始scale是1,否则反向缩放会出现偏差;
  • 两种方案都记得重置手势的scale为1,避免手势多次触发时的累积计算误差。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 20:39:19