如何整体移动通过多维数组创建的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
相关产品推荐
相关产品推荐

