JP Silvashy
JP Silvashy

Reputation: 48495

SceneKit and SpriteKit together

I'm building a 3D game scene with SceneKit and I want to build like a "hud" over top, in order to get it kind of working, I built my ViewController by using a subview and overlaySKScene like so:

class ViewController:UIViewController {
  var sceneView: SCNView!
  var mainScene = MainScene() // <- SCNScene
  var spriteScene: OverlayScene! // <- SKScene 

  override func viewDidLoad() {
    super.viewDidLoad()

    self.sceneView = SCNView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height))
    self.sceneView.scene = mainScene
    self.sceneView.backgroundColor = UIColor.clear
    self.view.addSubview(self.sceneView)

    self.spriteScene = OverlayScene(size: self.view.bounds.size)
    self.sceneView.overlaySKScene = self.spriteScene
  }
}

I've got a few questions about how this should be done the right way, as I'm running into some things that seem unusual.

First, lets say I need to do a segue, it doesn't seem clear to me how I would actually observe a tap on one of the SpriteKit nodes in the OverlayScene and then change controllers for the main parent ViewController. I haven't found any resources online that describe a similar situation.

Here is a trimmed down version of my OverlayScene:

import UIKit
import SpriteKit

class OverlayScene: SKScene {

  var actionBarNode: SKSpriteNode!

  override init(size: CGSize) {
    super.init(size: size)

    self.backgroundColor = UIColor.clear

    self.actionBarNode = SKSpriteNode()
    self.actionBarNode.size = CGSize(width: size.width, height: 100)
    self.actionBarNode.position = CGPoint(x: size.width / 2, y: 50)
    self.actionBarNode.color = .white
    self.addChild(self.actionBarNode)
  }
}

Upvotes: 2

Views: 1731

Answers (2)

JP Silvashy
JP Silvashy

Reputation: 48495

I found a solution for my problem for anyone who may stumble into this same issue (which I think is likely as many examples demonstrate an overlay scene added as a subview in the manner I did.

First the tapHandler I had in my viewController needed to have the property cancelsTouchesInView set to false. This will allow the gesture to be received by the underlying views.

let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
tapGesture.cancelsTouchesInView = false
sceneView.addGestureRecognizer(tapGesture)

The reason this doesn't happen to all subviews is because I was relying on a view that was sized to 100% of the frame, covering the underlying ones, rather than just having the view occupy a smaller screen area, like a button or scoreboard as seen in the example docs.

Upvotes: 1

Aleksandr
Aleksandr

Reputation: 553

I am not answering your two questions directly, instead I will deal with your larger issue which is that you want a HUD on your game. A user interface. I never made a Scenekit game, but I did make a Spritekit game and the HUD is a clever trick. Let me explain.

Imagine you are standing behind a camera and looking through to see what the camera is seeing through its lens. You see the scene in front of it. Now take a piece of paper, cut out a rectangular box in the middle and draw on the remaining periphery. Tape this piece of paper to the front of the camera and look through. You still see the scene (a little smaller now), but now you also see the paper with the drawings. This is how HUDs work for the game.

I did some searching and both SpriteKit and SceneKit have a camera. In sceneKit you create a camera node and set the point of view of the scene to that camera. This represents the player looking out into the scene.

I am not sure if it works the same way in SceneKit, but in SpriteKit you can add nodes to the camera that will be locked in place. These become your HUD elements (buttons, score, etc). Since these are all child nodes of the camera they move when you move the camera so it feels like they are a static HUD. This is how you achieve a HUD. Read up on the documentation for SceneKit cameras as this will help you understand how to achieve the same effect.

I once also thought about doing it the way you are going now and it proved to be a very painful experience to mix SceneKit and SpriteKit so I would caution against it.

Also, while you can mix Interface Builder and SpriteKit I would caution against it. It basically ruined my first game into a buggy mess. If you do decide to use Interface Builder, try to limit it to menu screens and options screens. But, I found that programmatically creating everything gives you a much smoother, cleaner, and bug free experience.

Hope this helps!

Upvotes: 3

Related Questions