2016-09-10 4 views
3

私はSwiftでDoodle Jumpクローンゲームを作成していますが、プレイヤーがジャンプすると、プラットフォームの底に頭が当たって通過しないという問題があります。どのようにすれば、プレイヤーはプラットフォームを通過してジャンプすることができますか?私はここに私のコードを持っています。これを行うにはSpriteキットの片方向プラットフォームの衝突

import SpriteKit 

class GameScene: SKScene, SKPhysicsContactDelegate { 

    var hero = SKSpriteNode(imageNamed: "hero"); 
    var stepSizeTest = SKSpriteNode(imageNamed: "step"); 
    var start = false; 
    var jumpSpeed = CGFloat(0); 
    var gravity = CGFloat(0); 
    var stepPositionDivision:CGFloat = 0 //allows the step to spawn on specific places on y axes 
    var setpPositionHeightIncrease:CGFloat = 0; 

    var positionX:CGFloat = 0; 
    var timeInterval:NSTimeInterval = 0; 
    var CurTime:NSTimeInterval = 0; 
    var TimeWhenThePreviousStepSpawned:NSTimeInterval = 0; 
    var standart:Bool = false; 
    var move:Bool = false; 
    var oneJumpOnly:Bool = false; 
    var cracked:Bool = false; 
    var jumped:Bool = false; 

    struct PhysicsCategory{ 
     static var None: UInt32 = 0; 
     static var step: UInt32 = 0b1; 
     static var hero: UInt32 = 0b10; 
     static var All: UInt32 = UInt32.max; 
    } 

    func didBeginContact(contact: SKPhysicsContact) { 
     var contactBody1: SKPhysicsBody; 
     var contactBody2: SKPhysicsBody; 
     if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask){ 
      contactBody1 = contact.bodyA; 
      contactBody2 = contact.bodyB; 
     } 
     else{ 
      contactBody1 = contact.bodyB; 
      contactBody2 = contact.bodyA; 
     } 

     if (contactBody1.categoryBitMask == PhysicsCategory.step && contactBody2.categoryBitMask == PhysicsCategory.hero){ 
      jumpSpeed = CGFloat(self.frame.size.height*0.01320422535); 

     } 
//  if (contactBody1.categoryBitMask == PhysicsCategory.ground && contactBody2.categoryBitMask == PhysicsCategory.hero){ 
// 
//  } 
    } 

    override func didMoveToView(view: SKView) { 
     /* Setup your scene here */ 
     stepPositionDivision = self.frame.size.height/23; 

     jumpSpeed = CGFloat(self.frame.size.height*0.01320422535); 
     gravity = CGFloat(self.frame.size.height*(-0.0003521126761)); 

     self.physicsWorld.contactDelegate = self; 

     self.physicsWorld.gravity = CGVectorMake(0,0); 

     let sceneBody = SKPhysicsBody(edgeLoopFromRect: self.frame); 
     sceneBody.friction = 0; 
     self.physicsBody = sceneBody; 


     self.hero.anchorPoint = CGPoint(x: 0.5, y: 0.5); 
     self.hero.position = CGPoint(x:self.frame.size.width/2, y:self.hero.size.height/2); 
     self.hero.physicsBody = SKPhysicsBody(rectangleOfSize: self.hero.size) 
     self.hero.physicsBody?.restitution = 1; 
     self.hero.physicsBody?.affectedByGravity = false; 
     self.hero.physicsBody?.friction = 0; 
     self.hero.physicsBody?.categoryBitMask = PhysicsCategory.hero; 
     self.hero.physicsBody?.collisionBitMask = PhysicsCategory.step; 
     self.hero.physicsBody?.contactTestBitMask = PhysicsCategory.step; 

     self.addChild(self.hero); 
    } 

    func ranPositionX() -> CGFloat{ 
     let stepSise = UInt32(self.stepSizeTest.size.width) 
     let posX = arc4random_uniform(UInt32(self.frame.size.width) - stepSise) + stepSise 
     return CGFloat(posX) 
    } 

    func stepSpawn(){ 
     if (setpPositionHeightIncrease < self.frame.size.height){ 
      let step = SKSpriteNode(imageNamed: "step"); 
      let posX = ranPositionX() 

      step.anchorPoint = CGPoint(x: 0.5, y: 0.5); 
      step.position = CGPoint(x:posX, y:setpPositionHeightIncrease); 
      step.physicsBody = SKPhysicsBody(rectangleOfSize: step.size); 
      step.physicsBody?.affectedByGravity = false; 
      step.physicsBody?.dynamic = true; 
      step.physicsBody?.friction = 0; 
      step.physicsBody?.categoryBitMask = PhysicsCategory.step; 
      step.physicsBody?.collisionBitMask = PhysicsCategory.None; 
      step.physicsBody?.contactTestBitMask = PhysicsCategory.hero; 

      self.addChild(step); 
      setpPositionHeightIncrease += stepPositionDivision 
     } 
    } 

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

     } 
    } 

    override func update(currentTime: CFTimeInterval) { 
     /* Called before each frame is rendered */ 

     self.hero.position.y += jumpSpeed 
     jumpSpeed += gravity 

     if (start == false){ 
      //self.hero.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 40)) 
      start = true; 
     } 
     stepSpawn() 
    } 
} 
+0

ためcategoryBitMaskの特定のビットを予約し、あればある彼らプレーヤの上にある場合は、collisionBitMaskを切り替えて衝突しないようにし、プレーヤの下にある場合は切り替えてください。 –

答えて

5

一つの方法は、ヒーローは転倒やジャンプされている場合、オン/オフ、適切な衝突ビット(複数可)を切り替えることです。主人公は、速度がdyの場合は0より小さく、dyが0より大きい場合はジャンプ(またはバウンス)すると落ちています。ここでこれを行う方法の例です:

// Add this to the update method 
if let body = hero.physicsBody { 
    let dy = body.velocity.dy 
    if dy > 0 { 
     // Prevent collisions if the hero is jumping 
     body.collisionBitMask &= ~PhysicsCategory.step 
    } 
    else { 
     // Allow collisions if the hero is falling 
     body.collisionBitMask |= PhysicsCategory.step 
    } 
} 
+3

これはまあまあのアプローチです。 1つのキャッチ、しかし:主人公が横たわって転倒している場合、彼の側はプラットフォームのそれと衝突する可能性があります。これを回避するために、私は上記のアプローチを最小限の物理学のボディと組み合わせます。プラットフォームの上端だけがボディを必要とし、全体の目に見える形状ではなく、ヒーロースプライトの下端のみが必要です。 (ヒーローの他の部分が敵などと衝突する必要がある場合は、床と衝突しない別のボディを使用してください) – rickster

+0

&PhysicsCategory.step、| =これらの文字は私を混乱させます。私が5歳の時に意味するものを詳しく説明できますか? – GeorGios

+2

高いレベルでは、これらのステートメントは特定のビットを設定および設定解除します。この場合、ヒーローが落ちているときには 'step'ノードに対応するカテゴリービットをオンにし、ジャンプするときにオフにします。 'x&=〜b010'は単純に' x = x&〜b010'を省略したもので、 'x | = b010'は' x = x | b010'、&、〜、および|それぞれ_and_、_not_、_or_ビット演算子です。詳細については、[Bitwise Operator](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-ID29)を参照してください。これらの演算子。 – 0x141E

1

これについて移動する最良の方法は、さんがCollisionPlatformそれを呼びましょう、2つのカテゴリを使用することであり、NoCollisionPlatform

のはラインではなく、ボックスする必要がありますNoCollisionPlatform

あなたのプラットフォームSKPhysicsBodyHero

セットのごSKSpriteNodeすべてのプラットフォームを呼ぶことにしましょう。これらのボディを作成するときは、エッジループを使用する方が良いですし、物理学の世界に負担をかけることはありません。

HerocontactTestBitMaskcollisionBitMaskCollisionPlatformが、両方CollisionPlatformNoCollisionPlatformを持っている必要があります。

Heroも以前の位置を知っている必要があります。あなたはNoCollisionPlatformと衝突あなたのdidBeginContact方法、オン

Heroの底がプラットフォーム以下であるとHeroの前の位置は、プラットフォーム上にある場合は、ご確認ください。これが真である場合は、ご使​​用のプラットフォーム上で、あなたのdidEndContact methodにCollisionPlatform

にプラットフォームのcategoryBitMaskを変更する今すぐバックNoCollisionPlatform

のプラットフォームのcategoryBitMaskを設定した場合ので、あなたがそれを行う方法には注意してください同じx軸上にある次のプラットフォームに移動すると、丸め誤差のために転倒する可能性があります。あなたは1/2画素位置を扱っていない場合、私は強制的にダウンジャンプを達成するためにInt

に丸めたりキャストをお勧めします、単にHeroが触れた最後のプラットフォームを覚えて、そしてコマンドで、categoryBitMaskバックを設定しますNoCollisionPlatform

この時点では、Heroをサブクラス化し、前回の位置とともにこのサブクラスの中で最後に触ったプラットフォームへのポインタを保持することをお勧めします。彼がもはやそれに触れないときは、それをクリアしないようにしてください。

このようにすると、重力以外の物理的な力をHeroに適用する必要がないので、SKActionはこれと連携します。重力をかけないと、Heroの速度が0になるため、プラットフォームにヒットしたときに何が起こるのか分かりません。どのようなプッシュ反応が起こるかは分かります。左右に動かすと(これも上に行く)、これは起こりますので、システムがあなたが動いている方向を知るように、スプライトに少しの速度を適用するだけですが、動きが弱いので弱くなりますピクセルを移動します。

あなたのプラットフォームには1ピクセルしかないので、あなたのHeroのチャンスは前のフレームよりも上にあり、その下の方のフレームはそのようになりますあなたのHeroがプラットフォームに着陸しないと期待しているのは本当にスリムです(これを達成するには、1フレームの長さに1度のような角度で落とす必要があります。

さらに進化したい場合は、これを考慮してマスクのビットを予約し、必要に応じて設定すれば、複数のカテゴリを持つことができます。複数のエントリを作る必要があります。私はビット30を予約するのが好きですこのケースを処理するために、ビット31は、スプライトが生きているか死んでいるかをチェックするために予約しています。

これが唯一のあなたが複数のHeroesを持つようにしたい場合は、あなたが別の方法で作業する必要が1 Hero

で動作しますのでご注意ください。

代わりに、個別のHerocollisionBitMaskをスワップしますか?このアプローチの問題は、階段状のプラットフォームを作成すると、2番目のプラットフォームの側面に衝突する可能性があります。

あなたがすることができる他の事は、私の事前の方法を使用して、私はあなたがすべてのノード上のシーンを列挙する必要があるとしていると思う各Hero