我有一个SKScene
,它在物理世界中启用了重力,每秒创建一个SKSpriteNode
。该节点的物理主体高度相同但宽度略小于精灵。
这些节点在场景的顶部创建,由于世界的重力而下降到场景的底部。然后,每个节点都位于其下方的节点之上。
请参阅https://www.youtube.com/watch?v=A9ImdZ0Un30了解我目前取得的效果。
我遇到了几个与实现相关的问题,我对如何开始修复它们感到很遗憾: -
每个节点/物理主体似乎仍然参与物理模拟,当有4行以上时可以看到,因为落在列上的节点的效果导致其下方的节点反弹。我希望已经下降的节点是静态的,不会受到落在它们上面的节点的影响。由于物理模拟计算所有物体上的重力,因此当屏幕填满时,这会导致FPS下降。
某些节点停留在与同一行上其他节点不同的Y坐标上。第3行第2列的节点略高于行上的其他节点。
在某些行上,垂直相邻节点之间存在间隙。为了达到理想的视觉效果,应该没有间隙。我已经尝试使物理体小于高度节点,但问题仍然存在。
这不是特别的问题,而是更多所需的功能。我想保留第一行或第二行的反弹效果,后续行不会反弹太多,可能是由于列中已有的节点质量吸收了下降节点的一些能量。
< / LI> 醇>此外,我希望能够知道节点何时停止,我已经能够使用SKPhysicsContactDelegate
的didBeginContact:方法,但是在反弹期间每次碰撞都会触发(这可能是2或3次)。
更新
另一个游戏机制是,当砖块落下时,列中的那些可能会消失。这应该导致列的其余部分下降到下一个最低的砖块,并且当前从屏幕顶部掉落的砖需要进一步下降以满足列的新“顶部”(我希望这是有意义的)。 / p>
结束更新
我希望以上所有对我有更多SpriteKit经验的人有意义,这里是我正在使用的场景的代码。在下面的代码中,需要在重复计时器上调用showBrick()函数。
import SpriteKit
internal class GameScene: SKScene {
private var i: UInt8 = 0
private let maximumNumberOfRows = 10
lazy var brickSize: CGSize = {
return CGSizeMake(self.size.width / 4.0, self.size.height / CGFloat(self.maximumNumberOfRows))
}()
lazy var minimumBrickPositionX: CGFloat = {
return self.brickSize.width * 0.5
}()
override func didMoveToView(view: SKView) {
super.didMoveToView(view)
self.physicsBody = SKPhysicsBody(edgeFromPoint: CGPointMake(0.0, 0.0), toPoint: CGPointMake(self.size.width, 0.0))
self.physicsWorld.gravity = CGVector(dx: 0.0, dy: -4.9)//-9.8)
}
internal func showBrick() {
let brick = SKSpriteNode(color: UIColor.orangeColor(), size: self.brickSize)
brick.position = CGPointMake(self.minimumBrickPositionX + self.brickSize.width * CGFloat(i++), self.size.height - brickSize.height / 2.0)
// Arbitrary smaller width than the actual brick size
// to ensure bricks don't collide with adjacent bricks
let brickPhysicsBodyWidth = self.brickSize.width - 10.0
brick.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(brickPhysicsBodyWidth, self.brickSize.height))
brick.physicsBody?.allowsRotation = false
brick.physicsBody?.usesPreciseCollisionDetection = true
if i >= 4 {
i = 0
}
self.addChild(brick)
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}