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:
parent
8f65131b7a
commit
3d45a25895
6 changed files with 124 additions and 92 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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));
|
||||
}
|
Loading…
Reference in a new issue