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"; public final static String INTENT_EXTRA_SCENARIO = "com.rubenvandeven.emotionhero.LEVEL";
final static String LOG_TAG = "EmotionHero"; 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; final int PERMISSIONS_REQUEST_CAMERA = 1;
@ -148,6 +148,7 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL
// currentScenario = new ScenarioAnger(this); // currentScenario = new ScenarioAnger(this);
currentScenario = new Scenario(scenarioLvlId, this); currentScenario = new Scenario(scenarioLvlId, this);
currentScenario.init(); // "start the clock"...
scenarioView = new ScenarioView(this, currentScenario); scenarioView = new ScenarioView(this, currentScenario);
RelativeLayout.LayoutParams scenarioViewParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 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 @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) { public void onImageResults(List<Face> list, Frame frame, float timestamp) {
// frame.getOriginalBitmapFrame() // frame.getOriginalBitmapFrame()
@ -341,34 +342,34 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL
sound = new SoundPool(5, AudioManager.STREAM_MUSIC,0); sound = new SoundPool(5, AudioManager.STREAM_MUSIC,0);
} }
public Highscores getHighscores() { public PlayerInfo getPlayerInfo() {
try{ try{
FileInputStream fis = openFileInput(HIGHSCORE_FILENAME); FileInputStream fis = openFileInput(PLAYERINFO_FILENAME );
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
int ch; int ch;
while((ch = fis.read()) != -1){ while((ch = fis.read()) != -1){
builder.append((char)ch); builder.append((char)ch);
} }
return Highscores.fromJson(builder.toString()); return PlayerInfo.fromJson(builder.toString());
} catch (IOException e) { } catch (IOException e) {
return new Highscores(); return new PlayerInfo();
} }
} }
public void addHighscore(Highscore score) { public void savePlayerScore(Score score) {
Highscores scores = getHighscores(); PlayerInfo playerInfo = getPlayerInfo();
scores.add(score); playerInfo.addScore(score);
saveHighscores(scores); savePlayerInfo(playerInfo);
} }
public void saveHighscores(Highscores scores) { public void savePlayerInfo(PlayerInfo playerInfo) {
try { try {
FileOutputStream fos = openFileOutput(HIGHSCORE_FILENAME, Context.MODE_PRIVATE); FileOutputStream fos = openFileOutput(PLAYERINFO_FILENAME, Context.MODE_PRIVATE);
fos.write(scores.toJson().getBytes()); fos.write(playerInfo.toJson().getBytes());
fos.close(); fos.close();
} catch(IOException e) { } catch(IOException e) {
// for now skip error // 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); nextLvlButton.setVisibility(View.VISIBLE);
} }
Highscores scores = getHighscores(); PlayerInfo playerInfo = getPlayerInfo();
Highscore score = currentScenario.getHighscore(); ScoreList scores = playerInfo.getScoresForLevel(currentScenario.id);
Score score = currentScenario.getScore();
if(score.score == currentScenario.getMaxScore()) { if(score.score == currentScenario.getMaxScore()) {
// Maximum SCORE!! // Maximum SCORE!!
@ -398,13 +400,13 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL
// show the highscores (top 3?)... // show the highscores (top 3?)...
scores.add(score); scores.add(score);
saveHighscores(scores); savePlayerInfo(playerInfo);
String highscoreText = "TOPSCORES\n"; 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; int i = 0;
for(Highscore topscore: topscores) { for(Score topscore: topscores) {
i++; i++;
highscoreText += String.format("%1$d. %2$.2f\n", i, topscore.score); //make line by line elements 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; package com.rubenvandeven.emotionhero;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log; import android.util.Log;
import com.affectiva.android.affdex.sdk.Frame;
import com.affectiva.android.affdex.sdk.detector.Face; import com.affectiva.android.affdex.sdk.detector.Face;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
@ -71,19 +67,19 @@ public class Scenario {
public Emotion emotion; public Emotion emotion;
public float value; public float value;
public float timestamp; 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; public float value;
/** /**
* Extra bonus given * Extra bonus given
*/ */
public boolean isSpotOn = false; public boolean isSpotOn = false;
// public Bitmap image; //image at time of score // public Bitmap image; //image at time of hit
public Face face; // face at time of score public Face face; // face at time of hit
} }
/** /**
@ -99,7 +95,6 @@ public class Scenario {
this.id = lvl_id; this.id = lvl_id;
_activity = activity; _activity = activity;
createTargets(); createTargets();
init();
} }
public void init() { public void init() {
@ -137,22 +132,22 @@ public class Scenario {
for (int i = targets.size() - 1; i >= 0; i--) { for (int i = targets.size() - 1; i >= 0; i--) {
Target target = targets.get(i); Target target = targets.get(i);
// skip targets that are already scored // skip targets that are already scored
if(target.score != null) { if(target.hit != null) {
continue; continue;
} }
if(target.timestamp <= runningTime) { if(target.timestamp <= runningTime) {
float scored_value = target.emotion.getValueFromFace(currentFace); float scored_value = target.emotion.getValueFromFace(currentFace);
float required_value = target.value; float required_value = target.value;
Score score = new Score(); Hit hit = new Hit();
score.value = Math.round(100 - Math.abs(scored_value-required_value)); hit.value = Math.round(100 - Math.abs(scored_value-required_value));
score.face = currentFace; hit.face = currentFace;
scores.add(score); hits.add(hit);
// //
_activity.sound.play(_activity.soundIds.get(_activity.SOUND_SCORE), 1, 1, _activity.sound.play(_activity.soundIds.get(_activity.SOUND_SCORE), 1, 1,
1,0, score.value / 200f + 0.5f ); // play back the sound slower 1,0, hit.value / 200f + 0.5f ); // play back the sound slower
// depending on score value // depending on hit value
target.score = score; target.hit = hit;
} }
} }
@ -209,19 +204,19 @@ public class Scenario {
if(target.timestamp > timestamp - 0.2 && target.timestamp < timestamp + 0.2) { if(target.timestamp > timestamp - 0.2 && target.timestamp < timestamp + 0.2) {
float scored_value = target.emotion.getValueFromFace(face); float scored_value = target.emotion.getValueFromFace(face);
float required_value = target.value; float required_value = target.value;
Score score = new Score(); Hit hit = new Hit();
score.value = 100 - Math.abs(scored_value-required_value); hit.value = 100 - Math.abs(scored_value-required_value);
target.score = score; target.hit = hit;
scores.add(score); hits.add(hit);
} }
} }
} }
public float getTotalScore() public float getHitTotalValue()
{ {
float value = 0; float value = 0;
for (Score score : scores) { for (Hit hit : hits) {
value += score.value; value += hit.value;
} }
return value; return value;
} }
@ -285,12 +280,12 @@ public class Scenario {
return runningTime > duration; return runningTime > duration;
} }
public Highscore getHighscore() { public Score getScore() {
if(!isFinished()) { if(!isFinished()) {
return null; return null;
} }
return new Highscore("Levelname!", getTotalScore()); return new Score(id, getHitTotalValue());
} }
public int getMaxScore() { public int getMaxScore() {
@ -300,6 +295,9 @@ public class Scenario {
public void createTargets() { public void createTargets() {
switch(id) { switch(id) {
case LVL_ANGER: case LVL_ANGER:
setTarget(Emotion.ANGER, 10, 1);
break;
case LVL_JOY:
setTarget(Emotion.ANGER, 10, 1); setTarget(Emotion.ANGER, 10, 1);
setTarget(Emotion.ANGER, 20, 2); setTarget(Emotion.ANGER, 20, 2);
setTarget(Emotion.ANGER, 40, 3); setTarget(Emotion.ANGER, 40, 3);
@ -310,8 +308,6 @@ public class Scenario {
setTarget(Emotion.JOY, 100, 15); setTarget(Emotion.JOY, 100, 15);
setTarget(Emotion.ANGER, 100, 20); setTarget(Emotion.ANGER, 100, 20);
break; break;
case LVL_JOY:
break;
case LVL_SURPRISE: case LVL_SURPRISE:
setTarget(Emotion.SURPRISE, 20, 1); setTarget(Emotion.SURPRISE, 20, 1);
setTarget(Emotion.SURPRISE, 50, 2); 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; 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 used_width = (float) 0.8; // 0.7: only use center
float padding_left = canvas.getWidth() * (1-used_width) / 2; float padding_left = canvas.getWidth() * (1-used_width) / 2;
float step_y = (canvas.getWidth() * used_width) / Emotion.values().length; 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(); float diff_y = sec_height * _scenario.getTime();
for(Scenario.Target target: _scenario.getTargets()) { 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 cy = bottomline_height - (target.timestamp * sec_height) + diff_y;
float cx = padding_left + (step_y * target.emotion.ordinal() + step_y / 2); 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)); canvas.drawCircle(cx, cy, max_ball_radius * target.value/100, emoPaints.get(target.emotion));
if(target.score != null) { if(target.hit != null) {
canvas.drawText(Float.toString(target.score.value), cx, cy, emoPaints.get(target.emotion)); canvas.drawText(Float.toString(target.hit.value), cx, cy, emoPaints.get(target.emotion));
canvas.drawCircle(cx, cy, max_ball_radius * target.score.value/100, emoScoredPaints.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. // TODO: Use target.hit.face to set Rect src.
// if(target.score.image != null) { // if(target.hit.image != null) {
// Rect rect = new Rect((int) cx-10, (int) cy-10, (int) cx+10, (int) cy+10); // 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); // 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; 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(); Rect scoreTextBounds = new Rect();
usedScorePaint.getTextBounds(scoreText, 0, scoreText.length(), scoreTextBounds); usedScorePaint.getTextBounds(scoreText, 0, scoreText.length(), scoreTextBounds);

View file

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

View file

@ -1,38 +1,22 @@
package com.rubenvandeven.emotionhero; 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.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.Date;
/** /**
* Created by ruben on 19/08/16. * Created by ruben on 19/08/16.
*/ */
public class Highscores extends ArrayList<Highscore>{ public class ScoreList extends ArrayList<Score>{
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);
}
/** /**
* Check if given highscore is highest score in this set. * Check if given highscore is highest hit in this set.
* @param score * @param score
* @return * @return
*/ */
public boolean isHighest(Highscore score) { public boolean isHighest(Score score) {
for(Highscore s: this) { for(Score s: this) {
if(s == score) // to allow comparison of items that are already in the set if(s == score) // to allow comparison of items that are already in the set
continue; // skip if it wants to compare with self. 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) { public ScoreList getTopN(int n) {
Collections.sort(this, new Comparator<Highscore>() { Collections.sort(this, new Comparator<Score>() {
@Override @Override
public int compare(Highscore score1, Highscore score2) public int compare(Score score1, Score score2)
{ {
// return highest first // return highest first
return score1.score > score2.score ? -1 : score1.score == score2.score ? 0 : 1; 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()) if(n > this.size())
n = this.size(); n = this.size();
Highscores scores = new Highscores(); ScoreList scores = new ScoreList();
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
scores.add(this.get(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!! * @todo only for current level!!
*/ */
public Highscores getLast(Integer n) { public ScoreList getLast(Integer n) {
Collections.sort(this, new Comparator<Highscore>() { Collections.sort(this, new Comparator<Score>() {
@Override @Override
public int compare(Highscore score1, Highscore score2) public int compare(Score score1, Score score2)
{ {
// return newest first // return newest first
return score1.time.before(score2.time) ? -1 : score1.time == score2.time ? 0 : 1; 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()) if(n > this.size())
n = this.size(); n = this.size();
Highscores scores = new Highscores(); ScoreList scores = new ScoreList();
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
scores.add(this.get(i)); scores.add(this.get(i));
} }