0
\$\begingroup\$

I'm trying to bounce a ball off of a wall based on angular movement. The ball comes in at angle X ( lets say 30 ). Bouncing off with the equation 360-ballangle works for the left and right walls 180-angle works for top and bottom walls.

Edit Sorry for the vagueness - heres whats going on When a ball hits a wall on any side, the ball bounces right back on the same angle . I'm not sure why it does this - I am trying to have the ball flip its X velocity on a horizontal collision, and flip its Y velocity on a verticle collision. Because I am using angular movement, I need to do this by modifying the ball's angle value, and I am not sure how to set it so it bounces correctly.

(wall.getDimensions returns a rectangle with the walls size and location)

public void moveBullet(Bullet b) {
    float xpos = (float) (speed * 2 * Math.sin(Math.toRadians(b.angle)));
    float ypos = (float) (speed * 2 * Math.cos(Math.toRadians(b.angle)));
    Rectangle bulletbounds = new Rectangle((int) (b.bulletx + xpos), (int) (b.bullety + ypos), 10, 10);
    for (Wall wall : walls) {
        if (bulletbounds.intersects(wall.getDimensions())) {
            if (b.bulletx + 10 > wall.getDimensions().x || b.bulletx < wall.getDimensions().x + wall.getDimensions().width) {
                b.angle = (360 - b.angle);
            }
            if (b.bullety - 10 < wall.getDimensions().y + wall.getDimensions().height || b.bullety > wall.getDimensions().y) {
                b.angle = (180 - b.angle);
            }
        }


    }
    xpos = (float) (speed * 2 * Math.sin(Math.toRadians(b.angle)));
    ypos = (float) (speed * 2 * Math.cos(Math.toRadians(b.angle)));
    b.bulletx += xpos;
    b.bullety += ypos;


}
\$\endgroup\$
4
  • \$\begingroup\$ I think you forgot to ask a question. Perhaps you could expand on what trying to combine them both means? Do you mean when the objects contacts the floor and a wall at the same exact time? In that case, I usually just reverse both velocity components. \$\endgroup\$
    – Dan
    May 25, 2016 at 18:28
  • \$\begingroup\$ Edited for clarification, sorry about that! @Dan \$\endgroup\$
    – Acuzik
    May 25, 2016 at 19:10
  • \$\begingroup\$ What is the range of b.angle, and which direction do you expect the object to be moving when angle == 0? Your code doesn't seem to conform to the standard unit circle, where normally x = cos(theta) and y = sin(theta). Example 1 Example 2 \$\endgroup\$
    – Dan
    May 25, 2016 at 20:18
  • \$\begingroup\$ Also, trigonometric functions are expensive to calculate, especially in tight loops (e.g. checking vs. every collidable object in your scene). Generally it's much easier to store position, velocity, and acceleration as distinct components of each major axis. Then it's as simple as reversing xVel when you collide with a vertical wall, and yVel when you collide with a horizontal wall. If you must store direction as an angle, or are colliding with non-AABB (axis-aligned bounding boxes), then that's a different story. \$\endgroup\$
    – Dan
    May 25, 2016 at 20:23

1 Answer 1

1
\$\begingroup\$

An Alternative Approach

As very astutely stated by Dan in the comments to your question, trigonometric functions are very expensive to calculate and for something as simple as a bouncy ball you can keep to simple and fast vector math.

It appears that you're only doing AABB collision so this method will work perfectly for you.

What to change

  • Your Ball would no longer need an angle attribute.
  • Create a Vector object with two variables x and y
  • Instantiate this new Vector object in your Ball class, we'll save it in a field called vel
  • Instead of all this trigonometry every frame to calculate your balls movement you can now simply use pos.x += vel.x, which is a lot faster!
  • And finally for your collision you could use a code along the lines of:

    /*
    * Will reverse the bouncing direction of the ball and lower it's velocity by half
    */
    public void onCollision(boolean x, boolean y){
        if(x){
            vel.x = -vel.x/2;
        }
        if(y){
            vel.y = -vel.y/2;
        }
    }
    

This method will reverse the x or y velocity depending on the two booleans you pass into it. You need to check which type of collision you have.

If for whatever reason you can't implement this method then I would speculate that you +-90 degrees and % the result by 360 to get crude bouncing. You would obviously look at the current angle and +90 if it's > 180 and -90 if it's < 180.

\$\endgroup\$
3
  • \$\begingroup\$ I don't think reversing both velocities for every collision is correct. You'd more likely want to reverse only the component which is perpendicular to the collision surface. \$\endgroup\$
    – Dan
    May 26, 2016 at 15:37
  • \$\begingroup\$ Oh, yes. Very true thanks for spotting that. I'll edit my answer. \$\endgroup\$
    – Shaun Wild
    May 26, 2016 at 15:42
  • \$\begingroup\$ It's also worth noting that dividing by 2 indefinitely will never reach exactly zero, so it's probably a good idea to implement an epsilon check for resting objects. e.g. in the update function where you are setting position based on velocity, do something like if (vel.x < epsilon) vel.x = 0.0f; and likewise for y; where epsilon is some negligible velocity e.g. float epsilon = 0.001f. \$\endgroup\$
    – Dan
    May 26, 2016 at 15:47

You must log in to answer this question.

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