package break_out.model; import break_out.Constants; /** * This class contains the information about the balls characteristics and behavior * * @author iSchumacher; modified by Gruppe 175 (Moritz Henseleit, Ruben Meyer) */ public class Ball implements IBall { /** * The balls position on the playground */ private Position position; /** * The balls direction */ private Vector2D direction; /** * The constructor of a ball * The balls position and direction are initialized here. */ public Ball() { this.position = new Position(0, 0); this.direction = new Vector2D(Constants.BALL_SPEED, Constants.BALL_SPEED); this.direction.rescale(); // start at bottom-center this.position.setX((Constants.SCREEN_WIDTH - Constants.BALL_DIAMETER) / 2.0); this.position.setY(Constants.SCREEN_HEIGHT - Constants.BALL_DIAMETER - Constants.PADDLE_HEIGHT); } /** * The getter for the balls position * * @return position The balls current position */ public Position getPosition() { return this.position; } /** * The getter for the balls direction * * @return direction The balls current direction */ public Vector2D getDirection() { return this.direction; } /** * updates ball position */ public void updatePosition() { // sets X position this.position.setX(this.position.getX() + this.direction.getDx()); // sets Y position this.position.setY(this.position.getY() + this.direction.getDy()); } /** * Ball reacts to contact with the borders */ public void reactOnBorder() { // reacts on left border if (this.position.getX() <= 0) { this.position.setX(0); this.direction.setDx(-(this.direction.getDx())); } // reacts on right border (-Diameter because of hitbox) if (this.position.getX() >= Constants.SCREEN_WIDTH - Constants.BALL_DIAMETER) { this.position.setX(Constants.SCREEN_WIDTH - Constants.BALL_DIAMETER); this.direction.setDx(-(this.direction.getDx())); } // reacts on top border if (this.position.getY() <= 0) { this.position.setY(0); this.direction.setDy(-(this.direction.getDy())); } // reacts on bottom border (+Diameter because of hitbox) if (this.position.getY() >= Constants.SCREEN_HEIGHT - Constants.BALL_DIAMETER) { this.position.setY(Constants.SCREEN_HEIGHT - Constants.BALL_DIAMETER); this.direction.setDy(-(this.direction.getDy())); } } /** * tests whether the ball touches the paddle's hit box. * @param paddle paddle which will be tested * @return true when ball hits the paddle */ public boolean hitsPaddle(Paddle paddle) { // paddles position Position posPaddle = paddle.getPosition(); // balls position Position posBall = this.getPosition(); // test balls y position against paddles y values // paddles y values can be interpreted as a closed interval therefore if balls y position is in the interval, its true boolean testPaddleY = ( posPaddle.getY() <= posBall.getY() && posBall.getY() <= posPaddle.getY()+paddle.getHeight() || posPaddle.getY() <= posBall.getY()+Constants.BALL_DIAMETER && posBall.getY()+Constants.BALL_DIAMETER <= posPaddle.getY()+paddle.getHeight() ); // test balls x position against paddles x values // paddles x values can be interpreted as a closed interval therefore if balls x position is in the interval, its true boolean testPaddleX = ( posPaddle.getX() <= posBall.getX() && posBall.getX() <= posPaddle.getX()+paddle.getWidth() || posPaddle.getX() <= posBall.getX()+Constants.BALL_DIAMETER && posBall.getX()+Constants.BALL_DIAMETER <= posPaddle.getX()+paddle.getWidth() ); // if balls y position is in paddles y values, verify x position if(testPaddleY) { // DEBUG OUTPUT //System.out.println("ball is in y area of paddle: "+String.format("x, y, w, h: %s, %s, %s, %s", posPaddle.getX(), posPaddle.getY(), paddle.getWidth(), paddle.getHeight())); // if ball is in paddles hit box if(testPaddleX) { // DEBUG OUTPUT //System.out.println("ball hits paddle: "+String.format("x, y, w, h: %s, %s, %s, %s", posPaddle.getX(), posPaddle.getY(), paddle.getWidth(), paddle.getHeight())); return true; } } // default output, ball doesn't hit paddle return false; } /** * Ball got hit by Paddle paddle * @param paddle hitbox mechanism of paddle */ public void reflectOnPaddle(Paddle paddle) { // reflection point / offset point Position reflectionPoint = new Position( paddle.getPosition().getX() + (paddle.getWidth() / 2.0), paddle.getPosition().getY() + (paddle.getHeight() / 2.0) ); // new direction vector; assignment not here Vector2D reflectionVector; // no general solution, estimation required // only two paddles defined in the game design, therefore greater or smaller than middle of screen //deciding if the paddle is at the top or bottom to adjust if its +or- y direction if (paddle.getPosition().getY() <= Constants.SCREEN_HEIGHT) { // top paddle reflectionPoint.setY(reflectionPoint.getY() - Constants.REFLECTION_OFFSET); } else { // bottom paddle reflectionPoint.setY(reflectionPoint.getY() + Constants.REFLECTION_OFFSET); } // calculating the center of the ball; needed for correct vector calculation Position ballCenter = new Position( position.getX() + (Constants.BALL_DIAMETER/2.0), position.getY() + (Constants.BALL_DIAMETER/2.0) ); // The direction is set to the vector between offset point and the ball's center reflectionVector = new Vector2D(reflectionPoint, ballCenter); // normalize vector reflectionVector.rescale(); // replace direction vector this.direction.setDx(reflectionVector.getDx()); this.direction.setDy(reflectionVector.getDy()); } }