I've spent the last 2 days figuring out the movement of an arrow shot from a bow with no perfect end result. Here is what I have so far:
- (void) update:(ccTime) dt {
elapsedTime += dt;
CGFloat t = elapsedTime;
float theta = CC_DEGREES_TO_RADIANS(angle);
velocity = ccp (initialVelocity.x* cos(theta), initialVelocity.y*sin(theta));
float k = 0.3; //this would be the air resistance factor
float vvx = sqrtf( velocity.x*velocity.x + velocity.y*velocity.y );
float vvy = sqrtf( velocity.x*velocity.x + velocity.y*velocity.y );
CGFloat ax = -k*vvx; //accelerationX
CGFloat ay = -k*vvy - gravity; //accelerationY
velocity = ccp(velocity.x + ax * t , velocity.y + ay * t);
CGPoint oldPosition = self.position;
CGPoint newPosition = ccp(self.position.x + velocity.x * t + ax * t * t, self.position.y + velocity.y * t + ay * t * t);
CGPoint v1 = CGPointMake(0.0, 0.0);
CGPoint v2 = CGPointMake(newPosition.x - oldPosition.x , newPosition.y - oldPosition.y);
CGFloat newAngle = (atan2(v2.y, v2.x) - atan2(v1.y, v1.x));
self.rotation = CC_RADIANS_TO_DEGREES(-newAngle);
self.position = newPosition;
}
Using this code I get this behaviour:
Using: k = 0.3 and angle = 0 degrees, gravity = 9.8
With initialVelocity = 100 the arrow has a nice parabola trajectory
With initialVelocity = 200 the arrow moves faster but has the exact same trajectory as with initialVelocity = 100
With initialVelocity = 300 the arrow moves a lot faster and the trajectory is slightly different but still very close to the trajectory of initialVelocity = 100
Is something wrong with my code? Please note that I don't have a very good understanding of all the notions, much of the implementation is a hit & miss based on what I've read online.
You're adding in acceleration multiple times. You have:
velocity = ccp(velocity.x + ax * t , velocity.y + ay * t);
and then below that:
CGPoint newPosition = ccp(self.position.x + velocity.x * t + ax * t * t, self.position.y + velocity.y * t + ay * t * t);
It looks to me like you could simplify that second line to just
CGPoint newPosition = ccp(self.position.x + velocity.x * t, self.position.y + velocity.y * t);
However, I think your overall algorithm is more complicated than it needs to be, and that makes bugs harder to find. There shouldn't be any reason to track angle; just separate the vectors and handle each independently. In pseudocode, something like this:
// setup
vx = cos(InitAngle) * InitVelocity;
vy = sin(InitAngle) * InitVelocity;
locx = 0;
locy = 0;
gravity = -1.0;
friction -0.01;
// loop
Update(t) {
vx *= 1+(friction * t);
vy +=gravity * t;
locx += vx * t;
locy += vy * t;
}
(I may have the sin/cos reversed; I always get that wrong.)