HomeKit Camera Streaming Not Working in Swift - swift

I've tried building a simple HomeKit app to stream video from a HomeKit Camera and while it appears to be working - the stream is not showing on the View Controller. Any help appreciated.
#IBOutlet weak var liveStreamView: HMCameraView!
// var liveStreamView: HMCameraView?
func startCameraStream(for accessory: HMAccessory) {
// Ensure this is a camera accessory
guard let cameraStreamControl = accessory.cameraProfiles?.first?.streamControl else
{ return }
cameraStreamControl.delegate = self
cameraStreamControl.startStream()
let liveStreamView = HMCameraView()
self.view.addSubview(liveStreamView)
self.liveStreamView = liveStreamView
self.liveStreamView.cameraSource = cameraStreamControl.cameraStream
self.liveStreamView?.setNeedsDisplay()
self.view.layoutIfNeeded()
}
extension ViewController: HMCameraStreamControlDelegate {
func cameraStreamControlDidStartStream(_ cameraStreamControl: HMCameraStreamControl) {
liveStreamView?.cameraSource = cameraStreamControl.cameraStream
}
}

So silly. I forgot to define the liveStreamView attributes including the frame. See below where I set the background color, alpha, tag, etc:
func startCameraStream( for accessory: HMAccessory) {
// Ensure this is a camera accessory
guard let cameraStreamControl = accessory.cameraProfiles?.first?.streamControl else
{ return }
cameraStreamControl.delegate = self
cameraStreamControl.startStream ( )
let liveStreamView = HMCameraView(frame: CGRect(x: 0, y: 0, width: 320, height: 568))
liveStreamView.backgroundColor = .clear
liveStreamView.alpha = 0.5
liveStreamView.tag = 100
liveStreamView.isUserInteractionEnabled = true
self.view.addSubview(liveStreamView)
self.liveStreamView = liveStreamView
}

Related

Swift5 UIView rotation behavior different for iPhone vs iPad

I have struggled with odd differences in behavior between iPhone and iPad (both in simulators as well as real devices) and despite trying different ways to diagnosis this with many visits to Stackoverflow, I am still struggling to get to a root cause. Specifically, I have a simple Test view controller that performs as expected with iPad but the same code behaves differently and not as expected on iPhone. I have one UIImageView centered on each device in portrait mode with 10px margins left, right and top. When I rotate the device, the objective is to resize the image in landscape so it remains 10px for these margins IE it gets scaled to fit the new geometry and the image always appears in its original orientation. The iPad does this perfectly without a lot of code. However the iPhone performs the scaling correctly but the image does not stay in its original orientation ... it rotates with the device rotation. How can the same code produce two different results?
I can solve this by detecting iPhone and writing code to rotate the image and determine the new origin for placement, in fact I have this working. However, it doesn't seem right to me to have different logic for iPhone versus iPad.
Some details: I am using Swift 5 Xcode 12 MacOS 10.15.6 Simulator 11.5 iPhone 11 with IOS 14.0.1 and iPad 7th Gen IOS 14.0.1
Using interface builder to build layout initially and linking to code with IBOutlet however I am using translatesAutoresizingMaskIntoConstraints = false and anchor constraints programmatically to place the UIImageView. I am using Notification Center to add and remove an observer to trigger rotation events. I am using begin and endGeneratingDeviceOrientationNotifications(). I override shouldAutorotate as true, supportedInterfaceOrientations as all, and preferredInterfaceOrientationForPresentation as portrait my Test VC as well as creating extensions for UINavigationController and UITabBarController in SceneDelegate to propagate these values given Test VC is embedded in a Nav Controller and uses tab bar. Info plist lists all 4 modes for supported interface orientations and the general tab for the Xcode project selects iPhone and iPad as deployable and all 4 orientation modes are unselected for Device Orientation.
I can add code here if helpful as well as screenshots. If anyone has had a similar experience or any ideas about this I would be grateful! Here is the code for TestVC:
import UIKit
class Test: UIViewController {
#IBOutlet weak var testImage: UIImageView!
let debug = true
let program = "TestViewController"
var deviceSize = CGRect.zero
var deviceWidth: CGFloat = 0
var deviceHeight: CGFloat = 0
let imageAsset = UIImage(named: "Cera.jpg")
var aspectRatio: CGFloat = 0.0
override var shouldAutorotate: Bool { return true }
override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return UIInterfaceOrientationMask.all }
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { return UIInterfaceOrientation.portrait }
// This routine triggered the first time this view controiller is loaded
override func viewDidLoad() {
super.viewDidLoad()
let rtn = "viewDidLoad"
top = self.view.topAnchor
lead = self.view.leadingAnchor
deviceSize = UIScreen.main.bounds
deviceWidth = deviceSize.width
deviceHeight = deviceSize.height
UIDevice.current.beginGeneratingDeviceOrientationNotifications()
NotificationCenter.default.addObserver(self, selector: #selector(deviceRotated), name: UIDevice.orientationDidChangeNotification, object: nil)
if debug { print(">>> \(program): \(rtn): device width[\(deviceWidth)] device height[\(deviceHeight)]") }
determineOrientation()
if debug { print(">>> \(program): \(rtn): rotated device width[\(rotatedDeviceWidth)] rotated device height[\(rotatedDeviceHeight)]") }
testImage.image = imageAsset
let imageWidth = testImage.image!.size.width
let imageHeight = testImage.image!.size.height
aspectRatio = imageHeight / imageWidth
calculateContraints()
}
// This routine triggered every time this view controller is presented
override func viewWillAppear(_ animated: Bool) {
let rtn = "viewWillAppear"
if debug { print(">>> \(program): \(rtn): device width[\(deviceWidth)] device height[\(deviceHeight)]") }
determineOrientation()
if debug { print(">>> \(program): \(rtn): rotated device width[\(rotatedDeviceWidth)] rotated device height[\(rotatedDeviceHeight)]") }
}
// This routine added to remove observer for rotation events
override func viewWillDisappear(_ animated: Bool) {
NotificationCenter.default.removeObserver(self, name: UIDevice.orientationDidChangeNotification, object: nil)
UIDevice.current.endGeneratingDeviceOrientationNotifications()
}
var orientation = "Portrait"
var rotatedDeviceWidth: CGFloat = 0
var rotatedDeviceHeight: CGFloat = 0
// This routine called by "viewWillTransition" to determoine "orientation" value
func determineOrientation() {
let rtn = "determineOrientation"
if debug { print(">>> \(program): \(rtn)") }
if UIDevice.current.orientation == UIDeviceOrientation.portrait { orientation = "Portrait" }
if UIDevice.current.orientation == UIDeviceOrientation.landscapeLeft { orientation = "LandscapeLeft" }
if UIDevice.current.orientation == UIDeviceOrientation.landscapeRight { orientation = "LandscapeRight" }
if UIDevice.current.orientation == UIDeviceOrientation.portraitUpsideDown { orientation = "PortraitUpsideDown" }
if orientation == "Portrait" || orientation == "PortraitUpsideDown" {
rotatedDeviceWidth = deviceWidth
rotatedDeviceHeight = deviceHeight
} else {
rotatedDeviceWidth = deviceHeight
rotatedDeviceHeight = deviceWidth
}
}
var imageWidth: CGFloat = 0
var imageHeight: CGFloat = 0
var imageXpos: CGFloat = 0
var imageYpos: CGFloat = 0
var v: CGFloat = 0
var h: CGFloat = 0
var w: CGFloat = 0
var ht: CGFloat = 0
// This routine determines the position of the display object "testImage"
func calculateContraints() {
let rtn = "calculateContraints"
if debug { print(">>> \(program): \(rtn): orientation[\(orientation)]") }
if orientation == "Portrait" {
imageWidth = deviceWidth / 2 - 20
imageHeight = imageWidth * CGFloat(aspectRatio)
imageXpos = 10
imageYpos = 10
if debug { print(">>> \(imageWidth): \(imageHeight)") }
}
if orientation == "LandscapeLeft" {
imageWidth = rotatedDeviceWidth / 2 - 20
imageHeight = imageWidth * CGFloat(aspectRatio)
imageXpos = 10
imageYpos = 10
if debug { print(">>> \(imageWidth): \(imageHeight)") }
}
if orientation == "LandscapeRight" {
imageWidth = rotatedDeviceWidth / 2 - 20
imageHeight = imageWidth * CGFloat(aspectRatio)
imageXpos = 10
imageYpos = 10
if debug { print(">>> \(imageWidth): \(imageHeight)") }
}
if orientation == "PortraitUpsideDown" {
imageWidth = deviceWidth / 2 - 20
imageHeight = imageWidth * CGFloat(aspectRatio)
imageXpos = 10
imageYpos = 10
if debug { print(">>> \(imageWidth): \(imageHeight)") }
}
layoutConstraints(v: imageXpos, h: imageYpos, w: imageWidth, ht: imageHeight)
}
var testImageTopConstraint: NSLayoutConstraint!
var testImageLeftConstraint: NSLayoutConstraint!
var testImageWidthConstraint: NSLayoutConstraint!
var testImageHeightConstraint: NSLayoutConstraint!
var top: NSLayoutYAxisAnchor!
var lead: NSLayoutXAxisAnchor!
var trail: NSLayoutXAxisAnchor!
var bot: NSLayoutYAxisAnchor!
// This routine lays out the display object "testImage"
func layoutConstraints(v: CGFloat, h: CGFloat, w: CGFloat, ht: CGFloat) {
let rtn = "layoutConstraints"
if debug { print(">>> \(program): \(rtn)") }
testImage.translatesAutoresizingMaskIntoConstraints = false
if testImageTopConstraint != nil { testImageTopConstraint.isActive = false }
if testImageLeftConstraint != nil { testImageLeftConstraint.isActive = false }
if testImageWidthConstraint != nil { testImageWidthConstraint.isActive = false }
if testImageHeightConstraint != nil { testImageHeightConstraint.isActive = false }
testImageTopConstraint = testImage.topAnchor.constraint(equalTo: top, constant: v)
testImageLeftConstraint = testImage.leadingAnchor.constraint(equalTo: lead, constant: h)
testImageWidthConstraint = testImage.widthAnchor.constraint(equalToConstant: w)
testImageHeightConstraint = testImage.heightAnchor.constraint(equalToConstant: ht)
testImageTopConstraint.isActive = true
testImageLeftConstraint.isActive = true
testImageWidthConstraint.isActive = true
testImageHeightConstraint.isActive = true
}
}
#objc extension Test {
func deviceRotated(_ notification: NSNotification) {
let device = notification.object as! UIDevice
let deviceOrientation = device.orientation
switch deviceOrientation {
case .landscapeLeft: print("<<<Landscape Left>>>")
case .landscapeRight: print("<<<Landscape Right>>>")
case .portrait: print("<<<Portrait>>>")
case .portraitUpsideDown: print("<<<Portrait Upside Down>>>")
case .faceDown: print("<<<Face Down>>>")
case .faceUp: print("<<<Face Up>>>")
case .unknown: print("<<<Unknown>>>")
#unknown default: print("<<<Default>>>")
}
let rtn = "deviceRotated2"
determineOrientation()
if debug { print(">>> \(program): \(rtn): Device rotated to: \(orientation)") }
if debug { print(">>> \(program): \(rtn): rotated device width[\(rotatedDeviceWidth)] rotated device height[\(rotatedDeviceHeight)]") }
calculateContraints()
}
}
Here is the code in SceneDelegate.swift
extension UINavigationController {
override open var shouldAutorotate: Bool {
get {
if let visibleVC = visibleViewController { return visibleVC.shouldAutorotate }
return super.shouldAutorotate } }
override open var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
get {
if let visibleVC = visibleViewController { return visibleVC.preferredInterfaceOrientationForPresentation }
return super.preferredInterfaceOrientationForPresentation } }
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
get {
if let visibleVC = visibleViewController { return visibleVC.supportedInterfaceOrientations }
return super.supportedInterfaceOrientations } }
}
// ===================================================================================
// UITabBarController Extension - used to manage tab bar style
//
extension UITabBarController {
open override var childForStatusBarStyle: UIViewController? {
return selectedViewController?.childForStatusBarStyle ?? selectedViewController
}
}
// ===================================================================================
// UITabBarController Extension - used to manage rotation
//
extension UITabBarController {
override open var shouldAutorotate: Bool {
if let viewController = self.viewControllers?[self.selectedIndex] { return viewController.shouldAutorotate }
return super.shouldAutorotate }
override open var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
if let viewController = self.viewControllers?[self.selectedIndex] { return viewController.preferredInterfaceOrientationForPresentation }
return super.preferredInterfaceOrientationForPresentation }
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if let viewController = self.viewControllers?[self.selectedIndex] { return viewController.supportedInterfaceOrientations }
return super.supportedInterfaceOrientations }
}
Here are the rotation results for the iPhone in the simulator:
Cera rotations for iPhone
... and iPad:
Cera rotations for iPad

UIscrollview issue with iPhone X

I am having a horizontal UIScrollview in my xib file. Scrollview looks great in all devices except iPhone X, XS and XR.
It looks good in iPhone 8
iPhone X
I have tried all the possible solutions, Unchecked the under top bar, under bottom bar, auto resize subviews,nothing works for me. iPhone X always looks the same. Top constraint of the scrollview is set to safe area. I am using xib file here.
if #available(iOS 11.0, *) {
scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentBehavior.never
} else {
self.automaticallyAdjustsScrollViewInsets = false
edgesForExtendedLayout = []
// Fallback on earlier versions
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.scrollView.contentSize = CGSize(width: self.lectureTable.frame.size.width , height: self.scrollView.frame.size.height)
self.automaticallyAdjustsScrollViewInsets = false
}
Please shed some light. Thanks a ton.
I have solved it by myself. Inside my scroll view, I have used UIView.
var hasTopNotch: Bool {
if #available(iOS 11.0, *) {
return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 20
}
return false
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
var topbarHeight: CGFloat {
return UIApplication.shared.statusBarFrame.size.height + (self.navigationController?.navigationBar.frame.height ?? 0.0)
}
if hasTopNotch{
let window = UIApplication.shared.keyWindow
if #available(iOS 11.0, *) {
let topPadding = window?.safeAreaInsets.top
self.customView.frame.size.height = UIScreen.main.bounds.height - (topbarHeight + topPadding!)
} else {
// Fallback on earlier versions
}
}else{
let NavBarHeight = self.navigationController!.navigationBar.frame.height + UIApplication.shared.statusBarFrame.height
self.customView.frame.size.height = UIScreen.main.bounds.height - NavBarHeight
}
}
This works great in all the devices.

ios - Swift 4: How to remove UIImageViews when UIImageView.animationImages is finished?

I am using .animationImages for UIImageViews in my project (it's a game). When the user presses a hint button I programmatically create a variable number of UIImageViews that will appear on screen and play the same image sequence once. I need to remove the UIImageViews from the view when the animation has stopped but I can't figure out how to do this.
I've been through the swift documentation for both .animationImages and .startAnimating but it's literally one paragraph and one line, neither of which is in relation to a completion or finish notifications etc. Any help will be much appreciated.
private func hideAnswerButtonsHint() {
// Clear all of the answer boxes that aren't hint locked
resetAnswerBoxes()
var imageArray = [UIImage]()
var remainingLetters = [String]()
for imageCount in 1...8 {
let imageName = "green_smoke_puff_0\(imageCount)"
let image = UIImage(named: imageName)!
imageArray.append(image)
}
for answerBox in answerBoxArray where answerBox.hintLock == false {
if let letter = answerBoxDict[answerBox.tag] {
remainingLetters.append(letter)
}
}
for answerButton in answerButtonArray where answerButton.hintLock == false {
if let index = remainingLetters.index(of: answerButton.titleText) {
answerButton.decompress()
remainingLetters.remove(at: index)
} else {
let frame = answerButton.superview?.convert(answerButton.frame.origin, to: nil)
let imageView = UIImageView()
imageView.animationImages = imageArray
imageView.animationDuration = 0.5
imageView.animationRepeatCount = 1
imageView.frame = CGRect(x: frame!.x, y: frame!.y, width: answerButton.frame.width, height: answerButton.frame.height)
view.addSubview(imageView)
imageView.startAnimating()
answerButton.compress()
answerButton.hintLock = true
}
}
}
UIImageView is an NSObject so you can always use KVO to watch its properties:
var observation: NSKeyValueObservation?
override func viewDidLoad() {
super.viewDidLoad()
observation = imageView.observe(\.isAnimating) { [weak self] imageView, change in
if let value = change.newValue,
value == true {
imageView.removeFromSuperview()
self?.observation = nil
}
}
}

UISlider not updating values

apologies if this is a stupid question. I can't seem to get my slider to update its value as its being interacted with. (I'm going to point everyone to the very last method in this long code)
class CustomSlider: UISlider {
override func trackRect(forBounds bounds: CGRect) -> CGRect {
var rect = super.trackRect(forBounds: bounds)
rect.size.height = 7
return rect
}
}
class FactionButton: CustomSlider {
var factionSlider = CustomSlider(frame: CGRect(x: 15, y: 542, width: 386, height: 57))
func factionBalanceSlider(){
factionSlider.minimumValueImage = #imageLiteral(resourceName: "Alliance Slider")
factionSlider.maximumValueImage = #imageLiteral(resourceName: "Horde Slider")
factionSlider.setThumbImage(#imageLiteral(resourceName: "Thumb Image"), for: .normal)
factionSlider.minimumTrackTintColor = UIColor(red:0.08, green:0.33, blue:0.69, alpha:0.8)
factionSlider.maximumTrackTintColor = UIColor(red:1.00, green:0.00, blue:0.00, alpha:0.59)
factionSlider.setValue(0.5, animated: true)
factionSlider.isContinuous = false
factionSlider.addTarget(self, action: #selector(recordFactionBalance(sender:)), for: .valueChanged)
}
func getSlider() -> CustomSlider {
return factionSlider
}
override func trackRect(forBounds bounds: CGRect) -> CGRect {
var customBounds = super.trackRect(forBounds: bounds)
customBounds.size.height = 10
return customBounds
}
#objc func recordFactionBalance(sender: CustomSlider){
//also calculates balance and adds it into the quiz data
print("hi")
print(sender.value) //It's this part that doesn't work
}
}
It's this bit nearest to the bottom that has the issue. (Everything else is fine) The action function doesn't seem to be triggered at all, even when I'm interacting with it. Neither print statements are being executed. Any ideas why?
Cheers
From the getSlider(), i can guess you are using this class as a utility to get the CustomSlider. So, i suspect you are adding the slider to the view as below,
let container = FactionButton()
container.factionBalanceSlider()
let slider = container.getSlider()
self.view.addSubview(slider)
If you will not add the container to the view which is set as the receiver for .valueChange event so it will not get any event. To receive events you also need to add the container in the view as below,
self.view.addSubview(container)

Converting UIKit to SceneKit

Trouble converting program from UIKit to SceneKit. Biggest difficulty for me is understanding how delegate file, Tile, synched with array, Board, is set up with SceneKit. It is a simple project. A screenshot: http://imgur.com/9hsv7X5. It displays a 3 x 5 array. User taps an item and it becomes highlighted. Then tap another item, it becomes highlighted, previous item, unhighlighted.
Here is the UIKit project composed of 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
}
}
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()
}
}
First of all, I recommend you to read Apple SceneKit document and some tutorials.
Scene Kit is a 3D-rendering Objective-C framework that combines a high-performance rendering engine with a high-level, descriptive API. Scene Kit supports the import, manipulation, and rendering of 3D assets without requiring the exact steps to render a scene the way 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 allows you to render 3D scene easily, without OpenGL ES APIs. However you should understand how Scene Kit works.
Basically, Scene Kit provides a view controller that maintains an animation loop. This loop follows a design pattern common in games and simulations, with two phases: update and render. In the implementation, Scene Kit has more phases like the following figure (from http://www.objc.io/issue-18/scenekit.html), but basically, two phases, update and render.
So how to create Scene Kit project, the basics is
Prepare SCNView
Initialize 3D scene
Create touch event handler
Implement Update phase: Update game board using the touched object or the touched position, Update the animation of the objects, or some sort of stuff.
Implement Render phase: Basically, Scene Kit automatically renders registered 3D objects and models.
Thus, you should implement as the following.
Use SCNView instead of ViewController
Create a scene
Place Board and Tiles as Scene Kit 3D objects
Use hitTest for touching Tile and update Tiles in Update phase
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
}
}
}
}
}
}
}