package game.habits;
import java.util.Set;
import engine.classes.Colour;
import engine.geometry.Circle;
import engine.geometry.Point;
import engine.geometry.Rectangle;
import engine.geometry.Vector;
import engine.hierarchy.DefaultHabit;
import engine.interfaces.Clock;
import engine.interfaces.Keyboard;
import engine.interfaces.Keyboard.Key;
import engine.interfaces.Mouse;
import engine.interfaces.Mouse.Button;
import engine.interfaces.RenderTarget;
import game.MagrayPhysics;
import game.scenes.LevelScene;
public class MagRayHabit extends DefaultHabit {
private static final double RADIUS = 64;
private static final double BEAM_WIDTH = 0.5;
private DynamicHabit dynamic;
private Vector centre;
private Vector mousePos;
private Vector direction;
private Point startPoint;
private Circle endCircle;
private Rectangle bounds;
private Colour colour = new Colour(0, 0, 255, 128);
private State state = State.OFF;
private double power = 0;
public enum State {ATTRACT, REPEL, OFF}
public MagRayHabit(DynamicHabit dynamic) {
this.dynamic = dynamic;
centre = new Vector();
mousePos = new Vector();
direction = new Vector();
startPoint = new Point();
endCircle = new Circle();
bounds = new Rectangle();
}
@Override
protected void onBeforeMove(Keyboard keyboard, Mouse mouse, Clock clock) {
mousePos.set(mouse.getX(), mouse.getY());
mousePos.add(new Vector(((LevelScene) getScene()).getViewX(), ((LevelScene) getScene()).getViewY()));
// calculate MagRay direction
dynamic.getPolygon().getMid(centre);
direction.set(mousePos);
direction.subtract(centre);
direction.normalise();
// calculate state
if (mouse.isDown(Button.MB_LEFT)) {
state = State.ATTRACT;
colour = new Colour(0, 255, 0, 128);
} else if (mouse.isDown(Button.MB_RIGHT)) {
state = State.REPEL;
colour = new Colour(255, 0, 0, 128);
} else {
if (keyboard.isDown(Key.VK_SPACE)) {
if (power < 30) {
power += 0.5;
}
} else {
power = 0;
}
state = State.OFF;
colour = new Colour(0, 0, 255, 128);
return; // don't do MagRay calculations if it is unactivated
}
// calculate bounding box
direction.multiply(RADIUS);
startPoint.set(centre);
endCircle.set(startPoint.getPosition().add(direction), RADIUS*BEAM_WIDTH);
bounds = endCircle.getBounds();
bounds.add(startPoint);
direction.divide(RADIUS); // re-normalise direction
// find all Metal object in this triangle
Set<MetalHabit> set = ((LevelScene) getScene()).getSpace().findObjects(bounds.toPolygon(), MetalHabit.class);
double maxAccelDynamic = 0;
for (MetalHabit other : set) {
double time = MagrayPhysics.computeTime(other.getCircle(), centre, direction, BEAM_WIDTH);
if (!(time < RADIUS && time > 0)) {
continue;
}
Vector normal = MagrayPhysics.computeNormal(other.getCircle(), centre, direction, time);
double strength = timeToStrength(time, power);
double accelOther = strength / (1 + other.getMass()/dynamic.getMass());
other.addVelocity(normal.multiply(accelOther));
double accelDynamic = strength / (1 + dynamic.getMass()/other.getMass());
// TODO: find a better way of combining forces
if (Math.abs(accelDynamic) > Math.abs(maxAccelDynamic)) {
maxAccelDynamic = accelDynamic;
}
}
dynamic.addVelocity(new Vector(direction).normalise().multiply(maxAccelDynamic));
power = 0; // reset power once released
}
double timeToStrength (double time, double power) {
switch (state) {
case ATTRACT:
return 0.5 + power; // TODO: figure out what this curve should be
case REPEL:
return -0.5 - power; // TODO: figure out what this curve should be
}
return 0;
}
@Override
protected void onAfterMove() {
// update centre
dynamic.getPolygon().getMid(centre);
mousePos.set(centre);
mousePos.add(direction.multiply(RADIUS));
}
@Override
protected void onDraw(RenderTarget target) {
target.drawCircle(new Circle(mousePos, 4), colour);
target.drawCircle(new Circle(mousePos, 6), colour);
// target.fillPolygon(bounds.toPolygon(), colour);
}
}