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.
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).
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).
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.
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)")
}
}
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);
}
};
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)")
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With