การควบคุม / ท่าทาง SpriteKit

โดยพื้นฐานแล้ว ฉันกำลังพยายามรวมปุ่ม X2 gamescene ที่ทำฟังก์ชันต่อไปนี้:

1) แตะเพื่อบิน (ฉันทำงานอยู่) 2) แตะเพื่อยิงกระสุนปืนจากตำแหน่งผู้เล่น (ฉันไม่มีงาน)

ปัญหาของฉันคือขณะนี้ฉันได้ตั้งค่า fly func เมื่อสัมผัสที่ใดก็ได้บนหน้าจอ ฉันได้ลองทำสิ่งต่อไปนี้แล้ว:

นี่เป็นการอ้างอิงถึง 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 ได้อย่างไรเพื่อให้ปรากฏ โดยที่ตำแหน่งท่าทาง/สัมผัสของฉันสามารถแปลไปที่โหนดนี้บนหน้าจอได้ ซึ่งตรงข้ามกับทั้งหน้าจอที่ฉันมีอยู่ในปัจจุบัน .

ฉันสามารถพูดได้ว่านี่ฟังดูง่ายกว่าในหัวของฉันตั้งแต่เริ่มต้นมากกว่าการเขียนโค้ดด้วยกัน


person AJ James    schedule 25.05.2020    source แหล่งที่มา


คำตอบ (1)


ประการแรก โค้ดด้านบนไม่มีการเรียกเรียกใช้แอนิเมชั่นด้วยปุ่ม "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's 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)
person Left as an exercise    schedule 25.05.2020
comment
สวัสดี! ขอขอบคุณที่สละเวลาอ่านโพสต์นี้! ฉันได้ดำเนินการตามข้อเสนอของคุณข้างต้นเพื่อพิจารณาแล้ว ทั้งหมดนี้ทำงานได้อย่างสมบูรณ์แบบ!! ชั่วโมงแห่งความหงุดหงิดได้รับการแก้ไขแล้ว! ในที่สุดฉันก็มีฟังก์ชั่นของปุ่มที่ทำงานระหว่าง GameScene ขอบคุณสำหรับคำแนะนำแบบลอจิคัล สิ่งนี้ช่วยให้ฉันเข้าใจได้อย่างแน่นอน!! - person AJ James; 26.05.2020