SpriteKit中的攻击按钮

时间:2017-04-25 00:56:24

标签: ios swift button sprite-kit

我是Xcode的新手,并且已经为我的班级制作了一个2D游戏。我一直有按钮问题一段时间了。我刚刚解决了为什么我的跳转按钮无法正常工作,但我也有一个攻击按钮。

我已将按钮设置为屏幕上的按钮,并在按下时更改图像。但是,我不知道将播放器图像更改为跳转动画的代码。我也不知道如何为它和敌人设置碰撞,以便攻击动画能够击中。

所以我的问题是,如何让按钮启动跳跃动画,以及如何设置碰撞以在击中时摧毁敌人?

到目前为止,这是我的代码:

override func sceneDidLoad() {
    //Setup start button
    jumpButton = SKSpriteNode(texture: jumpButtonTexture)
    jumpButton.position = CGPoint(x: 1850, y: 130)
    jumpButton.size = CGSize(width: 200, height: 200)
    jumpButton.zPosition = 20

    addChild(jumpButton)

    //Setup start button
    attackButton = SKSpriteNode(texture: attackButtonTexture)
    attackButton.position = CGPoint(x: 1550, y: 130)
    attackButton.size = CGSize(width: 200, height: 200)
    attackButton.zPosition = 20

    addChild(attackButton)
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        if selectedButton != nil {
            handleJumpButtonHover(isHovering: false)
            handleAttackButtonHover(isHovering: false)
        }

        if jumpButton.contains(touch.location(in: self)) {
            selectedButton = jumpButton
            handleJumpButtonHover(isHovering: true)
        } else if attackButton.contains(touch.location(in: self)) {
            selectedButton = attackButton
            handleAttackButtonHover(isHovering: true)
        }
    }
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        if selectedButton == jumpButton {
            handleJumpButtonHover(isHovering: false)

            if (jumpButton.contains(touch.location(in: self))) {
                handleJumpButtonClick()
            }
        } else if selectedButton == attackButton {
            handleAttackButtonHover(isHovering: false)

            if (attackButton.contains(touch.location(in: self))) {
                handleAttackButtonClick()
            }
        }
    }
    selectedButton = nil
    }

    func handleJumpButtonHover(isHovering : Bool) {
    if isHovering {
        jumpButton.texture = jumpButtonPressedTexture
    } else {
        jumpButton.texture = jumpButtonTexture
    }
}

func handleAttackButtonHover(isHovering : Bool) {
    if isHovering {
        attackButton.texture = attackButtonPressedTexture
    } else {
        attackButton.texture = attackButtonTexture
    }
}

func handleJumpButtonClick() {
    self.playerNode.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
    self.playerNode.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 20))
}

func handleAttackButtonClick() {
}

2 个答案:

答案 0 :(得分:2)

我写了一个小'启动'项目,以简单的方式(我希望)演示了很多概念 - 只需将代码放入一个新项目并运行:

这是一个简单的Sprite-Kit GameScene.swift。创建一个新的空SpriteKit项目,并用此替换GameScene.swift。然后构建并运行。

单击屏幕上的任何对象以使其移动。检查日志和注释,看看哪些碰撞,哪些碰撞。

//
//  GameScene.swift
//  bounceTest
//
//  Created by Stephen Ives on 05/04/2016.
//  Copyright (c) 2016 Stephen Ives. All rights reserved.
//

import SpriteKit



class GameScene: SKScene, SKPhysicsContactDelegate {

    let objectSize = 150
    let initialImpulse: UInt32 = 300  // Needs to be proportional to objectSize

    //Physics categories
    let purpleSquareCategory:   UInt32 = 1 << 0
    let redCircleCategory:      UInt32 = 1 << 1
    let blueSquareCategory:     UInt32 = 1 << 2
    let edgeCategory:           UInt32 = 1 << 31

    let purpleSquare = SKSpriteNode()
    let blueSquare = SKSpriteNode()
    let redCircle = SKSpriteNode()

    override func didMove(to view: SKView) {

        physicsWorld.gravity = CGVector(dx: 0, dy: 0)

        //Create an boundary else everything will fly off-screen
        let edge = frame.insetBy(dx: 0, dy: 0)
        physicsBody = SKPhysicsBody(edgeLoopFrom: edge)
        physicsBody?.isDynamic = false  //This won't move
        name = "Screen_edge"

        scene?.backgroundColor = SKColor.black

        //        Give our 3 objects their attributes

        blueSquare.color = SKColor.blue
        blueSquare.size = CGSize(width: objectSize, height: objectSize)
        blueSquare.name = "shape_blueSquare"
        blueSquare.position = CGPoint(x: size.width * -0.25, y: size.height * 0.2)

        let circleShape = SKShapeNode(circleOfRadius: CGFloat(objectSize))
        circleShape.fillColor = SKColor.red
        redCircle.texture = view.texture(from: circleShape)
        redCircle.size = CGSize(width: objectSize, height: objectSize)
        redCircle.name = "shape_redCircle"
        redCircle.position = CGPoint(x: size.width * 0.4, y: size.height * -0.4)

        purpleSquare.color = SKColor.purple
        purpleSquare.size = CGSize(width: objectSize, height: objectSize)
        purpleSquare.name = "shape_purpleSquare"
        purpleSquare.position = CGPoint(x: size.width * -0.35, y: size.height * 0.4)

        addChild(blueSquare)
        addChild(redCircle)
        addChild(purpleSquare)

        redCircle.physicsBody = SKPhysicsBody(circleOfRadius: redCircle.size.width/2)
        blueSquare.physicsBody = SKPhysicsBody(rectangleOf: blueSquare.frame.size)
        purpleSquare.physicsBody = SKPhysicsBody(rectangleOf: purpleSquare.frame.size)

        setUpCollisions()

        checkPhysics()

    }


    func setUpCollisions() {

        //Assign our category bit masks to our physics bodies
        purpleSquare.physicsBody?.categoryBitMask = purpleSquareCategory
        redCircle.physicsBody?.categoryBitMask = redCircleCategory
        blueSquare.physicsBody?.categoryBitMask = blueSquareCategory
        physicsBody?.categoryBitMask = edgeCategory  // This is the edge for the scene itself

        // Set up the collisions. By default, everything collides with everything.

        redCircle.physicsBody?.collisionBitMask &= ~purpleSquareCategory  // Circle doesn't collide with purple square
        purpleSquare.physicsBody?.collisionBitMask = 0   // purpleSquare collides with nothing
        //        purpleSquare.physicsBody?.collisionBitMask |= (redCircleCategory | blueSquareCategory)  // Add collisions with red circle and blue square
        purpleSquare.physicsBody?.collisionBitMask = (redCircleCategory)  // Add collisions with red circle
        blueSquare.physicsBody?.collisionBitMask = (redCircleCategory)  // Add collisions with red circle


        // Set up the contact notifications. By default, nothing contacts anything.
        redCircle.physicsBody?.contactTestBitMask |= purpleSquareCategory   // Notify when red circle and purple square contact
        blueSquare.physicsBody?.contactTestBitMask |= redCircleCategory     // Notify when blue square and red circle contact

        // Make sure everything collides with the screen edge and make everything really 'bouncy'
        enumerateChildNodes(withName: "//shape*") { node, _ in
            node.physicsBody?.collisionBitMask |= self.edgeCategory  //Add edgeCategory to the collision bit mask
            node.physicsBody?.restitution = 0.9 // Nice and bouncy...
            node.physicsBody?.linearDamping = 0.1 // Nice and bouncy...
        }

        //Lastly, set ourselves as the contact delegate
        physicsWorld.contactDelegate = self
    }

    func didBegin(_ contact: SKPhysicsContact) {
        let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

        switch contactMask {
        case purpleSquareCategory | blueSquareCategory:
            print("Purple square and Blue square have touched")
        case redCircleCategory | blueSquareCategory:
            print("Red circle and Blue square have touched")
        case redCircleCategory | purpleSquareCategory:
            print("Red circle and purple Square have touched")
        default: print("Unknown contact detected")
        }
    }

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

        for touch in touches {
            let touchedNode = selectNodeForTouch(touch.location(in: self))

            if let node = touchedNode {
                node.physicsBody?.applyImpulse(CGVector(dx: CGFloat(arc4random_uniform(initialImpulse)) - CGFloat(initialImpulse/2), dy: CGFloat(arc4random_uniform(initialImpulse)) - CGFloat(initialImpulse/2)))
                node.physicsBody?.applyTorque(CGFloat(arc4random_uniform(20)) - CGFloat(10))
            }

        }
    }

    // Return the sprite where the user touched the screen
    func selectNodeForTouch(_ touchLocation: CGPoint) -> SKSpriteNode? {

        let touchedNode = self.atPoint(touchLocation)
        print("Touched node is \(touchedNode.name)")
        //        let touchedColor = getPixelColorAtPoint(touchLocation)
        //        print("Touched colour is \(touchedColor)")

        if touchedNode is SKSpriteNode {
            return (touchedNode as! SKSpriteNode)
        } else {
            return nil
        }
    }

    //MARK: - Analyse the collision/contact set up.
    func checkPhysics() {

        // Create an array of all the nodes with physicsBodies
        var physicsNodes = [SKNode]()

        //Get all physics bodies
        enumerateChildNodes(withName: "//.") { node, _ in
            if let _ = node.physicsBody {
                physicsNodes.append(node)
            } else {
                print("\(node.name) does not have a physics body so cannot collide or be involved in contacts.")
            }
        }

        //For each node, check it's category against every other node's collion and contctTest bit mask
        for node in physicsNodes {
            let category = node.physicsBody!.categoryBitMask
            // Identify the node by its category if the name is blank
            let name = node.name != nil ? node.name! : "Category \(category)"

            let collisionMask = node.physicsBody!.collisionBitMask
            let contactMask = node.physicsBody!.contactTestBitMask

            // If all bits of the collisonmask set, just say it collides with everything.
            if collisionMask == UInt32.max {
                print("\(name) collides with everything")
            }

            for otherNode in physicsNodes {
            if (node.physicsBody?.dynamic == false) {
                print("This node \(name) is not dynamic")
            }
                if (node != otherNode) && (node.physicsBody?.isDynamic == true) {
                    let otherCategory = otherNode.physicsBody!.categoryBitMask
                    // Identify the node by its category if the name is blank
                    let otherName = otherNode.name != nil ? otherNode.name! : "Category \(otherCategory)"

                    // If the collisonmask and category match, they will collide
                    if ((collisionMask & otherCategory) != 0) && (collisionMask != UInt32.max) {
                        print("\(name) collides with \(otherName)")
                    }
                    // If the contactMAsk and category match, they will contact
                    if (contactMask & otherCategory) != 0 {print("\(name) notifies when contacting \(otherName)")}
                }
            }
        }
    }
}

答案 1 :(得分:1)

问题的前半部分非常简单。您只需在该功能中设置播放器的新纹理,然后在该动画完成后,恢复原始播放器动画。因此,我建议在类级别创建这两个动画,并为默认动画分配一个键,并使用攻击操作的完成处理程序将其设置回来。

class GameScene: SKScene {
    let frame2 = SKTexture(imageNamed: "Ttam2")
    let frame3 = SKTexture(imageNamed: "Ttam3")
    let frame4 = SKTexture(imageNamed: "Ttam4")

    let attackFrame1 = SKTexture(imageNamed: "Ttam1_ATTACK")
    let attackFrame2 = SKTexture(imageNamed: "Ttam2_ATTACK")

    var animation: SKAction!
    var attackAnination: SKAction!

    override func sceneDidLoad(){
       animation = SKAction.repeatForever(SKAction.animate(with: [playerTexture, frame2, frame3, frame4], timePerFrame: 0.2))

       attackAnimation = SKAction.animate(with: [attackFrame1,attackFrame2],timePerFrame: 0.2)

       playerNode.run(animation,withKey:"animate")
    }

    func handleAttackButtonClick(){
        playerNode.removeAction(forKey:"animate")
        playerNode.run(attackAnimation,completion:{
             self.playerNode.run(animation,withKey: "animate")
        })
    }
}

关于碰撞的下半部分,您要使用的是contactTestBitmask。您将SKPhysicsContactDelegate添加到场景类,并设置要在其上注册联系人的节点的位掩码。 SO的这方面有很多问题和答案。没有必要再回答我不认为。如果你被挂起来,请随时回来一个新问题。