Swift version of Obj.C macro : IS_RETINA - iphone

I used this code:
#define IS_RETINA ([[UIScreen mainScreen] respondsToSelector:#selector(displayLinkWithTarget:selector:)] && ([UIScreen mainScreen].scale == 2.0))
I need swift code for above macro.

You can just use a global constant for that:
let isRetina = UIScreen.mainScreen().respondsToSelector("displayLinkWithTarget:selector:") && UIScreen.mainScreen().scale == 2

Define this out of a class bracket
let IS_RETINA = UIScreen.mainScreen().respondsToSelector(Selector("displayLinkWithTarget:selector:")) && UIScreen.mainScreen().scale == 2.0

Related

Emitter not adding where players position is

I am trying to get a player to collide with a SKNode. Doing so, I want a particle to display an exposition where the SKNode just was(player) and display the effect. When I tried to create this, the emitter is not displaying where the player is. How can I fix this?
func didBegin(_ contact: SKPhysicsContact) {
let bodyA = contact.bodyA
let bodyB = contact.bodyB
if bodyA.categoryBitMask == 1 && bodyB.categoryBitMask == 2 || bodyB.categoryBitMask == 1 && bodyA.categoryBitMask == 2 {
let player = SKNode(fileNamed: "player")
let explostion = SKEmitterNode(fileNamed: "explosion.sks")
let addExplosion = SKAction.run {
player?.addChild(explostion!)
}
let seq = SKAction.sequence([addExplosion])
self.addChild(explostion!)
self.run(seq)
}
}
Probably one of physics body belongs to player's node? So you just can access it from body. For example let's player's body - is bodyA:
if bodyA.categoryBitMask == 1 && bodyB.categoryBitMask == 2 || bodyB.categoryBitMask == 1 && bodyA.categoryBitMask == 2 {
let player = bodyA.node
let explostion = SKEmitterNode(fileNamed: "explosion.sks")
player.addChild(explostion!)
}
}

play a sound when two nodes collide

I have an app with three sprite nodes, ball1, ball2, ball3. they move around the scene by tipping the device up, down, right, left. Everything is working fine.
I would like to add an effect in which when any two balls touch (collide) a sound plays. I am using SpriteKit and have each ball with a physicalBody and they have a ball shape property, I have precisionCollision Yes, categoryBitMask set to ballCategory1, 2, and 3 for each ball. (or can I just use one category)
I have tried various tutorials on how to do this but nothing seems to be working.
I have tried using Ray Wenderlich's example with a tweek for mine. but,
//here are my three categories
static const uint32_t ballCategory = 0x1 << 1;
static const uint32_t ballCategory2 = 0x1 << 2;
static const uint32_t ballCategory3 = 0x1 << 3;
//these are my three nodes
ball = [SKSpriteNode spriteNodeWithImageNamed:#"mankala piece"];
ball.scale = 1;
ball.position = CGPointMake(600, 500);
ball.physicsBody =
[SKPhysicsBody bodyWithCircleOfRadius:(ball.size.width/2)];
ball.physicsBody.usesPreciseCollisionDetection = YES;
ball.physicsBody.categoryBitMask = ballCategory;
ball.physicsBody.collisionBitMask = ballCategory2|ballCategory|ballCategory3;
ball.physicsBody.affectedByGravity = NO;
[self addChild:ball];
ball2 = [SKSpriteNode spriteNodeWithImageNamed:#"mankala piece"];
ball2.scale = 1;
ball2.position = CGPointMake(350, 200);
ball2.physicsBody =
[SKPhysicsBody bodyWithCircleOfRadius:(ball2.size.width/2)];
ball2.physicsBody.usesPreciseCollisionDetection = YES;
ball2.physicsBody.categoryBitMask = ballCategory2;
ball2.physicsBody.collisionBitMask = ballCategory2|ballCategory|ballCategory3;
ball2.physicsBody.affectedByGravity = NO;
[self addChild:ball2];
ball3 = [SKSpriteNode spriteNodeWithImageNamed:#"mankala piece"];
ball3.scale = 1;
ball3.position = CGPointMake(500, 400);
ball3.physicsBody =
[SKPhysicsBody bodyWithCircleOfRadius:(ball3.size.width/2)];
ball3.physicsBody.usesPreciseCollisionDetection = YES;
ball3.physicsBody.categoryBitMask = ballCategory3;
ball3.physicsBody.collisionBitMask = ballCategory2|ballCategory|ballCategory3;
ball3.physicsBody.affectedByGravity = NO;
[self addChild:ball3];
// and here is my revised contact code
- (void)didBeginContact:(SKPhysicsContact *)contact
{
SKPhysicsBody *firstBody, *secondBody;
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
{
firstBody = contact.bodyA;
secondBody = contact.bodyB;
}
else
{
firstBody = contact.bodyB;
secondBody = contact.bodyA;
}
if ((firstBody.categoryBitMask & ballCategory) != 0)
{
NSLog(#"click");
}
if ((firstBody.categoryBitMask & ballCategory2) != 0)
{
NSLog(#"click2");
}
if ((firstBody.categoryBitMask & ballCategory3) != 0)
{
NSLog(#"click3");
}
}
but still nothing happens.
has anyone worked with collisions in spriteKit. Just want to have a sound play when two different sprite nodes come in contact.
First, you do not have any contactTestBitMasks set up. Currently you're telling the physics delegate which nodes are set up to collide with one another, but nothing is set up to contact. Add this to each ball physicsBody:
ball2.physicsBody.contactTestBitMask = ballCategory | ballCategory2 | ballCategory3
This way, the physics delegate will understand that each ball can make contact with the others.
Your contact if statement is still incorrectly being used. ballCategory and ballCateogry2 are variables which you've equated to integers; this means that your categoryBitMask are now set equal to those integers.
What your if statement does is check to see if the physicsBody's category equals a specific integer, or just equals an integer greater than zero (it's up to you).
In this case, you will need to adjust your if statement to test the value of those categoryBitMasks you've set up:
if ((firstBody.physicsBody.categoryBitMask == ballCategory) &&
(secondBody.physicsBody.categoryBitMask == ballCategory2))
{
NSLog(#"click");
}
What you have is incorrect, as you're not testing the value of anything. You need to use your if statement to check if the firstBody and secondBody have a categoryBitMask set equal to specific ballCategory variable values.

iOS SKSpriteNode - Leave screen

Is there any way to remove from Parent a SKSpriteNode that has left area bounds?
for instance:
-(void)didBeginContact:(SKPhysicsContact *)contact
{
firstNode = (SKSpriteNode *)contact.bodyA.node;
if (firstNode.position.y<0) {
[firstNode removeFromParent];
}
}
Just point me in the right direction. Is it the update method enumerate through checking their rects or is their an action you can apply. I have gone through the documentation can't seem to find it but I would have thought it would be an easy implement since it saves memory
Update method is where you can do it alright:
- (void)update:(NSTimeInterval)currentTime {
//remove any nodes named "yourNode" that make it off screen
[self enumerateChildNodesWithName:#"yourNode" usingBlock:^(SKNode *node, BOOL *stop) {
if (node.position.x < 0){
[node removeFromParent];
}
}];
}
Though note that removing nodes doesn't guarantee freeing up memory!!
Here's how to test if the node has left any edge of the screen. In your update loop, iterate through all children object of your layer. Test if the object is of a specific type. Then test if the node's frame is outside each edge of the screen. If so call removeFromParent. Note that since the node's position is from its center you want to take that into account.
-(void)update:(CFTimeInterval)currentTime
{
[_gameLayer.children enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
{
if ([obj isKindOfClass:[MyNode class]])
{
MyNode *myNode = (MyNode *)obj;
if (myNode.position.x + myNode.size.width/2 < 0 ||
myNode.position.x - myNode.size.width/2 > self.size.width ||
myNode.position.y + myNode.size.height/2 < 0 ||
myNode.position.y - myNode.size.height/2 > self.size.height)
{
[myNode removeFromParent];
}
}
}];
}
You can also detect contact with the background SKSpriteNode and set a category for it.
And then, implement didEndContact: method to remove the object
- (void)didEndContact:(SKPhysicsContact *)contact
{
//Find out your object (Remember it could be bodyA or bodyB) and remove it here
}
You can use this function.
This function will be called every frame.(ps:My English is poor)
-(void)didSimulatePhysics
I prefer contact handling. Contact testing is done in each frame just like the processing of update:. But the contact detection by comparing bits (SKPhysicsBody.categoryBitMask) is very fast and leightweight.
I need to detect and remove balls that leave the screen.
So I setup an invisible border as the scenes physicsBody that is exactly large enough to detect balls the have left the screen completely.
If physicsBody.contactTestBitMask of node#1 == physicsBody.categoryBitMask of node #2 then didBeginContact: is being called when both of them get in touch.
-(void)didMoveToView:(SKView *)view {
// bitmasks:
static uint32_t const categoryBitMaskBall = 0x1<<1;
static uint32_t const categoryBitMaskBorder = 0x1<<6;
CGFloat ballDiameter = [BallSprite radius] *2;
// floorShape is my scenes background
CGRect largeFloorFrame = floorShape.frame;
largeFloorFrame.origin.x -= ballDiameter;
largeFloorFrame.origin.y -= ballDiameter;
largeFloorFrame.size.width += ballDiameter *2;
largeFloorFrame.size.height += ballDiameter *2;
CGPathRef pathMainView = CGPathCreateWithRect(largeFloorFrame, nil);
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromPath:pathMainView];
self.physicsBody.categoryBitMask = categoryBitMaskBorder;
}
- (BallSprite*)addBall {
// initialize ball with additional configuration...
BallSprite *ball = [BallSprite ballAtPoint:(CGPoint)p];
ball.categoryBitMask = categoryBitMaskBall;
ball.contactTestBitMask = categoryBitMaskBorder;
[self addChild:ball];
}
- (void)didBeginContact:(SKPhysicsContact *)contact {
SKPhysicsBody *firstBody, *secondBody;
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask) {
firstBody = contact.bodyA;
secondBody = contact.bodyB;
}
else {
firstBody = contact.bodyB;
secondBody = contact.bodyA;
}
/*!
Check on outside border contact
*/
if ((firstBody.categoryBitMask & categoryBitMaskBall) != 0 &&
(secondBody.categoryBitMask & categoryBitMaskBorder) != 0) {
[firstBody.node removeFromParent];
}
if ((firstBody.categoryBitMask & categoryBitMaskBorder) != 0 &&
(secondBody.categoryBitMask & categoryBitMaskBall) != 0) {
[secondBody.node removeFromParent];
}
}
Swift version
self.enumerateChildNodesWithName("enemy") {
node, stop in
if (node.position.x < 0) {
node.removeFromParent()
}
}

iOS device orientation disregarding orientation lock

I want to query the orientation the iPhone is currently in. Using
[UIDevice currentDevice].orientation
works as long as the device isn't orientation-locked. If it is locked, however, it always responds with the locked orientation, not with the actual orientation of the device.
Is there a high-level way to get the actual device orientation?
Also you can use CoreMotion
Orientation detection algorithm:
if abs( y ) < abs( x ) your iPhone is in landscape position, look sign of x to detect right
or left
else your iPhone is in portrait position, look sign of y to detect up or upside-down.
If you are interested in face-up or down, look value of z.
import CoreMotion
var uMM: CMMotionManager!
override func
viewWillAppear( p: Bool ) {
super.viewWillAppear( p )
uMM = CMMotionManager()
uMM.accelerometerUpdateInterval = 0.2
// Using main queue is not recommended. So create new operation queue and pass it to startAccelerometerUpdatesToQueue.
// Dispatch U/I code to main thread using dispach_async in the handler.
uMM.startAccelerometerUpdatesToQueue( NSOperationQueue() ) { p, _ in
if p != nil {
println(
abs( p.acceleration.y ) < abs( p.acceleration.x )
? p.acceleration.x > 0 ? "Right" : "Left"
: p.acceleration.y > 0 ? "Down" : "Up"
)
}
}
}
override func
viewDidDisappear( p: Bool ) {
super.viewDidDisappear( p )
uMM.stopAccelerometerUpdates()
}
That functionality is correct. If it always returned the device orientation, even if it was locked, the orientation changed notifications would fire. This would defeat the purpose of the lock.
To answer your question, there is no way to read the raw values from the accelerometer, without using private APIs.
Edit:
After reviewing the documentation, it seems that the UIAccelerometer class provides this data, even when the orientation is locked. This change was applied in iOS 4 and above. Even though you can use this data, you still need to process it to determine the orientation. This is not an easy task as you need to monitor the changes constantly and compare them to older values.
Also, take a look at this guide for handling motion events. This may provide you with another route to determining the orientation.
Set up your view controller or whatever to support the UIAccelerometerProtocol, and start listening for changes (you can set it to 10 hz).
#define kAccelerometerFrequency 10.0 //Hz
-(void)viewDidAppear:(BOOL)animated {
DLog(#"viewDidAppear");
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
UIAccelerometer* a = [UIAccelerometer sharedAccelerometer];
a.updateInterval = 1 / kAccelerometerFrequency;
a.delegate = self;
}
-(void)viewWillDisappear:(BOOL)animated {
DLog(#"viewWillDisappear");
UIAccelerometer* a = [UIAccelerometer sharedAccelerometer];
a.delegate = nil;
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
}
#ifdef DEBUG
+(NSString*)orientationToText:(const UIInterfaceOrientation)ORIENTATION {
switch (ORIENTATION) {
case UIInterfaceOrientationPortrait:
return #"UIInterfaceOrientationPortrait";
case UIInterfaceOrientationPortraitUpsideDown:
return #"UIInterfaceOrientationPortraitUpsideDown";
case UIInterfaceOrientationLandscapeLeft:
return #"UIInterfaceOrientationLandscapeLeft";
case UIInterfaceOrientationLandscapeRight:
return #"UIInterfaceOrientationLandscapeRight";
}
return #"Unknown orientation!";
}
#endif
#pragma mark UIAccelerometerDelegate
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
UIInterfaceOrientation orientationNew;
if (acceleration.x >= 0.75) {
orientationNew = UIInterfaceOrientationLandscapeLeft;
}
else if (acceleration.x <= -0.75) {
orientationNew = UIInterfaceOrientationLandscapeRight;
}
else if (acceleration.y <= -0.75) {
orientationNew = UIInterfaceOrientationPortrait;
}
else if (acceleration.y >= 0.75) {
orientationNew = UIInterfaceOrientationPortraitUpsideDown;
}
else {
// Consider same as last time
return;
}
if (orientationNew == orientationLast)
return;
NSLog(#"Going from %# to %#!", [[self class] orientationToText:orientationLast], [[self class] orientationToText:orientationNew]);
orientationLast = orientationNew;
}
#pragma mark -
You need to define UIInterfaceOrientation orientationLast as a member variable and you're set.
Handling all 6 orientations
Though we don't often care about FaceUp / FaceDown orientations, they're still important.
Taking them into account leads to a much more appropriate sensitivity for orientation changes, while leaving them out can lead to metastability & hysteresis.
Here's how I handled it -
- (void)startMonitoring
{
[self.motionManager startAccelerometerUpdatesToQueue:self.opQueue withHandler:^(CMAccelerometerData * _Nullable accelerometerData, NSError * _Nullable error) {
if (error != nil)
{
NSLog(#"Accelerometer error: %#", error);
}
else
{
float const threshold = 40.0;
BOOL (^isNearValue) (float value1, float value2) = ^BOOL(float value1, float value2)
{
return fabsf(value1 - value2) < threshold;
};
BOOL (^isNearValueABS) (float value1, float value2) = ^BOOL(float value1, float value2)
{
return isNearValue(fabsf(value1), fabsf(value2));
};
float yxAtan = (atan2(accelerometerData.acceleration.y, accelerometerData.acceleration.x)) * 180 / M_PI;
float zyAtan = (atan2(accelerometerData.acceleration.z, accelerometerData.acceleration.y)) * 180 / M_PI;
float zxAtan = (atan2(accelerometerData.acceleration.z, accelerometerData.acceleration.x)) * 180 / M_PI;
UIDeviceOrientation orientation = self.orientation;
if (isNearValue(-90.0, yxAtan) && isNearValueABS(180.0, zyAtan))
{
orientation = UIDeviceOrientationPortrait;
}
else if (isNearValueABS(180.0, yxAtan) && isNearValueABS(180.0, zxAtan))
{
orientation = UIDeviceOrientationLandscapeLeft;
}
else if (isNearValueABS(0.0, yxAtan) && isNearValueABS(0.0, zxAtan))
{
orientation = UIDeviceOrientationLandscapeRight;
}
else if (isNearValue(90.0, yxAtan) && isNearValueABS(0.0, zyAtan))
{
orientation = UIDeviceOrientationPortraitUpsideDown;
}
else if (isNearValue(-90.0, zyAtan) && isNearValue(-90.0, zxAtan))
{
orientation = UIDeviceOrientationFaceUp;
}
else if (isNearValue(90.0, zyAtan) && isNearValue(90.0, zxAtan))
{
orientation = UIDeviceOrientationFaceDown;
}
if (self.orientation != orientation)
{
dispatch_async(dispatch_get_main_queue(), ^{
[self orientationDidChange:orientation];
});
}
}
}];
}
Additionally, I've added a threshold value of 40.0 (instead of 45.0). This makes changes less sensitive, preventing hysteresis at inflection points.
If you only want to react to changes of the main 4 orientations, just do this
if (UIDeviceOrientationIsPortrait(orientation) || UIDeviceOrientationIsLandscape(orientation))
{
// Do something
}
The UIAccelerometer class continues to function when the device orientation is locked. You'll have to work out your own methods of turning its variables into orientation values, but it shouldn't be especially complicated.
Have a play with Apple's AcceleromoterGraph sample app to see what values the accelerometer outputs in different orientations.
my solution using coremotion,it work even when the device has his orientation locked.
let motionManager: CMMotionManager = CMMotionManager()
on the did load method
motionManager.deviceMotionUpdateInterval = 0.01
if motionManager.accelerometerAvailable{
let queue = NSOperationQueue()
motionManager.startAccelerometerUpdatesToQueue(queue, withHandler:
{data, error in
guard let data = data else{
return
}
let angle = (atan2(data.acceleration.y,data.acceleration.x))*180/M_PI;
print(angle)
if(fabs(angle)<=45){
self.orientation = AVCaptureVideoOrientation.LandscapeLeft
print("landscape left")
}else if((fabs(angle)>45)&&(fabs(angle)<135)){
if(angle>0){
self.orientation = AVCaptureVideoOrientation.PortraitUpsideDown
print("portrait upside Down")
}else{
self.orientation = AVCaptureVideoOrientation.Portrait
print("portrait")
}
}else{
self.orientation = AVCaptureVideoOrientation.LandscapeRight
print("landscape right")
}
}
)
} else {
print("Accelerometer is not available")
}
hope it helps.
Most of the answers are using accelerometer, which is the overall acceleration = user + gravity.
But to get a device orientation, it is more accurate to use the gravity acceleration. Using gravity will prevent the edge case when user moves in a particular direction. To access the gravity, we have to use startDeviceMotionUpdates API instead.
let motionManager = CMMotionManager()
motionManager.startDeviceMotionUpdates(to: OperationQueue()) { (data, error) in
guard let gravity = data?.gravity else { return }
let newDeviceOrientation: UIDeviceOrientation
if abs(gravity.y) < abs(gravity.x) {
newDeviceOrientation = gravity.x > 0 ? .landscapeRight : .landscapeLeft
} else {
newDeviceOrientation = gravity.y > 0 ? .portraitUpsideDown : .portrait
}
}
Here isĀ an example of detect device rotation and return UIDeviceOrientation.
This solution using CoreMotion and works in all cases.
Example
let orientationManager = APOrientationManager()
orientationManager.delegate = self
/// start detect rotation
orientationManager.startMeasuring()
/// get current interface orientation
let orientation = orientationManager.currentInterfaceOrientation()
print(orientation.rawValue)
/// stop detect rotation
orientationManager.stopMeasuring()
orientationManager.delegate = nil
conform delegate
extension ViewController: APOrientationManagerDelegate {
func didChange(deviceOrientation: UIDeviceOrientation) {
/// update UI in main thread
}
}
APOrientationManager.swift
import Foundation
import CoreMotion
import AVFoundation
import UIKit
protocol APOrientationManagerDelegate: class {
func didChange(deviceOrientation: UIDeviceOrientation)
}
class APOrientationManager {
private let motionManager = CMMotionManager()
private let queue = OperationQueue()
private var deviceOrientation: UIDeviceOrientation = .unknown
weak var delegate: APOrientationManagerDelegate?
init() {
motionManager.accelerometerUpdateInterval = 1.0
motionManager.deviceMotionUpdateInterval = 1.0
motionManager.gyroUpdateInterval = 1.0
motionManager.magnetometerUpdateInterval = 1.0
}
func startMeasuring() {
guard motionManager.isDeviceMotionAvailable else {
return
}
motionManager.startAccelerometerUpdates(to: queue) { [weak self] (accelerometerData, error) in
guard let strongSelf = self else {
return
}
guard let accelerometerData = accelerometerData else {
return
}
let acceleration = accelerometerData.acceleration
let xx = -acceleration.x
let yy = acceleration.y
let z = acceleration.z
let angle = atan2(yy, xx)
var deviceOrientation = strongSelf.deviceOrientation
let absoluteZ = fabs(z)
if deviceOrientation == .faceUp || deviceOrientation == .faceDown {
if absoluteZ < 0.845 {
if angle < -2.6 {
deviceOrientation = .landscapeRight
} else if angle > -2.05 && angle < -1.1 {
deviceOrientation = .portrait
} else if angle > -0.48 && angle < 0.48 {
deviceOrientation = .landscapeLeft
} else if angle > 1.08 && angle < 2.08 {
deviceOrientation = .portraitUpsideDown
}
} else if z < 0 {
deviceOrientation = .faceUp
} else if z > 0 {
deviceOrientation = .faceDown
}
} else {
if z > 0.875 {
deviceOrientation = .faceDown
} else if z < -0.875 {
deviceOrientation = .faceUp
} else {
switch deviceOrientation {
case .landscapeLeft:
if angle < -1.07 {
deviceOrientation = .portrait
}
if angle > 1.08 {
deviceOrientation = .portraitUpsideDown
}
case .landscapeRight:
if angle < 0 && angle > -2.05 {
deviceOrientation = .portrait
}
if angle > 0 && angle < 2.05 {
deviceOrientation = .portraitUpsideDown
}
case .portraitUpsideDown:
if angle > 2.66 {
deviceOrientation = .landscapeRight
}
if angle < 0.48 {
deviceOrientation = .landscapeLeft
}
case .portrait:
if angle > -0.47 {
deviceOrientation = .landscapeLeft
}
if angle < -2.64 {
deviceOrientation = .landscapeRight
}
default:
if angle > -0.47 {
deviceOrientation = .landscapeLeft
}
if angle < -2.64 {
deviceOrientation = .landscapeRight
}
}
}
}
if strongSelf.deviceOrientation != deviceOrientation {
strongSelf.deviceOrientation = deviceOrientation
strongSelf.delegate?.didChange(deviceOrientation: deviceOrientation)
}
}
}
func stopMeasuring() {
motionManager.stopAccelerometerUpdates()
}
func currentInterfaceOrientation() -> AVCaptureVideoOrientation {
switch deviceOrientation {
case .portrait:
return .portrait
case .landscapeRight:
return .landscapeLeft
case .landscapeLeft:
return .landscapeRight
case .portraitUpsideDown:
return .portraitUpsideDown
default:
return .portrait
}
}
}
Use of CMMotionManager may help, but not the above way. The above logic is not a stable one. I have tested throughly and found that by seeing the values of acceleration.x/y/z are not helping to determine the orientation.
Instead, I got a way to find the orientation WRT the angle i.e.
float angle = (atan2(accelerometerData.acceleration.y,accelerometerData.acceleration.x))*180/M_PI;
And for orientation,-
if(fabs(angle<=45)currOrientation=UIDeviceOrientationLandscapeRight;
else if((fabs(angle)>45)&&(fabs(angle)<135))currOrientation=((angle>0)?UIDeviceOrientationPortraitUpsideDown:UIDeviceOrientationPortrait);
else currOrientation = UIDeviceOrientationLandscapeLeft;
This might come handy for someone, though this doesn't help me to find 2 other orientations i.e. UIDeviceOrientationFaceUp & UIDeviceOrientationFaceDown.
Using Satachito's great answer here is code which will also detect if the device is face up or face down
import CoreMotion
var mm: CMMotionManager!
init() {
self.mm = CMMotionManager()
self.mm.accelerometerUpdateInterval = 0.2
}
public func startOrientationUpdates() {
// Using main queue is not recommended. So create new operation queue and pass it to startAccelerometerUpdatesToQueue.
// Dispatch U/I code to main thread using dispach_async in the handler.
self.mm.startAccelerometerUpdates( to: OperationQueue() ) { p, _ in
if let p = p {
if(p.acceleration.x > -0.3 && p.acceleration.x < 0.3 && p.acceleration.z < -0.95) {
print("face up")
}
else if(p.acceleration.x > -0.3 && p.acceleration.x < 0.3 && p.acceleration.z > 0.95) {
print("face down")
}
else {
print(
abs( p.acceleration.y ) < abs( p.acceleration.x )
? p.acceleration.x > 0 ? "Right" : "Left"
: p.acceleration.y > 0 ? "Down" : "Up"
)
}
}
}
}
public func endOrientationUpdates() {
self.mm.stopAccelerometerUpdates()
}

iPhone Accelerometer calibration

How do I properly calibrate the accelerometer for my iPhone game? Currently, when the phone is on a flat surface, the paddle drifts to the left. High or Low Pass filters are not an acceptable solution as I need complete control over the paddle even at low & high values. I know Apple has the BubbleLevel sample but I find it difficult to follow... could someone simplify the process?
My accelerometer code looks like this:
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
float acelx = -acceleration.y;
float x = acelx*40;
Board *board = [Board sharedBoard];
AtlasSprite *paddle = (AtlasSprite *)[board.spriteManager getChildByTag:10];
if ( paddle.position.x > 0 && paddle.position.x < 480) {
paddle.position = ccp(paddle.position.x+x, paddle.position.y);
}
if ( paddle.position.x < 55 ) {
paddle.position = ccp(56, paddle.position.y);
}
if ( paddle.position.x > 435 ) {
paddle.position = ccp(434, paddle.position.y);
}
if ( paddle.position.x < 55 && x > 1 ) {
paddle.position = ccp(paddle.position.x+x, paddle.position.y);
}
if ( paddle.position.x > 435 && x < 0) {
paddle.position = ccp(paddle.position.x+x, paddle.position.y);
}
}
Thank you!
Okay, problem SOLVED and the solution is so simple I'm actually embarrassed I didn't come up with it sooner. It's as simple as this:
In a "Calibration Button":
//store the current offset for a "neutral" position
calibration = -currentAccelX * accelerationFactor;
In the game time accelerometer function:
//add the offset to the accel value
float x = (-acceleration.y * accelerationFactor) + calibration;
It's as simple as adding the offset. * hides his head *
This is the code I have so far:
//calibrate code from StackOverflow
float calibration = -acceleration.x * accelerationFraction;
float x = (-acceleration.y * accelerationFraction) + calibration;
//My original code
accelerationFraction = acceleration.y*2;
if (accelerationFraction < -1) {
accelerationFraction = -1;
} else if (accelerationFraction > 1) {
accelerationFraction = 1;
}
//API CHANGE set delegate to self
if (orientation == UIDeviceOrientationLandscapeLeft){
accelerationFraction *= -1;
}