2015-07-16 13 views
14

Desidero spostare un SKSpriteNode su Y-Axis. Il SKSpriteNode chiamato Player non ha Velocity. Il giocatore può saltare solo se una piattaforma è in contatto.Kit sprite impostato min. e Max. per Jump

Ogni volta lo schermo viene toccato, voglio dare al giocatore un impulso con un impulso minimo o un massimo impulso

se lo schermo è sfruttato poco, l'impulso minima dovrebbe essere per esempio y = 50. Se lo schermo è premuto, significa che il dito è sullo schermo lungo, il massimo dovrebbe essere ad es. y = 100.

Ma il lettore dovrebbe anche essere in grado di saltare tra l'altezza minima e massima, se per es. lo schermo non è lungo ma anche non premuto brevemente, il lettore dovrebbe ricevere solo un impulso di y = 70.

Se lo schermo è premuto, il lettore dovrebbe saltare alla sua massima altezza, cadere e, se è di nuovo in contatto con la piattaforma, dovrebbe saltare, perché si tiene ancora lo schermo.

Ho già provato questo con la risposta suggerita in questa discussione: StackOverFlow Ma questo non dà il salto minimo, anche no Premere salto.

Per chiarezza: L'impulso non deve essere dopo che il rubinetto è finito, ma mentre è toccato. Più a lungo si tiene, più lungo è il salto.

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 

    } 

} 
+0

Mi piace la seconda risposta (con SKAction) dal link che hai postato. Hai provato quello? A proposito di saltare continuamente tenendo un dito ... Suppongo che dovresti aggiungere una variabile che indica che l'utente tiene ancora un dito sullo schermo, e se questo è un caso, quando viene rilevato il contatto tra piattaforma e giocatore, applicheresti l'impulso per il prossimo salto ... – Whirlwind

+0

Ho provato anche il secondo, non è ancora quello che intendevo. Sì, dovrei applicare un impulso per il salto successivo dopo aver effettuato un contatto, ma devo comunque impostare il minimo e il massimo. – Albert

+0

Controlla la mia risposta. Basta copiare e incollare il codice per vedere come funziona ... – Whirlwind

risposta

11

Ecco un esempio lavorando su come fare qualcosa di simile:

  • salto in lungo pressato in base alla durata della stampa
  • breve (un rubinetto salto)
  • limitare personaggio di saltare mentre nell'aria
  • mantenere il carattere che salta mentre il dito è sullo schermo

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

Si noti che questo è un semplice esempio e nella vera applicazione probabilmente si dovranno gestire stati come isOnTheGround in un modo diverso. In questo momento, per determinare se il personaggio è a terra, basta impostare isOnTheGround = true quando il personaggio crea un contatto con la piattaforma e impostarlo su false in didEndContact ... Ma ci sono situazioni in cui il personaggio può essere in contatto con la piattaforma mentre è in aria (ad esempio contatto laterale) ...

EDIT:.

ho cambiato il codice per permettere al giocatore di saltare mentre premuto. Ecco il risultato:

enter image description here

Importante:

effettiva movimentazione implementazione della piattaforma e il contatto è a voi e questo non è testato. L'unico scopo di questo esempio è mostrarti come saltare mentre premuto. Attualmente, physicsWorld.speed è impostato su 0,5 per rendere l'animazione più lenta perché è più facile eseguire il debug in questo modo, ma è possibile cambiarlo al valore predefinito (1.0).

Quindi, come puoi vedere dall'immagine, mentre il giocatore si trova sulla prima piattaforma vengono presentati alcuni piccoli salti (con un semplice tocco o una breve pressione). Quindi (il giocatore è ancora sulla prima piattaforma) è stata effettuata una lunga pressione e il giocatore è saltato sulla seconda piattaforma. Dopodiché, viene eseguita un'altra lunga pressione, ma questa volta senza rilasciare, e il giocatore inizia a saltare da una piattaforma all'altra usando la massima forza.

Questo richiede un sacco di tweaking e una corretta piattaforma di rilevamento contatto &, ma può darti un'idea su come implementare il salto che hai chiesto.

+0

Grazie per il tuo suggerimento! Non è proprio quello che volevo, ma il Codice per il "Salto quando il contatto con la Piattaforma è fatto mentre Premuto" sta funzionando per me. Ho aggiornato il mio post con un video di un gioco che utilizza la stessa logica. – Albert

+0

@Alber. Ciao ... Quale parte non funziona per te? Hai detto: "Ho già provato questo con la risposta suggerita in questo thread: http://stackoverflow.com/questions/30223997/increase-jump-height-on-longer-touch-until-maximum-height! Ma questo fa non dare il salto minimo, anche no Premere salto. " Il mio esempio era relativo a questa tua affermazione, e intendeva mostrarti come cambiare la forza di salto in base alla durata della pressione e avere "salto minimo" e "premere salto" (tocca breve = salto piccolo, pressione lunga = salto in alto ecc.) – Whirlwind

+0

Con questo codice, abbiamo un minimo e se la 'forza' è inferiore a 100, più a lungo si tocca dà +2 fino a 100, se ho capito bene. Tuttavia, il salto apparirà solo dopo aver finito il rubinetto, non mentre sta succedendo. Voglio avere il salto quando lo schermo viene toccato. – Albert