I am trying to make something with SceneKit for the WWDC Student Challenge, which requires my project be in a Swift playground. I keep getting the message that says “There was a problem running this page.” It offers no error messages. It just suggests that check my code or start over. I have tried removing pieces of code individually, but I cannot locate the source of this issue. I have also tried running it in man Xcode playground, which offered the warning of, and I quote, “The playground could not continue running because the playground source did”. I am stuck. What is wrong with my code.
import UIKit
import SceneKit
import QuartzCore
import PlaygroundSupport
class GameScene: UIViewController, SCNSceneRendererDelegate {
var primaryView: SCNView!
var primaryScene: SCNScene!
var cameraNode: SCNNode!
override func viewDidLoad() {
sceneAndViewInit()
cameraInit()
createGround()
moonInit()
}
func createGround() {
var ground = SCNBox(width: 200, height: 1, length: 200, chamferRadius: 0)
var groundPhysicsShape = SCNPhysicsShape(geometry: ground, options: nil)
var groundNode = SCNNode(geometry: ground)
ground.firstMaterial?.diffuse.contents = UIColor.orange
ground.firstMaterial?.specular.contents = UIColor.white
groundNode.position = SCNVector3(0, -6, 0)
groundNode.physicsBody = SCNPhysicsBody(type: .static, shape: groundPhysicsShape)
primaryScene.rootNode.addChildNode(groundNode)
}
func sceneAndViewInit() {
primaryView = SCNView(frame: CGRect(x: 0, y: 0, width: 500, height: 300))
primaryView.allowsCameraControl = true
primaryView.autoenablesDefaultLighting = true
primaryScene = SCNScene()
primaryView.scene = primaryScene
primaryView.isPlaying = true
}
func cameraInit() {
var cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 0, y: 0, z: 2)
cameraNode.camera?.fieldOfView = 65
cameraNode.camera?.wantsHDR = false
primaryScene.rootNode.addChildNode(cameraNode)
}
func moonInit() {
let moonScene = SCNScene(named: "Moon.scn")
var moonNode = moonScene?.rootNode.childNode(withName: "Sphere", recursively: true)
var moonPhysicsShape = SCNPhysicsShape(node: moonNode!, options: nil)
moonNode?.position = SCNVector3(0, 0, 0)
moonNode?.scale = SCNVector3(1, 1, 1)
moonNode?.name = "Moon"
moonNode?.physicsBody = SCNPhysicsBody(type: .static, shape: moonPhysicsShape)
primaryScene.rootNode.addChildNode(moonNode!)
}
func renderer(_ aRenderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
print(time)
}
}
let gameScene = GameScene()
PlaygroundPage.current.liveView = gameScene
(“Moon.scn” is a file that I have in the resources/files section along with its texture, and I still have the issue without any of the moon related code.)
Swift Fundamentals – Pluralsight As an aspiring app developer, you'll learn how Swift works with data and Swift playgrounds. You'll also adopt a protocol-oriented programming mindset as you work on developing apps on iPhone, Mac, or iPad. It takes about three to four learning hours to complete this course.
Swift Playgrounds 4 now available.
Swift Playgrounds is a beautiful looking environment to learn to code. It's a nice, modern, object-oriented language and I can learn concepts and conventions and put them to work later in Xcode. Children can choose step-by-step lessons and puzzles to build their coding knowledge and skills.
To view the full error message, go to Settings app -> Playgrounds -> turn on Authoring Debug Mode. This doesn't directly solve the issue but it's a lot more helpful for locating errors.
I have found a way to address this issue. However, I can only offer you a round-ish idea of what the issue is and how to fix it.
The problem seems to be with the variable declarations at the top of the class.
var primaryView: SCNView!
var primaryScene: SCNScene!
var cameraNode: SCNNode!
The exclamation mark following the type indicates that the variable is an implicitly-unwrapped optional
(I am quoting from this Stack Overflow response that explains what this is in more depth), but more-or-less the variable will automatically force unwrap whenever it is used. I have a more of a working knowledge of Swift than a technical one, so my guess is that when a GameScene
object is created a synthetic initializer tries to set up these variables, it, for some reason, needs to read from the variables, gets nil
, and cannot continue.
The solution appears to be putting the values of the variables in their initial declaration (There might be a better solution, but this at least works in my testing.), so that they are not nil
for the initializer. Now the reason that I cannot fully explain the issue here is that this only seems to be necessary for the SCNScene
variable. I don't really know why this is the case.
Code (***
mark important comments):
import UIKit
import SceneKit
import QuartzCore
import PlaygroundSupport
class GameScene: UIViewController, SCNSceneRendererDelegate {
var primaryView: SCNView!// = SCNView(frame: CGRect(x: 0, y: 0, width: 500, height: 300)) //***This seems to work for reasons beyond me with the implicitly-unwrapped optional***
var primaryScene = SCNScene() //***The implicitly unwrapped optional is removed here***
var cameraNode = SCNNode() //***The implicitly unwrapped optional is removed here (I am not sure if that is necessary but it probably good practice not to use it anywhere intros code. I use it earlier to demonstrate its weird complexities.)***
override func viewDidLoad() {
sceneAndViewInit()
cameraInit()
createGround()
//moonInit() ***I removed this for simplicity in the answer***
}
func createGround() {
var ground = SCNBox(width: 200, height: 1, length: 200, chamferRadius: 0)
var groundPhysicsShape = SCNPhysicsShape(geometry: ground, options: nil)
var groundNode = SCNNode(geometry: ground)
ground.firstMaterial?.diffuse.contents = UIColor.orange
ground.firstMaterial?.specular.contents = UIColor.white
groundNode.position = SCNVector3(0, -6, 0)
groundNode.physicsBody = SCNPhysicsBody(type: .static, shape: groundPhysicsShape)
primaryScene.rootNode.addChildNode(groundNode)
}
func sceneAndViewInit() {
primaryView = SCNView(frame: CGRect(x: 0, y: 0, width: 500, height: 300))
primaryView.allowsCameraControl = true
primaryView.autoenablesDefaultLighting = true
//primaryScene = SCNScene() ***This is not necessary when it is declared above***
self.primaryView.scene = primaryScene
//primaryView.isPlaying = true
self.view = primaryView //***I realized later you need this bit of code or the program will only display a blank screen***
}
func cameraInit() {
//var cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 0, y: 0, z: 2)
cameraNode.camera?.fieldOfView = 65
cameraNode.camera?.wantsHDR = false
primaryScene.rootNode.addChildNode(cameraNode)
}
func moonInit() {
let moonScene = SCNScene(named: "Moon.scn")
var moonNode = moonScene?.rootNode.childNode(withName: "Sphere", recursively: true)
var moonPhysicsShape = SCNPhysicsShape(node: moonNode!, options: nil)
moonNode?.position = SCNVector3(0, 0, 0)
moonNode?.scale = SCNVector3(1, 1, 1)
moonNode?.name = "Moon"
moonNode?.physicsBody = SCNPhysicsBody(type: .static, shape: moonPhysicsShape)
primaryScene.rootNode.addChildNode(moonNode!)
}
func renderer(_ aRenderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
print(time)
}
}
let gameScene = GameScene()
PlaygroundPage.current.liveView = gameScene
One final note:
The self.view = primaryView
code is really important. I make a note about in the full code, but I have found this way too hard to locate on the internet. I think this has to do with UIViewController
(I don't know much about UIKit
at all.), but either SceneKit
or UIKit
just displays a blank screen if you do now have that bit of code. If you don't figure out that these are separate issues they are really hard to decipher.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With