質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.40%

  • Swift

    9124questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

[swift3] contactDelegate 衝突判定を受け取れない

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,244

yohuchan

score 3

swiftの勉強を始めたばかりの初心者ですが、よろしくお願いします。
physicsBody?.categoryBitMask & collisionBitMask & contactTestBitMaskなどの設定はあっているように思うのですが、どうにも判定受け取れません。何か違うところに問題があるように思えるのですが、お知恵をお貸しいただけたら幸いです。

class GameScene: SKScene,SKPhysicsContactDelegate {
    〜〜略〜〜 
    let controllarea = SKShapeNode(rectOf: CGSize(width:1500 ,height:400))
    let guideSprite = SKShapeNode(circleOfRadius: 30)
   〜〜略〜〜
    //カテゴリー分け
    let category_guide: UInt32 = 1 << 1
    let category_box: UInt32 = 1 << 2

    override func didMove(to view: SKView) {

        self.backgroundColor = UIColor.white
        self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)//物理空間を作る
        self.physicsWorld.gravity = CGVector(dx:0,dy:0)//重力を切る
        self.physicsWorld.contactDelegate = self//衝突情報を自分で受ける
       〜〜略〜〜
        //boxづくり
        for i in 0...5 {
            for h in 0...5{            
                let townSprite = SKShapeNode(rectOf: CGSize(width:200 ,height:200))
                townSprite.fillColor = UIColor.blue
                townSprite.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width:200 ,height:200))
                townSprite.physicsBody?.isDynamic = false
                townSprite.physicsBody?.categoryBitMask = category_box
                townSprite.physicsBody?.collisionBitMask = category_guide
                townSprite.physicsBody?.contactTestBitMask = category_guide

                townSprite.position = CGPoint (x: -1000 + 400 * h, y: -1000 + 400 * i)

                ad_x = -1000 + 400 * h
                ad_y = -1000 + 400 * i

                addressArray_x.append(ad_x)
                addressArray_y.append(ad_y)
                townArray.append(townSprite)
  }

        guideSprite.fillColor = UIColor.red
        guideSprite.physicsBody = SKPhysicsBody(circleOfRadius: 30)
        guideSprite.physicsBody?.isDynamic = false
        guideSprite.physicsBody?.categoryBitMask = category_guide
        guideSprite.physicsBody?.collisionBitMask = category_box
        guideSprite.physicsBody?.contactTestBitMask = category_box

        guideSprite.position = CGPoint(x: 500,y: 800)

        self.addChild(guideSprite)



        //コントローラー表示
        controllarea.fillColor = UIColor(red: 0.6,green: 0.0 ,blue: 0.4,alpha: 0.5)
        controllarea.physicsBody?.isDynamic = false
        controllarea.position = CGPoint(x:0 ,y:0)
        self.addChild(controllarea)
     ~~~~~~~略~~~~~
    }//did

    //コントロールする
    override func update(_ currentTime: TimeInterval) {
    //上: 〜〜略〜〜         
   //下: 〜〜略〜〜 
    //左: 〜〜略〜〜 
    //右: 〜〜略〜〜 
  }


    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch: AnyObject in touches {
            let location = touch.location(in: self)
            let touchNode = self.atPoint(location)
            〜〜略〜〜 
        }
} //touchBegan

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch: AnyObject in touches {
            let location = touch.location(in: self)
            let touchNode = self.atPoint(location)
             〜〜略〜〜 
        }
    }

    func didBegin(_ contact: SKPhysicsContact) {
              〜〜略〜〜 
            }

    func didEnd(_ contact: SKPhysicsContact) {
              〜〜略〜〜 
            }       
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • fuzzball

    2016/12/11 03:36

    実際に確認できないので色々とテストしていただけますか?(リファレンス読みましたがイマイチ理解出来ませんでした)(その1)townSpriteとguideSpriteのcontactTestBitMaskの指定を逆にしてみる。(その2)両方のcontactTestBitMaskの指定をcategory_guide|category_boxにしてみる。(その3)両方のcontactTestBitMaskの指定を0xffffffffにしてみる。以上です。ちなみに、画面上ではちゃんと衝突してるんですよね?

    キャンセル

  • yohuchan

    2016/12/11 08:50

    色々と丁寧に考えて頂き本当にありがとうございます。このプログラムの概要は、碁盤の目のように並んだ箱の街を赤いボールがコントロールキー(画面上に作ったもの)の操作で移動をして行くと、言ったものでして、箱とボールが衝突した時にそれ以上その方向には動かないようにするために衝突判定をさせたいのですが、完全にボールは箱の上を通過してしまう次第です。アドバイス通りにテストしてみましたがやはり呼び込まれないです。didBeginの中にprint()でフラグを準備してますが立ちません。本来ならプログラム全て載せたいところですが文字数制限があって叶いません。ケアレスミスなのか文法のミスなのか判らない次第です。もっと自分なりに考えてみますが、何かお気付きの点がありましたら教えていただけるとありがたいです。本当に貴重な時間を使わせてしまってすみません。

    キャンセル

  • fuzzball

    2016/12/11 10:13 編集

    実際に使ったことがないのであまり自信が無いのですが、少なくともcategoryBitMaskとcollisionBitMaskの設定は間違っていないようなので、画面上では衝突していると思ったのですが、それすらしていないとなると、Maskの設定ではなく他の部分に問題がありそうですね。もっとシンプルなプログラムでテストしてみてはどうでしょうか?

    キャンセル

回答 1

checkベストアンサー

+1

didBeginが呼ばれないのはともかく、画面上でも衝突しないのはおかしいです。
各BitMaskを一切設定しなくても画面上では衝突します。
(boxのcollisionBitMaskを0にすると画面上でも衝突しなくなります)

ということで、衝突判定を受け取れる最小限のプロジェクトを作ってみましたので参考にして下さい。
Gameテンプレートで新規プロジェクトを作成し、GameScene.swiftを丸ごと置き換えるだけです。
Swift2なので適当に修正して下さい。

import SpriteKit

class GameScene: SKScene, SKPhysicsContactDelegate {

    let category_guide: UInt32 = 1 << 1
    let category_box: UInt32 = 1 << 2

    override func didMoveToView(view: SKView) {

        //world
        self.backgroundColor = UIColor.whiteColor()
        self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
        self.physicsWorld.gravity = CGVectorMake(0.0, -5.0)
        self.physicsWorld.contactDelegate = self
        self.name = "world"

        //guide
        let guideSprite = SKShapeNode(circleOfRadius: 30)
        guideSprite.position = CGPoint(x: self.frame.width/2, y: self.frame.height/2)
        guideSprite.fillColor = UIColor.redColor()
        guideSprite.physicsBody = SKPhysicsBody(circleOfRadius: 30)
        guideSprite.physicsBody!.dynamic = false
        guideSprite.physicsBody!.affectedByGravity = false
        guideSprite.physicsBody?.categoryBitMask = category_guide
        guideSprite.physicsBody?.collisionBitMask = category_box
        //guideSprite.physicsBody?.contactTestBitMask = category_box
        guideSprite.name = "guide"
        self.addChild(guideSprite)

        //box
        let townSprite = SKShapeNode(rectOfSize: CGSizeMake(50, 50))
        townSprite.position = CGPoint(x: self.frame.width/2-1, y: self.frame.height-5)
        townSprite.fillColor = UIColor.blueColor()
        townSprite.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(50, 50))
        townSprite.physicsBody?.categoryBitMask = category_box
        townSprite.physicsBody?.collisionBitMask = category_guide
        townSprite.physicsBody?.contactTestBitMask = category_guide
        townSprite.name = "box"
        self.addChild(townSprite)
    }

    override func update(currentTime: CFTimeInterval) {
    }

    func didBeginContact(contact: SKPhysicsContact) {
        print(contact.bodyA)
        print(contact.bodyB)
    }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/12/12 14:42

    サンプルプログラムまで作っていただいてありがとうございます。
    昨日アドバイス頂いた通りに超シンプルなプログラムを作ったりしながらfuzzballさんのプログラムを見て気が付きました。
         〜
    -------->townSprite.physicsBody?.isDynamic = false
    townSprite.physicsBody?.categoryBitMask = category_box
              〜
       guideSprite.physicsBody = SKPhysicsBody(circleOfRadius: 30)
    -------->guideSprite.physicsBody?.isDynamic = false
       guideSprite.physicsBody?.categoryBitMask = category_guide
      〜
    矢印の部分の ****Sprite.physicsBody?.isDynamic = false ですが衝突する両方とも重力の影響を受けない設定にしてしまうとただのすれ違いになってしまうようです。
    なので実際に移動するtownSpriteの方のtownSprite.physicsBody?.isDynamic = trueにしたら衝突判定されました。少なくとも衝突するどちらか一方が重力の影響を受けないとdidBeginは呼び出されないようです。(まだ推測の域を超えていないのですが。。)

    それにしても、fuzzballさんのように親身に考えていただける方がいるとは本当に感謝いたします。
    この先まだまだ出てくるであろうトラブルにも向き合う勇気が出てきました。甘えてばかりでもいけないので自力で解いていこうとは思いますが、心折れそうな時にはまた相談したいと思います。その時はご縁があればよろしくお願いします。

    キャンセル

  • 2016/12/12 15:07 編集

    なるほど。私のサンプルだと、両方ともfalseにすると衝突しないので試していませんでした。

    なお、isDynamic = falseは「重力の影響を受けない」ではなく「動かない」という意味だと思います。リファレンスの直訳だと「physics bodyはそれに適用された全ての力と衝動を無視します」(ちなみに、重力の影響はaffectedByGravityプロパティを使います)

    で、「動かない者同士は衝突することがない」ので判定を端折っているんじゃないかと想像します。

    キャンセル

  • 2016/12/12 22:25

    ありがとうございます。とても勉強になります。
    今はたくさんの有効な情報が必要なのでとても助かります。
    現在は、touchesBeganの長押し時の暴走と格闘中なので,
    また、お世話になるかもしれまでんが、よろしくお願いします。(^^;

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.40%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • Swift

    9124questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています