Apple Engine

Apple, iPhone, iOS, その周辺のことについて

iOS で SceneKit を試す(Swift 3) その5 - シーンエディタを使用しない空のテンプレートをつくる

今後、コードサンプルで使用するためのものを作成する。

シーングラフのルートノードに追加するもの。

  • オムニライト (配置した位置から全ての方向を照らす光源)
  • アンビエントライト (位置に関係なく画面全体を照らす環境光。ジオメトリに陰は落ちない)
  • カメラ

また、シーンにはタップした際の処理を入れる。

 

プロジェクトファイルを作る

前回同様にシングルページを作成し、UIViewController の Storyboard で設定している UIView を SCNView に変更する。

f:id:x67x6fx74x6f:20170530185634p:plain

 

Storyboard の修正が完了されたら、SCNScene のサブクラスを作成する。

新規作成 (command + N) から Swift File を選択し「Next」をクリック。

f:id:x67x6fx74x6f:20170601123446p:plain

 

今回は「GameScene.swift」と名前をつけて「Next」をクリック。

f:id:x67x6fx74x6f:20170601123825p:plain

 

GameScene.swift を修正する

import Foundation を import SceneKit に変更して以下の空のクラスを作る。

f:id:x67x6fx74x6f:20170601123535p:plain

import SceneKit

class GameScene: SCNScene {
}

 

ViewController.swift を修正する

まず、import UIKit の下に import SceneKit を書く。

import UIKit
import SceneKit 

 

override func viewDidLoad() の中身に以下のものを追加。
シーンを先ほど設定したものにしているだけで、以前のものと変わらない。

override func viewDidLoad() {
    super.viewDidLoad()
    
    // シーン設定
    let scene = GameScene()

    // SCNView 設定
    let scnView = self.view as! SCNView
    scnView.backgroundColor = UIColor.black
    scnView.scene = scene
    scnView.showsStatistics = true
    scnView.allowsCameraControl = true
}

ビルドすると画面下に統計情報が表示される。

f:id:x67x6fx74x6f:20170530190203p:plain

 

もう一度 GameScene.swift を修正する

初期化時に自前でつくった setUpScene() を呼び、setUpScene() でシーングラプを作成する。

 

初期化(イニシャライズ)

init() でオーバーライドして初期化しようと思うが、
SCNScene では必須のイニシャライザがあるのでそれも書く。

クラスの中に以下のものを書く。

class GameScene: SCNScene {

    override init() {
        super.init()
        
        self.setUpScene()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

 

シーングラフ

init() で setUpScene() の関数を呼んでいるので、それも書く。 シーングラフは上記のものだが、試しにビルドした際なのも表示されないの球を置いてみる。
問題なく表示されるのであれば球は消しても構わない。

func setUpScene() {
    
    // 球
    let sphere:SCNGeometry = SCNSphere(radius: 2)    
    let geometryNode = SCNNode(geometry: sphere)
    self.rootNode.addChildNode(geometryNode)
    
    // オムニ ライト
    let lightNode = SCNNode()
    lightNode.light = SCNLight()
    lightNode.light!.type = .omni
    lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
    self.rootNode.addChildNode(lightNode)
    
    // アンビエント ライト
    let ambientLightNode = SCNNode()
    ambientLightNode.light = SCNLight()
    ambientLightNode.light!.type = .ambient
    ambientLightNode.light!.color = UIColor.darkGray
    self.rootNode.addChildNode(ambientLightNode)

    // カメラ
    let cameraNode = SCNNode()
    cameraNode.camera = SCNCamera()
    cameraNode.position = SCNVector3(x: 0, y: 0, z: 10)
    self.rootNode.addChildNode(cameraNode)
    
}

f:id:x67x6fx74x6f:20170601124101p:plain

 

もう一度 ViewController.swift を修正する

画面タップ時の処理を付加する。

viewDidLoad() の SCNView で設定の下に以下のものを書く

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

 

ジェスチャーレコグナイザーの呼び出し先の関数を作成する。

didReceiveMemoryWarning() の後に以下の関数を作成する

func handleTap(_ gestureRecognize: UIGestureRecognizer) {
    print("タップされました")
}

 

問題がなければ、画面をタップするたびにデバッグログに「タップされました」が表示されるはず。

本来は、画面タップした際 SCNView の中から HitTest を呼ぶ。
Unity などと同様にタップからシーン内にレイキャスト(見えない光の線)を飛ばし、ぶつかったチルドノードを調べていく形となる。

 

とりあえず、テンプレートは完成したので、
今回はここまで。

 

 

全コード

GameScene.swift

import SceneKit

class GameScene: SCNScene {
    
    override init() {
        super.init()
        
        self.setUpScene()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func setUpScene() {
        
        // オムニ ライト
        let lightNode = SCNNode()
        lightNode.light = SCNLight()
        lightNode.light!.type = .omni
        lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
        self.rootNode.addChildNode(lightNode)
        
        // アンビエント ライト
        let ambientLightNode = SCNNode()
        ambientLightNode.light = SCNLight()
        ambientLightNode.light!.type = .ambient
        ambientLightNode.light!.color = UIColor.darkGray
        self.rootNode.addChildNode(ambientLightNode)

        // カメラ
        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 10)
        self.rootNode.addChildNode(cameraNode)
        
    }
}

 

ViewController.swift 

import UIKit
import SceneKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // シーン設定
        let scene = GameScene()

        // SCNView 設定
        let scnView = self.view as! SCNView
        scnView.backgroundColor = UIColor.black
        scnView.scene = scene
        scnView.showsStatistics = true
        scnView.allowsCameraControl = true
        
        // タップジェスチャー
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
        scnView.addGestureRecognizer(tapGesture)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func handleTap(_ gestureRecognize: UIGestureRecognizer) {

        print("タップされました")

    }
}