Cómo configurar la detección de colisiones de SceneKit

Hola, he echado sobre la documentación y no puedo encontrar la manera de configurar la detección de colisión en el kit de escena. ¿Alguien puede mostrar un ejemplo? Por favor ayuda, estoy muy desesperado por resolver esto. ¡Gracias!

Editar: Hola, muchas gracias, lamento haber olvidado mencionar que mi proyecto es rápido. No es gran cosa, puedo traducir mi yo en su mayor parte.

Tengo las BitMasks funcionando correctamente cuando los objetos colisionan y rebotan entre sí. Sin embargo, parece que no puedo hacer funcionar la función

func physicsWorld(world: SCNPhysicsWorld, didBeginContact contact: SCNPhysicsContact){ let contactMask = contact.nodeA.physicsBody!.categoryBitMask | contact.nodeB.physicsBody!.categoryBitMask if (contactMask == (CollisionBallCategory | CollisionTerminatorCategory)) { println("Collided") } } 

Mirando la documentación que aparece, necesito asignar el delegado de mundo de física de escenas a este método de alguna manera. No estoy seguro de cómo hacerlo.

Las principales cosas sobre la detección de colisiones en SceneKit:

  • se basa en máscaras de bits, que juntas forman una tabla.
  • un delegado de contacto es cómo respondes a las colisiones.

Hacer que los objetos colisionen

Por ejemplo, puede establecer un poco de diseño del juego en inglés simple como este:

Los asteroides se golpean entre sí (y hacen asteroides más pequeños). Los misiles deberían pasar uno sobre el otro, pero destruir cohetes y asteroides. Los cohetes no deberían hacer nada con los misiles (solo al revés), pero si uno se acerca demasiado a otro o a un asteroide, está teniendo un problema grave y no va a ir al espacio hoy.

El primer paso para darse cuenta de eso con la detección de colisiones es codificar ese diseño en términos de qué pares interactúan. Puedes hacer esto con una tabla:

  | Missile | Rocket | Asteroid -------------------------------------- Missile | No | Yes | Yes Rocket | No | Yes | Yes Asteroid | No | No | Yes 

Luego puede convertir los encabezados de la tabla en un conjunto de constantes de categoría para usar en su código.

 typedef NS_OPTIONS(NSUInteger, CollisionCategory) { CollisionCategoryMissile = 1 << 0, CollisionCategoryRocket = 1 << 1, CollisionCategoryAsteroid = 1 << 2, }; missile.physicsBody.categoryBitMask = CollisionCategoryMissile; rocket.physicsBody.categoryBitMask = CollisionCategoryRocket; asteroid.physicsBody.categoryBitMask = CollisionCategoryAsteroid; 

Use OR a nivel de bits en estas constantes para crear valores collisionBitMask que llenen la tabla.

 missile.physicsBody.collisionBitMask = CollisionCategoryRocket | CollisionCategoryAsteroid; rocket.physicsBody.collisionBitMask = CollisionCategoryRocket | CollisionCategoryAsteroid; asteroid.physicsBody.collisionBitMask = CollisionCategoryAsteroid; 

Eso es todo lo que necesita para que SceneKit resuelva colisiones por usted (es decir, rebote de objetos el uno del otro).

Respondiendo a colisiones

Si también quieres recibir notificaciones de colisiones (para que puedas hacer que los misiles exploten y ejecuten tu nave en un asteroide, finaliza el juego), deberás establecer un delegado de contacto en el mundo de la física de tu escena e implementar uno o más de los métodos de delegado de contacto que se llaman cuando ocurre un contacto.

En su método de delegado de contacto (por ejemplo, physicsWorld:didBeginContact: , necesitará averiguar qué categorías de cuerpos estuvieron involucrados en el contacto, y cuál fue cuál, para que pueda acceder a su código que hace lo que hace su juego para la colisión:

 - (void)physicsWorld:(SCNPhysicsWorld *)world didBeginContact:(SCNPhysicsContact *)contact { CollisionCategory contactMask = contact.nodeA.physicsBody.categoryBitMask | contact.nodeB.physicsBody.categoryBitMask; // first, sort out what kind of collision if (contactMask == (CollisionCategoryMissile | CollisionCategoryRocket)) { // next, sort out which body is the missile and which is the rocket // and do something about it if (contact.nodeA.physicsBody.categoryBitMask == CollisionCategoryMissile) { [self hitRocket:contact.nodeB withMissile:contact.nodeA]; } else { [self hitRocket:contact.nodeA withMissile:contact.nodeB]; } } else if (contactMask == (CollisionCategoryMissile | CollisionCategoryAsteroid)) { // ... and so on ... } } 

Coloque este código en una de sus clases (un controlador de vista, tal vez, donde sea que mantenga su lógica de juego es buena), y haga que la clase declare conformidad con el protocolo SCNPhysicsContactDelegate .

 @interface ViewController: UIViewController  

A continuación, asigne ese objeto al mundo de la física de la escena como delegado de contacto:

 // in initial setup, where presumbly you already have a reference to your scene scene.physicsWorld.contactDelegate = self 

Aprendiendo más

Hay un poco sobre la resolución de colisión en la documentación de referencia de SCNPhysicsBody . Y Apple tiene un código de muestra que usa la detección de colisión: es parte de la mezcla heterogénea de demostraciones en las diapositivas de WWDC y las aplicaciones de demostración , y en la demostración de física del vehículo también.

Más allá de eso, el modelo de manejo de colisiones de SceneKit es casi exactamente el mismo que el de SpriteKit, por lo que casi todo en la guía de progtwigción de SpriteKit también es útil para entender lo mismo en SceneKit.

    Intereting Posts