emotionhero/app/src/main/java/com/rubenvandeven/emotionhero/Scenario.java

279 lines
7.1 KiB
Java
Raw Normal View History

2016-08-16 19:25:28 +02:00
package com.rubenvandeven.emotionhero;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import com.affectiva.android.affdex.sdk.Frame;
2016-08-16 19:25:28 +02:00
import com.affectiva.android.affdex.sdk.detector.Face;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
2016-08-19 13:38:59 +02:00
import java.util.Timer;
import java.util.TimerTask;
2016-08-16 19:25:28 +02:00
/**
* Created by ruben on 16/08/16.
*/
abstract public class Scenario {
public Bitmap currentFrameBitmap;
2016-08-19 13:38:59 +02:00
static int DESIRED_FPS = 25;
2016-08-16 19:25:28 +02:00
float duration = 0;
2016-08-19 13:38:59 +02:00
/**
* @deprecated
*/
2016-08-17 13:17:04 +02:00
long startTime = 0;
2016-08-19 13:38:59 +02:00
/**
* The timer that provides the tick
*/
Timer timer;
/**
* Increment on each tick
*/
float runningTime = -1;
boolean isRunning = false;
private GamingActivity _activity;
/**
* The scorres in this moment, as to draw them on the screen.
* Indexes are Emotion ordinals
*/
private Face currentFace;
2016-08-19 13:38:59 +02:00
2016-08-16 19:25:28 +02:00
ArrayList<Target> targets = new ArrayList<>();
abstract void createScenario();
class Target {
public Emotion emotion;
public float value;
public float timestamp;
2016-08-19 13:38:59 +02:00
public Score score;
2016-08-16 19:25:28 +02:00
}
ArrayList<Score> scores = new ArrayList<>();
class Score {
public float value;
/**
* Extra bonus given
*/
public boolean isSpotOn = false;
// public Bitmap image; //image at time of score
public Face face; // face at time of score
2016-08-16 19:25:28 +02:00
}
/**
* Constructor
*/
2016-08-19 13:38:59 +02:00
public Scenario(GamingActivity activity)
2016-08-16 19:25:28 +02:00
{
createScenario();
2016-08-19 13:38:59 +02:00
timer = new Timer("ScenarioTimer");
TimerTask tickTask;
tickTask = new TimerTask() {
@Override
public void run() {
// if (System.currentTimeMillis() - scheduledExecutionTime() >=
// MAX_TARDINESS)
// return; // Too late; skip this execution.
tick();
}
};
timer.schedule(tickTask, 0, 1000/DESIRED_FPS);
_activity = activity;
}
/**
* To be called on each timer tick
*/
public void tick()
{
if(!isRunning)
return;
runningTime += 1.0f/DESIRED_FPS;
if(isFinished()) {
stop();
return;
}
for (int i = targets.size() - 1; i >= 0; i--) {
Target target = targets.get(i);
// skip targets that are already scored
if(target.score != null) {
continue;
}
if(target.timestamp <= runningTime) {
float scored_value = target.emotion.getValueFromFace(currentFace);
2016-08-19 13:38:59 +02:00
float required_value = target.value;
Score score = new Score();
score.value = Math.round(100 - Math.abs(scored_value-required_value));
score.face = currentFace;
2016-08-19 13:38:59 +02:00
scores.add(score);
//
_activity.sound.play(_activity.soundIds.get(_activity.SOUND_SCORE), 1, 1,
1,0, score.value / 200f + 0.5f ); // play back the sound slower
// depending on score value
target.score = score;
}
}
2016-08-16 19:25:28 +02:00
}
2016-08-19 13:38:59 +02:00
2016-08-16 19:25:28 +02:00
/**
* Add a target on given timestamp
* @param emotion
* @param value
* @param timestamp
*/
public void setTarget(Emotion emotion, float value, float timestamp)
{
2016-08-17 13:17:04 +02:00
// Log.e(GamingActivity.LOG_TAG, "Set target:" + Float.toString(timestamp) + " " + Float.toString(duration));
2016-08-19 13:38:59 +02:00
if((timestamp + 1) > duration)
2016-08-16 19:25:28 +02:00
{
2016-08-19 13:38:59 +02:00
duration = timestamp + 1; // always a bit onger than last target, as it otherwise the game does not finish pretty
2016-08-16 19:25:28 +02:00
}
Target target = new Target();
target.timestamp = timestamp;
target.value = value;
target.emotion = emotion;
targets.add(target);
}
/**
* Add target after existing targets, give delta with last item instead of absolute time.
* @param emotion
* @param value
* @param interval
*/
public void addTarget(Emotion emotion, float value, float interval)
{
float timestamp;
if(targets.isEmpty()) {
timestamp = interval;
} else {
timestamp = targets.get(targets.size() - 1).timestamp + interval;
}
setTarget(emotion, value, timestamp);
}
2016-08-19 13:38:59 +02:00
/**
* @deprecated use @see tick()
* @param face
* @param timestamp
*/
2016-08-16 19:25:28 +02:00
public void validateFaceOnTime(Face face, float timestamp)
{
// TODO: interpolation of time
for (int i = targets.size() - 1; i >= 0; i--) {
Target target = targets.get(i);
if(target.timestamp > timestamp - 0.2 && target.timestamp < timestamp + 0.2) {
float scored_value = target.emotion.getValueFromFace(face);
float required_value = target.value;
Score score = new Score();
score.value = 100 - Math.abs(scored_value-required_value);
2016-08-19 13:38:59 +02:00
target.score = score;
2016-08-16 19:25:28 +02:00
scores.add(score);
}
}
}
public float getTotalScore()
{
float value = 0;
for (Score score : scores) {
value += score.value;
}
return value;
}
/**
* Check whether given timestamp is within duration of the scenario
* @param timestamp
* @return
*/
public boolean isWithinTime(float timestamp)
{
return timestamp <= duration;
}
2016-08-17 19:21:16 +02:00
public ArrayList<Target> getTargets() {
return targets;
}
2016-08-17 13:17:04 +02:00
2016-08-17 19:21:16 +02:00
/**
* Get the time within the scenario (so since start() has been called)
*/
public float getTime() {
2016-08-19 13:38:59 +02:00
return runningTime;
2016-08-17 13:17:04 +02:00
// if not started, don't move the labels, if started, move them by diff_y
2016-08-19 13:38:59 +02:00
// if(startTime == 0) {
// return 0;
// } else {
// float diff_t = ((System.currentTimeMillis() - startTime)) / (float) 1000;
// if(diff_t > duration) { // never larger than scenario duration
// return duration;
// }
// return diff_t;
// }
2016-08-17 13:17:04 +02:00
}
public void start()
{
startTime = System.currentTimeMillis();
2016-08-19 13:38:59 +02:00
isRunning = true;
}
public void pause() {
isRunning = false;
}
public void stop()
{
isRunning = false;
}
// TODO: create AttributeScoreCollection class, with this method.
public void setCurrentFace(Face face)
2016-08-19 13:38:59 +02:00
{
currentFace = face;
2016-08-19 13:38:59 +02:00
}
public boolean isFinished()
{
return runningTime > duration;
2016-08-17 13:17:04 +02:00
}
2016-08-20 18:22:01 +02:00
public Highscore getHighscore() {
if(!isFinished()) {
return null;
}
return new Highscore("Levelname!", getTotalScore());
}
public int getMaxScore() {
return targets.size() * 100;
}
2016-08-17 19:21:16 +02:00
// TODO: create a 'tick' that checks all current values with requirements and increases the timer etc
// TODO: ... if scenario is running. This internal times makes it easier to pause etc.
2016-08-16 19:25:28 +02:00
}