Refactor the highscore to hits, score and playerinfo.

Save info it as JSON object and recover it on next run.
Which means that practically local highscores are working Fix #2
Also next level now works
This commit is contained in:
Ruben 2016-08-20 22:58:32 +01:00
parent 8f65131b7a
commit 3d45a25895
6 changed files with 124 additions and 92 deletions

View file

@ -42,7 +42,7 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL
public final static String INTENT_EXTRA_SCENARIO = "com.rubenvandeven.emotionhero.LEVEL";
final static String LOG_TAG = "EmotionHero";
final static String HIGHSCORE_FILENAME = "highscores.json";
final static String PLAYERINFO_FILENAME = "playerinfo.json";
final int PERMISSIONS_REQUEST_CAMERA = 1;
@ -148,6 +148,7 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL
// currentScenario = new ScenarioAnger(this);
currentScenario = new Scenario(scenarioLvlId, this);
currentScenario.init(); // "start the clock"...
scenarioView = new ScenarioView(this, currentScenario);
RelativeLayout.LayoutParams scenarioViewParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
@ -221,7 +222,7 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL
@Override
/**
* Detector callback gives the faces found so we can match their scores to the given scenario.
* Detector callback gives the faces found so we can match their hits to the given scenario.
*/
public void onImageResults(List<Face> list, Frame frame, float timestamp) {
// frame.getOriginalBitmapFrame()
@ -341,34 +342,34 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL
sound = new SoundPool(5, AudioManager.STREAM_MUSIC,0);
}
public Highscores getHighscores() {
public PlayerInfo getPlayerInfo() {
try{
FileInputStream fis = openFileInput(HIGHSCORE_FILENAME);
FileInputStream fis = openFileInput(PLAYERINFO_FILENAME );
StringBuilder builder = new StringBuilder();
int ch;
while((ch = fis.read()) != -1){
builder.append((char)ch);
}
return Highscores.fromJson(builder.toString());
return PlayerInfo.fromJson(builder.toString());
} catch (IOException e) {
return new Highscores();
return new PlayerInfo();
}
}
public void addHighscore(Highscore score) {
Highscores scores = getHighscores();
scores.add(score);
saveHighscores(scores);
public void savePlayerScore(Score score) {
PlayerInfo playerInfo = getPlayerInfo();
playerInfo.addScore(score);
savePlayerInfo(playerInfo);
}
public void saveHighscores(Highscores scores) {
public void savePlayerInfo(PlayerInfo playerInfo) {
try {
FileOutputStream fos = openFileOutput(HIGHSCORE_FILENAME, Context.MODE_PRIVATE);
fos.write(scores.toJson().getBytes());
FileOutputStream fos = openFileOutput(PLAYERINFO_FILENAME, Context.MODE_PRIVATE);
fos.write(playerInfo.toJson().getBytes());
fos.close();
} catch(IOException e) {
// for now skip error
Log.e(LOG_TAG, "Could not save highscore!");
Log.e(LOG_TAG, "Could not save player information!");
}
}
@ -380,8 +381,9 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL
nextLvlButton.setVisibility(View.VISIBLE);
}
Highscores scores = getHighscores();
Highscore score = currentScenario.getHighscore();
PlayerInfo playerInfo = getPlayerInfo();
ScoreList scores = playerInfo.getScoresForLevel(currentScenario.id);
Score score = currentScenario.getScore();
if(score.score == currentScenario.getMaxScore()) {
// Maximum SCORE!!
@ -398,13 +400,13 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL
// show the highscores (top 3?)...
scores.add(score);
saveHighscores(scores);
savePlayerInfo(playerInfo);
String highscoreText = "TOPSCORES\n";
Highscores topscores = scores.getTopN(3); // TODO: only highscores for current lEVEL!!!!!!!
ScoreList topscores = scores.getTopN(3); // TODO: only highscores for current lEVEL!!!!!!!
int i = 0;
for(Highscore topscore: topscores) {
for(Score topscore: topscores) {
i++;
highscoreText += String.format("%1$d. %2$.2f\n", i, topscore.score); //make line by line elements
}

View file

@ -0,0 +1,50 @@
package com.rubenvandeven.emotionhero;
import android.support.annotation.NonNull;
import android.util.SparseArray;
import com.google.gson.Gson;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Created by ruben on 20/08/16.
*/
public class PlayerInfo {
public Map<Integer, ScoreList> levelScores = new HashMap<>();
public ScoreList getScoresForLevel(int lvl_id) {
ScoreList scoreList;
if(!levelScores.containsKey(lvl_id)) {
scoreList = new ScoreList();
levelScores.put(lvl_id, scoreList);
} else {
scoreList = levelScores.get(lvl_id);
}
return scoreList;
}
/**
* The individual score object contains the level id, so we can fetch the corresponding
* scorelist to add this score
* @param score
*/
public void addScore(Score score) {
ScoreList scoreList = getScoresForLevel(score.lvl_id);
scoreList.add(score);
}
public static PlayerInfo fromJson(String json) {
Gson gson = new Gson();
return gson.fromJson(json, PlayerInfo.class);
}
public String toJson() {
Gson gson = new Gson();
return gson.toJson(this);
}
}

View file

@ -1,15 +1,11 @@
package com.rubenvandeven.emotionhero;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import com.affectiva.android.affdex.sdk.Frame;
import com.affectiva.android.affdex.sdk.detector.Face;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
@ -71,19 +67,19 @@ public class Scenario {
public Emotion emotion;
public float value;
public float timestamp;
public Score score;
public Hit hit;
}
ArrayList<Score> scores = new ArrayList<>();
ArrayList<Hit> hits = new ArrayList<>();
class Score {
class Hit {
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
// public Bitmap image; //image at time of hit
public Face face; // face at time of hit
}
/**
@ -99,7 +95,6 @@ public class Scenario {
this.id = lvl_id;
_activity = activity;
createTargets();
init();
}
public void init() {
@ -137,22 +132,22 @@ public class Scenario {
for (int i = targets.size() - 1; i >= 0; i--) {
Target target = targets.get(i);
// skip targets that are already scored
if(target.score != null) {
if(target.hit != null) {
continue;
}
if(target.timestamp <= runningTime) {
float scored_value = target.emotion.getValueFromFace(currentFace);
float required_value = target.value;
Score score = new Score();
score.value = Math.round(100 - Math.abs(scored_value-required_value));
score.face = currentFace;
scores.add(score);
Hit hit = new Hit();
hit.value = Math.round(100 - Math.abs(scored_value-required_value));
hit.face = currentFace;
hits.add(hit);
//
_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;
1,0, hit.value / 200f + 0.5f ); // play back the sound slower
// depending on hit value
target.hit = hit;
}
}
@ -209,19 +204,19 @@ public class Scenario {
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);
target.score = score;
scores.add(score);
Hit hit = new Hit();
hit.value = 100 - Math.abs(scored_value-required_value);
target.hit = hit;
hits.add(hit);
}
}
}
public float getTotalScore()
public float getHitTotalValue()
{
float value = 0;
for (Score score : scores) {
value += score.value;
for (Hit hit : hits) {
value += hit.value;
}
return value;
}
@ -285,12 +280,12 @@ public class Scenario {
return runningTime > duration;
}
public Highscore getHighscore() {
public Score getScore() {
if(!isFinished()) {
return null;
}
return new Highscore("Levelname!", getTotalScore());
return new Score(id, getHitTotalValue());
}
public int getMaxScore() {
@ -300,6 +295,9 @@ public class Scenario {
public void createTargets() {
switch(id) {
case LVL_ANGER:
setTarget(Emotion.ANGER, 10, 1);
break;
case LVL_JOY:
setTarget(Emotion.ANGER, 10, 1);
setTarget(Emotion.ANGER, 20, 2);
setTarget(Emotion.ANGER, 40, 3);
@ -310,8 +308,6 @@ public class Scenario {
setTarget(Emotion.JOY, 100, 15);
setTarget(Emotion.ANGER, 100, 20);
break;
case LVL_JOY:
break;
case LVL_SURPRISE:
setTarget(Emotion.SURPRISE, 20, 1);
setTarget(Emotion.SURPRISE, 50, 2);

View file

@ -144,7 +144,7 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback
float bottomline_height = height * (float) 0.8;
// draw current scores:
// draw current hits:
float used_width = (float) 0.8; // 0.7: only use center
float padding_left = canvas.getWidth() * (1-used_width) / 2;
float step_y = (canvas.getWidth() * used_width) / Emotion.values().length;
@ -189,21 +189,21 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback
float diff_y = sec_height * _scenario.getTime();
for(Scenario.Target target: _scenario.getTargets()) {
// Paint targetPaint = (target.score == null) ? emoPaints.get(target.emotion) : emoScoredPaints.get(target.emotion);
// Paint targetPaint = (target.hit == null) ? emoPaints.get(target.emotion) : emoScoredPaints.get(target.emotion);
float cy = bottomline_height - (target.timestamp * sec_height) + diff_y;
float cx = padding_left + (step_y * target.emotion.ordinal() + step_y / 2);
canvas.drawCircle(cx, cy, max_ball_radius * target.value/100, emoPaints.get(target.emotion));
if(target.score != null) {
canvas.drawText(Float.toString(target.score.value), cx, cy, emoPaints.get(target.emotion));
canvas.drawCircle(cx, cy, max_ball_radius * target.score.value/100, emoScoredPaints.get(target.emotion));
if(target.hit != null) {
canvas.drawText(Float.toString(target.hit.value), cx, cy, emoPaints.get(target.emotion));
canvas.drawCircle(cx, cy, max_ball_radius * target.hit.value/100, emoScoredPaints.get(target.emotion));
// TODO: Use target.score.face to set Rect src.
// if(target.score.image != null) {
// TODO: Use target.hit.face to set Rect src.
// if(target.hit.image != null) {
// Rect rect = new Rect((int) cx-10, (int) cy-10, (int) cx+10, (int) cy+10);
// canvas.drawBitmap(target.score.image, null, rect, null);
// canvas.drawBitmap(target.hit.image, null, rect, null);
// }
}
@ -212,9 +212,9 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback
// canvas.drawText(target_text, cx, y_pos + diff_y , emoPaint);
}
// draw the score middle bottom;
// draw the hit middle bottom;
Paint usedScorePaint = _scenario.isFinished() ? scoreFinishedPaint : scorePaint;
String scoreText = String.format("Total: %1$.0f", _scenario.getTotalScore());
String scoreText = String.format("Total: %1$.0f", _scenario.getHitTotalValue());
Rect scoreTextBounds = new Rect();
usedScorePaint.getTextBounds(scoreText, 0, scoreText.length(), scoreTextBounds);

View file

@ -6,13 +6,13 @@ import java.util.Date;
* Created by ruben on 19/08/16.
*/
public class Highscore {
String level;
public class Score {
int lvl_id;
float score;
Date time;
public Highscore(String level, float score) {
this.level = level;
public Score(int lvl_id, float score) {
this.lvl_id = lvl_id;
this.score = score;
this.time = new Date();
}

View file

@ -1,38 +1,22 @@
package com.rubenvandeven.emotionhero;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
/**
* Created by ruben on 19/08/16.
*/
public class Highscores extends ArrayList<Highscore>{
public static Highscores fromJson(String json) {
Gson gson = new Gson();
return gson.fromJson(json, Highscores.class);
}
public String toJson() {
Gson gson = new Gson();
return gson.toJson(this);
}
public class ScoreList extends ArrayList<Score>{
/**
* Check if given highscore is highest score in this set.
* Check if given highscore is highest hit in this set.
* @param score
* @return
*/
public boolean isHighest(Highscore score) {
for(Highscore s: this) {
public boolean isHighest(Score score) {
for(Score s: this) {
if(s == score) // to allow comparison of items that are already in the set
continue; // skip if it wants to compare with self.
@ -44,12 +28,12 @@ public class Highscores extends ArrayList<Highscore>{
}
/**
* Get the n highest scores
* Get the n highest hits
*/
public Highscores getTopN(int n) {
Collections.sort(this, new Comparator<Highscore>() {
public ScoreList getTopN(int n) {
Collections.sort(this, new Comparator<Score>() {
@Override
public int compare(Highscore score1, Highscore score2)
public int compare(Score score1, Score score2)
{
// return highest first
return score1.score > score2.score ? -1 : score1.score == score2.score ? 0 : 1;
@ -59,7 +43,7 @@ public class Highscores extends ArrayList<Highscore>{
if(n > this.size())
n = this.size();
Highscores scores = new Highscores();
ScoreList scores = new ScoreList();
for (int i = 0; i < n; i++) {
scores.add(this.get(i));
}
@ -67,13 +51,13 @@ public class Highscores extends ArrayList<Highscore>{
}
/**
* Get the n highest scores
* Get the n highest hits
* @todo only for current level!!
*/
public Highscores getLast(Integer n) {
Collections.sort(this, new Comparator<Highscore>() {
public ScoreList getLast(Integer n) {
Collections.sort(this, new Comparator<Score>() {
@Override
public int compare(Highscore score1, Highscore score2)
public int compare(Score score1, Score score2)
{
// return newest first
return score1.time.before(score2.time) ? -1 : score1.time == score2.time ? 0 : 1;
@ -87,7 +71,7 @@ public class Highscores extends ArrayList<Highscore>{
if(n > this.size())
n = this.size();
Highscores scores = new Highscores();
ScoreList scores = new ScoreList();
for (int i = 0; i < n; i++) {
scores.add(this.get(i));
}