swift scenekit

swift - Cómo configurar la detección de colisión SceneKit



(1)

Hola, he examinado la documentación y no puedo entender cómo configurar la detección de colisión en el kit de escena. ¿Puede alguien mostrar un ejemplo? Por favor ayuda, estoy muy desesperado por resolver esto. ¡Gracias!

Editar: Hola Muchas gracias, lo siento, olvidé mencionar que mi proyecto está en marcha. No es gran cosa, puedo traducirme en su mayor parte.

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

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 parece que necesito asignar de alguna manera el delegado mundial de física de escenas a este método. No estoy seguro de cómo hacerlo.


Lo más importante 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 responde a las colisiones.

Hacer colisionar objetos

Por ejemplo, puede indicar 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 deben cruzarse entre sí, pero destruyen cohetes y asteroides. Los cohetes no deberían hacer nada a los misiles (solo al revés), pero si uno se acerca demasiado a otro o a un asteroide, tiene un problema grave y no irá al espacio hoy.

El primer paso para darse cuenta de que con la detección de colisión 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 bit a bit 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 las colisiones por usted (es decir, rebotar objetos entre sí).

Respondiendo a colisiones

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

En su método de delegado de contactos (digamos, 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 su juego hace por 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 ... } }

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

@interface ViewController: UIViewController <SCNPhysicsContactDelegate>

Luego asigne ese objeto al mundo de física de su escena como delegado de contacto:

// in initial setup, where presumably 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 utiliza la detección de colisión: es parte de la gran variedad de demostraciones en las slides WWDC y las aplicaciones de muestra de demo , y también en la demostración de física del vehículo .

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 programación SpriteKit también es útil para comprender las mismas cosas en SceneKit.