2015-07-16 10 views
14

Chcę przenieść SKSpriteNode na Y-Axis. SKSpriteNode o nazwie Player nie ma Velocity. Gracz może skakać tylko wtedy, gdy platforma jest w kontakcie.Zestaw Sprite Kit min. i maks. dla Jump

każdym dotknięciu ekranu, chcę dać gracz impuls z minimalną lub maksymalną impuls impuls

jeśli ekran jest na podsłuchu krótko, a minimalny impuls powinien być na przykład y = 50. Jeśli ekran jest zatrzymany, oznacza to, że palec znajduje się na ekranie, wartość maksymalna powinna wynosić np. y = 100.

Ale odtwarzacz powinien również mieć możliwość przeskakiwania między minimalną i maksymalną wysokością, jeśli np. Ekran nie jest długi, ale też nie jest krótko wciśnięty, odtwarzacz powinien otrzymać impuls tylko o wartości y = 70.

Jeśli ekran jest zatrzymany, gracz powinien przeskoczyć na swoją maksymalną wysokość, opaść, a jeśli znowu będzie miał kontakt z platformą, powinien przeskoczyć, ponieważ nadal trzyma ekran.

Próbowałem już tego z sugerowaną odpowiedzią w tym wątku: StackOverFlow Ale to nie daje skoku minimalnego, także nie skoku prasy.

Dla przejrzystości: Impuls nie powinien być po zakończeniu kranu, ale gdy jest dotknięty. Im dłużej trzymasz, tym dłuższy jest skok.

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

Podoba mi się druga odpowiedź (z SKAction) z linku, który napisałeś. Czy próbowałeś tego? O ciągłym skakaniu, trzymając palec ... Chyba powinieneś dodać zmienną, która wskazuje, że użytkownik wciąż trzyma palec na ekranie, a jeśli to jest przypadek, gdy zostanie wykryty kontakt między platformą a graczem, zastosujesz impuls do następnego skoku ... – Whirlwind

+0

Próbowałem także drugiego, wciąż nie tego miałem na myśli. Tak, powinienem zastosować impuls do następnego skoku po nawiązaniu kontaktu, ale nadal muszę ustawić minimum i maksimum. – Albert

+0

Sprawdź moją odpowiedź. Po prostu skopiuj i wklej kod, aby zobaczyć, jak działa ... – Whirlwind

Odpowiedz

11

Oto przykład pracuje nad jak zrobić coś takiego:

  • przytrzymany skoku na podstawie czasu trwania prasie
  • krótkim (jeden kran jump)
  • ograniczyć charakter skakać chwilę w powietrzu
  • kontynuuj skakanie postaci, gdy palec jest na ekranie

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

Należy zauważyć, że jest to prosty przykład, aw prawdziwej aplikacji prawdopodobnie będziesz musiał obsługiwać stany takie jak isOnTheGround w inny sposób. Teraz, aby określić, czy postać jest na ziemi, po prostu ustaw isOnTheGround = true, gdy postać nawiązuje kontakt z platformą, i ustaw ją na false w didEndContact ... Ale są sytuacje, w których postać może być w kontakcie z platformą podczas lotu (na przykład kontakt z boku) ...

EDIT:.

Zmieniłem kod do niech skok player podczas wciśnięty. Oto wynik:

enter image description here

Ważne:

Rzeczywista obsługa wdrożenie platformy i kontakt do ciebie, a to nie jest badana. Jedynym celem tego przykładu jest pokazanie ci, jak skakać podczas naciskania. Obecnie wartość physicsWorld.speed jest ustawiona na 0,5, aby spowolnić animację, ponieważ jest łatwiejsza do debugowania, ale można ją zmienić na wartość domyślną (1.0).

Tak więc, jak widać na obrazku, podczas gdy gracz znajduje się na pierwszej platformie, prezentowane są małe skoki (przez proste stukanie lub krótkie naciśnięcie). Następnie (gracz wciąż znajduje się na pierwszej platformie) zostało wykonane długie naciśnięcie, a gracz wskoczył na drugą platformę. Następnie wykonuje się kolejne długie naciśnięcie, ale tym razem bez zwalniania, a gracz zaczyna przeskakiwać z jednej platformy na drugą używając maksymalnej siły.

To wymaga wielu poprawek i właściwej platformy & wykrywanie kontaktu, ale może dać ci pojęcie o tym, jak wykonać skoki, o które pytasz.

+0

Dzięki za sugestię! Nie jest to dokładnie to, czego chciałem, ale kod dla "Skoku, gdy kontakt z platformą powstaje podczas pracy z prasą" działa dla mnie. Zaktualizowałem swój post filmem z gry, która używa tej samej logiki. – Albert

+0

@Alber. Cześć ... Która część nie działa dla ciebie? Powiedziałeś: "Próbowałem już tego z sugerowaną odpowiedzią w tym wątku: http://stackoverflow.com/questions/30223997/increase-jump-height-on-longer-touch-until-maximum- height! Ale to robi nie daje skoku minimalnego, a także nie skoku prasy. " Mój przykład był związany z twoim stwierdzeniem, a jego celem było pokazanie ci, jak zmienić siłę skoku w oparciu o czas trwania naciśnięcia i aby uzyskać "minimalny skok" i "skok nacisku" (krótkie naciśnięcie = mały skok, długie naciśnięcie = duży skok itp.) – Whirlwind

+0

Z tym kodem mamy minimum, a jeśli "force" ma mniej niż 100, to dłuższy czas stuknięcia daje +2 do 100, jeśli zrozumiałem to poprawnie. Jednak skok pojawi się dopiero po zakończeniu kranu, a nie w trakcie jego działania. Chcę mieć skok po dotknięciu ekranu. – Albert

Powiązane problemy