当我只创建一个时,为什么会有多个 SKSpriteNode 和 SKAudioNode 对象?
Why are there multiple SKSpriteNode and SKAudioNode objects when I only created one of each?
我创建了一个 SKSpriteNode 对象,但是创建了多个对象,显示为它们的字符串。来自 SKAudioNode 对象的声音也被复制多次以产生回响效果。
下面是代码。当我在 didBegin 回调方法中添加代码以将 physicsBody 对象的固定属性设置为 true 时,我注意到它这样做了。
这是截图。注意有多个爆炸 SKSpriteNode 对象。我只为爆炸创建了一个 SKSpriteNode 对象。
我怀疑我可以更改某个设置以禁用此效果。
import UIKit
import SpriteKit
class GameScene: SKScene {
let player = SKSpriteNode(imageNamed: "player")
var moveRate: CGFloat!
override func didMove(to view: SKView) {
physicsWorld.contactDelegate = self
if UIDevice.current.userInterfaceIdiom == .phone {
moveRate = 5
} else {
moveRate = 15
}
player.physicsBody = SKPhysicsBody(rectangleOf: player.size)
player.physicsBody?.isDynamic = true
player.physicsBody?.affectedByGravity = false
player.physicsBody?.categoryBitMask = 0b00001
// player.physicsBody?.collisionBitMask = 0b00001
player.physicsBody?.contactTestBitMask = 0b00001
player.position = CGPoint(x: 20 + player.size.width/2, y: view.frame.height / 2)
addChild(player)
let carEngineStart = SKAudioNode(fileNamed: "car_engine_running")
addChild(carEngineStart)
run(SKAction.repeatForever(
SKAction.sequence([
SKAction.run(addCompetitor),
SKAction.wait(forDuration: 4)
])
))
}
override func update(_ currentTime: TimeInterval) {
let internalRollSign = TrialSpriteKit.sign(internalRoll)
switch internalRollSign {
case .zero:
break
case .positive:
if player.position.y < self.size.height {
player.position.y += moveRate
}
case .negative:
if player.position.y > 0 {
player.position.y -= moveRate
}
}
}
enum Car: String, CaseIterable {
case blue = "blue"
case green = "green"
case orange = "orange"
case purple = "purple"
case utili = "utili"
case white = "white"
case yellow = "yellow"
static func random<G: RandomNumberGenerator>(using generator: inout G) -> Car {
return Car.allCases.randomElement(using: &generator)!
}
static func random() -> Car {
var g = SystemRandomNumberGenerator()
return Car.random(using: &g)
}
}
func random() -> CGFloat {
return CGFloat(Float(arc4random()) / /* 0xFFFFFFFF */ 4294967296)
}
func random(min: CGFloat, max: CGFloat) -> CGFloat {
return random() * (max - min) + min
}
func addCompetitor() {
// Create sprite
let carString = Car.random().rawValue
let car = SKSpriteNode(imageNamed: carString)
car.physicsBody = SKPhysicsBody(rectangleOf: car.size) // 1
car.physicsBody?.isDynamic = true
car.physicsBody?.affectedByGravity = false
// car.physicsBody?.categoryBitMask = 0b00001
car.physicsBody?.collisionBitMask = 0b00001
car.physicsBody?.contactTestBitMask = 0b00001
// Determine where to spawn the car along the Y axis
let actualY = random(min: car.size.height/2, max: size.height - car.size.height/2)
// Position the car slightly off-screen along the right edge,
// and along a random position along the Y axis as calculated above
car.position = CGPoint(x: size.width + car.size.width/2, y: actualY)
// Add the car to the scene
addChild(car)
// Determine speed of the car
let actualDuration = random(min: CGFloat(2.0), max: CGFloat(4.0))
// Create the actions
let actionMove = SKAction.move(to: CGPoint(x: -car.size.width/2, y: actualY), duration: TimeInterval(actualDuration))
let actionMoveDone = SKAction.removeFromParent()
car.run(SKAction.sequence([actionMove, actionMoveDone]))
}
}
extension GameScene: SKPhysicsContactDelegate {
func didBegin(_ contact: SKPhysicsContact) {
contact.bodyA.pinned = true
player.physicsBody?.pinned = true
let explosion = SKSpriteNode(imageNamed: "explosion")
explosion.position = contact.contactPoint
addChild(explosion)
run(
SKAction.sequence(
[
SKAction.playSoundFileNamed("car_explosion", waitForCompletion: true),
SKAction.run({
explosion.removeFromParent()
contact.bodyB.node?.removeFromParent()
}),
SKAction.wait(forDuration: 1),
SKAction.run({
self.player.zRotation = 0
self.player.position = CGPoint(x: 20 + self.player.size.width/2, y: self.view!.frame.height / 2)
self.player.physicsBody?.pinned = false
})
]
)
)
}
}
你的问题有多个节点的原因。
I noticed it doing this when I added the code to set the pinned
properties of the physicsBody objects to true in the didBegin callback
method.
根据 SpriteKit 文档,当您将 pinned
属性 设置为 true 且父节点具有物理体时,这两个体被视为通过销关节连接.
因为两个物体是相连的,即使没有碰撞,也会重复接触,导致重复调用didBegin
函数。每次调用 didBegin
都会创建一个新的精灵节点。您的游戏调用 didBegin
的次数比您预期的要多,因此您最终得到的精灵节点比您预期的要多。
一般的解决方案是只有在发生碰撞时才创建爆炸精灵节点,并且每次碰撞只创建一次精灵节点。
我创建了一个 SKSpriteNode 对象,但是创建了多个对象,显示为它们的字符串。来自 SKAudioNode 对象的声音也被复制多次以产生回响效果。
下面是代码。当我在 didBegin 回调方法中添加代码以将 physicsBody 对象的固定属性设置为 true 时,我注意到它这样做了。
这是截图。注意有多个爆炸 SKSpriteNode 对象。我只为爆炸创建了一个 SKSpriteNode 对象。
我怀疑我可以更改某个设置以禁用此效果。
import UIKit
import SpriteKit
class GameScene: SKScene {
let player = SKSpriteNode(imageNamed: "player")
var moveRate: CGFloat!
override func didMove(to view: SKView) {
physicsWorld.contactDelegate = self
if UIDevice.current.userInterfaceIdiom == .phone {
moveRate = 5
} else {
moveRate = 15
}
player.physicsBody = SKPhysicsBody(rectangleOf: player.size)
player.physicsBody?.isDynamic = true
player.physicsBody?.affectedByGravity = false
player.physicsBody?.categoryBitMask = 0b00001
// player.physicsBody?.collisionBitMask = 0b00001
player.physicsBody?.contactTestBitMask = 0b00001
player.position = CGPoint(x: 20 + player.size.width/2, y: view.frame.height / 2)
addChild(player)
let carEngineStart = SKAudioNode(fileNamed: "car_engine_running")
addChild(carEngineStart)
run(SKAction.repeatForever(
SKAction.sequence([
SKAction.run(addCompetitor),
SKAction.wait(forDuration: 4)
])
))
}
override func update(_ currentTime: TimeInterval) {
let internalRollSign = TrialSpriteKit.sign(internalRoll)
switch internalRollSign {
case .zero:
break
case .positive:
if player.position.y < self.size.height {
player.position.y += moveRate
}
case .negative:
if player.position.y > 0 {
player.position.y -= moveRate
}
}
}
enum Car: String, CaseIterable {
case blue = "blue"
case green = "green"
case orange = "orange"
case purple = "purple"
case utili = "utili"
case white = "white"
case yellow = "yellow"
static func random<G: RandomNumberGenerator>(using generator: inout G) -> Car {
return Car.allCases.randomElement(using: &generator)!
}
static func random() -> Car {
var g = SystemRandomNumberGenerator()
return Car.random(using: &g)
}
}
func random() -> CGFloat {
return CGFloat(Float(arc4random()) / /* 0xFFFFFFFF */ 4294967296)
}
func random(min: CGFloat, max: CGFloat) -> CGFloat {
return random() * (max - min) + min
}
func addCompetitor() {
// Create sprite
let carString = Car.random().rawValue
let car = SKSpriteNode(imageNamed: carString)
car.physicsBody = SKPhysicsBody(rectangleOf: car.size) // 1
car.physicsBody?.isDynamic = true
car.physicsBody?.affectedByGravity = false
// car.physicsBody?.categoryBitMask = 0b00001
car.physicsBody?.collisionBitMask = 0b00001
car.physicsBody?.contactTestBitMask = 0b00001
// Determine where to spawn the car along the Y axis
let actualY = random(min: car.size.height/2, max: size.height - car.size.height/2)
// Position the car slightly off-screen along the right edge,
// and along a random position along the Y axis as calculated above
car.position = CGPoint(x: size.width + car.size.width/2, y: actualY)
// Add the car to the scene
addChild(car)
// Determine speed of the car
let actualDuration = random(min: CGFloat(2.0), max: CGFloat(4.0))
// Create the actions
let actionMove = SKAction.move(to: CGPoint(x: -car.size.width/2, y: actualY), duration: TimeInterval(actualDuration))
let actionMoveDone = SKAction.removeFromParent()
car.run(SKAction.sequence([actionMove, actionMoveDone]))
}
}
extension GameScene: SKPhysicsContactDelegate {
func didBegin(_ contact: SKPhysicsContact) {
contact.bodyA.pinned = true
player.physicsBody?.pinned = true
let explosion = SKSpriteNode(imageNamed: "explosion")
explosion.position = contact.contactPoint
addChild(explosion)
run(
SKAction.sequence(
[
SKAction.playSoundFileNamed("car_explosion", waitForCompletion: true),
SKAction.run({
explosion.removeFromParent()
contact.bodyB.node?.removeFromParent()
}),
SKAction.wait(forDuration: 1),
SKAction.run({
self.player.zRotation = 0
self.player.position = CGPoint(x: 20 + self.player.size.width/2, y: self.view!.frame.height / 2)
self.player.physicsBody?.pinned = false
})
]
)
)
}
}
你的问题有多个节点的原因。
I noticed it doing this when I added the code to set the pinned properties of the physicsBody objects to true in the didBegin callback method.
根据 SpriteKit 文档,当您将 pinned
属性 设置为 true 且父节点具有物理体时,这两个体被视为通过销关节连接.
因为两个物体是相连的,即使没有碰撞,也会重复接触,导致重复调用didBegin
函数。每次调用 didBegin
都会创建一个新的精灵节点。您的游戏调用 didBegin
的次数比您预期的要多,因此您最终得到的精灵节点比您预期的要多。
一般的解决方案是只有在发生碰撞时才创建爆炸精灵节点,并且每次碰撞只创建一次精灵节点。