问题
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.
回答1:
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)")
}
}
回答2:
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);
}
};
回答3:
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)")
}
}
来源:https://stackoverflow.com/questions/32832541/how-to-get-motion-events-with-the-apple-tv-remote