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

如何整体移动通过多维数组创建的SpriteKit组合图形对象?

解决组合图形整体移动的问题

嘿,这个问题我做方块类游戏的时候也踩过坑!你现在遇到的问题核心是:每次绘制方块时,你只保留了最后一个square的引用,移动的时候自然只有它会动,之前生成的所有方块都没被你“管起来”。下面给你两种最常用的解决方案,推荐第一种,因为SpriteKit的节点层级天生就适合干这个事儿~

方法一:用父容器节点统一管理(推荐)

SpriteKit里,父节点的位置变化会自动传递给所有子节点,所以我们可以创建一个空的SKNode作为容器,把所有方块都加到这个容器里,移动的时候只需要动这个容器就行。

步骤1:添加容器属性

在你的场景类里先声明一个容器节点的属性:

var pieceContainer: SKNode!

步骤2:修改绘制代码,把方块加到容器里

初始化容器,然后把每个生成的方块作为子节点添加到容器中,而不是直接加到场景:

// 先初始化容器,并设置初始位置
pieceContainer = SKNode()
pieceContainer.position = CGPoint(x: location.x, y: location.y)
self.addChild(pieceContainer)

for row in 0..<t.bitmap.count { 
    for col in 0..<t.bitmap[row].count { 
        if t.bitmap[row][col] > 0 { 
            let block = t.bitmap[row][col] 
            let square = SKSpriteNode(color: colors[block], size: CGSize(width: blockSize, height: blockSize)) 
            square.anchorPoint = CGPoint(x: 1.0, y: 0) 
            // 这里的位置是相对于容器的局部坐标,不用再加location了,容器已经帮你处理初始位置
            square.position = CGPoint(x: col * Int(blockSize) + col, y: -row * Int(blockSize) + -row) 
            pieceContainer.addChild(square) // 把方块加到容器里
        } 
    } 
}

步骤3:修改移动代码,只移动容器

现在移动的时候只需要更新容器的位置,所有子方块都会跟着整体移动:

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { 
    guard let touch = touches.first else { return }
    // 获取当前触摸位置和上一次触摸位置,计算偏移量(这样移动更平滑)
    let currentLocation = touch.location(in: self)
    let previousLocation = touch.previousLocation(in: self)
    
    let offsetX = currentLocation.x - previousLocation.x
    let offsetY = currentLocation.y - previousLocation.y
    
    // 移动容器节点
    pieceContainer.position.x += offsetX
    pieceContainer.position.y += offsetY
}

方法二:用数组保存所有方块,逐个更新位置

如果不想用容器节点,也可以把所有生成的方块保存到一个数组里,移动的时候遍历数组逐个更新每个方块的位置。

步骤1:添加数组属性

在场景类里声明一个数组来保存所有方块:

var blocks = [SKSpriteNode]()

步骤2:修改绘制代码,把方块加入数组

每次生成方块后,把它加到数组中:

for row in 0..<t.bitmap.count { 
    for col in 0..<t.bitmap[row].count { 
        if t.bitmap[row][col] > 0 { 
            let block = t.bitmap[row][col] 
            let square = SKSpriteNode(color: colors[block], size: CGSize(width: blockSize, height: blockSize)) 
            square.anchorPoint = CGPoint(x: 1.0, y: 0) 
            square.position = CGPoint(x: col * Int(blockSize) + col + location.x, y: -row * Int(blockSize) + -row + location.y) 
            self.addChild(square)
            blocks.append(square) // 把方块加入数组
        } 
    } 
}

步骤3:修改移动代码,遍历数组移动每个方块

计算触摸的偏移量,然后遍历数组里的每个方块,逐个更新位置:

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { 
    guard let touch = touches.first else { return }
    let currentLocation = touch.location(in: self)
    let previousLocation = touch.previousLocation(in: self)
    
    let offsetX = currentLocation.x - previousLocation.x
    let offsetY = currentLocation.y - previousLocation.y
    
    // 遍历所有方块,逐个应用偏移量
    for block in blocks {
        block.position.x += offsetX
        block.position.y += offsetY
    }
}

总结

  • 方法一用父容器节点是最符合SpriteKit设计思想的,代码更简洁,后续做旋转、碰撞检测也更容易扩展。
  • 方法二适合简单场景,但如果方块数量多,遍历数组的效率会比父节点移动稍差一点。

内容的提问来源于stack exchange,提问作者T.Cansiz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:21:09