Converting UIKit to SceneKit
UIKit to SceneKit problem conversion program. The biggest challenge for me is understanding how the delegate file, Tile, synchronized with the array, Board, is set to SceneKit. This is a simple project. Screenshot: http://imgur.com/9hsv7X5 . It renders a 3 x 5 array. The user removes the item and becomes highlighted. Then touch another item, it will be highlighted, the previous item is not highlighted.
Here is a UIKit project with 3 files:
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
}
}
TIP
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()
}
}
source to share
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
}
}
}
}
}
}
}
source to share
First of all, I recommend that you read the Apple SceneKit document and some tutorials.
Scene Kit is an Objective-C 3D rendering engine that combines a high-performance rendering engine with a high-level descriptive API. Scene Kit supports import, manipulation and rendering of 3D assets without requiring precise steps to render the scene like OpenGL does.
- http://www.objc.io/issue-18/scenekit.html
- https://www.weheartswift.com/introduction-scenekit-part-1/
- http://www.raywenderlich.com/83748/beginning-scene-kit-tutorial
- http://tacow.org/assets/attachments/SceneKit.pdf
Scene Kit makes it easy to render a 3D scene without the OpenGL ES API. However, you must understand how the Scene Kit works.
Basically, the Scene Kit provides a view controller that supports the animation loop. This cycle follows a design pattern commonly used in games and simulations, with two phases: refresh and render. The Scene Kit implementation has more phases like the following figure (from http://www.objc.io/issue-18/scenekit.html ), but basically two phases, update and do .
So how to create a Scene Kit project, the basics
- Prepare SCNView
- Initialize 3D scene
- Create touch event handler
- Implement an update phase: update the game board with an affected object or affected position, update animation of objects, or something like that.
- Render Phase Implementation: Basically, Scene Kit automatically displays registered 3D objects and models.
Thus, you must implement the following:
- Use SCNView instead of ViewController
- Create scene
- Place the panel and tiles as a 3D plot set
- Use hitTest to touch a tile and refresh the tile in the refresh phase
source to share