Attack button in SpriteKit

前端 未结 2 1111
无人共我
无人共我 2020-12-04 00:29

I\'m slightly new to Xcode and have been making a 2d game for my class. I have been having issues with buttons for a while now. I had just got a solution to why my jump butt

相关标签:
2条回答
  • 2020-12-04 01:00

    I've writen a small 'starter' project that demonstrates in a simple way (I hope) a lot of the concepts - just drop the code into a new project and run :


    Here is a simple Sprite-Kit GameScene.swift. Create a new, empty SpriteKit project and replace the GameScene.swift with this. Then build and run.

    Click on any of the objects on screen to give make them move. Check the logs and the comments to see which ones collide and which ones make contact.

    //
    //  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)")}
                    }
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-04 01:02

    The first half of your question is quite easy. You just need to set the new texture of your player in that function then once that animation is complete, revert back to the original player animation. So I would suggest creating those two animations at the class level and assigning a key to the default animation and use the completion handler of the attack action to set it back.

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

    As for your second half regarding collisions, what you want to use is contactTestBitmask. You add the SKPhysicsContactDelegate to your scene class and set the bitmasks of which nodes you want to register contacts on. There many questions and answers regarding that aspect all over SO. No need to answer again I don't think. Feel free to come back with a new question if you get hung up on it.

    0 讨论(0)
提交回复
热议问题