/**
*
*/
package com.szuppe.jakub.model;
import java.util.LinkedList;
import java.util.List;
import com.szuppe.jakub.common.Acceleration2D;
import com.szuppe.jakub.common.Coordinates2D;
import com.szuppe.jakub.common.Direction;
import com.szuppe.jakub.common.DoesnotIntersectException;
import com.szuppe.jakub.common.Line2D;
import com.szuppe.jakub.common.Ray2D;
import com.szuppe.jakub.common.SpeedVector2D;
import com.szuppe.jakub.common.Vertices2D;
import com.szuppe.jakub.config.model.PaddleConfig;
/**
* Klasa reprezentująca paletkę/platformę.
* Zawiera jej pozycję, prędkość, przyspieszenie
* oraz życia.
*
* @author Jakub Szuppe <j.szuppe at gmail.com>
*
*/
class Paddle
{
/** Prędkość. */
private final SpeedVector2D speed;
/** Przyspieszenie. */
private final Acceleration2D acceleration;
/** Wierzchołki platformy, w kolejności: lewy-dolny, lewy górny, prawy-górny, prawy-dolny. */
private Vertices2D verticles;
/** Konfiguracja platformy. */
private final PaddleConfig paddleConfig;
/**
* Tworzy nową platformę na podstawie podanej konfiguracji.
*
* @param paddleConfig - konfiguracja.
*/
public Paddle(PaddleConfig paddleConfig)
{
this.paddleConfig = paddleConfig;
this.speed = new SpeedVector2D(0, 0);
this.acceleration = new Acceleration2D(0, 0);
this.verticles = new Vertices2D(paddleConfig.getStartVertices());
}
/**
* Ustala stan platformy (współrzędne, prędkość,
* przyspieszenie) po czasie.
*
* @param timeInterval - czas, który upłynął.
*/
public void move(long timeInterval)
{
if (speed.getXSpeed() == 0)
{
return;
}
else
{
final long timeWhenPaddleWillStop = (long) Math.abs(speed.getXSpeed()
/ acceleration.getxAcc());
moveAlongVector(timeInterval, timeWhenPaddleWillStop);
countNewSpeedAndAcc(timeInterval, timeWhenPaddleWillStop);
}
}
/**
* Dostarcza platformie energie (jako prędkość) w podanym kierunku.
*
* @param direction
*/
public void accelerate(Direction direction)
{
if (direction == Direction.LEFT)
{
if (speed.getXSpeed() > 0)
{
speed.zero();
}
speed.subtract(paddleConfig.getAbsStepSpeed());
if (speed.compareTo(paddleConfig.getMaxAbsSpeed()) > 0)
{
float ySpeed = paddleConfig.getMaxAbsSpeed().getYSpeed();
float xSpeed = paddleConfig.getMaxAbsSpeed().getXSpeed();
SpeedVector2D maxSpeedInLeft = new SpeedVector2D(-xSpeed, -ySpeed);
speed.setSpeed(maxSpeedInLeft);
}
acceleration
.setAccelerationOppositTo(paddleConfig.getAbsRetardation(), speed);
}
if (direction == Direction.RIGHT)
{
if (speed.getXSpeed() < 0)
{
speed.zero();
}
speed.add(paddleConfig.getAbsStepSpeed());
if (speed.compareTo(paddleConfig.getMaxAbsSpeed()) > 0)
{
speed.setSpeed(paddleConfig.getMaxAbsSpeed());
}
acceleration
.setAccelerationOppositTo(paddleConfig.getAbsRetardation(), speed);
}
}
/**
* Sprawdza czy zajdzie kolizja między platformą
* a piłką. Jeżeli tak zwraca listę kolizji, jeżeli nie
* zwraca pustą listę.
*
* @param ball
* @return Lista kolizji między platformą a piłką.
*/
public List<Collision> checkCollisionsWithBall(Ball ball)
{
final List<Collision> collisionList = new LinkedList<>();
final Ray2D ballMovementRay = ball.getMovementRay();
final SpeedVector2D ballSpeed = ball.getSpeed();
final float radius = ball.getRadius();
final List<Coordinates2D> verticesList = verticles.getVerticesList();
try
{
// TOP CHECK
final Coordinates2D paddleLeftTopCo = verticesList.get(1).moveAlongVector(
new Coordinates2D(0, radius));
final Coordinates2D paddleRightTopCo = verticesList.get(2).moveAlongVector(
new Coordinates2D(0, radius));
Line2D paddleTop = new Line2D(paddleLeftTopCo, paddleRightTopCo);
Coordinates2D pointOfIntersection = paddleTop
.intersectionPoint(ballMovementRay);
double distance = Math.sqrt(Math.pow(
pointOfIntersection.getX() - ball.getX(), 2)
+ Math.pow(pointOfIntersection.getY() - ball.getY(), 2));
long timeTillCollision = (long) (distance / ballSpeed.getSpeedValue());
Coordinates2D displacementFromVelocity = speed.countDisplacement(timeTillCollision);
Coordinates2D displacementFromAcc = acceleration.countDisplacement(timeTillCollision);
Coordinates2D displacement = displacementFromVelocity
.moveAlongVector(displacementFromAcc);
final Coordinates2D paddleLeftTopCoAfterTime = paddleLeftTopCo
.moveAlongVector(displacement);
final Coordinates2D paddleRightTopCoAfterTime = paddleRightTopCo
.moveAlongVector(displacement);
if (paddleLeftTopCoAfterTime.getX() <= pointOfIntersection.getX()
&& pointOfIntersection.getX() <= paddleRightTopCoAfterTime.getX())
{
collisionList.add(new BallWithPaddleCollision(timeTillCollision));
}
// END TOP CHECK
} catch (DoesnotIntersectException e)
{
// To nie jest silent fail
// Piłka po prostu nie zderza się z tą ścianą klocka
}
return collisionList;
}
/**
* Przywraca platformę do sytuacji startowej.
* Zeruje prędkość, przyspieszenie, ustawia
* na startowej pozycji.
*/
public void resetToStartSituation()
{
speed.zero();
acceleration.zero();
verticles = null;
verticles = new Vertices2D(paddleConfig.getStartVertices());
}
/**
* Odwraca poziomą składową prędkości.
*/
public void reverseXSpeed()
{
speed.reverseXSpeed();
}
/**
* Odwraca poziomą składową przyspieszenia.
*/
public void reverseXAcc()
{
acceleration.reverseXAcc();
}
/**
* Zatrzymuje paletkę.
*/
public void stop()
{
acceleration.zero();
speed.zero();
}
/**
* @return Wartość najmniejszej współrzędnej poziomej wśród wierzchołków.
*/
public float getMinX()
{
return verticles.getMinX();
}
/**
* @return Wartość największej współrzędnej pionowej wśród wierzchołków.
*/
public float getMaxY()
{
return verticles.getMaxY();
}
/**
* @return Wartość najmniejszej współrzędnej pionowej wśród wierzchołków.
*/
public float getMinY()
{
return verticles.getMinY();
}
/**
* @return Wartość największej współrzędnej poziomej wśród wierzchołków.
*/
public float getMaxX()
{
return verticles.getMaxX();
}
/**
* @return Szerokość paletki.
*/
public float getWidth()
{
return verticles.getMaxX() - verticles.getMinX();
}
/**
* @return Wysokość paletki.
*/
public float getHeight()
{
return verticles.getMaxY() - verticles.getMinY();
}
/**
* @return Prędkość.
*/
public SpeedVector2D getSpeed()
{
return new SpeedVector2D(speed);
}
/**
* @return Przyspieszenie.
*/
public Acceleration2D getAcceleration()
{
return new Acceleration2D(acceleration);
}
/**
* @return Zbiór wierzchołków.
*/
public Vertices2D getVerticles()
{
return new Vertices2D(verticles);
}
/**
* Oblicza prędkość po zadanym czasie.
*
* @param timeInterval - czas.
* @param timeWhenPaddleWillStop - czas, po którym platforma się zatrzyma.
*/
private void countNewSpeedAndAcc(long timeInterval, long timeWhenPaddleWillStop)
{
if (timeInterval >= timeWhenPaddleWillStop)
{
speed.zero();
acceleration.zero();
}
else
{
long movementTime = Math.min(timeInterval, timeWhenPaddleWillStop);
speed.add(acceleration.countSpeedChange(movementTime));
}
}
/**
* Przemieszcza platformę po zadanym czasie.
*
* @param timeInterval - czas.
* @param timeWhenPaddleWillStop - czas, po którym platforma się zatrzyma.
*/
private void moveAlongVector(long timeInterval, long timeWhenPaddleWillStop)
{
long movementTime = Math.min(timeInterval, timeWhenPaddleWillStop);
Coordinates2D displacementFromVelocity = speed.countDisplacement(movementTime);
Coordinates2D displacementFromAcc = acceleration.countDisplacement(movementTime);
Coordinates2D displacement = displacementFromVelocity
.moveAlongVector(displacementFromAcc);
verticles.addToAll(displacement);
}
}