SpriteKit 节点穿墙
SpriteKit node going through wall
我正在开发一个 Xcode 游乐场,我遇到了一些 SpriteKit 碰撞问题。
第一个盒子的质量为 1,第二个盒子的质量为 100000(例如,当后者为 100 时,一切正常)。碰撞是弹性的(restitution
设置为 1)并且根本没有摩擦或阻尼。
这是我场景的代码(ColliderType
只是类别的 enum
):
class GameScene: SKScene {
private var wall: SKSpriteNode!
private var floor: SKSpriteNode!
private var box1: SKSpriteNode!
private var box2: SKSpriteNode!
override func didMove(to view: SKView) {
self.backgroundColor = .white
wall = SKSpriteNode(color: SKColor.black, size: CGSize(width: 10, height: self.frame.height))
wall.position = CGPoint(x: 100, y: self.frame.height/2)
wall.physicsBody = SKPhysicsBody(rectangleOf: wall.frame.size)
wall.physicsBody?.isDynamic = false
floor = SKSpriteNode(color: SKColor.black, size: CGSize(width: self.frame.width, height: 10))
floor.position = CGPoint(x: self.frame.width/2, y: 100)
floor.physicsBody = SKPhysicsBody(rectangleOf: floor.frame.size)
floor.physicsBody?.isDynamic = false
box1 = SKSpriteNode(color: SKColor.black, size: CGSize(width: 100, height: 100))
box1.position = CGPoint(x: 300, y: floor.position.y+box1.size.height/2)
box1.physicsBody = SKPhysicsBody(circleOfRadius: box1.frame.size.width/2)
box2 = SKSpriteNode(color: SKColor.black, size: CGSize(width: 100, height: 100))
box2.position = CGPoint(x: 750, y: floor.position.y+box2.size.height/2)
box2.physicsBody = SKPhysicsBody(circleOfRadius: box2.frame.size.width/2)
self.addChild(wall)
self.addChild(floor)
self.addChild(box1)
self.addChild(box2)
box1.physicsBody?.allowsRotation = false
box2.physicsBody?.allowsRotation = false
box1.physicsBody?.restitution = 1
box2.physicsBody?.restitution = 1
box1.physicsBody?.mass = 1
box2.physicsBody?.mass = 100000
box1.physicsBody?.friction = 0
box2.physicsBody?.friction = 0
box1.physicsBody?.linearDamping = 0
box2.physicsBody?.linearDamping = 0
wall.physicsBody?.categoryBitMask = ColliderType.Wall.rawValue
box1.physicsBody?.categoryBitMask = ColliderType.Box1.rawValue
box2.physicsBody?.categoryBitMask = ColliderType.Box2.rawValue
box1.physicsBody?.collisionBitMask = ColliderType.Wall.rawValue | ColliderType.Floor.rawValue | ColliderType.Box2.rawValue
box2.physicsBody?.collisionBitMask = ColliderType.Floor.rawValue | ColliderType.Box1.rawValue
box1.physicsBody?.contactTestBitMask = ColliderType.Box2.rawValue | ColliderType.Wall.rawValue
box1.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
box2.physicsBody?.velocity = CGVector(dx: -50, dy: 0)
}
}
我尝试过的事情:
- 在第一个盒子上设置
usesPreciseCollisionDetection = true
- 通过覆盖更新方法自行更新位置并检查碰撞(它没有像 SpriteKit 引擎那样优化,所以非常慢)
- 让第二个盒子变慢并设置
physicsWorld.speed
为大于1的数字
我认为总的来说,您可能期望过高。 SpriteKit 是一个游戏引擎,旨在为涉及普通物理的场景提供定性合理的行为。这不是一个高精度的物理模拟,当你把它推到一个它必须做一些极端的事情的区域时,它可能会失败。
在这种情况下,您期望它在少量时间和距离内模拟大量完美弹性碰撞(模拟的每个动画帧都有许多碰撞,因为重块将轻块混合成微小的差距)。它将找到帧中的第一个碰撞,计算出应用于块的脉冲,然后前进到下一帧,结果是大块愉快地混入小块所在的 space。在寻找 60 fps 的过程中,所有可以防止发生碰撞的后续碰撞都被遗漏了。
我正在开发一个 Xcode 游乐场,我遇到了一些 SpriteKit 碰撞问题。
第一个盒子的质量为 1,第二个盒子的质量为 100000(例如,当后者为 100 时,一切正常)。碰撞是弹性的(restitution
设置为 1)并且根本没有摩擦或阻尼。
这是我场景的代码(ColliderType
只是类别的 enum
):
class GameScene: SKScene {
private var wall: SKSpriteNode!
private var floor: SKSpriteNode!
private var box1: SKSpriteNode!
private var box2: SKSpriteNode!
override func didMove(to view: SKView) {
self.backgroundColor = .white
wall = SKSpriteNode(color: SKColor.black, size: CGSize(width: 10, height: self.frame.height))
wall.position = CGPoint(x: 100, y: self.frame.height/2)
wall.physicsBody = SKPhysicsBody(rectangleOf: wall.frame.size)
wall.physicsBody?.isDynamic = false
floor = SKSpriteNode(color: SKColor.black, size: CGSize(width: self.frame.width, height: 10))
floor.position = CGPoint(x: self.frame.width/2, y: 100)
floor.physicsBody = SKPhysicsBody(rectangleOf: floor.frame.size)
floor.physicsBody?.isDynamic = false
box1 = SKSpriteNode(color: SKColor.black, size: CGSize(width: 100, height: 100))
box1.position = CGPoint(x: 300, y: floor.position.y+box1.size.height/2)
box1.physicsBody = SKPhysicsBody(circleOfRadius: box1.frame.size.width/2)
box2 = SKSpriteNode(color: SKColor.black, size: CGSize(width: 100, height: 100))
box2.position = CGPoint(x: 750, y: floor.position.y+box2.size.height/2)
box2.physicsBody = SKPhysicsBody(circleOfRadius: box2.frame.size.width/2)
self.addChild(wall)
self.addChild(floor)
self.addChild(box1)
self.addChild(box2)
box1.physicsBody?.allowsRotation = false
box2.physicsBody?.allowsRotation = false
box1.physicsBody?.restitution = 1
box2.physicsBody?.restitution = 1
box1.physicsBody?.mass = 1
box2.physicsBody?.mass = 100000
box1.physicsBody?.friction = 0
box2.physicsBody?.friction = 0
box1.physicsBody?.linearDamping = 0
box2.physicsBody?.linearDamping = 0
wall.physicsBody?.categoryBitMask = ColliderType.Wall.rawValue
box1.physicsBody?.categoryBitMask = ColliderType.Box1.rawValue
box2.physicsBody?.categoryBitMask = ColliderType.Box2.rawValue
box1.physicsBody?.collisionBitMask = ColliderType.Wall.rawValue | ColliderType.Floor.rawValue | ColliderType.Box2.rawValue
box2.physicsBody?.collisionBitMask = ColliderType.Floor.rawValue | ColliderType.Box1.rawValue
box1.physicsBody?.contactTestBitMask = ColliderType.Box2.rawValue | ColliderType.Wall.rawValue
box1.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
box2.physicsBody?.velocity = CGVector(dx: -50, dy: 0)
}
}
我尝试过的事情:
- 在第一个盒子上设置
usesPreciseCollisionDetection = true
- 通过覆盖更新方法自行更新位置并检查碰撞(它没有像 SpriteKit 引擎那样优化,所以非常慢)
- 让第二个盒子变慢并设置
physicsWorld.speed
为大于1的数字
我认为总的来说,您可能期望过高。 SpriteKit 是一个游戏引擎,旨在为涉及普通物理的场景提供定性合理的行为。这不是一个高精度的物理模拟,当你把它推到一个它必须做一些极端的事情的区域时,它可能会失败。
在这种情况下,您期望它在少量时间和距离内模拟大量完美弹性碰撞(模拟的每个动画帧都有许多碰撞,因为重块将轻块混合成微小的差距)。它将找到帧中的第一个碰撞,计算出应用于块的脉冲,然后前进到下一帧,结果是大块愉快地混入小块所在的 space。在寻找 60 fps 的过程中,所有可以防止发生碰撞的后续碰撞都被遗漏了。