What is happening in the following code? - iphone

This code is used in the accelerometer
method.
It uses a CGPoint variable called playerVelocity.
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
//controls how quickly the velocity decelerates
float deceleration = 0.4f;
//determines how sensitive the accelerometer reacts
float sensitivity = 6.0f;
//how fast the velocity can be at most
float maxVelocity = 100;
playerVelocity.x = playerVelocity.x *deceleration + acceleration.x *sensitivity;
if (playerVelocity.x < -maxVelocity)
{
playerVelocity.x = -maxVelocity;
}
else if (playerVelocity.x > maxVelocity)
{
playerVelocity.x = maxVelocity;
}
}
Now I know that the playerVelocity variable is a CGPoint so I imagine it as a X,Y Graph.
I'm assuming that wherever the playerVelocity variable is resting (let's say 150,0), it first multiplies whatever coordinates by 0.4 whenever the accelerometer input is received (which is by the iPhone being tilted)and it then add's the accelerometer.x multiplied by 6.0 to the playerVelocity variable. Is this correct?
Later on in another method, this is added to my other objects position via
CGPoint pos = playerObject.position;
pos.x+= playerVelocity.x;
playerObject.position = pos;
What I'm confused about is what exactly is happening behind the scenes here. Is my assumption above correct?
When the playerVelocity is at 150,0 and is multiplied by 0.4, does the X coordinate of the playerVelocity variable gradually reduce, i.e. 150,0 , 145,0 , 130,0 etc.. ?
If I figure this out I'll then know how my playerObject is moving.

It looks like you have a constant deceleration (.4) that is opposing motion in whatever direction you are currently traveling subtracted from the acceleration as received via the accelerometer, which is multiplied by a constant. This value is then added to your current velocity. So you are essentially adding the difference of (acceleration from accelerometer - constant deceleration) to your current velocity for each calculation.

Related

Projectile Motion in Cocos2d iphone

I want to throw a ball that has a projectile motion. I have a monkey on centre of screen and onTouchBegin I am taking the starting point of the touch and onTouchEnded I am taking the ending points. From the starting and ending points I am taking the angle value between them. Like 30 degrees, 45 or 90 degree.
This is my code by which I have calculated angle of start to endpoint
float angleRadians = atan2(startTouchPoint.x - touchPoint.x, startTouchPoint.y - touchPoint.y);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
float cocosAngle = -1 * angleDegrees;
Now i am using Projectile motion formula to throw ball with angle i have calculated from above formula .
inside init method
gravity = 9.8; // metres per second square
X = 0;
Y = 0;
V0 = 50; // meters per second -- elevation
VX0 = V0 * cos(angle); // meters per second
VY0 = V0 * sin(angle); // meters per second
gameTime = 0;
and onTouchEnded i have called fire method which will throw ball .
-(void)fire:(ccTime) dt
{
CCLOG(#"Angle 1: %.2f",angle);
gameTime += dt*6;
// x = v0 * t * cos(angle)
X = (V0 * gameTime * cos(angle))/2+120;
// y = v0 * t * sin(angle) - 0.5 * g * t^2
Y = (V0 * gameTime * sin(angle) - 0.5 * gravity * pow(gameTime, 2))/2+255;
if (Y > 50)
{
sprite_webfire.position = ccp(X,Y);
flag = true;
}
else
{
//angleValue += 15;
angleValue = angle;
angle = [self DegreesToRadians:angleValue];
gravity = 9.8; // metres per second square
X = 0;
Y = 0;
V0 = 50; // meters per second -- elevation
VX0 = V0 * cos(angle); // meters per second
VY0 = V0 * sin(angle); // meters per second
gameTime = 0;
// [self pauseSchedulerAndActions];
}
if (Y < 50)
{
[self unschedule:#selector(fire:)];
}
NSLog(#"ball (%lf,%lf), dt = %lf angle value %d", X, Y, dt,angleValue);
}
this code is working . by this code i can throw ball in projectile motion but i cant throw it where i want to. i cant throw wrt to given angle from start to end point.
i can throw it like red mark but i want to throw it blue mark with swipe . but its not throwing like i am swiping screen.
I am not certain on what math you are using to do this, I find your documentation a bit confusing.
Generally, for project tile motion this is what you need to do:
Find out what the take off angle is relative to the horizontal. Then depending on whatever initial velocity you want the object to have, use that and you trig equations to put your initial velocities into rectangular components.
For example:
If initial velocity was 10, the initial velocity in the y direction would be 10sin(angle), and in the x direction it would be 10cos(angle).
Then in to update the position of the sprite you should use kinematics equations: http://www.physicsclassroom.com/class/1dkin/u1l6c.cfm
First update velocities:
Velocity in the Y direction: V = v(initial) + gravity*(Delta-time)
Velocity in the X direction is constant unless you want to factor in some sort of resistance to make things a lot more complicated.
then position y = oldPositionY + velocity(in Y direction)*(Delta-time) + 1/2(gravity)(delta-time)^2.
and position x = oldPositionX + Xvelocity*delta-time
I have done some projectile motion stuff, and I have found you need to make gravity a large constant, something around 500 to make it look life-like. Let me know if this is confusing or you don't know how to implement it.
I would suggest that you take a look at the following tutorial: http://www.raywenderlich.com/4756/how-to-make-a-catapult-shooting-game-with-cocos2d-and-box2d-part-1.
It shows you how to use a physics engine, so you don't need to do much of the math. All the 'bullets' in the tutorial are also moving with projectile motion.
I'll add a bit to what was already said (which was good). Firstly, you should not be wasting time computing any angles. Stick with vectors for your velocity. In other words, get the initial velocity vector from the touch start and end location, and that will be your (v0x, v0y). For example:
CGPoint initialVelocity = ccpSub(touchPoint, startTouchPoint);
float v0x = initialVelocity.x;
float v0y = initialVelocity.y;
If you wish to assign a different magnitude to the initial velocity vector, simply normalize it and then multiply it by a new magnitude.
CGPoint unitVelocity = ccpNormalize(initialVelocity);
float magnitude = 200; // or whatever you want it to be
CGPoint velocity = ccpMult(unitVelocity, magnitude);
Anyway, with this velocity set properly you can then use it in your position calculations as before, but without the added complexity of calculating the angles.
-(void) fire:(ccTime)dt
{
.
.
gameTime += dt;
// if x(t) = x0 + v0x*t, then dx = v0x*dt
x += v0x*dt;
// if y(t) = y0 + v0y*t - 0.5t^2, then dy = v0y*dt - g*t*dt
y += (v0y * dt - g*gameTime*dt);
.
.
}
Also you should not set v0 = 50. Calculate the velocity from the vector as I suggested.
Something important to consider is that you are calculating what the movement should be in a physical world based upon units of meters. The screen is operating in points, not meters, so you will probably have to apply a scaling factor to the new position (x,y) to get the look that you are going for.
Edit: my bad, I had to revisit my math in the position calculation. My differentials was a bit rusty.

Throw ball using cocos2d but without any physic engine

I want to throw a ball with swipe speed but do not want to use any physic engine. so please can any one suggest me how i do this.
thanks
A simple yet effective approach without having to explicitly use any physics engine is to step the velocity and position of the ball sprite manually in your update loop, Euler-style.
In the typical case (with downward gravity), you will have non-constant velocity in the y-direction and constant velocity in the x-direction, hence the following code:
-(void) update: (ccTime) dt
{
// Step only the y-velocity
velocity_y += GRAVITY * dt;
// Step the position values and update the ball sprite position accordingly
ball.position.x += velocity_x * dt;
ball.position.y += velocity_y * dt;
}
Then when a swipe event is detected,
Capture the swipe velocity (you will have to compute the change in position of the finger touch in the current and last frame)
Multiply the velocity with a scaling factor if necessary.
Set *velocity_x* and *velocity_y* to these initial values.
I am using projectile motion formulas to do this, http://en.wikipedia.org/wiki/Projectile_motion, along with cocos actions. Here you have a possible approach:
First
Implement a CCActionInterval subclass that receives the projectile formula parameters and updates the projectile position. In this case, ProjectileAction. These are the key methods you need to over-ride:
-(void) startWithTarget:(id)target
{
self.initialPosition = [target position];
self.elapsedTime = 0;
[super startWithTarget:target];
}
-(void) update: (ccTime) tt
{
self.elapsedTime += tt;
float t = self.elapsedTime;
float theta = CC_DEGREES_TO_RADIANS(self.angle);
float v0 = self.velocity;
float g = self.gravitationalAcceleration;
double x = v0 * cos(theta) * t;
double y = v0 * sin(theta) * t - 0.5 * g * t * t ;
[self.target setPosition: ccp(self.initialPosition.x + (float)x, self.initialPosition.y + (float)y)];
}
Second
Use your swipe gesture to recognize the speed, that will translate to the ball's initial velocity in the equation above and to the theVelocity parameter bellow. I leave that part to you.
Third
Run the action. i.e.
ProjectileLaunch* action = [ProjectileLaunch actionWithDuration:10
angle:45
initialVelocity:theVelocity
g:9.8];
[sprite runAction:action];
I hope this helps you.
Regards.

Box2d:apply velocity in a direction

I apply impulse in an object in box2d iPhone app and now want to increase its speed in particuler direction....i mean i need two thing
1.through the object in a direction
2.increase speed
plz help..
b2Vec2 force = b2Vec2(xAcceleration, yAcceleration);
force *= dt; // Use this if your game engine uses an explicit time step
b2Vec2 p = myObjectBody->GetWorldPoint(b2Vec2(0.0f, 0.0f));
body->ApplyForce(force, p);
By modifying xAcceleration and yAcceleration, you can make the object move with various speeds in different directions. (If you calculate angles, you might want to use force.Normalize(); and then multiply by a velocity.)
b2Vec2 vector = self.speed * b2Vec2(cos(angle), sin(angle));
self.yourbodyBody->SetLinearVelocity(vector);
[self schedule:#selector(increaseSpeed) interval:0.1];
- (void)increaseSpeed
{
self.speed += 0.01;
float angle = self.yourbodyBody->GetAngle();
b2Vec2 vector = self.speed * b2Vec2(cos(angle), sin(angle));
self.yourbodyBody->SetLinearVelocity(vector);
}

How to get colliding effect or bouncy when ball hits the track

** STILL NOT WORKING **
I am using below formula to move the ball circular, where accelX and accelY are the values from accelerometer, it is working fine.
But the problem in this code is mRadius (I fixed its value to 50), i need to change mRadius according to accelerometer values and also i need bouncing effect when it touches the track. Currently i am developing code by assuming only one ball is on the board.
float degrees = -atan2(accelX, accelY);
int x = cCentrePoint.x + mRadius * cos(degrees);
int y = cCentrePoint.y + mRadius * sin(degrees);
Here is the snap of the game i want to develop:
Balls Game http://iphront.com/wp-content/uploads/2009/12/bdece528ea334033.jpg.jpg
Updated: I am sending the updated code...
mRadius = 5;
mRange = NSMakeRange(0,60);
-(void) updateBall: (UIAccelerationValue) accelX
withY:(UIAccelerationValue)accelY
{
float degrees = -atan2(accelX, accelY);
int x = cCentrePoint.x + mRadius * cos(degrees);
int y = cCentrePoint.y + mRadius * sin(degrees);
//self.targetRect is rect of ball Object
self.targetRect = CGRectMake(newX, newY, 8, 9);
self.currentRect = self.targetRect;
static NSDate *lastDrawTime;
if(lastDrawTime!=nil)
{
NSTimeInterval secondsSinceLastDraw =
-([lastDrawTime timeIntervalSinceNow]);
ballXVelocity = ballXVelocity + (accelX * secondsSinceLastDraw)
* [self isTouchedTrack:mRadius andRange:mRange];
ballYVelocity = ballYVelocity + -(accelY * secondsSinceLastDraw)
* [self isTouchedTrack:mRadius andRange:mRange];
distXTravelled = distXTravelled + secondsSinceLastDraw
* ballXVelocity * 50;
distYTravelled = distYTravelled + secondsSinceLastDraw
* ballYVelocity * 50;
//Updating the ball rect
CGRect temp = self.targetRect;
temp.origin.x += distXTravelled;
temp.origin.y += distYTravelled;
//calculating new radius after updating ball position
int radius = (temp.origin.x - cCentrePoint.x) /
cos(degreesToRadians(degrees));
if( !NSLocationInRange(abs(radius),mRange))
{
//Colided with the tracks...Need a better logic here
ballXVelocity = -ballXVelocity;
}
else
{
// Need a better logic here
self.targetRect = temp;
}
}
[lastDrawTime release];
lastDrawTime = [ [NSDate alloc] init];
}
In the above code i have initialized mRadius and mRange(indicate track) to some constant for testing, i am not getting the moving of the ball as i expected( bouncing effect when Collided with track ) with respect to accelerometer. Help me to recognize where i went wrong or send some code snippets or links which does the similar job.
I am searching for better logic than my code, if you found share with me.
If I understand your code correctly, then the ball's position is directly controlled by the iPhone's orientation (tilt). So, tilting the iPhone to the right will place the ball at the right side of the track (3 o'clock). I believe you may want the balls acceleration (or, at least, its velocity) to be controlled. Then, you integrate the acceleration to velocity and the velocity to place, taking into account the constraints (the track walls).
The way it is set now, I don't see how you'd control more than one ball (as per the image you posted).
Then, for the bouncing effect: if you mean bouncing by the track's wall, then this will be a small modulation of the mRadius. If you mean bounce by other ball, then you'd modulate the angular position (by means of angular velocity) of the two balls to reflect the reaction.
EDIT: for integration of acceleration to velocity and then to position, for the purpose of this game, you can do with 1st order rectangular integration. Also, it will be more realistic to make the acceleration proportional to the tilt angle. Given the accel values from the iPhone itself, you can assign a 1:1 relation between the balls accel and the device reading. So, you'd like something like:
BallAccX = AccelX * Am_I_NOT_touching_a_wall_in_X_direction() * Ka
BallVelX = BallVelX + BallAccX * dT * Kv
BallPosX = BallPosX + BallVelX * dT * Kp
Note: the above formulae for velocity and position are 1st order approximation but should be sufficient for the purpose of this game.
Ka, Kv, Kp are some proportion coefficients. Choose them to make the relation between the sensed acceleration and the ball movement as you like. dT is the time difference between updates of the state of the ball. The function Am_I_NOT_touching_a_wall_in_X_direction() returns a 1 if the ball is free to move horizontally (in the direction of the tilt) and 0 otherwise.
Calculations for Y movement is symmetrical.
After trying alot I thought it is not easy to produce real time effect without using any physics engine. So its better to use BOX2d or Chipmunks or any other physics engines.

Why do my accelerometers respond so slowly?

I'm asking them at 50Hz / 50 times per second for data. When I suddenly flip the device on the x-axis by 90 degrees while the device was flat on a table with display facing up bevore, the values move pretty slowly to the "target" value for that position.
Now the weird thing is: If I increase the measurement-rate, the value will move faster to that new value upon suddenly flipping the device by 90 degrees. But if I just ask once per second for the new value, it take's very long until the value reaches the target. What can be the reason for this?
I don't do any kind of data aggregation, and don't accumulate anything. I just do some simple filtering to get rid of the noise. My method looks like this:
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
// Use a basic low-pass filter to only keep the gravity in the accelerometer values for the X and Y axes
// accelerationX is an instance variable
accelerationX = acceleration.x * 0.05 + accelerationX * (1.0 - 0.05);
// round
int i = accelerationX * 100;
float clippedAccelerationValue = i;
clippedAccelerationValue /= 100;
[self moveViews:clippedAccelerationValue];
}
later on, in my -moveViews: method, I do this:
-(IBAction)moveSceneForPseudo3D:(float)accelerationValue {
if(fabs(lastAccelerationValue - accelerationValue) > 0.02) { // some little treshold to prevent flickering when it lays on a table
float viewAccelerationOffset = accelerationValue * 19 * -1;
newXPos = initialViewOrigin + viewAccelerationOffset;
myView.frame = CGRectMake(newXPos, myView.frame.origin.y, myView.frame.size.width, myView.frame.size.height);
lastAccelerationValue = accelerationValue;
}
}
As a result, of the device gets turned 90 degrees on the x-achsis, or 180 degrees, the view just moves pretty slowly to it's target position. I don't know if that's because of the physics of the accelerometers, or if it's a bug in my filtering code. I only know that there are fast paced games where the accelerometers are used for steering, so I almost can't imagine that's a hardware problem.
This line:
accelerationX = acceleration.x * 0.05 + accelerationX * (1.0 - 0.05);
is a low-pass filter, which works by computing a moving average of the x acceleration. In other words, each time that callback is called, you're only moving the accelerationX by 5% towards the new accelerometer value. That's why it takes many iterations before accelerationX reflects the new orientation.
What you should do is increase the 0.05 value, to say 0.2. I'd make a global #define and play around with different values along with different refresh rates.