4
\$\begingroup\$

Edit: My goal is to have it function like this:

Ball hits 1st Quarter = rebounds higher (aka Y++) Ball hits 2nd Quarter = rebounds higher (using random value) Ball hits 3rd Quarter = rebounds lower (using random value) Ball hits 4th Quarter = rebounds lower (aka Y--)

I'm currently using Rectangle Collision for my collision detection, and it's worked. Now I wish to expand it.

Instead of it simply detecting whether or not the paddle/ball intersect, I want to make it so that it can determine what section of the paddle gets hit. I wanted it in 4 parts, with each having a different reaction to impact.

My first thought is to base it on the Ball's Y position compared to the Paddle's Y position. But since I want it in 4 parts, I don't know how to do that.

So it's essentially be

if (ball.Y > Paddle.Y)
{
PaddleSection1 == true;
}

Except modified so that instead of being top half/bottom half, it's 1st Quarter, etc.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ What's your goal? We can tell you how to use this tool of quarter-detection, but it may not be the best tool for your goal. For instance if you want to make the ball bounce in a different direction depending on the part of the bat hit, you would not determine the quarter. Instead you'd calculate the normal of the paddle where it's hit, perpendicular at the centre and closer to parallel when the ball hits closer to the side. This works fine on top of rectangle collision, whilst mathematically creating the illusion the rectangle is an ellipse (though only once it has collided with the rect). \$\endgroup\$ Commented Jan 25, 2011 at 3:44
  • \$\begingroup\$ Related to: gamedev.stackexchange.com/questions/7300/… \$\endgroup\$
    – bummzack
    Commented Jan 25, 2011 at 7:29
  • \$\begingroup\$ My goal is to have it function like this: Ball hits 1st Quarter = rebounds higher (aka Y++) Ball hits 2nd Quarter = rebounds higher (using random value) Ball hits 3rd Quarter = rebounds lower (using random value) Ball hits 4th Quarter = rebounds lower (aka Y--) \$\endgroup\$
    – Slateboard
    Commented Jan 25, 2011 at 7:47
  • \$\begingroup\$ I take it from your description you mean vertical quarter, so that a paddle oriented like so: ====== would have the 1st quarter facing upwards, the 4th downwards, and the 2nd and 3rd are essentially inside (except where exposed on the ends)? \$\endgroup\$ Commented Jan 25, 2011 at 8:31

4 Answers 4

1
\$\begingroup\$

If you want to split the paddle into 4 areas and see which one of the four sections it has hit you could do simple comparisons like your if statement above.. if its above or below the mid point in the X or Y position you will now if its left or right, top or bottom...

Assuming ball.Y and Paddle.Y are in the same coordinate system (I am assuming 0,0 is in the bottom left corner of the screen) and you already know that the two have collided, then

if ( ball.Y > Paddle.Y + (Paddle.Width * 0.5))
{
    Top of Paddle
}
else
{
    Bottom of Paddle
}

And you could extend this to the X coords for Left and right as well.

Hope this helps

\$\endgroup\$
2
  • \$\begingroup\$ So based on your example, 0.25 would be 1/4th? \$\endgroup\$
    – Slateboard
    Commented Jan 25, 2011 at 2:31
  • \$\begingroup\$ @Slateboard, Yup. Multiplication of decimal forms of fractions is faster than division in most cases :) Bit shifting can also half values (Num >> 1) very fast. I was unsure what data type .Y and .Width would be so I went with the straight math :) \$\endgroup\$
    – James
    Commented Jan 25, 2011 at 17:16
1
\$\begingroup\$

To split a paddle into four sections along its Y-axis, you could measure penetration percentage through the bat. Hitting the top would be 0.0f, the bottom would be 1.0f. The second quarter would be between 0.25f and 0.5f, etc.

Following is a method to calculate the penetration depth and a method which translates that into the far more important quarter.

// Note: This method can return a value > 1.0 or < 0.0 if the paddle and ball are
// not actually colliding.
float PenetrationDepth(Vector2 ballOrigin, Vector2 paddleOrigin, float paddleThickness)
{
    float paddleEdge = paddleOrigin.Y - paddleThickness * 0.5f;
    float ballRelativePos = ballOrigin.Y - paddleEdge;

    float ballDepth = ballRelativePos / paddleThickness;
    return ballDepth;
}

enum PenetrationQuarter { None = 0, First, Second, Third, Fourth }

PenetrationQuarter GetPenetrationQuarter(Vector2 ballOrigin, Vector2 paddleOrigin,
    float paddleThickness)
{
    float depth = PenetrationDepth(ballOrigin, paddleOrigin, paddleThickness);
    if (depth > 1.0f || depth < 0.0f) return PenetrationQuarter.None;

    int quarter = (int)(depth * 4) + 1;
    // Edge case: If depth was 1.0, quarter will be 5, which is within quarter 4
    if (quarter == 5) quarter = 4;

    return (PenetrationQuarter)quarter;
}

Edit: Fixed some (fairly terrible) logic errors.

\$\endgroup\$
1
\$\begingroup\$

The most efficient way I've found to do this exact thing in my game is by inserting this code:

    public void BatHit(int block)
    {
        if (direction > Math.PI * 1.5f || direction < Math.PI * 0.5f)
        {
            switch (block)
            {
                case 1:
                    direction = MathHelper.ToRadians(200);
                    break;
                case 2:
                    direction = MathHelper.ToRadians(195);
                    break;
                case 3:
                    direction = MathHelper.ToRadians(180);
                    break;
                case 4:
                    direction = MathHelper.ToRadians(180);
                    break;
                case 5:
                    direction = MathHelper.ToRadians(165);
                    break;
                case 6:
                    direction = MathHelper.ToRadians(130);
                    break;
            }
        }
        else
        {
            switch (block)
            {
                case 1:
                    direction = MathHelper.ToRadians(310);
                    break;
                case 2:
                    direction = MathHelper.ToRadians(345);
                    break;
                case 3:
                    direction = MathHelper.ToRadians(0);
                    break;
                case 4:
                    direction = MathHelper.ToRadians(0);
                    break;
                case 5:
                    direction = MathHelper.ToRadians(15);
                    break;
                case 6:
                    direction = MathHelper.ToRadians(50);
                    break;
            }
        }

        if (rand.Next(2) == 0)
        {
            direction += MathHelper.ToRadians(rand.Next(3));
        }
            else
        {
            direction -= MathHelper.ToRadians(rand.Next(3));
        }
        AudioManager.Instance.PlaySoundEffect("hit");

    }
\$\endgroup\$
0
\$\begingroup\$

Johnathan Hobbs is close in his answer. I would suggest ditching corners, and going with a percentage base.

Hitting the paddle on the left-most edge gives an angle of, say, -60 degrees (2pi/3, I think). Hitting the right-most edge is +60 degrees.

So your range is 120 degrees. Calculate the relative Y of where the ball hit, map it from [0 .. 1] (a percentage) to [-60 ... 60] and that's the angle of reflection.

I used something quite similar in my Flash block-paddle game. The benefit of this approach is:

  • simplistic (easy to code)
  • "realistic" (users can understand how it works quickly and "aim" where they want the ball to go).
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .