373 lines
9.8 KiB
Java
373 lines
9.8 KiB
Java
package com.rubenvandeven.emotionhero;
|
|
|
|
import android.graphics.Bitmap;
|
|
import android.util.Log;
|
|
|
|
import com.affectiva.android.affdex.sdk.detector.Face;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Date;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import java.util.Timer;
|
|
import java.util.TimerTask;
|
|
|
|
/**
|
|
* Created by ruben on 16/08/16.
|
|
*/
|
|
|
|
public class Scenario {
|
|
|
|
public int id;
|
|
|
|
public Bitmap currentFrameBitmap;
|
|
|
|
public static final int LVL_NONE = 0;
|
|
public static final int LVL_ANGER = 1;
|
|
public static final int LVL_JOY = 2;
|
|
public static final int LVL_SURPRISE = 3;
|
|
public static final int LVL_SADDNESS= 4;
|
|
|
|
// the levels in the right order.
|
|
public static final ArrayList<Integer> SCENARIOS = new ArrayList<Integer>() {{
|
|
add(LVL_ANGER);
|
|
add(LVL_JOY);
|
|
add(LVL_SURPRISE);
|
|
add(LVL_SADDNESS);
|
|
}};
|
|
|
|
static int DESIRED_FPS = 25;
|
|
|
|
float duration = 0;
|
|
|
|
/**
|
|
* Minimum score to be able to pass to the next level.
|
|
*/
|
|
float minimumScore = 0;
|
|
|
|
/**
|
|
* If a game is beign played.
|
|
*/
|
|
Game game;
|
|
|
|
/**
|
|
* @deprecated
|
|
*/
|
|
long startTime = 0;
|
|
|
|
/**
|
|
* 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;
|
|
|
|
ArrayList<Target> targets = new ArrayList<>();
|
|
|
|
class Target {
|
|
public int index;
|
|
public Emotion emotion;
|
|
public float value;
|
|
public float timestamp;
|
|
public boolean isHit = false;
|
|
}
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
public Scenario(int lvl_id, GamingActivity activity)
|
|
{
|
|
// go to first scenario if unexisting is given
|
|
if(!SCENARIOS.contains(lvl_id)) {
|
|
lvl_id = SCENARIOS.get(0);
|
|
}
|
|
|
|
this.id = lvl_id;
|
|
_activity = activity;
|
|
createTargets();
|
|
}
|
|
|
|
public void init() {
|
|
|
|
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);
|
|
this.game = new Game(null, this, 0, new Date(), null);
|
|
}
|
|
|
|
/**
|
|
* To be called on each timer tick
|
|
*/
|
|
public void tick()
|
|
{
|
|
if(!isRunning)
|
|
return;
|
|
|
|
runningTime += 1.0f/DESIRED_FPS;
|
|
|
|
if(isFinished()) {
|
|
stop();
|
|
return;
|
|
}
|
|
|
|
for(Target target: targets) {
|
|
// skip targets that are already scored
|
|
if(target.isHit == true) {
|
|
continue;
|
|
}
|
|
if(target.timestamp <= runningTime) {
|
|
float scored_value = target.emotion.getValueFromFace(currentFace);
|
|
float required_value = target.value;
|
|
float score = 100 - Math.abs(scored_value-required_value);
|
|
Hit hit = new Hit(target, game, currentFace, score);
|
|
|
|
//
|
|
_activity.sound.play(_activity.soundIds.get(_activity.SOUND_SCORE), 1, 1,
|
|
1,0, hit.score / 200f + 0.5f ); // play back the sound slower
|
|
// depending on hit value
|
|
target.isHit = true;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public Target getTargetByIndex(int target_index) {
|
|
return targets.get(target_index-1);
|
|
}
|
|
|
|
/**
|
|
* Add a target on given timestamp
|
|
* @param emotion
|
|
* @param value
|
|
* @param timestamp
|
|
*/
|
|
public void setTarget(Emotion emotion, float value, float timestamp)
|
|
{
|
|
// Log.e(GamingActivity.LOG_TAG, "Set target:" + Float.toString(timestamp) + " " + Float.toString(duration));
|
|
if((timestamp + 1) > duration)
|
|
{
|
|
duration = timestamp + 1; // always a bit onger than last target, as it otherwise the game does not finish pretty
|
|
}
|
|
Target target = new Target();
|
|
target.timestamp = timestamp;
|
|
target.value = value;
|
|
target.emotion = emotion;
|
|
target.index = targets.size() + 1;
|
|
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);
|
|
}
|
|
|
|
public float getHitTotalValue()
|
|
{
|
|
float value = 0;
|
|
for (Hit hit : game.hits.values()) {
|
|
value += hit.score;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
/**
|
|
* Check whether given timestamp is within duration of the scenario
|
|
* @param timestamp
|
|
* @return
|
|
*/
|
|
public boolean isWithinTime(float timestamp)
|
|
{
|
|
return timestamp <= duration;
|
|
}
|
|
|
|
public ArrayList<Target> getTargets() {
|
|
return targets;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the time within the scenario (so since start() has been called)
|
|
*/
|
|
public float getTime() {
|
|
return runningTime;
|
|
// if not started, don't move the labels, if started, move them by diff_y
|
|
// 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;
|
|
// }
|
|
}
|
|
|
|
public void start()
|
|
{
|
|
startTime = System.currentTimeMillis();
|
|
isRunning = true;
|
|
}
|
|
|
|
public void pause() {
|
|
isRunning = false;
|
|
}
|
|
|
|
public void stop()
|
|
{
|
|
isRunning = false;
|
|
}
|
|
|
|
|
|
// TODO: create AttributeScoreCollection class, with this method.
|
|
public void setCurrentFace(Face face)
|
|
{
|
|
currentFace = face;
|
|
}
|
|
|
|
public boolean isFinished()
|
|
{
|
|
return runningTime > duration;
|
|
}
|
|
|
|
public Score getScore() {
|
|
if(!isFinished()) {
|
|
return null;
|
|
}
|
|
|
|
Score score = new Score(id, getHitTotalValue());
|
|
score.setTargets(targets);
|
|
return score;
|
|
}
|
|
|
|
public int getMaxScore() {
|
|
return targets.size() * 100;
|
|
}
|
|
|
|
public void createTargets() {
|
|
switch(id) {
|
|
case LVL_ANGER:
|
|
setTarget(Emotion.ANGER, 100, 1);
|
|
setTarget(Emotion.ANGER, 100, 2);
|
|
setTarget(Emotion.ANGER, 10, 3);
|
|
setTarget(Emotion.ANGER, 20, 4);
|
|
setTarget(Emotion.ANGER, 40, 5);
|
|
setTarget(Emotion.ANGER, 70, 6);
|
|
setTarget(Emotion.ANGER, 100, 7);
|
|
break;
|
|
case LVL_JOY:
|
|
setTarget(Emotion.JOY, 100, 1);
|
|
setTarget(Emotion.JOY, 100, 2);
|
|
setTarget(Emotion.JOY, 100, 4);
|
|
setTarget(Emotion.CONTEMPT, 20, 4);
|
|
setTarget(Emotion.ANGER, 100, 5);
|
|
setTarget(Emotion.JOY, 100, 7);
|
|
setTarget(Emotion.ANGER, 100, 9);
|
|
setTarget(Emotion.JOY, 100, 11);
|
|
setTarget(Emotion.JOY, 70, 12);
|
|
setTarget(Emotion.JOY, 60, 13);
|
|
setTarget(Emotion.JOY, 30, 14);
|
|
setTarget(Emotion.JOY, 10, 14.5f);
|
|
setTarget(Emotion.ANGER, 100, 16);
|
|
setTarget(Emotion.JOY, 100, 17);
|
|
setTarget(Emotion.JOY, 100, 18);
|
|
setTarget(Emotion.JOY, 100, 19);
|
|
setTarget(Emotion.JOY, 100, 20);
|
|
break;
|
|
case LVL_SURPRISE:
|
|
setTarget(Emotion.SURPRISE, 20, 1);
|
|
setTarget(Emotion.SURPRISE, 50, 2);
|
|
setTarget(Emotion.SURPRISE, 80, 3);
|
|
setTarget(Emotion.SURPRISE, 100, 4);
|
|
break;
|
|
case LVL_SADDNESS:
|
|
setTarget(Emotion.SADNESS, 20, 1);
|
|
setTarget(Emotion.SADNESS, 50, 2);
|
|
setTarget(Emotion.SADNESS, 80, 3);
|
|
setTarget(Emotion.SADNESS, 100, 4);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
public int getNextLevelId() {
|
|
int nextIdx = SCENARIOS.indexOf(id) + 1;
|
|
if(SCENARIOS.size() <= nextIdx) {
|
|
return SCENARIOS.get(0);
|
|
}
|
|
return SCENARIOS.get(nextIdx);
|
|
}
|
|
|
|
public boolean isFinalLevel() {
|
|
if(SCENARIOS.get(SCENARIOS.size()-1) == id)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
public boolean isHigherThen(int lvl_id) {
|
|
return isHigherLevel(id, lvl_id);
|
|
}
|
|
|
|
public static boolean isHigherLevel(int lvl_id, int then_lvl_id) {
|
|
if(lvl_id == then_lvl_id) {
|
|
return false;
|
|
}
|
|
|
|
return SCENARIOS.indexOf(lvl_id) > SCENARIOS.indexOf(then_lvl_id);
|
|
}
|
|
|
|
public String toString() {
|
|
|
|
switch(id) {
|
|
case LVL_ANGER:
|
|
return "I am sooo ANGRY";
|
|
case LVL_JOY:
|
|
return "Let's be joyfull!";
|
|
case LVL_SURPRISE:
|
|
return "What a surprise";
|
|
case LVL_SADDNESS:
|
|
return "Please, don't cry...";
|
|
}
|
|
return "...";
|
|
}
|
|
|
|
public Hit getHitForTarget(Target target) {
|
|
return game.hits.get(target.index);
|
|
}
|
|
|
|
}
|