202 lines
6.1 KiB
Java
202 lines
6.1 KiB
Java
package worms.model;
|
|
|
|
import static java.lang.Math.*;
|
|
import worms.util.Coordinate;
|
|
import java.util.List;
|
|
|
|
public abstract class Projectile extends GameObject implements IJumpable {
|
|
|
|
// region constructor
|
|
//===================================================================================
|
|
|
|
public static final double G = 5.0;
|
|
public static final double FORCE_TIME = 0.5;
|
|
private static final int rho = 7800;
|
|
|
|
protected Projectile (Worm worm, double mass, double force) {
|
|
super(worm.getWorld(), calcLocation(worm.getLocation(), worm.getOrientation(), worm.getRadius(), mass), calcRadius(mass));
|
|
super.mass = mass;
|
|
this.force = force;
|
|
this.orientation = worm.getOrientation();
|
|
this.hitPoints = getRandomHitPoints();
|
|
}
|
|
|
|
// ===================================================================================
|
|
// endregion
|
|
|
|
|
|
// region radius / orientation / force
|
|
//===================================================================================
|
|
|
|
public double getOrientation() {
|
|
return orientation;
|
|
}
|
|
|
|
private final double orientation;
|
|
|
|
|
|
public static double calcRadius(double mass) {
|
|
return pow(((mass / 1000.0 / rho) * (3.0 / (4.0 * PI))), 1.0 / 3.0);
|
|
}
|
|
|
|
|
|
public double getForce() {
|
|
return this.force;
|
|
}
|
|
|
|
protected final double force;
|
|
|
|
|
|
|
|
// ===================================================================================
|
|
// endregion
|
|
|
|
|
|
// region hitpoints
|
|
//===================================================================================
|
|
|
|
public int getHitPoints() {
|
|
return this.hitPoints;
|
|
}
|
|
|
|
public void incrementHitPoints(int value) {
|
|
setHitPoints(this.hitPoints + value);
|
|
}
|
|
|
|
public void hit(Worm worm){
|
|
|
|
worm.decreaseHitPoints(getImpactHitPoints());
|
|
terminate();
|
|
}
|
|
|
|
protected abstract void setHitPoints(int value) throws IllegalArgumentException;
|
|
|
|
protected abstract int getImpactHitPoints();
|
|
|
|
protected abstract int getRandomHitPoints();
|
|
|
|
protected int hitPoints;
|
|
|
|
// ===================================================================================
|
|
// endregion
|
|
|
|
// region jump
|
|
//===================================================================================
|
|
|
|
public void jump(double jumpTimeStep) throws IllegalStateException {
|
|
if (!canJump())
|
|
throw new IllegalStateException();
|
|
|
|
double v = jumpVelocity();
|
|
double t = jumpTime(jumpTimeStep);
|
|
double a = getOrientation();
|
|
|
|
Coordinate newLocation = this.location;
|
|
|
|
List<Worm> worms = getWorld().getGameObjectsByClass(Worm.class);
|
|
|
|
if (!getWorld().isAdjacent(getLocation(),getRadius())) {
|
|
newLocation = Coordinate.create(getLocation().getX() + v * t * cos(a),
|
|
getLocation().getY() + v * t * sin(a) - (G * t * t) / 2.0);
|
|
}
|
|
if (!isValidLocation(newLocation)) {
|
|
terminate();
|
|
return;
|
|
}
|
|
setLocation(newLocation);
|
|
|
|
for (Worm worm: worms) {
|
|
if (this.getDistance(worm) < 0) {
|
|
setLocation(newLocation);
|
|
hit(worm);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public double jumpTime(double timeStep) {
|
|
World world = getWorld();
|
|
|
|
if (world == null) {
|
|
throw new IllegalStateException("World cannot be null");
|
|
}
|
|
|
|
double v = jumpVelocity();
|
|
double time = 0;
|
|
double a = getOrientation();
|
|
double radius = getRadius();
|
|
List<Worm> worms = world.getGameObjectsByClass(Worm.class);
|
|
|
|
if (!world.isPassable(this.location) || worms.stream().anyMatch(w -> w.getDistance(this) < 0)) {
|
|
return 0.0;
|
|
}
|
|
|
|
while(true) {
|
|
time += timeStep;
|
|
Coordinate newLoc = Coordinate.create(this.location.getX() + v * time * cos(a),
|
|
this.location.getY() + v * time * sin(a) - (G * time * time) / 2.0);
|
|
|
|
if (newLoc.getX() - radius < 0 || newLoc.getY() - radius < 0 || newLoc.getX() + radius > world.getWidth() ||
|
|
newLoc.getY() + radius > world.getHeight() || !world.isPassable(newLoc) ||
|
|
worms.stream().anyMatch(w -> w.getDistance(newLoc, this.radius) < 0)) {
|
|
return time;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public Coordinate jumpStep(double elapsedTime) {
|
|
if (Double.isNaN(elapsedTime) || elapsedTime < 0)
|
|
throw new IllegalArgumentException();
|
|
|
|
double velocity = this.jumpVelocity();
|
|
|
|
return Coordinate.create(getLocation().getX() + velocity * cos(getOrientation()) * elapsedTime,
|
|
getLocation().getY() + velocity * sin(getOrientation()) * elapsedTime - 0.5 * G * pow(elapsedTime, 2));
|
|
}
|
|
|
|
|
|
private boolean canJump() {
|
|
return getOrientation() < PI;
|
|
}
|
|
|
|
|
|
private double jumpVelocity() {
|
|
return (getForce() / (getMass() / 1000)) * FORCE_TIME;
|
|
}
|
|
|
|
// ===================================================================================
|
|
// endregion
|
|
|
|
|
|
// region location
|
|
//===================================================================================
|
|
|
|
@Override
|
|
protected boolean isValidLocation(Coordinate location) {
|
|
double radius = getRadius();
|
|
|
|
if (getWorld() == null) {
|
|
return !Double.isNaN(location.getX()) &&
|
|
!Double.isNaN(location.getY());
|
|
}
|
|
return !Double.isNaN(location.getX()) &&
|
|
!Double.isNaN(location.getY()) &&
|
|
!(location.getX() - radius < 0) &&
|
|
!(location.getX() + radius > getWorld().getWidth()) &&
|
|
!(location.getY() + radius > getWorld().getHeight()) &&
|
|
!(location.getY() - radius < 0);
|
|
}
|
|
|
|
public static Coordinate calcLocation(Coordinate wormLocation, double wormOrientation, double wormRadius, double mass) {
|
|
double radius = calcRadius(mass);
|
|
|
|
return Coordinate.create(wormLocation.getX() + cos(wormOrientation) * (wormRadius + radius),
|
|
wormLocation.getY() + sin(wormOrientation) * (wormRadius + radius));
|
|
}
|
|
|
|
|
|
// ===================================================================================
|
|
// endregion
|
|
|
|
} |