1. 問題の現象

SKPhysicsBodyとはXcodeのSpriteKitでNodeに物理シミュレートを追加するためのオブジェクトですが、画像を利用して初期化した場合にうまく動かない現象が発生しました。
やりたかった事と発生した現象は以下です。

  1. 背景Nodeの上にアイテムNodeを載せる。
  2. アイテムNodeには林檎の画像でSKPhysicsBodyを設定。
  3. タッチした時、タッチポイントからどのノードが触られたか判定したい。
  4. しかしタッチ位置からNodeがうまく割り出せないバグ発生。
  5. しかもiPadでは正常に動くのにiPhoneだと動かない。

2. 原因

結構いろんな要因を探ったりググったりした結果、teratailで質問投げてる方と同じ現象でした。そのページがコチラです。

元々の画像をひきのばして使用していたのですが、元のサイズで使用したらうまく機能しました。

https://teratail.com/questions/35649

マジでした。
元の画像をAdobeXDでトリミングして出力していたのですが、オリジナルの元画像よりも@3xの画像サイズの方が大きくなっていました。
iPadは@2xの画像を利用するため、正常に動いていた様です。

3. 解決

元画像が@3xよりも大きくなるようにPhotoshopで出力しなおして、画像を差し替えたら直りました。
Photoshopで出力する時も元画像より拡大して出力したのですが、これはOKでした。
見た目ではわからない出力時の質ってものがあるのかもしれません….
ゲームの作成途中で仮置き画像だったので、この様なバグを引き起こしてしまったとはいえ、、、これはハマります…。

最後に

蛇足ですが、今回のやりたかったことの説明ソースコード版です。

// アイテムノードの作成時にSKPhysicsBodyを設定
let itemNode = SKSpriteNode(imageNamed: "apple")
itemNode.physicsBody = SKPhysicsBody(texture: itemNode.texture!, size: itemNode.size)
// タッチされた時にNodeの取得
func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let location = self.singleTouchLocation(touches) {
        let touchNode = self.scene?.physicsWorld.body(at: location)
    }
 }