package break_out.model; import break_out.Constants; import java.awt.Color; import java.util.Random; /** * 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 balls hit state for paddles; custom implementation */ private boolean hitsPaddle; /** * The balls color with default component color */ private Color color = Constants.COLOR_COMPONENT; /** * 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; } /** * The getter for the balls color * * @return color The balls current color */ public Color getColor() { return this.color; } /** * The setter for the balls color * * @param color The balls new color */ public void setColor(Color color) { this.color = color; } /** * Creates new random color for the ball and sets it * * @see Stackoverflow Answer 4247219 */ public void newRandomColor() { Random random = new Random(); // random hue without blue colors to prevent ghosting // 65 <~ 170/255 float hue = (random.nextInt(65)) / 100f; // saturation between 0.5 and 0.7 float saturation = (random.nextInt(2000) + 5000) / 10000f; float luminance = 0.9f; Color randColor = Color.getHSBColor(hue, saturation, luminance); setColor(randColor); } /** * The getter for the balls hit state * * @return hitsPaddle The balls current hit state */ public boolean getHitState() { return this.hitsPaddle; } /** * The setter for the balls hit state * * @param state The balls new hit state */ public void setHitState(boolean state) { this.hitsPaddle = state; } /** * 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/2.0) { // 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()); } }