Элементы управления SpriteKit / Жесты - PullRequest
0 голосов
/ 25 мая 2020

По сути, я пытаюсь включить кнопки игровой сцены X2, которые выполняют следующие функции:

1) Нажмите, чтобы летать (это у меня работает) 2) Нажмите, чтобы выстрелить снарядом из позиции игрока (у меня нет работает).

Моя проблема в том, что в настоящее время у меня установлена ​​функция c fly fun при прикосновении к любому месту экрана. Я пробовал следующее:

Это относится к моей GameScene: я подумал, что для того, чтобы разделить это, мне понадобится узел на экране, чтобы ссылаться на эту функцию. Это не вызывает ошибки в консоли, но не отображается в GameScene.

// Кнопка для запуска стрельбы:

    let btnTest = SKSpriteNode(imageNamed: "Crater")
    btnTest.setScale(0.2)
    btnTest.name = "Button"
    btnTest.zPosition = 10
    btnTest.position = CGPoint(x: 100, y: 200)
    self.addChild(btnTest)

Далее в классе Player у меня есть следующее разбито:

var shooting = false

var shootAnimation = SKAction()
var noshootAnimation = SKAction()


   Init func: 

    self.run(noshootAnimation, withKey: "noshootAnimation")

    let projectile = SKSpriteNode(imageNamed: "Crater")
    projectile.position = CGPoint (x: 100, y: 50)
    projectile.zPosition = 20
    projectile.name = "projectile"


    // Assigning categories to Game objects:
    self.physicsBody?.categoryBitMask =
        PhysicsCategory.plane.rawValue
    self.physicsBody?.contactTestBitMask =
        PhysicsCategory.ground.rawValue 
    self.physicsBody?.collisionBitMask =
        PhysicsCategory.ground.rawValue

    self.physicsBody?.applyImpulse(CGVector(dx: 300, dy: 0))
    self.addChild(projectile)



      // Start the shoot animation, set shooting to true:
       func startShooting() {


       self.removeAction(forKey: "noshootAnimation")
       self.shooting = true

   }

   // Stop the shoot animation, set shooting to false:
   func stopShooting() {


       self.removeAction(forKey: "shootAnimation")
       self.shooting = false
   }

Узел появляется в GameScene, что выглядит многообещающе, наконец, я перехожу к последнему фрагменту кода в GameScene следующим образом:

                override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)            for touch in (touches) {

                    let location = touch.location(in: self)

                    let nodeTouched = atPoint(location)

                    if let gameSprite = nodeTouched as? GameSprite {

                    gameSprite.onTap()
                    }

                    // Check the HUD buttons which I have appearing when game is over…
                    if nodeTouched.name == "restartGame" {
                    // Transition to a new version of the GameScene
                    // To restart the Game
                        self.view?.presentScene(GameScene(size: self.size), transition: .crossFade(withDuration: 0.6))
                    }
                    else if nodeTouched.name == "returnToMenu"{
                    // Transition to the main menu scene
                        self.view?.presentScene(MenuScene(size: self.size), transition: . crossFade(withDuration: 0.6))

                    }
            }

                Player.startFly()
                player.startShooting()

                    }

            override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
                Player.stopFly()
                player.stopShooting()

            }

            override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
                Player.stopFly()
                player.stopShooting()

            }

            override func update(_ currentTime: TimeInterval) {

                player.update()         
}
}

К сожалению, в GameScene и узел не срабатывает при нажатии на экран, с приведенным выше кодом я все равно могу исправить это, чтобы разрешить обе функции «касание, чтобы летать» + «касание, чтобы стрелять». Я до сих пор не могу понять, как заставить появиться кнопку, которую я объявил в начале GameScene, в которой положение моего жеста / касания может быть локализовано на этот узел на экране, а не на весь экран, на котором я сейчас. .

Я могу сказать, что в моей голове это прозвучало проще, чем на самом деле кодирование вместе.

1 Ответ

0 голосов
/ 25 мая 2020

Во-первых, в приведенном выше коде нет вызовов для запуска анимации с ключом "shootAnimation" и отсутствует вызов для повторного запуска анимации без съемки при stopShooting() и вызов для повторного запуска съемки. анимация в формате startShooting(). Методы должны включать их, как показано ниже

func startShooting() {
    self.removeAction(forKey: "noshootAnimation")

    // Add this call
    self.run(shootAnimation)
    self.shooting = true
}

func stopShooting() {
    self.removeAction(forKey: "shootAnimation")

    // Add this call
    self.run(noshootAnimation)
    self.shooting = true
}

Во-вторых, анимации noshootAnimation и shootAnimation являются пустыми действиями: они ничего не будут делать, если инициализированы как SKAction(). В зависимости от того, что вы пытаетесь сделать, существует ряд методов класса SKAction, которые будут создавать для вас действия здесь .

В-третьих, любые SKNode (напомним, что сцена является подклассом SKNode) не будет получать сенсорные вызовы, если для свойства isUserInteractionEnabled узла установлено значение false (для которого оно установлено по умолчанию); вместо этого он будет обработан так, как если бы его родитель получил вызов. Однако, если isUserInteractionEnabled узла будет true, это будет тот, который получает вызовы UIResponder, а не его родительский узел. Убедитесь, что для этого свойства установлено значение true для сцены и для всех узлов, которые должны получать касания (вы можете сделать это в didMove(to:) в сцене или где-то еще).

Теперь я предлагаю улучшение. Я часто использую кнопки в Spritekit, но все они являются подклассами настраиваемого класса кнопок (сам является подклассом SKSpriteNode), который использует делегирование протокола для оповещения участников о событиях касания. Схема выглядит так:

class Button: SKSpriteNode {
    weak var responder: ButtonResponder?
    // Custom code

    // MARK: UIResponder
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesBegan(touches, with: event)

        // Respond here
        responder?.respond(to: self)
    }
}

protocol ButtonResponder: AnyObject {
    func respond(to button: Button)
}

class MyScene: SKScene, ButtonResponder {
    func respond(to button: Button) {
        // Do something on touch, but typically check the name

        switch button.name {
        case "myButton":
            // Do something specific
        default:
            break
        }
    }

    override func didMove(to view: SKView) {
        // Set the scene as a responder
        let buttonInScene = childNode(withName: "myButton") as! Button
        buttonInScene.responder = self
    }
}

Подробнее о делегировании см. здесь . Надеюсь, это немного помогло.

РЕДАКТИРОВАТЬ: преобразовать местоположение касания

Вы можете преобразовать касание в узел на экране, передав вместо этого ссылку на метод location(in:) из UITouch сцены, как вы это делали в своем коде

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesBegan(touches, with: event)

    let yourNode = childNode(withName: "yourNode")!
    for touch in touches {
        let touchLocationToYourNode = touch.location(in: yourNode)
        // Do something
    }
}

В качестве альтернативы используйте методы SKNode convert(_:from:) и convert(_:to:)

let nodeA = SKNode()
let nodeB = SKNode()

nodeA.xScale = 1.5
nodeA.yScale = 1.2
nodeA.position = .init(x: 100, y: 100)
nodeA.zRotation = .pi

let pointInNodeACoordinateSystem = CGPoint(x: 100, y: 100)
let thatSamePointInNodeBCoordinateSystem = nodeB.convert(pointInNodeACoordinateSystem, from: nodeA)
...