Sprite Kit设置Min.和马克斯.跳跃

Alb*_*ert 14 game-physics ios sprite-kit swift

我想在上面移动一个SKSpriteNode Y-Axis.名为Player的SKSpriteNode没有Velocity.播放器只有在平台接触时才能跳转.

每次触摸屏幕时,我都想给玩家一个最小冲动或最大冲动的冲动

如果屏幕很快被点击,最小脉冲应该是例如y = 50.如果屏幕被保持,这意味着手指在屏幕上长,最大值应该是例如y = 100.

但是玩家也应该能够在最小高度和最高高度之间跳跃,如果对于例如屏幕不长但也没有很快按下,玩家应该只能得到一个冲动y = 70.

如果屏幕被保持,播放器应该跳到他的最大高度,跌倒,如果它再次与平台接触,它应该跳,因为你仍然按住屏幕.

我已经尝试过这个线程中的建议答案:StackOverFlow 但是这不会给出最小跳跃,也没有按下跳转.

为清楚起见:冲击不应该在敲击完成后,而是在敲击时.你握的时间越长,跳跃的时间就越长.

import SpriteKit
import GameKit

struct Constants {

static let minimumJumpForce:CGFloat = 40.0
static let maximumJumpForce:CGFloat = 60.0
static let characterSideSpeed:CGFloat = 18.0
}

class GameScene: SKScene, SKPhysicsContactDelegate {

var Player: SKSpriteNode!

var Platform0: SKSpriteNode!

var World: SKNode!
var Camera: SKNode!

var force: CGFloat = 40.0

var pressed = false

var isCharacterOnGround = false

.....

func SpawnPlatforms() {

Platform0 = SKSpriteNode (color: SKColor.greenColor(), size: CGSize(width: self.frame.size.width , height: 25))
Platform0.position = CGPoint(x: self.frame.size.width / 2, y: -36)
Platform0.zPosition = 1

Platform0.physicsBody = SKPhysicsBody(rectangleOfSize:Platform0.size)
Platform0.physicsBody?.dynamic = false
Platform0.physicsBody?.allowsRotation = false
Platform0.physicsBody?.restitution = 0
Platform0.physicsBody?.usesPreciseCollisionDetection = true

Platform0.physicsBody?.categoryBitMask = Platform0Category
Platform0.physicsBody?.collisionBitMask = PlayerCategory
Platform0.physicsBody?.contactTestBitMask = PlayerCategory

World.addChild(Platform0)

}

func SpawnPlayer(){

Player = SKSpriteNode (imageNamed: "Image.png")
Player.size = CGSize(width: 64, height: 64)
Player.position = CGPoint(x: self.frame.size.width / 2, y: 0)
Player.zPosition = 2

Player.physicsBody = SKPhysicsBody(rectangleOfSize:CGSize(width: 35, height: 50))
Player.physicsBody?.dynamic = true
Player.physicsBody?.allowsRotation = false
Player.physicsBody?.restitution = 0.1
Player.physicsBody?.usesPreciseCollisionDetection = true

Player.physicsBody?.categoryBitMask = PlayerCategory
Player.physicsBody?.collisionBitMask = Platform0Category
Player.physicsBody?.contactTestBitMask = Platform0Category | Platform1Category | Platform2Category | Platform3Category | Platform4Category | Platform5Category

World.addChild(Player)

}

func jump(force : CGFloat){


    if(self.isCharacterOnGround){

        self.Player.physicsBody?.applyImpulse(CGVectorMake(0, force))
        self.isCharacterOnGround = false
    }

}

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

    for touch in (touches as! Set<UITouch>) {
        let location = touch.locationInNode(self)

        self.pressed = true

        let timerAction = SKAction.waitForDuration(0.0)

        let update = SKAction.runBlock({
            if(self.force < Constants.maximumJumpForce){
                self.force += 2.0
            }else{
                self.jump(Constants.maximumJumpForce)
                self.force = Constants.maximumJumpForce
            }
        })
        let sequence = SKAction.sequence([timerAction, update])
        let repeat = SKAction.repeatActionForever(sequence)
        self.runAction(repeat, withKey:"repeatAction")
    }
}

override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
    for touch in (touches as! Set<UITouch>) {
        let location = touch.locationInNode(self)

        self.removeActionForKey("repeatAction")

        self.jump(self.force)

        self.force = Constants.minimumJumpForce

        self.pressed = false

}
}

func didBeginContact(contact: SKPhysicsContact) {

    //this gets called automatically when two objects begin contact with each other

    let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

    switch(contactMask) {

    case PlayerCategory | Platform0Category:
        //either the contactMask was the bro type or the ground type
        println("Contact Made0")
        Green = true
        self.isCharacterOnGround = true

    default:
        return

    }

}
Run Code Online (Sandbox Code Playgroud)

Whi*_*ind 11

这是一个关于如何制作如下内容的工作示例:

  • 基于按压持续时间的长按跳跃
  • 短(一次跳跃)
  • 限制角色在空中跳跃
  • 手指在屏幕上时保持角色跳跃

    import SpriteKit
    
    struct Constants {
        static let minimumJumpForce:CGFloat = 15.0
        static let maximumJumpForce:CGFloat = 30.0
        static let characterSideSpeed:CGFloat = 18.0
    }
    
    class GameScene: SKScene,SKPhysicsContactDelegate
    {
        let CharacterCategory   : UInt32 = 0x1 << 1
        let PlatformCategory    : UInt32 = 0x1 << 2
        let WallCategory        : UInt32 = 0x1 << 3
    
        var force: CGFloat = 16.0 //Initial force
        var pressed = false
        var isCharacterOnGround = false // Use this to prevent jumping while in the air
        let character = SKSpriteNode(color: .green, size: CGSize(width: 30, height:30))
        let debugLabel = SKLabelNode(fontNamed: "Geneva")
    
        override func didMove(to view: SKView)
        {
            //Setup contact delegate so we can use didBeginContact and didEndContact methods
            physicsWorld.contactDelegate = self
            physicsWorld.speed = 0.5
            //Setup borders so character can't escape from us :-)
            self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
            self.physicsBody?.categoryBitMask = WallCategory
            self.physicsBody?.collisionBitMask = CharacterCategory
    
            //Setup character
            character.position = CGPoint(x: 150, y: 150)
            character.physicsBody = SKPhysicsBody(rectangleOf: character.size)
            character.physicsBody?.categoryBitMask = CharacterCategory
            character.physicsBody?.contactTestBitMask = PlatformCategory
            character.physicsBody?.collisionBitMask = PlatformCategory | WallCategory
            character.physicsBody?.allowsRotation = false
            character.physicsBody?.isDynamic = true
            character.physicsBody?.restitution = 0.1
    
            self.addChild(character)
    
            generatePlatforms()
    
            debugLabel.text = " DEBUG: "
            debugLabel.fontColor = .white
            debugLabel.fontSize = 12.0
            debugLabel.position = CGPoint(x: frame.midX, y: frame.midY+100)
            self.addChild(debugLabel)
        }
    
        func generatePlatforms(){
            for i in 1...4
            {
                let position = CGPoint(x: frame.midX, y: CGFloat(i)*140.0 - 100)
                let platform = createPlatformAtPosition(position: position)
                self.addChild(platform)
            }
        }
    
    
        func createPlatformAtPosition(position : CGPoint)->SKSpriteNode{
    
            let platform = SKSpriteNode(color: .green, size: CGSize(width: frame.size.width, height:20))
    
            platform.position = position
    
            platform.physicsBody = SKPhysicsBody(
                edgeFrom: CGPoint(x: -platform.size.width/2.0, y:platform.size.height/2.0),
                to:CGPoint(x: platform.size.width/2.0, y: platform.size.height/2.0))
    
            platform.physicsBody?.categoryBitMask       = PlatformCategory
            platform.physicsBody?.contactTestBitMask    = CharacterCategory
            platform.physicsBody?.collisionBitMask      = CharacterCategory
            platform.physicsBody?.allowsRotation        = false
            platform.name                               = "platform"
            platform.physicsBody?.isDynamic             = false
            platform.physicsBody?.restitution           = 0.0
    
            return platform
        }
    
        func jump(force : CGFloat){
            if(self.isCharacterOnGround){
                self.character.physicsBody?.applyImpulse(CGVector(dx: 0, dy: force))
                self.character.physicsBody?.collisionBitMask = WallCategory
                self.isCharacterOnGround = false
            }
        }
    
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            self.pressed = true
    
            let timerAction = SKAction.wait(forDuration: 0.05)
    
            let update = SKAction.run({
                if(self.force < Constants.maximumJumpForce){
                    self.force += 2.0
                }else{
                    self.jump(force: Constants.maximumJumpForce)
                    self.force = Constants.maximumJumpForce
                }
            })
    
            let sequence = SKAction.sequence([timerAction, update])
            let repeat_seq = SKAction.repeatForever(sequence)
            self.run(repeat_seq, withKey:"repeatAction")
        }
    
    
        override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    
            self.removeAction(forKey: "repeatAction")
            self.jump(force: self.force)
            self.force = Constants.minimumJumpForce
            self.pressed = false
    
        }
    
        override func update(_ currentTime: TimeInterval) {
    
            debugLabel.text = "DEBUG: onTheGround : \(isCharacterOnGround), force \(force)"
    
            if(character.position.x <= character.size.width/2.0 + 5.0 && character.physicsBody!.velocity.dx < 0.0 ){
                character.physicsBody?.applyForce(CGVector(dx: Constants.characterSideSpeed, dy: 0.0))
            }else if((character.position.x >= self.frame.size.width - character.size.width/2.0 - 5.0) && character.physicsBody!.velocity.dx >= 0.0){
                character.physicsBody?.applyForce(CGVector(dx: -Constants.characterSideSpeed, dy: 0.0))
            }else if(character.physicsBody!.velocity.dx > 0.0){
                character.physicsBody!.applyForce(CGVector(dx: Constants.characterSideSpeed, dy: 0.0))
            }else{
                character.physicsBody!.applyForce(CGVector(dx: -Constants.characterSideSpeed, dy: 0.0))
            }
        }
    
        func didBegin(_ contact: SKPhysicsContact) {
    
            var firstBody, secondBody: SKPhysicsBody
    
            if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
                firstBody = contact.bodyA
                secondBody = contact.bodyB
            } else {
                firstBody = contact.bodyB
                secondBody = contact.bodyA
            }
    
            if ((firstBody.categoryBitMask & CharacterCategory) != 0 &&
                (secondBody.categoryBitMask & PlatformCategory != 0)) {
    
    
                let platform = secondBody.node! as! SKSpriteNode
                //  platform.color = UIColor.redColor()
                let platformSurfaceYPos = platform.position.y + platform.size.height/2.0
    
                let player = contact.bodyB.node! as! SKSpriteNode
                let playerLegsYPos = player.position.y - player.size.height/2.0
    
                if((platformSurfaceYPos <= playerLegsYPos)){
                    character.physicsBody?.collisionBitMask = PlatformCategory | WallCategory
                    self.isCharacterOnGround = true
    
                    if(self.pressed){
                        let characterDx = character.physicsBody?.velocity.dx
                        character.physicsBody?.velocity = CGVector(dx: characterDx!, dy: 0.0)
                        self.jump(force: Constants.maximumJumpForce)
                    }
                }
            }
        }
    
        func didEnd(_ contact: SKPhysicsContact) {
    
            var firstBody, secondBody: SKPhysicsBody
    
            if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
                firstBody = contact.bodyA
                secondBody = contact.bodyB
            } else {
                firstBody = contact.bodyB
                secondBody = contact.bodyA
            }
    
            if ((firstBody.categoryBitMask & CharacterCategory) != 0 &&
                (secondBody.categoryBitMask & PlatformCategory != 0)) {
    
                let platform = secondBody.node as! SKSpriteNode
                let platformSurfaceYPos = platform.position.y + platform.size.height/2.0
    
                let player = contact.bodyB.node as! SKSpriteNode
                let playerLegsYPos = player.position.y - player.size.height/2.0
    
                if((platformSurfaceYPos <= playerLegsYPos) && ((character.physicsBody?.velocity.dy)! > CGFloat(0.0))){
                    character.physicsBody?.collisionBitMask = WallCategory
                    self.isCharacterOnGround = false
                }
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

请注意,这是一个简单的示例,在实际应用中,您可能必须以不同的方式处理isOnTheGround等状态.眼下,以确定是否字符是你刚才设置的地面isOnTheGround = true时,人物与制造平台接触,并将其设置为falsedidEndContact......但也有情况下,当字符可以在同时在空中平台接触(例如,侧联系)...

编辑:

我更改了代码,让玩家在按下时跳转.结果如下:

在此输入图像描述

重要:

实际的平台实施和联系处理取决于您,并且未经过测试.此示例的唯一目的是向您展示如何在按下时跳转.目前,physicsWorld.speed设置为0.5以使动画更慢,因为它更容易调试,但您可以将其更改为默认值(1.0).

因此,正如您从图像中看到的那样,当玩家在第一个平台上时,会出现一些小的跳跃(通过简单的敲击或短按).然后(玩家仍然在第一个平台上)长按已经完成,并且玩家已经跳到了第二个平台上.之后,又完成了另一次长按,但这次没有释放,玩家开始使用最大力量从一个平台跳到另一个平台.

这需要大量的调整和适当的平台和联系人检测,但它可以让您了解如何实现您询问的跳跃.