views:

404

answers:

3

I'd like to deflect a ball at an angle depending on where it hits a paddle. Right now, I'm only changing the y coordinate, which results in an uninteresting deflection. It will angle but independent on impact location against the paddle. I'd like something more fun. Speed, momentum, mass and other factors don't need to be taken into consideration. Just angle depending on impact location of paddle. I've read this http://stackoverflow.com/questions/656002/not-a-number-error-nan-doing-collision-detection-in-an-iphone-app but it seems overly complicated for what I'm looking for. Is there a simpler way to calculate the deflection?

The objects are two UIImageViews.

A: 

You don't necessarily want realistic, you want fun. Those aren't always one and the same. If you wanted realistic, you can't throw out speed, momentum, mass, etc. In a normal game of ping pong, the point where it hits the paddle doesn't really matter, theres not a sweet spot like on a tennis racket.

Develop a mathematical function that will return an output vector, or a velocity and a unit vector, representing the output angle and velocity of the ball, givin an input angle, velocity, impact point on the paddle, and velocity of the paddle.

We expect already that the output angle = -1 * input angle. Output velocity also would be expected to be -1 * the input velocity. So if you want to mix it up, adjust those. You could increase the output angle proportional to the distance from the center of the paddle. You could also increase the angle or the speed proportional to the velocity of the paddle when its hit.

There's a lot of ways you could do that, so I can't really tell you exactly what function you would use, you're going to have to figure that out with testing and playing. If you still need more info add more specifics to your question.

whatsisname
Thanks. I've edited the question to reflect "fun" rather than realistic, which you are right about. But would still like some advice on setting up the code. As mentioned in the OP, I'd like to follow a simpler path on doing the calculations.
4thSpace
+4  A: 

Well, nothing realistic but you could do something so that the outbound angle is only dependent on where on the paddle it hits.

I have never done any iPhone or objective C coding so I'll just write up something in pseudo/C code.

First I'd calculate the speed, which is the length of the speed vector, or:

double speed = sqrt(velX * velX + velY * velY); // trigonometry, a^2 + o^2 = h^2

Then we want to calculate the new angle based on where we hit the paddle. I'm going to assume that you store the X collision in impactX and the length of the paddle in paddleLength. That way we can calculate an outbound angle. First let's figure out how to calculate the range so that we get a value between -1 and 1.

double proportionOfPaddle = impactX / (double) paddleLength; // between 0 and 1
double impactRange = proportionOfPaddle * 2 - 1; // adjust to -1 and 1

Let's assume that we do not want to deflect the ball completely to the side, or 90 degrees, since that would be pretty hard to recover from. Since I'm going to use the impactRange as the new velY, I'm going to scale it down to say -0.9 to 0.9.

impactRange = impactRange * 0.9;

Now we need to calculate the velX so that the speed is constant.

double newVelX = impactRange;
double newVelY = sqrt(speed * speed - newVelX * newVelX); // trigonometry again

Now you return the newVelX and newVelY and you have an impact and speed dependent bounce.

Good luck!

(Might very well be bugs in here, and I might have inverted the X or Y, but I hope you get the general idea).

EDIT: Adding some thoughts about getting the impactX.

Let's assume you have the ball.center.x and the paddle.center.x (don't know what you call it, but let's assume that paddle.center.x will give us the center of the paddle) we should be able to calculate the impactRange from that.

We also need the ball radius (I'll assume ball.width as the diameter) and the paddle size (paddle.width?).

int ballPaddleDiff = paddle.center.x - ball.center.x;
int totalRange = paddle.width + ball.width;

The smallest value for ballPaddleDiff would be when the ball is just touching the side of the paddle. That ballPaddleDiff would then be paddle.width/2 + ball.width/2. So, the new impactRange would therefore be

double impactRange = ballPaddleDiff / (double) totalRange / 2;

You should probably check the impactRange so that it actually is between -1 and 1 so that the ball doesn't shoot off into the stars or something.

Mats Fredriksson
Excellent! This was simple to get up and running. I don't store the impactX value. I just check if the ball is in the paddle's rectangle and reverse ball.center.y. I tried using ball.center.x for impactX but sometimes the ball will hit the edge and bounce straight up. How are you calculating impactX?
4thSpace
A: 

The following code (C++ but easy enough to convert to ObjC), takes an incoming 2D vector and reflects it based on a surface normal (the face of your pong bat).

You could add some random 'fun factor' by randomizing an offset that you'd either apply to 'scalar' - to change velocity, or to the surface normal, to alter the reflection angle.

I'm using this in my iPhone project, and it works fine :)

void vec2ReflectScalar(vec2& vResult, const vec2& v1, const vec2& normal, float scalar)
{
    vec2  _2ndotvn;
    float dotVal = vec2DotProduct(v1, normal); 

    vec2Scale(_2ndotvn, normal, scalar * 2.f * dotVal);
    vec2Subtract(vResult, v1, _2ndotvn); 
}

void vec2Reflect(vec2& vResult, const vec2& v1, const vec2& normal)
{
    vec2ReflectScalar(vResult, v1, normal, 1.f);
}
Ali Parr