0

I am having trouble with connecting my player to a jump button in SpriteKit. I have created the game through the Swift file. This is what I have so far:

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.player.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
    //self.player.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 20))
}

func handleAttackButtonClick() {
}

So far, the //self.player in the handlejumpButtonClick is supposed to allow the character to jump up and then gravity would bring him back down. However, as of right now, when the jump button is pressed the game crashes and gives a thread 1 exc error.

Would anyone know of a way to get the button to work with the character? And if possible, is there a shorter way of doing this without having to rebuild the game?

 func createPlayer(_ position: CGPoint) { 

    //graphic stuff
    let playerTexture = SKTexture(imageNamed: "Ttam1") //create variable with graphic assigned to it
    let player = SKSpriteNode(texture: playerTexture) //give player the graphic
    player.size = CGSize(width: 125, height: 200) //player sprite size
    player.zPosition = 20
    //physics stuff
    player.physicsBody = SKPhysicsBody(texture: playerTexture, size: player.size) //Set up pixel-perfect collision mesh for the player
    player.physicsBody?.isDynamic = true
    player.physicsBody!.affectedByGravity = true //Stop the player from being affected by gravity
    player.physicsBody?.allowsRotation = false

    //spawny stuff
    insertChild(player, at: 0) //spawn player
    player.position = position //move player to position passed into this method
    playerNode = player //Create a node where the player is, filled by the player itself... Like a D.Va ult! The call mech one, not the self-destruct one.

    let frame2 = SKTexture(imageNamed: "Ttam2")
    let frame3 = SKTexture(imageNamed: "Ttam3")
    let frame4 = SKTexture(imageNamed: "Ttam4")
    let animation = SKAction.animate(with: [playerTexture, frame2, frame3, frame4], timePerFrame: 0.2)
    let runForever = SKAction.repeatForever(animation)

    player.run(runForever)
}

This may also be something people need to see(this is also code from AnalogJoystick.swift):

let moveAnalogStick =  joystick(diameter: 240) //This is the size of the joystick on screen, probably in pixels


func createJoystick() {

    moveAnalogStick.position = CGPoint(x: moveAnalogStick.radius + 100, y: moveAnalogStick.radius + 5) //position of joystick on screen
    addChild(moveAnalogStick) //add joystick to screen

    moveAnalogStick.stick.color = UIColor.black //Joystick "stick" color
    //moveAnalogStick.stick.image = UIImage(named: "jStick") //Joystick "stick" graphic
    moveAnalogStick.substrate.color = UIColor.clear //Joystick "base" color
    moveAnalogStick.substrate.image = UIImage(named: "jSubstrate") //Joystick "base" graphic

    //MARK: Handlers begin
    moveAnalogStick.startHandler = { [unowned self] data in //These things happen only when the joystick is first pressed

        //CODE GOES HERE

    }

    moveAnalogStick.trackingHandler = { [unowned self] data in //These things happen while the joystick is being touched- regardless of movement. But honestly, this sucker is so sensitive, I'd give someone a medal if they can touch it without moving it at all

        //self.playerNode?.zRotation = (data.angular + 3.14159265359) //player rotation matches joystick, had to add in pi because of graphic facing wrong way- asked Jenny to fix this, but not a priority

        //these two lines are linked in a way I can't figure out how to untangle right now
        //They control movement though, I know that for a fact
        guard let pN = self.playerNode else { return }
        pN.position = CGPoint(x: pN.position.x + (data.velocity.x * 0.07), y: pN.position.y + (data.velocity.x * 0))

}

    moveAnalogStick.stopHandler = { [unowned self] data in //These things happen only when the joystick stops being pressed

        ///CODE GOES HERE

    }
    //MARK: Handlers end
}
  • Please post the code showing where you declare and initialize the `player` – TheValyreanGroup Apr 24 '17 at 21:50
  • I think thats what you were meaning, i added it to the bottom of the post – Matthew Dunkirk Apr 24 '17 at 21:59
  • Also, i have the character hooked into a virtual joystick, that may have some play in why it won't work? i can post that code as well if it's necessary – Matthew Dunkirk Apr 24 '17 at 22:12
  • There's nothing that sticks out that should cause a crash when that button is tapped. Does the debugger point to any specific call or line? Or is there an error message? – TheValyreanGroup Apr 24 '17 at 22:44
  • when I have the //self.player.physicsBody?.velocity = CGVector(dx: 0, dy: 0) //self.player.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 20)) uncommented, it would come up that there was a thread 1 exc error. I will have to wait to reply till tomorrow due to me having to leave my classroom due to another class coming in. I will reply as soon as I can. thank you so much so far for trying to help me. I've been stuck with this error for 2 days now and have to have it gone soon since the game I am making is for a class. P.S i'll upload my whole code if I have to haha – Matthew Dunkirk Apr 25 '17 at 00:27

1 Answers1

1

I see the problem now.

You declare a local variable of player in your createPlayer() function, but set that instance of the player to the global variable playerNode. But you are trying to reference the local variable when you apply your impulse. Change the two lines to

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

You are probably getting THREAD 1 EXC_BAD_INSTRUCTION. Which usually means the compiler doesn't exactly know what you're trying to do. In other words, it knows the variable player exists, but it can't use it. The error should be more explanatory.

TheValyreanGroup
  • 3,554
  • 2
  • 12
  • 30
  • oooh ok, that makes sense now. i'll try that as soon as I get to the room – Matthew Dunkirk Apr 25 '17 at 00:38
  • also, would you mind me asking another question revolving around another 1 of my buttons? – Matthew Dunkirk Apr 25 '17 at 00:39
  • You'll need to post a separate question, but I'll be more than happy to take a look at it. After you post it feel free to come back here and post the new link so I can find it. – TheValyreanGroup Apr 25 '17 at 00:41
  • so i just went to the classroom now. i changed the self.player to the self.playerNode. when changing it, it has came up with an error saying "Value of optional type 'SKSpriteNode?' not unwrapped; did you mean to use '!' or '?'?" should i do this or will this effect it? – Matthew Dunkirk Apr 25 '17 at 01:45
  • You did not show where you declared `playerNode` but apparently it's an optional. So yes, use `self.playerNode?.physicsBody?`.... – TheValyreanGroup Apr 25 '17 at 01:52
  • Great. Please remember to up vote and mark as the answer if this helped you and answered your question. – TheValyreanGroup Apr 25 '17 at 02:00