Cocos2d iPhone: Rotate Sprite using Accelerometer - iphone

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.. :)

Related

Rotating device while using accelerometer

I'm using accelerometer in my first Cocos2D game and it work fine, i'm able to move the sprite using the below code however, when i change the orientation from landscapeLeft to landscapeRight, the sprite stops responding to Y coordination, and the sprite goes to the top of the screen and doesn't properly respond... I believe it's because of changing the device orientation, but i'm not sure since i'm pretty new to App Development, any help will be appreciated.
Here is the sample code i'm using...
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
//this determines how sensitive the accelerometer reacts (higher = more sensitive)
NSUserDefaults *defaulObj = [NSUserDefaults standardUserDefaults];
float sensitivity = [defaulObj floatForKey:#"Sensitivity"]; //10.0f
if (!sensitivity) {
sensitivity = 6;
}
// this controls how quickly the velocity decelerates (lower = quicker to change direction)
float deceleration = 0.4f;
static float xVal = 0;
if (!self.isFlag) {
xVal = -acceleration.x;
self.isFlag = TRUE;
}
playerVelocity.x = playerVelocity.x * deceleration + (xVal + acceleration.x) * sensitivity;
playerVelocity.y = playerVelocity.y * deceleration + acceleration.y * sensitivity;
playerVelocity.y = playerVelocity.y*-1;
}
Perhaps this helps out, flips Y along your current device orientation.
float rotatedY = acceleration.y;
if ([UIApplication sharedApplication].statusBarOrientation==UIInterfaceOrientationLandscapeLeft) {
rotatedY *= -1;
}
then use rotatedY insteat of acceleration.y

Rotate UIView without deformation

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.

how use Accelerometer in Landscape in iphone/ipad

i am working on game in which i want to move CCSprite in direction of accelerometer tilt.i have referred this tutorial http://www.raywenderlich.com/457/intro-to-box2d-with-cocos2d-tutorial-bouncing-balls but i am not clear with it. Please can any one help me.
Thanks in Advance.
Refer this solution. I used same for moving sprite from left to right in landscape game.: See answer here
Only change for landscape mode is use accelerometer y in place of x.
-(void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
if(self.isGamePaused || self.isGameOver)
return;
float deceleration = 1.0f, sensitivity = 15.0f, maxVelocity = 450;
if(sGame.IsIpad)
{
sensitivity = 14.0f;
maxVelocity = 850;
deceleration = 1.5f;
}
// adjust velocity based on current accelerometer acceleration
// vel.x = vel.x * deceleration + acceleration.x * sensitivity;
AppController *app = (AppController*)[UIApplication sharedApplication].delegate;
float velocity_x = self.gameActor.velocity.x ;
self.gameActor.accelVal = ABS(acceleration.y);
if(app.orient == UIInterfaceOrientationLandscapeLeft)
{
velocity_x = velocity_x * deceleration + acceleration.y * sensitivity;
}
else
{
velocity_x = velocity_x * deceleration + (-acceleration.y) * sensitivity;
}
//limit the maximum velocity of the player sprite, in both directions (positive & negative values)
velocity_x = fmaxf(fminf(velocity_x, maxVelocity), -maxVelocity);
self.gameActor.velocity = ccp(velocity_x, self.gameActor.velocity.y);
}

Accelerometer not working after uploading game to the App Store

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];
}

Trouble tying a CCSprite deceleration to the ccTime dt

I've got a subclass of CCSprite that knows how to move itself based on two float properties, velX and velY. I call the subclass's - (void)update:(ccTime)dt method from the method of the same name in my game layer.
I use dt to scale how much I move the player and it works great. I'd like to use dt to scale a deceleration factor to make how the player slows down consistent regardless of how often it's updated.
But it just makes my CCSprite not even show up.
Here's the CCSprite class...
#import "Player.h"
#define kDeceleration 0.95
#implementation Player
#synthesize velX, velY;
# pragma mark
+ (id)player
{
Player *player = nil;
if ((player = [[[super alloc] initWithFile:#"rocket.png"] autorelease])) {
player.velX = 0.0;
player.velY = 0.0;
}
return player;
}
- (void)update:(ccTime)dt
{
CGSize winSize = [[CCDirector sharedDirector] winSize];
// move
self.position = ccp(self.position.x + self.velX * dt, self.position.y + self.velY * dt);
if (self.position.x < -self.contentSize.width/2) self.position = ccp(winSize.width + self.contentSize.width/2, self.position.y);
if (self.position.x > winSize.width + self.contentSize.width/2) self.position = ccp(-self.contentSize.width/2, self.position.y);
if (self.position.y < -self.contentSize.width/2) self.position = ccp(self.position.x, winSize.height + self.contentSize.width/2);
if (self.position.y > winSize.height + self.contentSize.width/2) self.position = ccp(self.position.x, -self.contentSize.width/2);
// decelerate
self.velX *= kDeceleration * 0.0165 / dt; // works if the line is: self.velX *= kDeceleration;
if (fabs(self.velX) < 1.0) self.velX = 0.0;
self.velY *= kDeceleration * 0.0165 / dt; // works if the line is: self.velY *= kDeceleration;
if (fabs(self.velY) < 1.0) self.velY = 0.0;
}
- (void)draw
{
[super draw];
glLineWidth(1);
ccDrawCircle(ccp(self.contentSize.width/2, self.contentSize.height/2), 3*self.contentSize.width/4, CC_DEGREES_TO_RADIANS(360), 60, NO);
}
#end
The problem is in the // decelerate section. If I leave out the * 0.0165 / dt part of the two lines that decelerate the player, it works, but it's way faster on the phone than the simulator due to framerate differences. This should scale it, but it just screws it up.
I've tried all kinds of NSLogging and if I use dt at all, I get nan for the value of my velX and velY properties.
Could it have something to do with using the method name -update?
Try using this formula instead:
float decelerator = pow(kDeceleration, 60 * dt);
self.velX *= decelerator;
self.velY *= decelerator;
The logic behind the math:
Suppose the framerate on simulator is at 30fps compared to the normal 60fps on device. Thus, for every frame on simulator, the device already shows 2 frames. Thus every call on the update on simulator should give the same result for 2 calls on device. After two calls on device, self.velX has been multiplied by kDeceleration two times, meaning the new value is equal to self.velX * kDeceleration * kDeceleration. By same logic, if the framerate on simulator is 1/3 of that on device, the new value is self.velX * kDeceleration * kDeceleration * kDeceleration. Thus, we can generalize it as self.velX * pow(kDeceleration, n) where n is the number of times the update method to be called to catch up with framerate of 60fps, which is 60 * dt.