Sprite Kit设置Min。和马克斯。跳跃 [英] Sprite Kit set Min. and Max. for Jump

查看:110
本文介绍了Sprite Kit设置Min。和马克斯。跳跃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在 Y轴上移动SKSpriteNode。名为Player的SKSpriteNode没有 Velocity 。只有在平台联系时,玩家才能跳转。



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



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



但是玩家也应该能够在最小和最大高度之间跳转,如果是屏幕不长但也不会很快按下,玩家只能得到 y = 70 的冲动。



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



我已经尝试过这个线程中的建议答案:



重要提示:



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



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



这需要大量的调整和适当的平台和接触检测,但它可以让你知道如何实现你所询问的跳跃。


I want to move a SKSpriteNode on the Y-Axis. The SKSpriteNode called Player has no Velocity.The Player can only jump if a Platform is in contact.

Everytime the Screen is touched, I want to give the Player an impulse with a minimum impulse or a maximum impulse

If the Screen is tapped shortly, the Minimum impulse should be e.g. y = 50. If the Screen is hold, that means the finger is on the Screen long, the Maximum should be e.g. y = 100.

But the Player should be also able to jump between the Minimum and Maximum height, if for e.g. the Screen is not long but also not shortly pressed, the Player should only get an impulse of y = 70.

If the Screen is hold, the Player should jump to his max height, fall down, and if it is in contact with the Platform again, it should jump, because you still hold the Screen.

I have already tried this with the suggested answer in this Thread:StackOverFlow But this does not give the Minimum jump, also no Press jump.

For clarity: The impulse should not be after the tap is done, but while it is tapped. The longer you hold, the longer the jump is.

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

    }

}

解决方案

Here is an working example on how to make something like:

  • long pressed jump based on duration of press
  • short (one tap jump)
  • restrict character to jump while in the air
  • keep character jumping while finger is on screen

    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: SKColor.greenColor(), size: CGSize(width: 30, height:30))
    
    
            let   debugLabel = SKLabelNode(fontNamed: "Geneva")
    
            override func didMoveToView(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(edgeLoopFromRect: self.frame)
                self.physicsBody?.categoryBitMask = WallCategory
                self.physicsBody?.collisionBitMask = CharacterCategory
    
    
                //Setup character
                character.position = CGPoint(x: 150, y: 150)
                character.physicsBody = SKPhysicsBody(rectangleOfSize: character.size)
                character.physicsBody?.categoryBitMask = CharacterCategory
                character.physicsBody?.contactTestBitMask = PlatformCategory
                character.physicsBody?.collisionBitMask = PlatformCategory | WallCategory
                character.physicsBody?.allowsRotation = false
                character.physicsBody?.dynamic = true
                character.physicsBody?.restitution = 0.1
    
                self.addChild(character)
    
                generatePlatforms()
    
                debugLabel.text = " DEBUG: "
                debugLabel.fontColor = SKColor.whiteColor()
                debugLabel.fontSize = 12.0
                debugLabel.position = CGPoint(x: CGRectGetMidX(frame), y: CGRectGetMidY(frame)+100)
                self.addChild(debugLabel)
    
    
            }
    
            func generatePlatforms(){
    
    
                for i in 1...4
                {
    
    
    
                    let position = CGPoint(x: CGRectGetMidX(frame), y: CGFloat(i)*140.0 - 100)
    
                    let platform = createPlatformAtPosition(position)
    
                    self.addChild(platform)
    
                }
    
    
            }
    
    
            func createPlatformAtPosition(position : CGPoint)->SKSpriteNode{
    
                let platform = SKSpriteNode(color: SKColor.greenColor(), size: CGSize(width:frame.size.width, height:20))
    
                platform.position = position
    
                platform.physicsBody = SKPhysicsBody(
                    edgeFromPoint: CGPoint(x: -platform.size.width/2.0, y:platform.size.height/2.0),
                    toPoint: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?.dynamic               = false
                platform.physicsBody?.restitution = 0.0
    
                return platform
            }
    
            func jump(force : CGFloat){
    
    
                if(self.isCharacterOnGround){
    
                    self.character.physicsBody?.applyImpulse(CGVectorMake(0, force))
                    self.character.physicsBody?.collisionBitMask = WallCategory
                    self.isCharacterOnGround = false
                }
    
            }
    
            override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
    
                self.pressed = true
    
                let timerAction = SKAction.waitForDuration(0.05)
    
                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: NSSet, withEvent event: UIEvent) {
    
                self.removeActionForKey("repeatAction")
    
                self.jump(self.force)
    
                self.force = Constants.minimumJumpForce
    
                self.pressed = false
            }
    
    
            override func update(currentTime: NSTimeInterval) {
    
    
                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(CGVectorMake(Constants.characterSideSpeed, 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(CGVectorMake(-Constants.characterSideSpeed, 0.0))
    
                }else if(character.physicsBody?.velocity.dx > 0.0){
    
                   character.physicsBody?.applyForce(CGVectorMake(Constants.characterSideSpeed, 0.0))
    
                }else{
    
                    character.physicsBody?.applyForce(CGVectorMake(-Constants.characterSideSpeed, 0.0))
    
                }
    
    
            }
    
    
        func didBeginContact(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){
    
    
                        var characterDx = character.physicsBody?.velocity.dx
    
                        character.physicsBody?.velocity = CGVector(dx: characterDx!, dy: 0.0)
    
                        self.jump(Constants.maximumJumpForce)
                    }
    
                }
    
    
            }
    
    
    
        }
    
        func didEndContact(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 > 0.0)){
    
                    character.physicsBody?.collisionBitMask = WallCategory
    
                    self.isCharacterOnGround = false
    
                }
    
            }
    
        }
    
    }
    

Note that this is simple example, and in real application you will probably have to handle states like isOnTheGround in a different way. Right now, to determine if character is on the ground you just set isOnTheGround = true when character make a contact with platform, and set it to false in didEndContact...But there are situations when character can be in contact with platform while in the air (eg. side contact)...

EDIT:

I changed the code to let the player jump while pressed. Here is the result:

Important:

Actual platform implementation and contact handling is up to you and this is not tested. The only purpose of this example is to show you how to jump while pressed. Currently, physicsWorld.speed is set to 0.5 to make animation slower because its easier to debug like that, but you can change this to default value (1.0).

So, as you can see from the image, while player is on the first platform some small jumps are presented (by simple tapping, or short pressing). Then (player is still on first platform) long press has been made, and player has jumped on second platform. After that, another long press is done, but this time without releasing, and player starts jumping from one platform to another using maximum force.

This needs a lot of tweaking and proper platform & contact detection, but it can give you an idea about how to implement jumping you asked about.

这篇关于Sprite Kit设置Min。和马克斯。跳跃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆