将UIKit转换为SceneKit

时间:2014-12-21 22:34:22

标签: swift scenekit

无法将程序从UIKit转换为SceneKit。对我来说最大的困难是理解如何使用SceneKit设置委托文件Tile,与数组,Board同步。这是一个简单的项目。截图:http://imgur.com/9hsv7X5。它显示一个3 x 5阵列。用户点击一个项目,它会突出显示。然后点击另一个项目,它突出显示,上一个项目,未突出显示。

这是由3个文件组成的UIKit项目:

VIEWCONTROLLER

import UIKit

struct BoardLoc {
    var x: Int
    var y: Int
}

class ViewController: UIViewController, TileDelegate {

    var tile: Tile!

    override func viewDidLoad() {
        super.viewDidLoad()

        let scene = Board()
        tile.tileDelegate = self
        tile.board = scene
    }

    func getTileAtLoc(tile: Tile, _ boardLoc: BoardLoc) {
        tile.boardLoc = boardLoc
    }  
}

BOARD

import Foundation

class Board {
    var board: Array<Array<String>> = Array(count:3, repeatedValue:Array(count:5, repeatedValue:"foo"))

    func putTileAt(boardLoc: BoardLoc) -> String {
        return board[boardLoc.x][boardLoc.y]
    }  
}

TILE

import UIKit

protocol TileDelegate {
    func getTileAtLoc(tile: Tile, _ boardLoc: BoardLoc)
}

class Tile: UIView {
    var boardLoc: BoardLoc?
    var board: Board?
    var tileDelegate: TileDelegate?

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        addGestureRecognizer(UITapGestureRecognizer(target: self, action:"handleTap:"))
    }

    override func drawRect(rect: CGRect) {
        for x in 0...2 {
            for y in 0...4 {

                let context = UIGraphicsGetCurrentContext()
                let red = UIColor.redColor().CGColor
                let orange = UIColor.orangeColor().CGColor
                let bigCircle = CGRectMake(CGFloat(106 * x),CGFloat(106 * y), 106, 106)
                let smallCircle = CGRectMake(CGFloat(106 * x) + 3, CGFloat(106 * y) + 3, 100, 100)

                if (boardLoc != nil && boardLoc!.x == x && boardLoc!.y == y) {
                    CGContextSetFillColorWithColor(context, red)
                    CGContextFillEllipseInRect(context, bigCircle)
                }

                if board!.putTileAt(BoardLoc(x: x, y: y)) == "foo" {
                    CGContextSetFillColorWithColor(context, orange)
                    CGContextFillEllipseInRect(context, smallCircle)
                }
            }
        }
    }

    func handleTap(gestureRecognizer: UIGestureRecognizer) {
        let point = gestureRecognizer.locationInView(self)
        let boardLoc = BoardLoc(x: Int(point.x) / 106, y: Int(point.y) / 106)
        tileDelegate!.getTileAtLoc(self, boardLoc)
        setNeedsDisplay()
    }
}

2 个答案:

答案 0 :(得分:2)

首先,我建议您阅读Apple SceneKit document和一些教程。

  

Scene Kit是一个3D渲染的Objective-C框架,它将高性能渲染引擎与高级描述性API相结合。 Scene Kit支持导入,操作和渲染3D资源,而无需按照OpenGL的方式渲染场景。

Scene Kit允许您轻松渲染3D场景,无需OpenGL ES API。但是,您应该了解Scene Kit的工作原理。

基本上,Scene Kit提供了一个维护动画循环的视图控制器。这个循环遵循游戏和模拟中常见的设计模式,有两个阶段:更新和渲染。在实现中,Scene Kit有更多阶段,如下图所示(来自http://www.objc.io/issue-18/scenekit.html),但基本上有两个阶段,更新渲染

Scene Kit phases

那么如何创建Scene Kit项目,基础是

  • 准备SCNView
  • 初始化3D场景
  • 创建触摸事件处理程序
  • 实施更新阶段:使用触摸的对象或触摸的位置更新游戏板,更新对象的动画或某种东西。
  • 实现渲染阶段:基本上,Scene Kit会自动渲染已注册的3D对象和模型。

因此,您应该实现如下。

  • 使用SCNView代替ViewController
  • 制作一个场景
  • 将Board和Tiles放置为Scene Kit 3D对象
  • 使用hitTest触摸平铺并在更新阶段更新平铺

答案 1 :(得分:1)

import SceneKit

class GameViewController: UIViewController {

struct BoardLoc {
    var x: Int
    var y: Int
}

enum Type {
    case Yellow
    case Orange
}

var boardArray: Array<Array<Type>> = []

override func viewDidLoad() {
    super.viewDidLoad()

    for x in 0...2 {
        boardArray.append(Array(count:5, repeatedValue:Type.Orange))
        for y in 0...4 {
            boardArray[x][y] = Type.Orange
        }
    }

    let scene = SCNScene(named: "art.scnassets/balls8.dae")
    let scnView = self.view as SCNView
    scnView.scene = scene

    scnView.autoenablesDefaultLighting = true

    let taps = NSMutableArray()
    let tap = UITapGestureRecognizer(target: self, action: "handleTap:")
    taps.addObject(tap)
    scnView.gestureRecognizers = taps
}

func handleTap(gestureRecognizer: UIGestureRecognizer) {
    let scnView = view as SCNView
    let point = gestureRecognizer.locationInView(scnView)
    if let hitResults = scnView.hitTest(point, options: nil) {
        if hitResults.count > 0 {

            let result: AnyObject! = hitResults[0]

            if !result.node!.name!.hasPrefix("Orange") {
                return
            }

            let tapLoc = BoardLoc(x: Int(point.x) / 106, y: Int(point.y) / 106)

            boardArray[tapLoc.x][tapLoc.y] = Type.Yellow



            for col in 0...2 {
                for row in 0...4 {
                    var yellowBall = scnView.scene!.rootNode.childNodeWithName("Yellow", recursively: true)
                    var secxtorX = Float(col) * 16.5 - 16
                    var sectorY = 34 - (Float(row) * 16.5)
                    if boardArray[col][row] == Type.Yellow {
                        yellowBall!.runAction(SCNAction.moveTo(SCNVector3(x: secxtorX, y: sectorY, z: 25), duration: 0.01))
                        boardArray[tapLoc.x][tapLoc.y] = Type.Orange
                    }
                }
            }
        }
    }
}
}