package fr.umlv.escapeir.gesture;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.util.ArrayList;
import java.util.LinkedList;
import org.jbox2d.common.Vec2;
import fr.umlv.escapeir.physic.World;
import fr.umlv.escapeir.utils.Renderable;
import fr.umlv.zen2.ApplicationContext;
import fr.umlv.zen2.MotionEvent;
/**
* Handle gestures catching and recognition
* A gesture being a movement starting when the left-click is pressed and ending when the left click is released
* @author Joachim ARCHAMBAULT, Alexandre ANDRE
*
*/
public final class GestureRecognizer implements Renderable {
/**
* Enumeration representing types of gestures
* @author Joachim ARCHAMBAULT, Alexandre ANDRE
*/
public enum GestureID {
/**
* A simple movement on the left and slightly forward
*/
LEFT_DRIFT,
/**
* A simple movement on the left and slightly forward
*/
RIGHT_DRIFT,
/**
* A simple backward movement (kind of defensive)
*/
BACKOFF,
/**
* A forward movement with shoot
*/
ATTACK,
/**
* A simple shoot
*/
SHOOT,
/**
* A looping on the left
*/
LEFT_LOOPING,
/**
* A looping on the right
*/
RIGHT_LOOPING,
/**
* Represents an invalid gesture
*/
INVALID,
/**
* Represents an unknown or unfinished gesture
*/
UNKNOWN,
/**
* A click to pick a weapon
*/
SELECT,
}
private static GestureRecognizer instance = null;
private boolean capturing;
private GestureID recognizedGesture;
private GestureID drawedRecognizedGesture;
private ArrayList<Point> points;
private LinkedList<Gesture> gestures;
private GestureRecognizer() {
this.capturing = false;
this.setGesture(GestureID.UNKNOWN);
this.points = new ArrayList<>();
this.gestures = new LinkedList<>();
this.gestures.add(new Backoff());
this.gestures.add(new Shoot());
this.gestures.add(new Attack());
this.gestures.add(new LeftLooping());
this.gestures.add(new RightLooping());
this.gestures.add(new LeftDrift());
this.gestures.add(new RightDrift());
this.gestures.add(new Select());
}
/**
* Returns the unique instance of GestureRecognizer
* @return an instance of GestureRecognizer
*/
public static GestureRecognizer getInstance() {
if (GestureRecognizer.instance == null)
GestureRecognizer.instance = new GestureRecognizer();
return GestureRecognizer.instance;
}
/**
* Update the point list representing a possible gesture
* @param context The application context to handle event
*/
public void update(ApplicationContext context) {
while (true) {
final MotionEvent event = context.pollMotion();
if (event == null)
break;
if (this.capturing == false && event.getKind() == MotionEvent.Kind.ACTION_DOWN) {
this.points = new ArrayList<>();
this.capturing = true;
this.setGesture(GestureID.UNKNOWN);
this.points.add(new Point(event.getX(), event.getY()));
} else if (this.capturing == true && event.getKind() == MotionEvent.Kind.ACTION_UP) {
this.capturing = false;
this.analyze();
} else if (this.capturing == true && event.getKind() == MotionEvent.Kind.ACTION_MOVE) {
this.points.add(new Point(event.getX(), event.getY()));
}
}
}
/**
* Analyze the list of points and try to define a gesture
*/
private void analyze() {
this.setGesture(GestureID.INVALID);
for (Gesture gesture : this.gestures) {
if (!gesture.recognized(this.points))
continue;
this.setGesture(gesture.getId());
return;
}
}
/**
* Draw the gesture on the screen
*/
public void render(Graphics2D graphics) {
if (this.points.size() < 2)
return;
Point last = this.points.get(0);
for (Point point : this.points) {
if (this.drawedRecognizedGesture == GestureID.UNKNOWN)
graphics.setColor(Color.WHITE);
else if (this.drawedRecognizedGesture == GestureID.INVALID)
graphics.setColor(Color.RED);
else {
graphics.setColor(Color.GREEN);
}
graphics.setStroke(new BasicStroke(5));
graphics.drawLine((int) last.getX(), (int) last.getY(), (int) point.getX(), (int) point.getY());
last = point;
}
}
/**
* Return the analyzed gesture
* @return the gesture identifier
*/
public GestureID getGesture() {
return this.recognizedGesture;
}
/**
* Clear the analyzed gesture
*/
public void clearGesture() {
this.recognizedGesture = GestureID.UNKNOWN;
}
private void setGesture(GestureID gesture) {
this.recognizedGesture = gesture;
this.drawedRecognizedGesture = gesture;
}
public Point getStartingPoint() {
return this.points.get(0);
}
protected Point getEndingPoint() {
return this.points.get(this.points.size() - 1);
}
public ArrayList<Point> getPoints(){
return this.points;
}
/**
* Returns the distance between the first and last stored points
* @return distance between first and last point
*/
public double getDistance() {
if (this.points.size() < 2)
return 0;
return this.getEndingPoint().distance(this.getStartingPoint());
}
/**
* Returns the distance angle the first and last stored points
* @return angle between first and last point
*/
public Vec2 getAngle() {
if (this.points.size() < 2)
return new Vec2(0, 0);
return World.angle(this.getStartingPoint(), this.getEndingPoint());
}
}