small changes
This commit is contained in:
545
OGP1718-Worms/src/worms/model/Worm.java
Normal file
545
OGP1718-Worms/src/worms/model/Worm.java
Normal file
@@ -0,0 +1,545 @@
|
||||
package worms.model;
|
||||
|
||||
import be.kuleuven.cs.som.annotate.*;
|
||||
|
||||
public class Worm {
|
||||
/**
|
||||
* a class with the specifications of the worm
|
||||
*
|
||||
* @invar the location of the worm must be a valid location
|
||||
* |...
|
||||
* @invar
|
||||
*
|
||||
* @version 1.0
|
||||
* @author Arthur Bols and Leen Dereu
|
||||
*/
|
||||
|
||||
// region properties
|
||||
//===================================================================================
|
||||
|
||||
// Location
|
||||
private Tuple<Double, Double> location;
|
||||
|
||||
|
||||
// jumping
|
||||
private Tuple<Double, Double> oldLocation;
|
||||
private double jumpForce;
|
||||
private double jumpVelocity;
|
||||
|
||||
/**
|
||||
* this variable contains the orientation of the worm
|
||||
*/
|
||||
private double orientation;
|
||||
|
||||
/**
|
||||
* this variable contains the radius of the worm
|
||||
*/
|
||||
private double radius;
|
||||
|
||||
/**
|
||||
* this variable contains the minimum value of the radius
|
||||
*/
|
||||
private final double minimumRadius;
|
||||
|
||||
/**
|
||||
* this variable contains the mass of the worm
|
||||
*/
|
||||
private double mass;
|
||||
|
||||
/**
|
||||
* this variable contains the current action points of the worm
|
||||
*/
|
||||
private int points;
|
||||
|
||||
/**
|
||||
* this variable contains the maximum points a worm can have
|
||||
*/
|
||||
private int maxPoints;
|
||||
|
||||
/**
|
||||
* this variable contains the name of the worm
|
||||
*/
|
||||
private String name;
|
||||
|
||||
//===================================================================================
|
||||
// endregion
|
||||
|
||||
|
||||
// region constructor
|
||||
//===================================================================================
|
||||
|
||||
/**
|
||||
*
|
||||
* @param location ...
|
||||
* @param orientation ...
|
||||
* @param name ...
|
||||
* @param radius ...
|
||||
*/
|
||||
public Worm(Tuple<Double, Double> location, double orientation, String name, double radius) {
|
||||
|
||||
this(location, orientation, name, radius, 0.25);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param location ...
|
||||
* @param orientation ...
|
||||
* @param name ...
|
||||
* @param radius ...
|
||||
* @param minimumRadius ...
|
||||
* @throws IllegalArgumentException ...
|
||||
*/
|
||||
public Worm(Tuple<Double, Double> location, double orientation, String name, double radius, double minimumRadius)
|
||||
throws IllegalArgumentException {
|
||||
|
||||
setLocation(location);
|
||||
|
||||
setOrientation(orientation);
|
||||
|
||||
if (!isValidMininmumRadius(minimumRadius))
|
||||
throw new IllegalArgumentException("Invalid minimum radius"); // TODO add decent exception msg
|
||||
|
||||
setRadius(radius);
|
||||
this.minimumRadius = minimumRadius;
|
||||
this.points = this.maxPoints;
|
||||
|
||||
int validName = isValidName(name);
|
||||
if (validName != -1)
|
||||
throw new IllegalNameException(validName, name);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
//===================================================================================
|
||||
// endregion
|
||||
|
||||
|
||||
|
||||
// region location
|
||||
//===================================================================================
|
||||
|
||||
/**
|
||||
* Return the location of the worm
|
||||
* the location of the worm expresses the place of the worm
|
||||
* in the play area
|
||||
*/
|
||||
public Tuple<Double, Double> getLocation() {
|
||||
return this.location;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the location of the worm to the given location
|
||||
*
|
||||
* @param location
|
||||
* the new location for the worm
|
||||
* @post the new location of the worm is equal to the given location
|
||||
* |new.getLocation() == location
|
||||
* @throws IllegalArgumentException
|
||||
* the given location is not a valid location for a worm
|
||||
* |! isValidLocation(location)
|
||||
*/
|
||||
private void setLocation(Tuple<Double, Double> location) throws IllegalArgumentException {
|
||||
|
||||
if (location == null || Double.isNaN(location.item1) || Double.isNaN(location.item2))
|
||||
throw new IllegalArgumentException("Illegal value for location"); // TODO add decent exception msg
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
//===================================================================================
|
||||
// endregion
|
||||
|
||||
|
||||
// region Orientation
|
||||
//===================================================================================
|
||||
|
||||
/**
|
||||
* set the orientation of the worm to the given orientation
|
||||
*
|
||||
* @param orientation
|
||||
* the new orientation of the worm
|
||||
* @pre the given orientation must be a valid orientation for any worm
|
||||
* |isValidOrientation(orientation)
|
||||
* @post the new orientation of the worm must be equal to the given orientation
|
||||
* |new.getOrientation() == orientation
|
||||
*/
|
||||
private void setOrientation(double orientation) {
|
||||
// TODO nominal checking
|
||||
this.orientation = orientation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the orientation of the worm
|
||||
* the orientation of a worm expresses the direction in which
|
||||
* the worm is looking
|
||||
*/
|
||||
@Basic
|
||||
public double getOrientation() {
|
||||
return orientation;
|
||||
}
|
||||
|
||||
//===================================================================================
|
||||
// endregion
|
||||
|
||||
|
||||
|
||||
|
||||
// region Shape mass/radius
|
||||
//===================================================================================
|
||||
|
||||
/**
|
||||
* Return the radius of the worm
|
||||
* the radius of the worm expresses half of the
|
||||
* width of the worm
|
||||
*/
|
||||
@Basic
|
||||
public double getRadius() {
|
||||
return this.radius;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the radius of the worm to the given radius
|
||||
*
|
||||
* @param radius
|
||||
* the new radius for the worm
|
||||
* @post the new radius of the worm is equal to the given radius
|
||||
* |new.getRadius() == radius
|
||||
* @throws IllegalArgumentException
|
||||
* the given radius is not a valid radius for any worm
|
||||
* |! isValidRadius(radius)
|
||||
*/
|
||||
public void setRadius(double radius) throws IllegalArgumentException {
|
||||
if (radius < this.minimumRadius || Double.isNaN(radius))
|
||||
throw new IllegalArgumentException("Invalid radius");
|
||||
|
||||
this.radius = radius;
|
||||
setMass(radius);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum radius the worm can have
|
||||
* the minimum radius of the worm expresses the minimum length
|
||||
* of half of the width of the worm
|
||||
*/
|
||||
public double getMinimumRadius() {
|
||||
return this.minimumRadius;
|
||||
}
|
||||
|
||||
private boolean isValidMininmumRadius(double radius) {
|
||||
return !Double.isNaN(radius) && radius > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mass of the worm
|
||||
* the mass of the worm expresses the weight of the worm
|
||||
*/
|
||||
public double getMass() {
|
||||
return this.mass;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the mass of the worm to the given mass (dependent on the radius)
|
||||
*
|
||||
* @param radius
|
||||
* part of the formula to calculate the mass
|
||||
* @post the new mass of the worm is equal to
|
||||
* rho * (4 / 3 * Math.PI * Math.pow(radius, 3))
|
||||
* |new.getMass() == rho * (4 / 3 * Math.PI * Math.pow(radius, 3))
|
||||
*/
|
||||
private void setMass(double radius) {
|
||||
|
||||
final int rho = 1062;
|
||||
double mass = rho * (4 / 3 * Math.PI * Math.pow(radius, 3));
|
||||
|
||||
this.mass = mass;
|
||||
setMaxPoints(mass);
|
||||
}
|
||||
|
||||
//===================================================================================
|
||||
// endregion
|
||||
|
||||
|
||||
|
||||
// region Points
|
||||
//===================================================================================
|
||||
|
||||
public int getPoints() {
|
||||
return this.points;
|
||||
}
|
||||
|
||||
public void setPoints(int points) {
|
||||
if (points > this.maxPoints)
|
||||
points = this.maxPoints;
|
||||
else if (points < 0)
|
||||
points = 0;
|
||||
|
||||
this.points = points;
|
||||
}
|
||||
private void setMaxPoints(double maxPoints) {
|
||||
this.maxPoints = (int) Math.ceil(maxPoints);
|
||||
setPoints(this.points);
|
||||
}
|
||||
private void subtractPoints (int value) {
|
||||
|
||||
setPoints(this.points - value);
|
||||
}
|
||||
private void subtractPoints (double angle) {
|
||||
|
||||
setPoints(this.points - (int) Math.ceil(Math.toDegrees(angle) / 6));
|
||||
}
|
||||
|
||||
//===================================================================================
|
||||
// endregion
|
||||
|
||||
|
||||
|
||||
// region name
|
||||
//===================================================================================
|
||||
|
||||
/**
|
||||
* Return the name of the worm
|
||||
* the name of the worm expresses the identity of the worm
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the name of the worm tot the given name
|
||||
*
|
||||
* @param name
|
||||
* the new name for the worm
|
||||
* @post the new name of the worm is equal to the given name
|
||||
* |new.GetName() == name
|
||||
* @throws IllegalNameException
|
||||
* the given name is not a valid name for any worm
|
||||
* |! isValidName(name)
|
||||
*/
|
||||
public void setName(String name) {
|
||||
|
||||
int validName = isValidName(name);
|
||||
if (validName != -1)
|
||||
throw new IllegalNameException(validName, name);
|
||||
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* check whether the given name is a valid name for all worms
|
||||
*
|
||||
* @param name
|
||||
* the name to check
|
||||
* @return -1 if and only if the given name is longer then 2,
|
||||
* the first letter is uppercase and the name only exists
|
||||
* of letters, " ", " ' " and " "" "
|
||||
* |for (i = 0; i < name.length(); i++)
|
||||
* |result == (name.length() > 2 && Character.isUpperCase(name.charAt(0)
|
||||
* |&& Character.isLetter(name.charAt(i)) &&
|
||||
* |allowedCharacters.indexOf(name.charAt(i)))
|
||||
*/
|
||||
private int isValidName (String name) {
|
||||
|
||||
if (name.length() < 2 || !Character.isUpperCase(name.charAt(0))) {
|
||||
return 0;
|
||||
}
|
||||
String allowedCharacters = "'\" ";
|
||||
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
if (!Character.isLetter(name.charAt(i))) {
|
||||
if (allowedCharacters.indexOf(name.charAt(i)) == -1) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//===================================================================================
|
||||
// endregion
|
||||
|
||||
|
||||
// region move
|
||||
//===================================================================================
|
||||
|
||||
/**
|
||||
* move the worm for the given number of steps
|
||||
*
|
||||
* @param numberSteps
|
||||
* the number of steps the worm should take
|
||||
*
|
||||
* @post the x-coordinate of the new location of the worm schould be the location of
|
||||
* the old x-coordinate plus the number of steps multiplied with the distance
|
||||
* that the x-coordinate schould move (distance is equal to the radius multiplied
|
||||
* with the cosinus of the orientation)
|
||||
* |distanceX = this.radius * Math.cos(this.orientation)
|
||||
* |new.xCoordinate = this.location.item1 + numberSteps * distanceX
|
||||
* @post the y-coordinate of the new location of the worm schould be the location of
|
||||
* the old y-coordinate plus the number of steps multiplied with the distance
|
||||
* that the y-coordinate schould move (distance is equal to the radius multiplied
|
||||
* with the sinus of the orientation)
|
||||
* |distanceY = this.radius * Math.sin(this.orientation)
|
||||
* |new.yCoordinate = this.location.item2 + numberSteps * distanceY
|
||||
* @post the current value of action points has changed. The current value of action points
|
||||
* minus the cost of moving (abs(cos(theta)) + abs(4 sin(theta)))
|
||||
* |value = (int) Math.ceil(Math.abs(Math.cos(this.orientation)) + Math.abs(4 * Math.sin(this.orientation)))
|
||||
* |setPoints(this.points - value)
|
||||
* @throws IllegalArgumentException
|
||||
* when the total of steps is lower then 0 or when the cost of action point is more
|
||||
* then the current value of action point
|
||||
* |NumberSteps < 0 || cost > this.points
|
||||
*/
|
||||
public void move(int numberSteps) {
|
||||
if (numberSteps < 0)
|
||||
throw new IllegalArgumentException(); // TODO add decent exception msg
|
||||
|
||||
int cost = (int) Math.ceil(Math.abs(Math.cos(this.orientation)) + Math.abs(4 * Math.sin(this.orientation)));
|
||||
if (cost > this.points)
|
||||
throw new IllegalArgumentException(); // TODO add decent exception msg
|
||||
|
||||
double distanceX = this.radius * Math.cos(this.orientation);
|
||||
double distanceY = this.radius * Math.sin(this.orientation);
|
||||
this.location = Tuple.create(this.location.item1 + numberSteps * distanceX,
|
||||
this.location.item2 + numberSteps * distanceY);
|
||||
subtractPoints(cost);
|
||||
|
||||
}
|
||||
|
||||
//===================================================================================
|
||||
// endregion
|
||||
|
||||
|
||||
// region turn
|
||||
//===================================================================================
|
||||
|
||||
/**
|
||||
* turns the worm with the given angle
|
||||
*
|
||||
* @param angle
|
||||
* the angle that must be added to the orientation
|
||||
* @pre the angle to add must be between 0 and 2pi (including 0)
|
||||
* |0 <= angle < 2pi
|
||||
* @post the new orientation is the old orientation plus the given angle
|
||||
* |new.getOrientation() = this.getOrientation() + angle
|
||||
* @post the resulting angle (= the new orientation) must be between 0 and 2pi (including 0)
|
||||
* |0 <= new.getOrientation() < 2pi
|
||||
* @post current points of action points schould be reduced, for this there is another
|
||||
* method with as parameter the given angle
|
||||
* |substractPoints(angle)
|
||||
*/
|
||||
public void turn(double angle) {
|
||||
assert 0 <= angle && angle < (2 * Math.PI);
|
||||
|
||||
setOrientation((this.orientation + angle) % (2 * Math.PI));
|
||||
subtractPoints(angle);
|
||||
}
|
||||
|
||||
//===================================================================================
|
||||
// endregion
|
||||
|
||||
|
||||
// region Jump
|
||||
//===================================================================================
|
||||
|
||||
/**
|
||||
* this constant contains the gravity
|
||||
*/
|
||||
private final double G = 5.0;
|
||||
|
||||
/**
|
||||
* this constant contains the duration of the force
|
||||
*/
|
||||
private final double FORCE_TIME = 0.5;
|
||||
|
||||
/**
|
||||
* let the worm jump
|
||||
*
|
||||
* @post the worm jumps to his new place. The new place is the x-coordinate plus the jump distance
|
||||
* with the jump velocity
|
||||
* |Tuple.create(location.item1 + jumpDistance(this.jumpVelocity), location.item2)
|
||||
* @post the current action points schould be 0 after a jump
|
||||
* |this.points = 0
|
||||
* @throws IllegalStateException()
|
||||
* if the current action points is equal to 0 or the orientation is more then
|
||||
* pi the worm can not jump
|
||||
* |this.points == 0 || this.orientation < Math.PI
|
||||
*/
|
||||
public void jump() {
|
||||
|
||||
if (!canJump())
|
||||
throw new IllegalStateException();
|
||||
|
||||
this.oldLocation = this.location;
|
||||
this.jumpVelocity = jumpVelocity();
|
||||
this.location = Tuple.create(location.item1 + jumpDistance(this.jumpVelocity), location.item2);
|
||||
this.points = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a boolean whether the worm can jump or not
|
||||
*
|
||||
* @return True if and only if the action points is bigger then 0 and the orientation
|
||||
* is lower then pi
|
||||
* |result == this.points > 0 && this.orientation < Math.PI
|
||||
*/
|
||||
private boolean canJump() {
|
||||
return this.points > 0 && this.orientation < Math.PI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time the worm will jump
|
||||
*
|
||||
* @return the time the worm will jump. The distance divided by the velocity multiplied
|
||||
* with the cosinus of the orientation
|
||||
* |jumpDistance(this.jumpVelocity) / (this.jumpVelocity * Math.cos(this.orientation))
|
||||
*/
|
||||
public double jumpTime() {
|
||||
|
||||
return jumpDistance(this.jumpVelocity) / (this.jumpVelocity * Math.cos(this.orientation));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param deltaTime
|
||||
* @return
|
||||
*/
|
||||
public Tuple<Double, Double> jumpStep(double deltaTime) {
|
||||
if (Double.isNaN(deltaTime)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
return Tuple.create(oldLocation.item1 + this.jumpVelocity * Math.cos(this.orientation) * deltaTime,
|
||||
oldLocation.item2 + this.jumpVelocity * Math.sin(this.orientation) * deltaTime - 0.5 * G * Math.pow(deltaTime, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the distance the worm will jump
|
||||
*
|
||||
* @param v
|
||||
* the velocity of the jump
|
||||
* @return the distance the worm will jump. The distance is equal to the velocity powered by 2 multiplied
|
||||
* with the sinus of 2 times the orientation en this divided with the gravity
|
||||
* |(Math.pow(v, 2) * Math.sin(2 * this.orientation)) / this.G
|
||||
*/
|
||||
private double jumpDistance(double v) {
|
||||
return (Math.pow(v, 2) * Math.sin(2 * this.orientation)) / this.G;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the velocity of the jump
|
||||
*
|
||||
* @return the velocity of the jump. The force of the jump is equal to 5 multiplied with the
|
||||
* current action points plus the mass multiplied with the gravity. Therefrom the velocity
|
||||
* is equal to the force divided with the mass, multiplied with the time te force takes
|
||||
* |force = 5 * this.points + this.mass * G
|
||||
* |velocity = (force / this.mass) * FORCE_TIME
|
||||
*/
|
||||
private double jumpVelocity() {
|
||||
|
||||
double force = 5 * this.points + this.mass * G;
|
||||
return (force / this.mass) * FORCE_TIME;
|
||||
}
|
||||
|
||||
|
||||
//===================================================================================
|
||||
// endregion
|
||||
|
||||
|
||||
}
|
Reference in New Issue
Block a user