💥

【visionOS】衝突判定してEntityをシーンから削除する

2024/06/04に公開

はじめに

今回はvisionOSで衝突判定の方法を紹介します。
個人開発している妖怪バスターZ[1]では、ハンドジェスチャーで弾を撃ち、鬼に当たったら両方ともシーンから削除するようにしています。
※ゲームではアニメーションさせてから削除していますが、今回は衝突したら即削除しています

つくったもの

環境

  1. Xcode Version 15.3
  2. visionOS 1.1

CollisionとPhysicsBodyをEntityに追加

CollisionComponent[2]とPhysicsBodyComponent[3]を衝突判定したいEntityそれぞれに追加することで衝突判定ができるようになります。

// 弾のEntityを作成
let soulBullet = ModelEntity(
    mesh: .generateSphere(radius: 2.0),
    materials: [material]
)

// 判定用に名前をつける
soulBullet.name = "SoulBullet"

// 弾のEntityにCollisionを追加
soulBullet.collision = CollisionComponent(
    shapes: [.generateSphere(radius: 2.0)],
    mode: .default
)

// addForceして弾を飛ばすためPhysicsBodyを追加
soulBullet.physicsBody = PhysicsBodyComponent(
    shapes: [ShapeResource.generateSphere(radius: 2.0)],
    mass: 0.1,
    material: nil,
    mode: .dynamic
)

// 鬼のEntityを作成
let oni = oniTemplate.clone(recursive: true)

// 判定用に名前をつける
oni.name = "Oni"

// 鬼のEntityにCollisionを追加
oni.components.set(CollisionComponent(
    shapes: [.generateCapsule(height: 60, radius: 10)],
    mode: .default
))

// Deviceとの衝突判定のため、鬼にもPhysicsBodyを追加
oni.components.set(PhysicsBodyComponent(
    shapes: [ShapeResource.generateCapsule(height: 60, radius: 10)],
    mass: 0,
    material: nil,
    mode: .dynamic
))

弾を撃って衝突したら鬼を撃破する

RealityViewクロージャの戻り値であるcontentをsubscribeしてCollistionEventsを取得し、衝突したEntityを条件分岐で処理していきます。

そして、SceneにcontentEntityというグローバルなrootエンティティを持っておき、それにすべてのEntityを追加しているので、removeFromParent()でSceneからEntityを削除することができます。

struct ImmersiveView: View {
    @State private var subscription: EventSubscription?

    var body: some View {
        RealityView { content in
            // rootエンティティを追加
            content.add(contentEntity)

            // 衝突判定
            subscription = content.subscribe(to: CollisionEvents.Began.self) { collisionEvent in
                // 弾と鬼が衝突したら両方をシーンから削除
                // nameで判別する
                if collisionEvent.entityA.name == "SoulBullet" && collisionEvent.entityB.name == "Oni" {

                    gameModel.playSoundEffect(fileName: "Hit", entity: deviceEntity)
                    // entityAが弾
                    collisionEvent.entityA.removeFromParent()
                    // entityBが鬼
                    collisionEvent.entityB.removeFromParent()
                }
            }
        }
    }
}

おわりに

以上、「衝突判定してEntityをシーンから削除する」でした。
RealityViewの中に書いていくので冗長になりそうですが、HappyBeamなどのサンプルを調査したところ、visionOSではこれがベターのようです。
公式ドキュメントでも微妙に書いてなかったりするので、もし他に方法がありましたらコメント等でご教示いただけるとありがたいです。(RealityComposerProを使ったやり方もありますね。)

また、今回の記事で紹介している空間シューティングゲーム「妖怪バスターZ」を日本発売前の2024年5月3日にリリースしました。
ぜひインストールして遊んでみてください。

https://apps.apple.com/us/app/yokai-buster-z/id6502185713

今後もvisionOSについて発信していきますので、この記事が参考になったと思ったらぜひ♡をお願いします。

参考

https://developer.apple.com/documentation/realitykit/scene/subscribe(to:on:_:)
https://developer.apple.com/documentation/realitykit/realityview/

脚注
  1. https://apps.apple.com/us/app/yokai-buster-z/id6502185713 ↩︎

  2. https://developer.apple.com/documentation/realitykit/collisioncomponent ↩︎

  3. https://developer.apple.com/documentation/realitykit/physicsbodycomponent ↩︎

Discussion