2019-11-19 00:55:13 +00:00
package break_out.model ;
import break_out.Constants ;
2019-12-13 00:14:58 +00:00
import java.awt.Color ;
import java.util.Random ;
2019-11-19 00:55:13 +00:00
/ * *
* This class contains the information about the balls characteristics and behavior
2019-12-01 17:31:50 +00:00
*
2019-12-07 23:15:20 +00:00
* @author iSchumacher ; modified by Gruppe 175 ( Moritz Henseleit , Ruben Meyer )
2019-11-19 00:55:13 +00:00
* /
2019-12-01 17:31:50 +00:00
public class Ball implements IBall {
2019-11-19 00:55:13 +00:00
/ * *
* The balls position on the playground
* /
private Position position ;
2019-12-01 17:31:50 +00:00
2019-11-19 00:55:13 +00:00
/ * *
* The balls direction
* /
private Vector2D direction ;
2019-12-01 17:31:50 +00:00
2019-12-13 00:14:58 +00:00
/ * *
* The balls hit state for paddles ; custom implementation
* /
private boolean hitsPaddle ;
/ * *
* The balls color with default component color
* /
private Color color = Constants . COLOR_COMPONENT ;
2019-11-19 00:55:13 +00:00
/ * *
* The constructor of a ball
* The balls position and direction are initialized here .
* /
public Ball ( ) {
this . position = new Position ( 0 , 0 ) ;
2019-12-01 17:31:50 +00:00
this . direction = new Vector2D ( Constants . BALL_SPEED , Constants . BALL_SPEED ) ;
2019-11-19 13:11:56 +00:00
this . direction . rescale ( ) ;
2019-11-19 02:05:45 +00:00
// start at bottom-center
2019-12-01 17:31:50 +00:00
this . position . setX ( ( Constants . SCREEN_WIDTH - Constants . BALL_DIAMETER ) / 2 . 0 ) ;
this . position . setY ( Constants . SCREEN_HEIGHT - Constants . BALL_DIAMETER - Constants . PADDLE_HEIGHT ) ;
2019-11-19 00:55:13 +00:00
}
2019-12-01 17:31:50 +00:00
2019-11-19 00:55:13 +00:00
/ * *
* The getter for the balls position
2019-12-01 17:31:50 +00:00
*
2019-11-19 00:55:13 +00:00
* @return position The balls current position
* /
public Position getPosition ( ) {
return this . position ;
}
2019-12-01 17:31:50 +00:00
2019-11-19 00:55:13 +00:00
/ * *
* The getter for the balls direction
2019-12-01 17:31:50 +00:00
*
2019-11-19 00:55:13 +00:00
* @return direction The balls current direction
* /
public Vector2D getDirection ( ) {
return this . direction ;
}
2019-12-01 17:31:50 +00:00
2019-12-13 00:14:58 +00:00
/ * *
* 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 < a href = " https://stackoverflow.com/a/4247219 " > Stackoverflow Answer 4247219 < / a >
* /
public void newRandomColor ( ) {
Random random = new Random ( ) ;
2019-12-13 00:51:03 +00:00
// random hue without blue colors to prevent ghosting
// 65 <~ 170/255
float hue = ( random . nextInt ( 65 ) ) / 100f ;
2019-12-13 00:14:58 +00:00
// 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 ; }
2019-11-19 00:55:13 +00:00
/ * *
2019-11-19 14:06:25 +00:00
* updates ball position
2019-11-19 00:55:13 +00:00
* /
public void updatePosition ( ) {
2019-11-19 14:06:25 +00:00
// sets X position
2019-12-01 17:31:50 +00:00
this . position . setX ( this . position . getX ( ) + this . direction . getDx ( ) ) ;
2019-11-19 14:06:25 +00:00
2019-12-01 17:31:50 +00:00
// sets Y position
this . position . setY ( this . position . getY ( ) + this . direction . getDy ( ) ) ;
2019-11-19 00:55:13 +00:00
}
2019-12-01 17:31:50 +00:00
2019-11-19 00:55:13 +00:00
/ * *
2019-11-19 14:06:25 +00:00
* Ball reacts to contact with the borders
2019-11-19 00:55:13 +00:00
* /
public void reactOnBorder ( ) {
2019-12-01 17:31:50 +00:00
// reacts on left border
if ( this . position . getX ( ) < = 0 ) {
this . position . setX ( 0 ) ;
this . direction . setDx ( - ( this . direction . getDx ( ) ) ) ;
2019-11-26 22:45:59 +00:00
}
2019-11-19 02:05:45 +00:00
2019-12-01 17:31:50 +00:00
// reacts on right border (-Diameter because of hitbox)
if ( this . position . getX ( ) > = Constants . SCREEN_WIDTH - Constants . BALL_DIAMETER ) {
2019-11-26 22:45:59 +00:00
this . position . setX ( Constants . SCREEN_WIDTH - Constants . BALL_DIAMETER ) ;
this . direction . setDx ( - ( this . direction . getDx ( ) ) ) ;
}
2019-11-19 02:05:45 +00:00
2019-12-01 17:31:50 +00:00
// reacts on top border
if ( this . position . getY ( ) < = 0 ) {
this . position . setY ( 0 ) ;
this . direction . setDy ( - ( this . direction . getDy ( ) ) ) ;
2019-11-26 22:45:59 +00:00
}
2019-11-19 02:05:45 +00:00
2019-12-01 17:31:50 +00:00
// 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 ( ) ) ) ;
2019-11-26 22:45:59 +00:00
}
2019-11-19 00:55:13 +00:00
}
2019-12-01 17:31:50 +00:00
2019-12-02 21:51:46 +00:00
/ * *
2019-12-02 23:03:36 +00:00
* tests whether the ball touches the paddle ' s hit box .
2019-12-02 21:51:46 +00:00
* @param paddle paddle which will be tested
2019-12-02 23:03:36 +00:00
* @return true when ball hits the paddle
2019-12-02 21:51:46 +00:00
* /
public boolean hitsPaddle ( Paddle paddle ) {
2019-12-02 23:03:36 +00:00
// paddles position
Position posPaddle = paddle . getPosition ( ) ;
// balls position
Position posBall = this . getPosition ( ) ;
// test balls y position against paddles y values
2019-12-07 16:24:39 +00:00
// paddles y values can be interpreted as a closed interval therefore if balls y position is in the interval, its true
2019-12-02 23:03:36 +00:00
boolean testPaddleY = (
2019-12-07 16:24:39 +00:00
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 ( )
2019-12-02 23:03:36 +00:00
) ;
// test balls x position against paddles x values
2019-12-07 16:24:39 +00:00
// paddles x values can be interpreted as a closed interval therefore if balls x position is in the interval, its true
2019-12-02 23:03:36 +00:00
boolean testPaddleX = (
2019-12-07 16:24:39 +00:00
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 ( )
2019-12-02 23:03:36 +00:00
) ;
// 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
2019-12-02 21:51:46 +00:00
return false ;
}
/ * *
* Ball got hit by Paddle paddle
* @param paddle hitbox mechanism of paddle
* /
2019-12-07 22:58:50 +00:00
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
2019-12-07 22:21:22 +00:00
//deciding if the paddle is at the top or bottom to adjust if its +or- y direction
2019-12-31 14:21:40 +00:00
if ( paddle . getPosition ( ) . getY ( ) < = Constants . SCREEN_HEIGHT / 2 . 0 ) {
2019-12-07 22:58:50 +00:00
// top paddle
reflectionPoint . setY ( reflectionPoint . getY ( ) - Constants . REFLECTION_OFFSET ) ;
} else {
// bottom paddle
reflectionPoint . setY ( reflectionPoint . getY ( ) + Constants . REFLECTION_OFFSET ) ;
2019-12-07 22:21:22 +00:00
}
2019-12-07 22:58:50 +00:00
// calculating the center of the ball; needed for correct vector calculation
2019-12-07 22:21:22 +00:00
Position ballCenter = new Position (
2019-12-07 22:58:50 +00:00
position . getX ( ) + ( Constants . BALL_DIAMETER / 2 . 0 ) ,
position . getY ( ) + ( Constants . BALL_DIAMETER / 2 . 0 )
) ;
2019-12-07 22:21:22 +00:00
2019-12-07 22:58:50 +00:00
// 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 ( ) ) ;
2019-12-31 14:21:40 +00:00
}
2019-12-02 21:51:46 +00:00
2019-11-19 00:55:13 +00:00
}