I'm French so excuse me for my English. So I use an accelerometer, but in my code the accelerometer works for a view and not for an image. What I want to do is to use this accelerometer for an image instead of a view. How can I do this? Here is the code:
#define CONST_fps 100.
#define CONST_map_shift 0.01
#define kFilteringFactor 0.1
UIAccelerationValue rollingX, rollingY, rollingZ;
#implementation MapViewRotationViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// accelerometer settings
[[UIAccelerometer sharedAccelerometer] setDelegate:self];
[[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / CONST_fps)];
}
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
rollingX = (acceleration.x * kFilteringFactor) + (rollingX * (1.0 - kFilteringFactor));
rollingY = (acceleration.y * kFilteringFactor) + (rollingY * (1.0 - kFilteringFactor));
rollingZ = (acceleration.z * kFilteringFactor) + (rollingZ * (1.0 - kFilteringFactor));
float accelX = acceleration.x - rollingX;
float accelY = acceleration.y - rollingY;
float accelZ = acceleration.z - rollingZ;
static CGFloat ZZ = 0.;
CGFloat z = (atan2(rollingX, rollingY) + M_PI);
if (fabsf(ZZ - z) > CONST_map_shift)
{
viewToRotate.layer.transform = CATransform3DMakeRotation(ZZ=z, 0., 0., 1.);
}
}
#end
You don't need to have a view as callback instead you can choose any class to conform to protocol UIAccelerometerDelegate. Just declare your class in the header file as
#interface MyClass : NSObject <UIAccelerometerDelegate> {
// my members
}
In MyClass.m you have to implement method
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
// do what you like
}
But if you are not forced to support iOS version 3.x, you should consider using CoreMotion API. See Event Handling Guide for iOS / Motion Events for more information and samples.
Related
I'm rotating a UIView based on the accelerometer data, and it works fine except that the UIView is deformed. I'm not sure how to fix the issue. Here's the code in my didAccelerate method:
float kFilteringFactor = 0.175;
CGFloat x = acceleration.x * kFilteringFactor + acceleration.x * (1.0 - kFilteringFactor);
CGFloat y = acceleration.y * kFilteringFactor + acceleration.y * (1.0 - kFilteringFactor);
float radians = M_PI - atan2(y, x);
[_horizonView setTransform:CGAffineTransformMakeRotation(radians)];
Am I performing the rotation incorrectly? I've changed the origin point in Xcode, but that appears to have no effect.
what kind of deformation occures? I think the the rotation is fine.
I am searching for a good and fluid way to move multiple UIViews over the Screen at once. The Action should happen when the Accelerometer detects acceleration. I have already tried this way:
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration{
CGPoint ObjectPos = Object.center;
ObjectPos.x -= acceleration.x;
Object.center = ObjectPos;
}
(of course I added some tweaking to improve the movement detection), but all in all, it still is not very fluid.
I hoped there is some way with core animation, but it does not seem to work with the acceleration pretty well.
Help is really appreciated, thanks!
I advise you to read this piece of documentation: Isolating the Gravity Component from Acceleration Data and the section below that called 'Isolating Instantaneous Motion from Acceleration Data'.
Basically, you need to filter out gravity in order to get smooth movement. The link provides sample-code.
Edit: UIAccelerometer was deprecated in iOS 5.0, and the accompanying documentation seems to be gone as well.
For future reference I did some digging and found, what seems to be, a 'carbon copy' of the original sample code (source):
// This example uses a low-value filtering factor to generate a value that uses 10 percent of the
// unfiltered acceleration data and 90 percent of the previously filtered value
// Isolating the effects of gravity from accelerometer data
#define kFilteringFactor 0.1
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
// Use a basic low-pass filter to keep only the gravity component of each axis.
accelX = (acceleration.x * kFilteringFactor) + (accelX * (1.0 - kFilteringFactor));
accelY = (acceleration.y * kFilteringFactor) + (accelY * (1.0 - kFilteringFactor));
accelZ = (acceleration.z * kFilteringFactor) + (accelZ * (1.0 - kFilteringFactor));
// Use the acceleration data.
}
// shows a simplified high-pass filter computation with constant effect of gravity.
// Getting the instantaneous portion of movement from accelerometer data
#define kFilteringFactor 0.1
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
// Subtract the low-pass value from the current value to get a simplified high-pass filter
accelX = acceleration.x - ( (acceleration.x * kFilteringFactor) + (accelX * (1.0 - kFilteringFactor)) );
accelY = acceleration.y - ( (acceleration.y * kFilteringFactor) + (accelY * (1.0 - kFilteringFactor)) );
accelZ = acceleration.z - ( (acceleration.z * kFilteringFactor) + (accelZ * (1.0 - kFilteringFactor)) );
// Use the acceleration data.
}
I need to calculate iphone velocity in space, punch speed for example.
My first question is: Are the acceleration values accelerometer:didAcceleratewith this filtering actions:
gravity_x = acceleration.x * kFilteringFactor + gravity_x * (1.0 - kFilteringFactor);
gravity_y = acceleration.y * kFilteringFactor + gravity_y * (1.0 - kFilteringFactor);
gravity_z = acceleration.z * kFilteringFactor + gravity_z * (1.0 - kFilteringFactor);
float gravityNorm = sqrt(gravity_x * gravity_x + gravity_y * gravity_y + gravity_z * gravity_z);
accelX = acceleration.x - gravity_x / gravityNorm;
accelY = acceleration.y - gravity_y / gravityNorm;
accelZ = acceleration.z - gravity_z / gravityNorm;
the same as using CoreMotion's
motionManager.deviceMotion.userAcceleration.x;
motionManager.deviceMotion.userAcceleration.y;
motionManager.deviceMotion.userAcceleration.z; ?
Next, according to same questions, I do the following
const float accuracy=10;
float accx = (float) ((int) (accelX * accuracy))/ accuracy;
float accy= (float) ((int) (accelY * accuracy))/ accuracy;
float accz= (float) ((int) (accelZ * accuracy))/ accuracy;
for rounding values, then, as I think, I obtain current speed
float dx = accx*9.81+prevX*9.81;
float dy = accy*9.81+prevY*9.81;
float dz = accz*9.81+prevZ*9.81;
speed_after_x = dx/2*myAccelerometer.updateInterval+speed_before_x;
speed_after_y = dy/2*myAccelerometer.updateInterval+speed_before_y;
speed_after_z = dz/2*myAccelerometer.updateInterval+speed_before_z;
according to iphone accelerometer speed and distance
then
prevX=accx;
prevY=accy;
prevZ=accz;
speed_before_x=speed_after_x;
speed_before_y=speed_after_y;
speed_before_z=speed_after_z;
and finally calculating speed as vector's length
float speed = sqrt(speed_after_x*speed_after_x+speed_after_y*speed_after_y+speed_after_z*speed_after_z);
if (max_speed<speed) max_speed = speed;
But speed value, that is containing in label, is always increasing. I mean if i moved device and then stopped, speed value doesn't become to 0. Doesn't acceleration compensate itself at 0?
Here's the example code I managed to hash out. I'll just put it here for now:
//
// ViewController.m
// Acce
//
// Created by Diziet on 14/05/2012.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "ViewController.h"
#interface ViewController () {
UIAccelerationValue gravX;
UIAccelerationValue gravY;
UIAccelerationValue gravZ;
UIAccelerationValue prevVelocity;
UIAccelerationValue prevAcce;
}
#property (strong) UIAccelerometer *sharedAcc;
#end
#implementation ViewController
#synthesize sharedAcc = _sharedAcc;
#define kAccelerometerFrequency 50.0 //Hz
#define kFilteringFactor 0.1
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.sharedAcc = [UIAccelerometer sharedAccelerometer];
self.sharedAcc.delegate = self;
self.sharedAcc.updateInterval = 1 / kAccelerometerFrequency;
gravX = gravY = gravZ = prevVelocity = prevAcce = 0.f;
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (UIAccelerationValue)tendToZero:(UIAccelerationValue)value {
if (value < 0) {
return ceil(value);
} else {
return floor(value);
}
}
#define kAccelerometerFrequency 50.0 //Hz
#define kFilteringFactor 0.1
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
gravX = (acceleration.x * kFilteringFactor) + (gravX * (1.0 - kFilteringFactor));
gravY = (acceleration.y * kFilteringFactor) + (gravY * (1.0 - kFilteringFactor));
gravZ = (acceleration.z * kFilteringFactor) + (gravZ * (1.0 - kFilteringFactor));
UIAccelerationValue accelX = acceleration.x - ( (acceleration.x * kFilteringFactor) + (gravX * (1.0 - kFilteringFactor)) );
UIAccelerationValue accelY = acceleration.y - ( (acceleration.y * kFilteringFactor) + (gravY * (1.0 - kFilteringFactor)) );
UIAccelerationValue accelZ = acceleration.z - ( (acceleration.z * kFilteringFactor) + (gravZ * (1.0 - kFilteringFactor)) );
accelX *= 9.81f;
accelY *= 9.81f;
accelZ *= 9.81f;
accelX = [self tendToZero:accelX];
accelY = [self tendToZero:accelY];
accelZ = [self tendToZero:accelZ];
UIAccelerationValue vector = sqrt(pow(accelX,2)+pow(accelY,2)+pow(accelZ, 2));
UIAccelerationValue acce = vector - prevVelocity;
UIAccelerationValue velocity = (((acce - prevAcce)/2) * (1/kAccelerometerFrequency)) + prevVelocity;
NSLog(#"X %g Y %g Z %g, Vector %g, Velocity %g",accelX,accelY,accelZ,vector,velocity);
prevAcce = acce;
prevVelocity = velocity;
}
#end
It'll need modifying for your needs, especially as I'm just throwing the values away afterwards. The resultant value 'velocity' logged as 'Velocity' tends back towards extremely small negative values after acceleration events have ceased, e.g. *10^-17. So yeah, that's practically zero in my book. You'll want to do some rounding in there and probably even scale the values up. I don't think I could get it higher than 0.2 or 0.3 but then again I don't want to hurl my phone across the room (yet).
I made a space game where you use the accelerometer to move a spaceship, When I try the game on my devices (iPad, iPhone) it work well with no errors or incorrect behavior.
I upload my game to the App Store and it was approved, but when I downloaded the game from the App Store, the accelerometer wasn't working and my spaceship was stuck in one direction.
I tried many devices and they all have same problem.
Note: I used the cocos2d and box2d frameworks.
If anybody have any idea, please help!
Use UIAccelerometerDelegate
UIAccelerometer *accelerometer;
In .m file
# pragma mark To Enable Acceleromete
self.isAccelerometerEnabled = YES;
self.accelerometer = [UIAccelerometer sharedAccelerometer];
self.accelerometer.updateInterval = 0.025;
self.accelerometer.delegate = self;
Use these delegates methods
#pragma Mark Accelerometer
-(void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
// Set up variables
CGSize winSize = [CCDirector sharedDirector].winSize;
#define kFilteringFactor 0.5
#define kShipMaxPointsPerSec (winSize.height*0.5)
#define kRestAccelX (xCallib)
#define kMaxDiff 0.2
#define kRestAccelY (yCallib)
#define kMaxDiffY 0.1
UIAccelerationValue rollingX=0;
float accelX;
// High pass filter for reducing jitter
rollingX = (acceleration.x * kFilteringFactor) + (rollingX * (1.0 - kFilteringFactor));
accelX = acceleration.x - rollingX;
// Calculate movement for x and y axis
float accelDiffX = accelX - kRestAccelX;///
float accelFractionX = accelDiffX / kMaxDiff;//
movementX = kShipMaxPointsPerSec * accelFractionX;
// Thresh holds for x and y axis movement
willMoveX = YES;
if (((movementX < 45.0f) && (movementX > -45.0f)))
willMoveX = NO;
}
#pragma Mark Accelerometer Update Methods
-(void) update:(ccTime)dt
{
CCSprite *player =(CCSprite *) [self getChildByTag:objPlayerShipTag];
CGSize screenSize = [[CCDirector sharedDirector]winSize];
float oldX = [player position].x;
float newX;
if (willMoveX) {
newX = [player position].x + (movementX * dt);
} else newX = oldX;
if ((newX > (screenSize.width -45)) || newX < 45.0f ) {
newX = oldX;
}
[player setPosition:ccp(newX,90)];
// ++++++++ To generate Bullet and Bomb Power +++++++
[self checkForCollisionWithPowersBullets]; //NEW
[self checkForCollisionWithPowersBomb];
}
I'm trying to rotate a sprite using the accelerometer. when I tilt right, I want him to rotate slightly to the right, and when I tilt left, I want him to rotate slightly to the left...
Thanks in advance,
Reed
Firs off - in your h file you need to make the following variables:
UIAccelerationValue accelerationX;
UIAccelerationValue accelerationY;
float currentRawReading;
float calibrationOffset;
Also ensure that your h file has:
#interface myViewName : UIViewController <UIAccelerometerDelegate>
Then in your .m file just below your imports at the top put:
#define kFilteringFactor 0.05
CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
CGFloat RadiansToDegrees(CGFloat radians) {return radians * 180/M_PI;};
Then in your .m file on your viewDidLoad Function put:
UIAccelerometer *accel = [UIAccelerometer sharedAccelerometer];
accel.delegate = self;
accel.updateInterval = 1.0f/60.0f;
also add the following function to your .m file:
-(void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration{
accelerationX = acceleration.x * kFilteringFactor + accelerationX * (1.0 - kFilteringFactor);
accelerationY = acceleration.y * kFilteringFactor + accelerationY * (1.0 - kFilteringFactor);
// keep the raw reading, to use during calibrations
currentRawReading = atan2(accelerationY, accelerationX);
float rotation = -RadiansToDegrees(currentRawReading);
targetView.transform = CGAffineTransformMakeRotation(-(DegreesToRadians(rotation)));
//targetView.transform = CGAffineTransformRotate(targetView.transform, -(rotation * 3)); //if you want easing
}
you will have to tweak it slightly based on what view or object you are targeting -- but thats pretty much it.
Hope this helps,
Michael
Shouldn't be too difficult. Just have somewhere in your code that handles the UIAccelerometerDelegate class and apply changes to your sprites based on the values you receive through parameters to the – accelerometer:didAccelerate: callback.
Apple docs for the delegate class are available at...
https://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIAccelerometerDelegate_Protocol/UIAccelerometerDelegate/UIAccelerometerDelegate.html
In the delegate function of accelerometer just write the code -->>
float angleRadians = atanf((float)X_Position / (float)Y_Position);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
float cocosAngle = 1 * angleDegrees;
sprite.rotation = cocosAngle;
and the sprite will get rotated to desired angle with changes in the values of X_position, Y_Position and angle.
Njoy.. :)