Почему существует несколько объектов SKSpriteNode и SKAudioNode, когда я создал только один из них? - PullRequest
0 голосов
/ 11 мая 2019

Я создал объект SKSpriteNode, но создано несколько объектов, которые отображаются в виде их строк. Звук, исходящий от объекта SKAudioNode, также многократно дублируется, чтобы дать эффект реверберации.

Вот код ниже. Я заметил, что это происходит, когда я добавил код, чтобы установить для закрепленных свойств объектов физики значение true в методе обратного вызова didBegin.

Вот скриншот. Обратите внимание, что существует несколько объектов SKSpriteNode взрыва. Я только создал один объект SKSpriteNode для взрыва.

multiple car explosions

Я подозреваю, что где-то есть настройка, которую я могу изменить, чтобы отключить этот эффект.

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
                    })
                ]
            )
        )

     }

}

1 Ответ

1 голос
/ 14 мая 2019

У вас есть причина для нескольких узлов в вашем вопросе.

Я заметил, что это происходит, когда я добавил код для установки закрепленных свойств объектов физики в значение true в методе обратного вызова didBegin.

Согласно документации SpriteKitесли для свойства pinned установлено значение true, а родительский узел имеет физическое тело, эти два тела обрабатываются так, как если бы они были соединены штифтовым соединением.

Поскольку два тела соединены, контактвыполняется многократно, даже если нет столкновения, что приводит к повторным вызовам функции didBegin.Каждый вызов didBegin создает новый узел спрайта.Ваша игра вызывает didBegin намного больше, чем вы ожидаете, поэтому у вас будет больше спрайтов, чем вы ожидаете.

Общее решение - создать спрайтовый узел взрыва только при столкновении и создать толькоузел спрайта один раз за столкновение.

...