Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get motion events with the Apple TV remote

Has anybody figured out how to get motion events working with the new apple TV remote? Thanks.

I've tried calling

override func motionBegan(motion: UIEventSubtype, withEvent event: UIEvent?) {
    super.motionBegan(motion, withEvent: event)
    print("motion!")
}
override func motionEnded(motion: UIEventSubtype, withEvent event: UIEvent?) {
    super.motionEnded(motion, withEvent: event)
    print("motion ended!")
}

With and without calling super gives me nothing.

like image 873
CodyMace Avatar asked Sep 28 '15 22:09

CodyMace


People also ask

Does Apple TV Remote have motion?

Answer: A: Answer: A: … and the game does not see the remote's motion sensor. That is because the Siri Remote (2nd generation) doesn't have an accelerometer and gyro, unlike the Siri Remote (1st generation).

Does the new Apple TV Remote have accelerometer?

Either find a Siri Remote (1st generation), or a third party game controller, or an iPhone or iPad with companion app (if supported for that game). The Siri Remote (2nd generation) unfortunately lacks an accelerometer and gyroscope (unlike the previous black remote).

What do the buttons on the Apple TV Remote do?

The remote has dedicated buttons for Menu and Play, and a round navigation button for pressing up, down, left, and right. *Apple TV 4K and Apple TV HD ship with the same remote everywhere. In countries and regions that support Siri, the remote is called Siri Remote. Elsewhere, it's called Apple TV Remote.


Video Answer


3 Answers

A great swift example can be found here: https://forums.developer.apple.com/message/65560#65560 It's basically what Daniel Storm said above, but following this got it working for me. Here's what I did.

In appDelegate:

 var motionDelegate: ReactToMotionEvents? = nil   

     func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {  
        let center = NSNotificationCenter.defaultCenter()  
        center.addObserver(self, selector: "setupControllers:", name: GCControllerDidConnectNotification, object: nil)  
        center.addObserver(self, selector: "setupControllers:", name: GCControllerDidDisconnectNotification, object: nil)  
        GCController.startWirelessControllerDiscoveryWithCompletionHandler { () -> Void in  

        }  
        return true  
    }  

    func setupControllers(notif: NSNotification) {  
        print("controller connection")  
        let controllers = GCController.controllers()  
        for controller in controllers {  
            controller.motion?.valueChangedHandler = { (motion: GCMotion)->() in  
                if let delegate = self.motionDelegate {  
                    delegate.motionUpdate(motion)  
                }  
            }  
        }  
    }  

protocol ReactToMotionEvents {  
    func motionUpdate(motion: GCMotion) -> Void  
}  

Where I want it implemented, in my case an SKScene:

import SpriteKit  
import GameController  
class GameScene: SKScene, ReactToMotionEvents {  

    override func didMoveToView(view: SKView) {   
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate  
        appDelegate.motionDelegate = self  

    }  

    func motionUpdate(motion: GCMotion) {  
        print("x: \(motion.userAcceleration.x)   y: \(motion.userAcceleration.y)")  
    }  
}  
like image 144
CodyMace Avatar answered Oct 10 '22 20:10

CodyMace


Via How to access motion & orientation information of remote:


First of all, one needs to use NSNotificationCenter to find the controllers. Probably best to do this when app launches. Something like this:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerDidConnect:) name:GCControllerDidConnectNotification object:nil];  

We can then use the following code after connecting to store the device info in a property:

- (void)controllerDidConnect:(NSNotification *)notification {  
    self.myController = notification.object;  
}  

The remote profile is a subclass of the micro gamepad profile. Motion and other data can be tracked by adding a value changed event handler:

  GCMicroGamepad *profile =  self.myController.microGamepad  
  profile.valueChangedHandler= ^ (GCMicroGamepad *gamepad, GCControllerElement *element) {  
        if (self.myController.motion) {  
            NSLog(@"motion supported");  
            NSLog(@"gravity: %f %f %f", self.myController.motion.gravity.x, self.myController.motion.gravity.y, self.myController.motion.gravity.z);  
            NSLog(@"userAcc: %f %f %f", self.myController.motion.userAcceleration.x, self.myController.motion.userAcceleration.y, self.myController.motion.userAcceleration.z);  
            NSLog(@"rotationRate: %f %f %f", self.myController.motion.rotationRate.x, self.myController.motion.rotationRate.y, self.myController.motion.rotationRate.z);  
            NSLog(@"attitude: %f %f %f %f", self.myController.motion.attitude.x, self.myController.motion.attitude.y, self.myController.motion.attitude.z, self.myController.motion.attitude.w);  
        }  
    };  

like image 21
Daniel Storm Avatar answered Oct 10 '22 21:10

Daniel Storm


Thought I would update CodyMace's great answer with Swift 4.0 syntax

In appDelegate (You will need to import GameController here, too):

var motionDelegate: ReactToMotionEvents? = nil


func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    let center = NotificationCenter.default
    center.addObserver(self, selector: #selector(setupControllers), name: NSNotification.Name.GCControllerDidConnect, object: nil)
    center.addObserver(self, selector: #selector(setupControllers), name: NSNotification.Name.GCControllerDidDisconnect, object: nil)
    GCController.startWirelessControllerDiscovery { () -> Void in

    }
    return true
}

@objc func setupControllers(notif: NSNotification) {
    print("controller connection")
    let controllers = GCController.controllers()
    for controller in controllers {
        controller.motion?.valueChangedHandler = { (motion: GCMotion)->() in
            if let delegate = self.motionDelegate {
                delegate.motionUpdate(motion: motion)
            }
        }
    }
}

The protocol stays the same

protocol ReactToMotionEvents {
func motionUpdate(motion: GCMotion) -> Void

}

And where you want implemented

import SpriteKit  
import GameController  
class GameScene: SKScene, ReactToMotionEvents {  

    override func didMoveToView(view: SKView) {   
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        appDelegate.motionDelegate = self

    }  

    func motionUpdate(motion: GCMotion) {  
        print("x: \(motion.userAcceleration.x)   y: \(motion.userAcceleration.y)")  
    }  
}  
like image 35
D. Pratt Avatar answered Oct 10 '22 20:10

D. Pratt