Making ball roll with iphone being tilted using Accelerometer - iphone

I am making an iphone app where a ball will roll around the screen based on how the user tilts the device. If the device is lies flat on the table theoretically the ball would not move. If the device is tilted standing completely upward the I want the ball to roll straight down at maximum speed. The speed depends on how far from the flat position the device is tilted. Also, it also works for if the user tilts right or left or up or combinations of the four. I am using the accelerometer right now and the ball moves and it works okay, I am just not real familiar with physics. If someone has any suggestions on how to get this to work smoothly please let me know.
Thanks!
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
float xx = -[acceleration x];
float yy = [acceleration y];
float z = -[acceleration z];
z = 1 - z;
NSString * zaxis = [NSString stringWithFormat:#"%f", z];
lblz.text = zaxis;
lbly.text = [NSString stringWithFormat:#"%f", yy];
lblx.text = [NSString stringWithFormat:#"%f", xx];
CGFloat newx;
CGFloat newy;
if (yy > 0)
{
newy = ball.center.y - ((1 - yy) * z);
}
else
{
newy = ball.center.y + ((1 - yy) * z);
}
if (xx > 0)
{
newx = ball.center.x - ((1 - xx) * z);
}
else
{
newx = ball.center.x + ((1 - xx) * z);
}
CGPoint newPoint = CGPointMake(newx, newy);
ball.center = newPoint;

If you want to make it look more realistic and leverage existing stuff, look at some of the existing physics engines and 2d frameworks, Box2d and Cocos2d, but there are many others.

I think the key thing you are messing here is the difference between acceleration and velocity. You want the 'amount of tilt' to work as an acceleration. Each frame the balls Velocity should change by the acceleration, then the balls position should change by the balls velocity.
So just in X it should be something like:
float accelX = acceleration.x;
mVel.x += accelX; \\mVel is a member variable you have to store
ball.center.x += mVel.x;
---More Complex version
Now the more I think about it, it might not be the 'amount of tilt' you want to be the acceleration. You might want the amount of tilt to be the 'Target Velocity.' But you still want to use an acceleration to get there.
mTargetVel.x = acceleration.x;
//Now apply an acceleration to the velocity to move towards the Target Velocity
if(mVel.x < mTargetVel.x) {
mVel.x += ACCEL_X; //ACCEL_X is just a constant value that works well for you
}
else if(mVel.x > mTargetVel.x) {
mVel.x -= ACCEL_X;
}
//Now update the position based on the new velocity
ball.center.x += mVel.x;

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 sprite image according to user touch location?

I m start learning game development. As a beginner i create one demo game in which one cannon hit bullets to the enemies (coming toward cannon from different direction).
Now i stuck on cannon sprite image rotation anywhere user touch on the screen or enemies. How i do that, My initial code as following,
void HelloWorld:: ccTouchesBegan(CCSet *touches, CCEvent * event)
{
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
CCTouch* touch = (CCTouch*)( touches->anyObject() );
CCPoint location = touch->locationInView(touch->view());
location = CCDirector::sharedDirector()->convertToGL(location);
//Rotate cannon direction toward touch point
CCPoint diffPoint = ccpSub(_cannonImage->getPosition(), location);
float angleRadians = atanf((float)diffPoint.y/(float)diffPoint.x);
float angleOffset = CC_DEGREES_TO_RADIANS(180);
if(diffPoint.x < 0){
angleRadians += angleOffset;
}else{
angleRadians -= angleOffset;
}
CCLog("angle to be rotate = %f", angleRadians);
_cannonImage->runAction(CCRotateBy::actionWithDuration(0.1, angleRadians));
}
The code is written in cocos2d-x . I also accepting answer by someone who written in plain cocos2d.
Thanks
iHungry
The perfect answer as follows,
float HelloWorld::changingAngleAccordingToCoordinateSystem(CCPoint imageCenter, CCPoint touchLocation, float calculatedAngle){
//Consideration :- all Angles is in Degree
if((calculatedAngle >= 0 && calculatedAngle <= 90) || (calculatedAngle >= 90 && calculatedAngle <= 180)){
//Ist quardant
calculatedAngle = calculatedAngle;
}
else if(calculatedAngle < 0 && calculatedAngle >= -90){
//IInd quardant
calculatedAngle = 270 + (90 + calculatedAngle);
}
else if(calculatedAngle < -90 && calculatedAngle >= -180){
calculatedAngle = 180 + (180 + calculatedAngle);
}
return calculatedAngle;
}
//Rotate cannon direction toward touch point
float diff_X = touchLocation.x - myImage->getPosition().x;
float diff_Y = touchLocation.y - myImage->getPosition().y;
CCPoint diffPoint = CCPoint(diff_X, diff_Y);
float angleRadians = atan2f(diffPoint.y,diffPoint.x);
angleRadians = CC_RADIANS_TO_DEGREES(angleRadians);
angleRadians = HelloWorld::changingAngleAccordingToCoordinateSystem(myImage->getPosition(), touchLocation, angleRadians);
myImage->setRotation(-angleRadians);
i used this code to rotate my sprite. i Was moving the sprite according to my accelerometer reading.
float angleRadians =-accelX;
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
objGlider->sprite_Glider.rotation = cocosAngle;
Check it. The reason of slow may be that you may be using CClog or NSLog in the code.
Here goes the complete code.
if(!boolPlayerDied)
{
static float prevX=0, prevY=0;
#define kFilterFactor 1.0f// don't use filter. the code is here just as an example
float accelX = (float) acceleration.x * kFilterFactor + (1- kFilterFactor)*prevX;
float accelY = (float) acceleration.y * kFilterFactor + (1- kFilterFactor)*prevY;
prevX = accelX;
prevY = accelY;
accelX = accelX-0.5;// Angle check fot tgfor the player to play
float angleRadians =-accelX;
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
if(accelX>0)
{
cocosAngle = 1.1 * angleDegrees;
}
else
{
if(accelX<-0.5)
accelX=-0.5;
cocosAngle = 1.1 * angleDegrees;
}
objGlider->sprite_Glider.rotation = cocosAngle;
}
objGlider is the object of the class which creates glider sprite and sprite_Glider is the sprite used in glider class.
you can use rotation property with your sprite to be rotated. In cocos2Dx it might be setRotation.
First of all, replace
float angleRadians = atanf((float)diffPoint.y/(float)diffPoint.x);
float angleOffset = CC_DEGREES_TO_RADIANS(180);
if(diffPoint.x < 0){
angleRadians += angleOffset;
}else{
angleRadians -= angleOffset;
}
by
float angleRadians = atan2f(diffPoint.y, diffPoint.x);
Then it would be better to set rotation immediately (without actions) to process multiple frequent touches.
_cannonImage->setRotation(angleRadians);
Maybe you will need to adjust rotation like setRotation(-angleRadians) or setRotation(angleRadians+90) - it depends on your coordinate system.

Moving a sprite with touches began, casting and parameters in obj - c?

I've been reading a book on the cocos2d framework for ios5 for a few days and have developed a small game that the book walks you through. To control the sprite in this game you use the accelerometer:
-(void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
float deceleration = 0.4f;
float sensitivity = 6.0f;
float maxVelocity = 100;
// adjust velocity based on current accelerometer acceleration
playerVelocity.x = playerVelocity.x * deceleration + acceleration.x * sensitivity;
// we must limit the maximum velocity of the player sprite, in both directions (positive & negative values)
if (playerVelocity.x > maxVelocity)
{
playerVelocity.x = maxVelocity;
}
else if (playerVelocity.x < -maxVelocity)
{
playerVelocity.x = -maxVelocity;
}
// Alternatively, the above if/else if block can be rewritten using fminf and fmaxf more neatly like so:
// playerVelocity.x = fmaxf(fminf(playerVelocity.x, maxVelocity), -maxVelocity);
}
Now I'm wondering if I can change this code to allow the sprite to still accelerate/decelerate along the x axis, but to use touch input rather than the accelerometer, and to go faster the longer the touch is held down for? So a touch to the right would move the sprite to that spot slowly, if the touch is released, it stops moving to that spot. The longer a touch is held down, the faster the sprite moves.
is there anything in the framework to allow me to implement a rotation mechanism that allows my sprite to rotate to the position that the touch was in, so it looks like its facing the point thats been touched?
Well, afaik theres no method that will determine the angle to the touch and then rotate the sprite accordingly, but if you have the x and y coordinates of the sprite and the touch you can calculate it yourself fairly easily.
CGPoint spriteCenter; // this should represent the center position of the sprite
CGPoint touchPoint; //location of touch
float distanceX = touchPoint.x - spriteCenter.x;
float distanceY = touchPoint.y - spriteCenter.y;
float angle = atan2f(distanceY,distanceX); // returns angle in radians
// do whatever you need to with the angle
Once you have the angle you can set the rotation of the sprite.

Figure out angle with right triangle in objective-c

I'm trying to calculate the angle of the click i am making in relationship to the middle of the screen. But maybe i am confused on how atanf is suppsoed to work.
CGPoint pt = [self convertTouchToNodeSpace:[touches anyObject]];
float adj = pt.x - 512;
float opposite = pt.y - 384;
float combined = opposite / adj;
float tan = atanf(combined);
but when i try to NSLog Tan, i just get some giant number like 0.1253649
thoughts?
The right way to convert vector to angle is through atan2 function:
float angle = atan2f (pt.y - 384, pt.x - 512) * 180 / PI;
PS: Are you using cocos2d engine? It has ccpToAngle(...) function.

Move object into screen without gravity into box2d in iPhone

i use following code to move my Box2D object into screen, but because gravity of my world or something else i dont know why my objects is forced to move down, i am new to box2d.
i want to move my object in entire world without gravity.
-(void) tick:(NSTimer *)timer {
int32 velocityIterations = 8;
int32 positionIterations = 1;
world->Step(1.0f/60.0f, velocityIterations, positionIterations);
for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
{
if (b->GetUserData() != NULL)
{
UIView *oneView = (UIView *)b->GetUserData();
CGPoint newCenter = CGPointMake(b->GetPosition().x * PTM_RATIO,self.view.bounds.size.height - b->GetPosition().y * PTM_RATIO);
oneView.center = newCenter;
CGAffineTransform transform = CGAffineTransformMakeRotation(- b->GetAngle());
oneView.transform = transform;
}
}
}
my accelerometer code is as follow.
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
b2Vec2 gravity;
gravity.Set( acceleration.x * 1.81, acceleration.y * 1.81 );
world->SetGravity(gravity);
}
pleas if any one work around.
Thanks.
As i understand you want to move your object setting it's position. It's a bad idea because it will provide non-physical behavior of the bodies colliding with your object. That's because if you will only change the position of your body it's velocity for physics engine will be still zero and collision will be processed according to zero speed of your object.
A better solution is to use b2_kinematicBody type for your object. Then you will be able to control it's motion specifying it's velocity vector and physics will behave as expected. Also the gravity (and no other forces) will not be applied to your object because of it's type.
EDIT
//creation
b2BodyDef bDef;
bDef.type = b2_kinematicBody;
bDef.position.Set(5, 6);
b2Body *body = physWorld->CreateBody(&bDef);
//control
body->SetLinearVelocity(b2Vec2(3, 4));