"lldb" crash with XCODE & ARKIT : 0 __ UpdateAudioTransform - ios

I have written a game using ARKIT that pops up random nodes (with drones) in the 3d space around the player, using ARKIT, and I get an incomprehensible crash, as only thing in the console is "lldb" , and the rest of the crash details are on the screenshot attached (I am still a newbie in Swift so not able to debug it).
The crash happens when there's a lot of nodes on the screen (maybe 20-30) and the FPS drops - ie happens "mid - game" and the FPS drops a lot.
Can someone point me to the right direction for this crash?
The part of the code that is in my opinion relevant is the function that spawns the random 3d nodes (they also have SCNActions attached that play sounds when they're tapped - perhaps this could be relevant as the left hand side debugger opens with that line highlighted when the crash occurs, as per the photo attached). In case it is also relevant, the program uses some SCNParticleSystem calls as well. Attaching relevant code, and also the snapshot of the crash screen:
var droneSound : SCNAudioSource()
override func viewDidLoad() {
super.viewDidLoad()
droneSound = SCNAudioSource(named: "Sounds/drone1.wav")!
playDroneSound = SCNAction.playAudio(self.droneSound, waitForCompletion: true)
}
func startGame() {
DispatchQueue.main.async {
self.spawnTimer = Timer.scheduledTimer(timeInterval: TimeInterval(self.randomFloat(min: 2.5, max: 5)), target: self, selector: #selector(self.spawnDronesInterim), userInfo: nil, repeats: true)
}
}
#objc func spawnDronesInterim() {
for _ in 0...5 {
spawnDrone()
}
}
#objc func spawnDrone() {
let newDroneScene = SCNScene(named: "Ar.scnassets/DroneScene.scn")!
var newDroneNode = newDroneScene.rootNode.childNode(withName: "Drone", recursively: false)!
newDroneNode.name = "Drone\(self.droneCounter)"
newDroneNode = newDroneScene.rootNode.childNode(withName: "Drone\(self.droneCounter)", recursively: false)!
newDroneNode.position.x = newDroneNode.presentation.position.x + self.randomFloat(min: -10, max: 10)
newDroneNode.position.y = newDroneNode.presentation.position.y + self.randomFloat(min: -1, max: 5)
newDroneNode.position.z = newDroneNode.presentation.position.z + self.randomFloat(min: -10, max: 10)
let move1 = SCNAction.move(to: SCNVector3((self.randomFloat(min: -7, max: 7)), (self.randomFloat(min: 1, max: 5)), (self.randomFloat(min: -7, max: 7))), duration: 15)
let disappearMove = SCNAction.move(to: SCNVector3((self.randomFloat(min: -10, max: 10)), (self.randomFloat(min: 1, max: 5)), (self.randomFloat(min: -10, max: 10))), duration: 3)
let rotateAction = SCNAction.run { (SCNNode) in
let rotate = SCNAction.rotateBy(x: 0, y: CGFloat(360.degreesToRadians), z: 0, duration: 2)
newDroneNode.runAction(rotate)
}
let removeIt = SCNAction.removeFromParentNode()
let sequence = SCNAction.sequence([waitFive,move1,rotateAction,waitFive,disappearMove,waitTwo,removeIt])
newDroneNode.runAction(sequence)
self.sceneView.scene.rootNode.addChildNode(newDroneNode)
if self.droneCounter >= 5 {
self.sceneView.scene.rootNode.childNode(withName: "Drone\(self.droneCounter)", recursively: true)!.runAction(SCNAction.repeatForever(self.playDroneSound))
}
self.droneCounter += 1
}
when user taps on one of the 3d nodes, this gets called:
func handleExplosion (node : SCNNode) {
self.sceneView.scene.rootNode.childNode(withName: node.name!, recursively: true)!.runAction(self.playExplosionSound)
node.opacity = 0
print (self.sceneView.scene.rootNode.position)
let confetti = SCNParticleSystem(named: "Ar.scnassets/confetti.scnp", inDirectory: nil)
confetti?.loops = false
confetti?.particleLifeSpan = 1.5
confetti?.emitterShape = node.geometry
let confettiNode = SCNNode()
confettiNode.addParticleSystem(confetti!)
confettiNode.position = node.presentation.position
self.sceneView.scene.rootNode.addChildNode(confettiNode)
let fire = SCNParticleSystem(named: "Ar.scnassets/fire", inDirectory: nil)
fire?.loops = false
fire?.particleLifeSpan = 0.1
fire?.emitterShape = node.geometry
let fireNode = SCNNode()
fireNode.addParticleSystem(fire!)
fireNode.position = node.presentation.position
self.sceneView.scene.rootNode.addChildNode(fireNode)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
node.removeFromParentNode()
self.killedLabel.text = "Killed: \(self.killedCount)"
self.dronesOut -= 1
}
}
Any pointer to the right direction for solving this crash would be greatly appreciated]1

Related

Panoramic View iOS

So I have generated an nice panoramic viewer but the camera is pointing downward. Meaning if I hold my phone flat like it was on a table, it rotates and looks around the sphere nicely. I want to be able to hold it normal (up) and look around. Here is my code.
I have an extension I am using here:
import UIKit
import SceneKit
import CoreMotion
extension CMDeviceMotion {
func gaze(atOrientation orientation: UIInterfaceOrientation) -> SCNVector4 {
let attitude = self.attitude.quaternion
let aq = GLKQuaternionMake(Float(attitude.x), Float(attitude.y), Float(attitude.z), Float(attitude.w))
let final: SCNVector4
switch UIApplication.shared.statusBarOrientation {
case .landscapeRight:
let cq = GLKQuaternionMakeWithAngleAndAxis(Float(Double.pi), 0, 1, 0)
let q = GLKQuaternionMultiply(cq, aq)
final = SCNVector4(x: -q.y, y: q.x, z: q.z, w: q.w)
case .landscapeLeft:
let cq = GLKQuaternionMakeWithAngleAndAxis(Float(-Double.pi), 0, 1, 0)
let q = GLKQuaternionMultiply(cq, aq)
final = SCNVector4(x: q.y, y: -q.x, z: q.z, w: q.w)
case .portraitUpsideDown:
let cq = GLKQuaternionMakeWithAngleAndAxis(Float(Double.pi), 1, 0, 0)
let q = GLKQuaternionMultiply(cq, aq)
final = SCNVector4(x: -q.x, y: -q.y, z: q.z, w: q.w)
case .unknown:
fallthrough
case .portrait:
let cq = GLKQuaternionMakeWithAngleAndAxis(Float(-Double.pi), 1, 0, 0)
let q = GLKQuaternionMultiply(cq, aq)
final = SCNVector4(x: q.x, y: q.y, z: q.z, w: q.w)
}
return final
}
}
Then the viewcontroller looks like this:
import UIKit
import SceneKit
import CoreMotion
class ViewController: UIViewController {
let motionManager = CMMotionManager()
let cameraNode = SCNNode()
#IBOutlet weak var sceneView: SCNView!
override func viewDidLoad() {
super.viewDidLoad()
guard let imagePath = Bundle.main.path(forResource: "Hellbrunn25", ofType: "jpg") else {
fatalError("Failed to find path for panaromic file.")
}
guard let image = UIImage(contentsOfFile:imagePath) else {
fatalError("Failed to load panoramic image")
}
let scene = SCNScene()
sceneView.scene = scene
sceneView.allowsCameraControl = true
//Create node, containing a sphere, using the panoramic image as a texture
let sphere = SCNSphere(radius: 20.0)
sphere.firstMaterial!.isDoubleSided = true
sphere.firstMaterial!.diffuse.contents = image
let sphereNode = SCNNode(geometry: sphere)
sphereNode.position = SCNVector3Make(0,0,0)
scene.rootNode.addChildNode(sphereNode)
// Camera, ...
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3Make(0, 0, 0)
scene.rootNode.addChildNode(cameraNode)
guard motionManager.isDeviceMotionAvailable else {
fatalError("Device motion is not available")
}
// Action
motionManager.deviceMotionUpdateInterval = 1.0 / 60.0
motionManager.startDeviceMotionUpdates(to: OperationQueue.main, withHandler: {
(deviceDidMove, Error)-> Void in
let attitude: CMAttitude = deviceDidMove!.attitude
self.cameraNode.orientation = SCNVector4Make(Float(attitude.quaternion.x), Float(attitude.quaternion.y), Float(attitude.quaternion.z), Float(attitude.quaternion.w))
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func deviceDidMove(motion: CMDeviceMotion?, error: NSError?) {
if let motion = motion {
let orientation = motion.gaze(atOrientation: UIApplication.shared.statusBarOrientation)
cameraNode.orientation = orientation
}
}
}
How do I get the camera to face forward on the image. Thanks
I figured this out if any one else is looking for an answer. I changed the portrait mode case to the following:
let cq = GLKQuaternionMakeWithAngleAndAxis(Float(-Double.pi*0.5), 1, 0, 0)
let q = GLKQuaternionMultiply(cq, aq)
final = SCNVector4(x: q.x, y: q.y, z: q.z, w: q.w)

Declaring SKSpriteNode outside spawn function returns SIGABRT in Swift

I have a game that I am making where I have a player and an unlimited number of enemies that's spawn at a given position in a certain amount of time. These enemies are shooting bullets at the player. I need to be able to access the Enemy variable outside the SpawnEnemies() function so that I can use it in my SpawnBullets() function. I tried declaring the Enemy variable outside the SpawnEnemies() function but it returned Sigabrt and I don't know how to access the Enemy variable outside the function without getting this error.
Enemy declaration:
var Enemy = SKSpriteNode(imageNamed: "Enemy.png")
SpawnEnemies function:
func SpawnEnemies() {
let MinValue = self.size.width/8
let MaxValue = self.size.width-20
let SpawnPoint = UInt32(MaxValue-MinValue)
self.Enemy.position = CGPoint(x: CGFloat(arc4random_uniform(SpawnPoint)), y: self.size.height)
let action = SKAction.moveToY(-70, duration: 3.0)
self.Enemy.runAction(SKAction.repeatActionForever(action))
self.addChild(Enemy)
}
SpawnBullets function:
func SpawnBullets(){
let Bullet = SKSpriteNode(imageNamed: "bullet.png")
Bullet.zPosition = -5
Bullet.position = CGPointMake(Enemy.position.x, Enemy.position.y)
let action = SKAction.moveToY(self.size.height + 30, duration: 1.0)
Bullet.runAction(SKAction.repeatActionForever(action))
self.addChild(Bullet)
}
Call SpawnEnemies function in didMoveToView():
var EnemyTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("SpawnEnemies"),userInfo: nil, repeats: true)
Call SpawnBullets function in didMoveToView():
var BulletTimer = NSTimer.scheduledTimerWithTimeInterval(0.2, target: self, selector: Selector("SpawnBullets"),userInfo: nil, repeats: true)
I get this error which is a sigabrt but I used a breakpoint to figure out exactly where the error was and what it was:
Attemped to add a SKNode which already has a parent: <SKSpriteNode> name:'(null)' texture:[<SKTexture> 'Enemy.png' (60 x 80)] position:{132, 1024} scale:{1.00, 1.00} size:{60, 80} anchor:{0.5, 0.5} rotation:0.00
Adding children to a scene already is "infinite", you just need to use it to your advantage.
First rework your bullet function like this so that you are passing in an enemy.
func SpawnBullets(enemy : SKSpriteNode){
let Bullet = SKSpriteNode(imageNamed: "bullet.png")
Bullet.zPosition = -5
Bullet.position = CGPointMake(enemy.position.x, enemy.position.y)
let action = SKAction.moveToY(-self.size.height - 70, duration: 1.0)
Bullet.runAction(SKAction.repeatActionForever(action))
self.addChild(Bullet)
}
Then rework your enemy function so that overtime you call it you spawn a new enemy.
func SpawnEnemies() {
var Enemy = SKSpriteNode(imageNamed: "Enemy.png")
Enemy.name = "enemy";
let MinValue = self.size.width/8
let MaxValue = self.size.width-20
let SpawnPoint = UInt32(MaxValue-MinValue)
Enemy.position = CGPoint(x: CGFloat(arc4random_uniform(SpawnPoint)), y: self.size.height)
let action = SKAction.moveToY(-70, duration: 3.0)
Enemy.runAction(SKAction.repeatActionForever(action))
self.addChild(Enemy)
}
In the function didMoveToView, lets add actions to the scene that handles our timing so that we do not use NSTimer
{
...
let spawnEnemy = SKAction.sequence([SKAction.runBlock(
{
[unowned self] in
self.SpawnEnemies();
}),SKAction.waitForDuration(1)]);
let spawnBullet = SKAction.sequence([SKAction.runBlock(
{
[unowned self] in
self.enumerateChildNodesWithName("enemy", usingBlock:
{
(enemy : SKNode,stop: UnsafeMutablePointer <ObjCBool>) in
  self.SpawnBullets(enemy as! SKSpriteNode);
});
}),SKAction.waitForDuration(0.2)]);
let group = SKAction.group([spawnEnemy, spawnBullet])
self.runAction(SKAction.repeatActionForever(group))
}
This code is not tested so let me know if I need to update anything.

Unexpectedly found nil while unwrapping an Optional value - boxNode.addChildNode(importedBox!)

I have some code that runs a for loop to create 2 objects and stuffs them into the boxArray then adds them to the scene. The first time through the code works fine to create one box but during the addBox(num: Int) function to create the second box it crashes with the error in the subject line. Its this line that is responsible "boxNode.addChildNode(importedBox!)" but Im at a loss as to why since it works the first time.
importedSceneBox = SCNScene(named: "art.scnassets/boxObject.dae")
for var i = 0; i <= 1; ++i {
let boxNode = self.addBox(i)
boxArray.append(boxNode)
theScene.rootNode.addChildNode(boxArray[i])
}
func addBox(num: Int) -> SCNNode{
let boxNode = SCNNode()
let importedBox = importedSceneBox.rootNode.childNodeWithName("pCube4", recursively: false)
importedBox?.scale = SCNVector3Make(70, 70, 70)
boxNode.addChildNode(importedBox!)
boxNode.position = SCNVector3Make(5, 100, 3)
let collisionBox = SCNBox(width: 5.0, height: 5.0, length: 5.0, chamferRadius: 0)
boxNode.physicsBody?.physicsShape = SCNPhysicsShape(geometry: collisionBox, options: nil)
boxNode.physicsBody = SCNPhysicsBody.dynamicBody()
boxNode.physicsBody?.mass = 1
boxNode.physicsBody?.restitution = 0.8
boxNode.physicsBody?.damping = 0.5
boxNode.name = "dice" + String(num)
boxNode.physicsBody?.allowsResting = true
return boxNode
}
hi your importedBox is an optional meaning it can have a value or it can be nil.
you are using "!"(IUO implicitly unwrapped optional) behind importedBox which means that your telling the compiler that your sure its not be nil. How ever in this case it WAS nil thus the crash "found nil when unwrapping optional"
So recap importedBox is nil but you marked it with ! so the compiler think it will never have a nil value but a nil was found thus the crash.
to fix this you can use guard or optional binding
Guard example
func addBox(num: Int) -> SCNNode{
let boxNode = SCNNode()
let importedBox = importedSceneBox.rootNode.childNodeWithName("pCube4", recursively: false)
importedBox?.scale = SCNVector3Make(70, 70, 70)
guard let unwrapBox = importedBox else {
//do your error handling here
return SCNNode()
}
boxNode.addChildNode(unwrapBox)
boxNode.position = SCNVector3Make(5, 100, 3)
let collisionBox = SCNBox(width: 5.0, height: 5.0, length: 5.0, chamferRadius: 0)
boxNode.physicsBody?.physicsShape = SCNPhysicsShape(geometry: collisionBox, options: nil)
boxNode.physicsBody = SCNPhysicsBody.dynamicBody()
boxNode.physicsBody?.mass = 1
boxNode.physicsBody?.restitution = 0.8
boxNode.physicsBody?.damping = 0.5
boxNode.name = "dice" + String(num)
boxNode.physicsBody?.allowsResting = true
return boxNode
}
optional binding example
func addBox(num: Int) -> SCNNode{
let boxNode = SCNNode()
let importedBox = importedSceneBox.rootNode.childNodeWithName("pCube4", recursively: false)
importedBox?.scale = SCNVector3Make(70, 70, 70)
if let unwrapBox = importedBox else {
boxNode.addChildNode(unwrapBox)
boxNode.position = SCNVector3Make(5, 100, 3)
let collisionBox = SCNBox(width: 5.0, height: 5.0, length: 5.0, chamferRadius: 0)
boxNode.physicsBody?.physicsShape = SCNPhysicsShape(geometry: collisionBox, options: nil)
boxNode.physicsBody = SCNPhysicsBody.dynamicBody()
boxNode.physicsBody?.mass = 1
boxNode.physicsBody?.restitution = 0.8
boxNode.physicsBody?.damping = 0.5
boxNode.name = "dice" + String(num)
boxNode.physicsBody?.allowsResting = true
return boxNode
}else{
//do your error handling here
return SCNNode()
}
}
also as a side note in the error handling cases we are creating a default value since your function returns a SCNNode and not a SCNNode optional.
Alternatively you can return nil if you change your function signature to be
func addBox(num: Int) -> SCNNode? {
if let unwrappedBox = importedBox {
//do stuff
}else{
return nil
}
}

How to lower Renderer Utilization?

I am having sever performance issues with a SceneKit game. Total vertices count 4000. Renderer Utilization is 100% on ipad3, framerate 16fps, even though Tiler utilization is only about 8%. This is screenshot from OPENGL ES Analysis.
This is the entire code that is used to specify what the object should look like. As you can see there is no custom shaders. Just a box that falls on the floor because of physics applied to it. Textures and 2 lights are applied in the .scn file. Everything is simple, basic but the performance is terrible. How do I lower Renderer Utilization on the device? I am guessing some default settings that sceneKit uses aren't suitable for my app and cause severe performance problems. Which one should I double check?
//called in viewDidLoad:
func setupScene(){
scene = SCNScene(named: "GameScene.scn")
sceneView.scene = scene
sceneView.delegate = self
scene.physicsWorld.contactDelegate = self
scene.physicsWorld.gravity = SCNVector3Make(0, 0, 0)
scene.physicsWorld.speed = 1.8
sceneView.jitteringEnabled = true
sceneView.autoenablesDefaultLighting = false
sceneView.antialiasingMode = SCNAntialiasingMode.None
let valueVector: NSValue = NSValue(SCNVector3: SCNVector3Make(0.7, 0.7, 0.7))
objectNode = scene.rootNode.childNodeWithName("object", recursively: true)!
let physicsShape = SCNPhysicsShape(node: objectNode, options: [SCNPhysicsShapeTypeKey:SCNPhysicsShapeTypeBoundingBox, SCNPhysicsShapeScaleKey:valueVector])
objectNode.physicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.Dynamic, shape: physicsShape)
let floorNode = scene.rootNode.childNodeWithName("floor", recursively: true)
floorNode?.physicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.Static, shape: nil)
objectNode.categoryBitMask = 1
floorNode?.categoryBitMask = 1
objectNode.physicsBody?.categoryBitMask = 1
floorNode?.physicsBody?.categoryBitMask = 1
objectNode.physicsBody?.collisionBitMask = 1
floorNode?.physicsBody?.collisionBitMask = 1
floorNode?.physicsBody?.restitution = 0.7
objectNode.physicsBody?.restitution = 0.7
}
func speed(velocity:SCNVector3) -> Float
{
let dx = Float(velocity.x)
let dy = Float(velocity.y)
let dz = Float(velocity.z)
return sqrtf(dx*dx+dy*dy+dz*dz)
}
func angularSpeed(angularSpeed: SCNVector4)->Float{
let x = angularSpeed.x
let y = angularSpeed.y
let z = angularSpeed.z
return sqrtf(x*x+y*y+z*z)
}
func nearlyAtRest(node:SCNNode) -> Bool
{
return speed((node.physicsBody?.velocity)!) < 0.05 && ( self.resting == false) && (angularSpeed((node.physicsBody?.angularVelocity)!) < 1)
}
// PHYSICS CONTACT DELEGATE DELEGATE METHOD
func renderer(renderer: SCNSceneRenderer, didSimulatePhysicsAtTime time: NSTimeInterval) {
if nearlyAtRest(objectNode) && speed((objectNode.physicsBody?.velocity)!) != 0 {
print("it stopped")
}

runAction SKAction.sequence not working

I can't get the runAction method to work for this code block. I'm not sure what I am doing wrong or if there is a problem outside the block, but if anyone sees anything inside that is wrong, let's start there (*Edited to include entire function). All variables work and I'm getting zero compile errors, the program just appears to skip the line currentTestIndicator.runAction(SKAction.sequence(runCheck)). All print statements work except the one inside recurse, also current++ isn't getting called. I tried running the code without recurse and it still didn't work. Ideas?
func runLevelCheck(node: SKSpriteNode, _ state: SKSpriteNode, _ bluePatterns:Array<Array<String>>, _ blueSize: CGFloat, _ blueLocations: Array<CGPoint>, _ greenPatterns:Array<Array<String>>, _ greenSize: CGFloat, _ greenLocations:Array<CGPoint>, _ redPatterns:Array<Array<String>>, _ redSize: CGFloat, _ redLocations:Array<CGPoint>, _ orangePatterns:Array<Array<String>>, _ orangeSize: CGFloat, _ orangeLocations:Array<CGPoint>)->Bool {
var passLevel = true
var current = 0
let currentTestIndicator = SKSpriteNode()
currentTestIndicator.name = "indicator"
currentTestIndicator.size = CGSizeMake(0, 128)
blueLocations[current].y)
currentTestIndicator.anchorPoint = CGPoint(x: 0.0, y: 0.5)
currentTestIndicator.zPosition = 0
node.addChild(currentTestIndicator)
let patterns = [bluePatterns, greenPatterns, redPatterns, orangePatterns]
let sizes = [blueSize, greenSize, redSize, orangeSize]
let locations = [blueLocations, greenLocations, redLocations, orangeLocations]
let colors = [color("Light Blue 01"), color("Light Green 01"), color("Light Red 01"), color("Light Orange 01")]
for sets in patterns {
for rows in sets {
if rows != [] {
print("Current set: \(current)")
print(rows)
currentTestIndicator.color = colors[current]
currentTestIndicator.position = CGPoint(x: 0.0, y: locations[current][0].y)
print(currentTestIndicator.position)
print("Sizes current = \(sizes[current])")
let growRight = SKAction.resizeToWidth(sizes[current], duration: 0.2)
let recurse = SKAction.runBlock() {
recursion(state, rows, 0, 0, &passLevel)
current++
print("Changed current value to \(current)")
}
let pause = SKAction.waitForDuration(5.0)
let shrinkLeft = SKAction.resizeToWidth(0, duration: 0.2)
let runCheck = [growRight, recurse, pause, shrinkLeft]
currentTestIndicator.runAction(SKAction.sequence(runCheck))
}
}
current = 0
}
currentTestIndicator.removeFromParent()
print("Ran level check")
switch passLevel {
case true:
print("Level passed")
case false:
print("Lavel failed")
}
return passLevel
}

Resources