swift - Jump only when landed

2019-07-10 20:51发布

问题:

I'm looking to restrict my character (cat), to only jump when it's either on the ground (dummy SKNode), or when on the tree (treeP SKNode).

Currently I don't have any restrictions to touchesBegan and as a result the cat is able to fly through the air if the user clicks in quick succession, whilst this could be useful in other games it's not welcome here.

If anyone could help me I'd be really happy.

What i would like to do but have no experience would be to enable a click (jump), if the cat was in contact with either dummy or tree and likewise disable clicks if not in contact with either dummy or tree.

Here is everything that may be of use....

class GameScene: SKScene, SKPhysicsContactDelegate {

let catCategory: UInt32 = 1 << 0
let treeCategory: UInt32 = 1 << 1
let worldCategory: UInt32 = 1 << 1

override func didMoveToView(view: SKView) {

// part of cat code    

    cat = SKSpriteNode(texture: catTexture1)
    cat.position = CGPoint(x: self.frame.size.width / 2.2, y: self.frame.size.height / 7.0 )
    cat.physicsBody?.categoryBitMask = catCategory
    cat.physicsBody?.collisionBitMask = crowCategory | worldCategory
    cat.physicsBody?.contactTestBitMask = crowCategory | contact2Category

// part of the ground code

    var dummy = SKNode()
    dummy.position = CGPointMake(0, groundTexture.size().height / 2)
    dummy.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.frame.size.width, groundTexture.size().height))
    dummy.physicsBody!.dynamic = false
    dummy.physicsBody?.categoryBitMask = worldCategory
    dummy.physicsBody?.collisionBitMask = 0
    dummy.physicsBody?.contactTestBitMask = 0
    moving.addChild(dummy)

// part of the tree code

func spawnTrees() {
    var treeP = SKNode()
    treeP.position = CGPointMake( self.frame.size.width + treeTexture1.size().width * 2, 0 );
    treeP.zPosition = -10; 
    var height = UInt32( self.frame.size.height / 4 )
    var y = arc4random() % height;
    var tree1 = SKSpriteNode(texture: treeTexture1)
    tree1.position = CGPointMake(0.0, CGFloat(y))
    tree1.physicsBody = SKPhysicsBody(rectangleOfSize: tree1.size)
    tree1.physicsBody?.dynamic = false
    tree1.physicsBody?.categoryBitMask = treeCategory;
    tree1.physicsBody?.collisionBitMask = 0
    tree1.physicsBody?.contactTestBitMask = 0
    treeP.addChild(tree1)

    treeP.runAction(moveAndRemoveTrees)

    trees.addChild(treeP)

}

// all of touchesBegan

override func  touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
    /* Called when a touch begins */


    if (moving.speed > 0){
        cat.physicsBody!.velocity = CGVectorMake(0, 0)
        cat.physicsBody!.applyImpulse(CGVectorMake(0, 20))

                } else if (canRestart) {
                    self.resetScene()
    }

}

回答1:

I recently had this problem. This is how I fixed it. In the game scene create this variable:

    var ableToJump = true

Then in the update method put this code:

    if cat.physicsBody?.velocity.dy == 0 {
ableToJump = true
    }
    else {
ableToJump = false
    }

The above code will work because the update method is ran every frame of the game. Every frame it checks if your cat is moving on the y axis. If you do not have an update method, just type override func update and it should autocomplete.

Now the last step is put this code in the touchesBegan:

    if ableToJump == true {
cat.physicsBody!.applyImpulse(CGVectorMake(0,40))
 }

Note: You may have to tinker with the impulse to get desired jump height



回答2:

You can use some custom boolean variable called isOnTheGround in order to restrict jumping while in the air. This variable need to be updated by you.Note that character is not necessarily on the ground just if it is in contact with "platform" (eg. side contact can occur). So, it's up to you to define what means "on the ground". When you define that, then it's easy:

Hint: You can compare character's y position with platform's y position to see is character is really on the platform.

Assuming that both character's and platform's anchor point are unchanged (0.5,0.5), to calculate character's legs y position you can do something like this (pseudo code):

characterLegsY = characterYPos - characterHeight/2

And to to get platform's surace:

platformSurfaceYPos = platformYPos + platformHeight/2

Preventing jumping while in the air

In touchesBegan:

  • if isOnTheGround -> jump

In didEndContact:

  • here you set isOnTheGround to false (character ended contact with ground/platform)

In didBeginContact:

  • check if character is really on the ground
  • set isOnTheGround variable to true

Here you can find an example of something similar...