0

I am attempting to detect the intersection of two scnnodes in SceneKit. They are registered as GKEntities. I want to associate a component to both entities that will detect the intersection of their physics bodies using SCNPhysicsContactDelegate, but I don't want to do this in the view controller as I know it is not best practice and it would make it difficult to register that as a component. Any help would be appreciated.

Thanks for the assistance,

Montreaux

import Foundation
import SpriteKit
import GameplayKit
import SceneKit

class MeleeComponent: GKComponent, SCNPhysicsContactDelegate {

 let damage: CGFloat
 let destroySelf: Bool
 let damageRate: CGFloat
 var lastDamageTime: TimeInterval
 let aoe: Bool
 //  let sound: SKAction
   let entityManager: EntityManager
   init(damage: CGFloat, destroySelf: Bool, damageRate: CGFloat, aoe:      Bool, entityManager: EntityManager) {
 self.damage = damage
self.destroySelf = destroySelf
self.damageRate = damageRate
self.aoe = aoe
 //    self.sound = sound
self.lastDamageTime = 0
self.entityManager = entityManager
super.init()
 }

 required init?(coder aDecoder: NSCoder) {
     fatalError("init(coder:) has not been implemented")
}


 override func update(deltaTime seconds: TimeInterval) {

super.update(deltaTime: seconds)

// Get required components
guard let teamComponent = entity?.component(ofType: TeamComponent.self),
          let spriteComponent = entity?.component(ofType: SpriteComponent.self) else {
  return
}

// Loop through enemy entities
var aoeDamageCaused = false
let enemyEntities = entityManager.entitiesForTeam(teamComponent.team.oppositeTeam())
for enemyEntity in enemyEntities {

  // Get required components
  guard let enemySpriteComponent = enemyEntity.component(ofType: SpriteComponent.self),
        let enemyHealthComponent = enemyEntity.component(ofType: HealthComponent.self) else {
    continue
  }

  // Check for intersection

  if       (spriteComponent.node.frame.intersects(enemySpriteComponent.node.frame)) {

    // Check damage rate
    if (CGFloat(CACurrentMediaTime() - lastDamageTime) > damageRate) {

      // Cause damage
//          spriteComponent.node.parent?.run(sound)
      if (aoe) {
        aoeDamageCaused = true
      } else {
        lastDamageTime = CACurrentMediaTime()
      }

      // Subtract health
      enemyHealthComponent.takeDamage(damage)

      // Destroy self
      if destroySelf {
        entityManager.remove(entity!)
      }
    }
  }
}

if (aoeDamageCaused) {
  lastDamageTime = CACurrentMediaTime()
}

} }

1 Answers1

0

In SCNPhysicsWorld, There are a few APIs can help you.

such as

 func contactTestBetween(_ bodyA: SCNPhysicsBody, _ bodyB: SCNPhysicsBody, options: [SCNPhysicsWorld.TestOption : Any]? = nil) -> [SCNPhysicsContact]

It's similar to the code in your example:

if  (spriteComponent.node.frame.intersects(enemySpriteComponent.node.frame))

But it's in SceneKit and will give you more information about the contact.

E.Coms
  • 11,065
  • 2
  • 23
  • 35