Add a bonus culture

This commit is contained in:
Ruben 2016-09-10 00:03:10 +01:00
parent 2c4af60582
commit fedb7563d9
8 changed files with 154 additions and 27 deletions

View file

@ -174,6 +174,7 @@ public class ApiRestClient {
try {
j.put("lvl_id", game.scenario.id);
j.put("score", game.score);
j.put("bonus", game.bonus);
TimeZone tz = TimeZone.getTimeZone("UTC");
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
df.setTimeZone(tz);
@ -187,6 +188,7 @@ public class ApiRestClient {
jHit.put("id", hit.id);
jHit.put("target_index", hit.target.index);
jHit.put("score", hit.score);
jHit.put("bonus", hit.bonus);
jHit.put("glasses", hit.glasses);
jHit.put("ethnicity", hit.ethnicity);
jHit.put("age", hit.age);

View file

@ -18,18 +18,20 @@ public class Game {
public Long id;
public Scenario scenario;
public float score;
public float bonus;
public Date time;
public String remoteId;
public Map<Integer, Hit> hits = new HashMap<>();
public Game(Long id, int lvl_id, float score, Date time, String remoteId) {
this(id, new Scenario(lvl_id, null), score, time, remoteId);
public Game(Long id, int lvl_id, float score, float bonus, Date time, String remoteId) {
this(id, new Scenario(lvl_id, null), score, bonus, time, remoteId);
}
public Game(Long id, Scenario scenario, float score, Date time, String remoteId) {
public Game(Long id, Scenario scenario, float score, float bonus, Date time, String remoteId) {
this.id = id;
this.scenario= scenario;
this.score = score;
this.bonus = bonus;
this.time = time == null ? new Date() : time;
this.remoteId = remoteId;
}
@ -37,6 +39,7 @@ public class Game {
public void addHit(Hit hit) {
hits.put(hit.target.index, hit);
score = calculateScore();
bonus = calculateBonus();
}
private float calculateScore() {
@ -46,4 +49,12 @@ public class Game {
}
return s;
}
private float calculateBonus() {
float s = 0;
for(Hit hit: hits.values()) {
s += hit.bonus;
}
return s;
}
}

View file

@ -20,13 +20,14 @@ import java.util.Date;
* adb pull /sdcard/emotionhero.db
*/
public class GameOpenHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 3;
private static final int DATABASE_VERSION = 4;
private static final String GAME_TABLE_NAME = "games";
private static final String GAME_TABLE_CREATE =
"CREATE TABLE " + GAME_TABLE_NAME + " (" +
"id INTEGER NOT NULL," +
"lvl_id INTEGER NOT NULL," +
"score VARCHAR(255) NOT NULL," +
"bonus VARCHAR(255) NOT NULL," +
"time INTEGER NOT NULL," +
"remoteId VARCHAR(255) DEFAULT NULL, " +
"PRIMARY KEY(id));";
@ -34,6 +35,7 @@ public class GameOpenHelper extends SQLiteOpenHelper {
"id",
"lvl_id",
"score",
"bonus",
"time",
"remoteId"
};
@ -45,6 +47,7 @@ public class GameOpenHelper extends SQLiteOpenHelper {
"game_id INTEGER NOT NULL," +
"target_index INTEGER NOT_NULL," +
"score VARCHAR(20)," +
"bonus VARCHAR(20)," +
"remoteId VARCHAR(20)," +
"glasses VARCHAR(20)," +
"ethnicity VARCHAR(20)," +
@ -149,7 +152,7 @@ public class GameOpenHelper extends SQLiteOpenHelper {
"image BLOB," +
"PRIMARY KEY (id));" ;
private static final String[] HIT_PROJECTION = {
"id","game_id", "target_index","score","remoteId","glasses","ethnicity","age","gender","anger","contempt","disgust","fear","joy","sadness","surprise","roll","pitch","yaw","inter_ocular_distance","mouth_open","lip_press","brow_raise","nose_wrinkler","lip_depressor","brow_furrow","attention","smile","inner_brow_raiser","chin_raiser","smirk","lip_suck","upper_lip_raiser","lip_pucker","eye_closure","engagement","valence","point_0x","point_0y","point_1x","point_1y","point_2x","point_2y","point_3x","point_3y","point_4x","point_4y","point_5x","point_5y","point_6x","point_6y","point_7x","point_7y","point_8x","point_8y","point_9x","point_9y","point_10x","point_10y","point_11x","point_11y","point_12x","point_12y","point_13x","point_13y","point_14x","point_14y","point_15x","point_15y","point_16x","point_16y","point_17x","point_17y","point_18x","point_18y","point_19x","point_19y","point_20x","point_20y","point_21x","point_21y","point_22x","point_22y","point_23x","point_23y","point_24x","point_24y","point_25x","point_25y","point_26x","point_26y","point_27x","point_27y","point_28x","point_28y","point_29x","point_29y","point_30x","point_30y","point_31x","point_31y","point_32x","point_32y","point_33x","point_33y", "image"
"id","game_id", "target_index","score","bonus","remoteId","glasses","ethnicity","age","gender","anger","contempt","disgust","fear","joy","sadness","surprise","roll","pitch","yaw","inter_ocular_distance","mouth_open","lip_press","brow_raise","nose_wrinkler","lip_depressor","brow_furrow","attention","smile","inner_brow_raiser","chin_raiser","smirk","lip_suck","upper_lip_raiser","lip_pucker","eye_closure","engagement","valence","point_0x","point_0y","point_1x","point_1y","point_2x","point_2y","point_3x","point_3y","point_4x","point_4y","point_5x","point_5y","point_6x","point_6y","point_7x","point_7y","point_8x","point_8y","point_9x","point_9y","point_10x","point_10y","point_11x","point_11y","point_12x","point_12y","point_13x","point_13y","point_14x","point_14y","point_15x","point_15y","point_16x","point_16y","point_17x","point_17y","point_18x","point_18y","point_19x","point_19y","point_20x","point_20y","point_21x","point_21y","point_22x","point_22y","point_23x","point_23y","point_24x","point_24y","point_25x","point_25y","point_26x","point_26y","point_27x","point_27y","point_28x","point_28y","point_29x","point_29y","point_30x","point_30y","point_31x","point_31y","point_32x","point_32y","point_33x","point_33y", "image"
};
private Context context;
@ -179,6 +182,10 @@ public class GameOpenHelper extends SQLiteOpenHelper {
if(oldVersion == 2 && newVersion == 3) {
db.execSQL("ALTER TABLE hits ADD image BLOB;");
}
if(oldVersion == 3 && newVersion == 4) {
db.execSQL("ALTER TABLE hits ADD bonus VARCHAR(20);");
db.execSQL("ALTER TABLE games ADD bonus VARCHAR(255);");
}
}
public void insertGame(Game game) {
@ -189,6 +196,7 @@ public class GameOpenHelper extends SQLiteOpenHelper {
ContentValues values = new ContentValues();
values.put("lvl_id", game.scenario.id);
values.put("score", game.score);
values.put("bonus", game.bonus);
values.put("time", game.time.getTime());
if(game.remoteId == null) {
values.putNull("remoteId");
@ -216,7 +224,7 @@ public class GameOpenHelper extends SQLiteOpenHelper {
String selection = "lvl_id = ?";
String[] selectionArgs = { Integer.toString(s.id) };
String sortOrder = "score DESC";
String sortOrder = "score+bonus DESC";
Cursor c = db.query(
GAME_TABLE_NAME, // The table to query
@ -237,8 +245,15 @@ public class GameOpenHelper extends SQLiteOpenHelper {
c.moveToFirst();
while (!c.isAfterLast()) {
Scenario scenario = s == null ? new Scenario(c.getInt(1), null) : s;
Game game = new Game(c.getLong(0), scenario, c.getFloat(2), new Date(c.getLong(3)), c.getString(4));
Scenario scenario = s == null ? new Scenario(c.getInt(c.getColumnIndex("lvl_id")), null) : s;
Game game = new Game(
c.getLong(c.getColumnIndex("id")),
scenario,
c.getFloat(c.getColumnIndex("score")),
c.getFloat(c.getColumnIndex("bonus")),
new Date(c.getLong(c.getColumnIndex("time"))),
c.getString(c.getColumnIndex("remoteId"))
);
games[i] = game;
this.getHitsForGame(game); // hits are appended to game object
i++;
@ -277,6 +292,7 @@ public class GameOpenHelper extends SQLiteOpenHelper {
values.put("game_id", hit.game.id);
values.put("target_index", hit.target.index);
values.put("score", hit.score);
values.put("bonus", hit.bonus);
values.put("glasses", hit.glasses);
values.put("ethnicity", hit.ethnicity);
@ -389,10 +405,10 @@ public class GameOpenHelper extends SQLiteOpenHelper {
}
public int getLocalRankOfGame(Game game) {
String[] params = { Long.toString(game.scenario.id), Double.toString(game.score) };
String[] params = { Long.toString(game.scenario.id), Double.toString(game.score + game.bonus) };
Log.e("GAME",params[0].toString());
Log.e("GAME",params[1].toString());
Cursor c = getReadableDatabase().rawQuery("SELECT COUNT(id)+1 FROM games WHERE lvl_id = ? AND score > ?", params);
Cursor c = getReadableDatabase().rawQuery("SELECT COUNT(id)+1 FROM games WHERE lvl_id = ? AND score+bonus > ?", params);
c.moveToFirst();
return c.getInt(0);
}

View file

@ -217,7 +217,7 @@ public class HighscoreActivity extends AppCompatActivity {
for(Game game: games) {
final long itemGameId = game.id;
i++;
String highscoreText = String.format("%1$d. %2$.4f", i, game.score); //make line by line elements
String highscoreText = String.format("%1$d. %2$.4f", i, game.score+game.bonus); //make line by line elements
TextView scoreItem = new TextView(getContext());
scoreItem.setText(highscoreText);
scoreItem.setTextColor(ContextCompat.getColor(getContext(), R.color.highscore));

View file

@ -6,6 +6,7 @@ import android.graphics.BitmapFactory;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.Base64;
import android.util.Log;
import com.affectiva.android.affdex.sdk.detector.Face;
import com.google.gson.annotations.Expose;
@ -29,6 +30,7 @@ public class Hit {
public Game game;
public float score;
public float bonus;
public Map<Emotion, Float> emotions = new HashMap<>(7);
@ -48,8 +50,7 @@ public class Hit {
/**
* Constructor for game moment
*/
public Hit(Scenario.Target target, Game game, Face face, float score, Bitmap frame) {
this.score = score;
public Hit(Scenario.Target target, Game game, Face face) {
this.target = target;
this.game = game;
for(Emotion emotion: Emotion.values()) {
@ -67,7 +68,10 @@ public class Hit {
this.points = face.getFacePoints().clone();
this.frame = frame;
// this.frame = frame;
this.score = calculateScore();
this.bonus = calculateBonus();
// this in a way is strange behaviour:
// preferably do the game.addHit after creating hit, and call hit.game = game from there.
@ -80,6 +84,7 @@ public class Hit {
public Hit(Game game, Cursor c) {
this.id = c.getLong(c.getColumnIndex("id"));
this.score = c.getFloat(c.getColumnIndex("score"));
this.bonus = c.getFloat(c.getColumnIndex("bonus"));
String rId = c.getString(c.getColumnIndex("remoteId"));
this.remoteId = (rId == null || rId.length() == 0) ? null : c.getString(c.getColumnIndex("remoteId"));
this.target = game.scenario.getTargetByIndex(c.getInt(c.getColumnIndex("target_index")));
@ -136,11 +141,12 @@ public class Hit {
this.points[32] = new PointF(c.getFloat(c.getColumnIndex("point_32x")), c.getFloat(c.getColumnIndex("point_32y")));
this.points[33] = new PointF(c.getFloat(c.getColumnIndex("point_33x")), c.getFloat(c.getColumnIndex("point_33y")));
byte[] image = c.getBlob(c.getColumnIndex("image"));
if(image != null)
{
frame = BitmapFactory.decodeByteArray(image, 0, image.length);
}
// skip for now, unused and bad for performance ;-)
// byte[] image = c.getBlob(c.getColumnIndex("image"));
// if(image != null)
// {
// frame = BitmapFactory.decodeByteArray(image, 0, image.length);
// }
game.addHit(this);
}
@ -184,4 +190,37 @@ public class Hit {
frame.compress(Bitmap.CompressFormat.JPEG, 90, stream);
return stream.toByteArray();
}
public float calculateScore() {
float scored_value = emotions.get(target.emotion);
float required_value = target.value;
float diff = Math.abs(scored_value-required_value);
return 100 - diff;
}
public float calculateBonus() {
float scored_value = emotions.get(target.emotion);
float required_value = target.value;
float diff = Math.abs(scored_value-required_value);
float bonus = 0;
// precision score
if(diff < 25) {
bonus = ((25-diff)/25) * 50;
}
// double score if its exact!!
if(diff < 0.001) {
bonus += 50;
}
Log.e("HIT", "bonus: " + bonus + " (diff "+diff+")");
return bonus;
}
public boolean hasPrecisionBonus() {
return (this.bonus > 0);
}
}

View file

@ -160,7 +160,7 @@ public class ReviewActivity extends AppCompatActivity {
lvlNameText.setText("\""+game.scenario.toString()+"\"");
PrettyTime p = new PrettyTime();
dateText.setText(p.format(game.time));
scoreText.setText(String.format("%1$.4f", game.score));
scoreText.setText(String.format("%1$.4f", game.score+game.bonus));
// overallScorePercText.setText(String.format("%1$.0f%%", 30f));
loadRemoteInfo.run();

View file

@ -136,7 +136,7 @@ public class Scenario {
}
};
timer.schedule(tickTask, 0, 1000/DESIRED_FPS);
this.game = new Game(null, this, 0, new Date(), null);
this.game = new Game(null, this, 0, 0, new Date(), null);
rs = RenderScript.create(_activity);
squarePaint = new Paint();
@ -164,12 +164,10 @@ public class Scenario {
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);
_activity.sound.play(_activity.soundIds.get(_activity.SOUND_SCORE), 1, 1,
1,0, score / 200f + 0.5f ); // play back the sound slower
1,0, hit.score / 200f + 0.5f ); // play back the sound slower
// depending on hit value
target.isHit = true;
@ -198,7 +196,7 @@ public class Scenario {
*/
}
Hit hit = new Hit(target, game, currentFace, score, outputBitmap);
hit.frame = outputBitmap;
}
}
@ -264,10 +262,22 @@ public class Scenario {
}
return value;
}
public float getBonusTotalValue()
{
float value = 0;
for (Hit hit : game.hits.values()) {
value += hit.bonus;
}
return value;
}
public float getHitPercentage() {
return (getHitTotalValue()/maxScore) * 100;
}
public float getBonusPercentage() {
// maxScore for bonus == normal maxScore
return (getBonusTotalValue()/maxScore) * 100;
}
public float getMissedPercentage() {
return (getHitTotalMisValue()/maxScore) * 100;

View file

@ -3,9 +3,11 @@ package com.rubenvandeven.emotionhero;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.util.Log;
@ -43,6 +45,13 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback
private Paint linePaint = new Paint();
private Paint scorePaint = new Paint();
private Paint scoreFinishedPaint = new Paint();
private Paint bonusBarPaint = new Paint();
private Point mLeftTop;
private Point mRightTop;
private Point mLeftBot;
private Point mRightBot;
private Matrix matrix;
public boolean drawOverlay = false;
@ -97,6 +106,8 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback
scorePaint.setTextSize(50);
scorePaint.setTypeface(Typeface.DEFAULT_BOLD);
bonusBarPaint.setColor(Color.rgb(132, 0, 255));
scoreFinishedPaint.setColor(Color.YELLOW);
scoreFinishedPaint.setTextSize(100);
scoreFinishedPaint.setTypeface(Typeface.DEFAULT_BOLD);
@ -116,12 +127,14 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback
Paint emoPaint = new Paint();
emoPaint.setTextSize(22);
emoPaint.setColor(emotion.getColor());
// emoPaint.setShadowLayer(10,0,0,Color.BLACK);
emoPaints.put(emotion, emoPaint);
Paint emoPaintOutline = new Paint();
emoPaintOutline.setColor(emotion.getColor());
emoPaintOutline.setStyle(Paint.Style.STROKE);
emoPaintOutline.setStrokeWidth(3);
// emoPaintOutline.setShadowLayer(10,0,0,Color.BLACK);
emoOutlinePaints.put(emotion, emoPaintOutline);
Paint emoScoredPaint = new Paint();
@ -136,8 +149,13 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback
emoScoredPaint.setTextSize(20);
emoScoredPaint.setStrokeWidth(2);
emoScoredPaint.setStyle(Paint.Style.FILL_AND_STROKE);
// emoScoredPaint.setShadowLayer(10,0,0,Color.BLACK);
emoScoredPaints.put(emotion, emoScoredPaint);
setLayerType(LAYER_TYPE_SOFTWARE, emoPaint);
setLayerType(LAYER_TYPE_SOFTWARE, emoPaintOutline);
setLayerType(LAYER_TYPE_SOFTWARE, emoScoredPaint);
}
}
@ -147,6 +165,12 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback
if(drawOverlay) {
canvas.drawColor(0x990000FF);
}
if(matrix != null) {
canvas.concat(matrix);
}
//do drawing stuff here.
if (noFace)
@ -215,6 +239,10 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback
// Paint targetPaint = (target.hit == null) ? emoPaints.get(target.emotion) : emoScoredPaints.get(target.emotion);
float cy = bottomline_height - (target.timestamp * sec_height) + diff_y;
if(cy < (-1 * canvas.getHeight()) ) {
continue;
}
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));
@ -241,20 +269,24 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback
float hitWidth = width*(_scenario.getHitPercentage()/100);
float misWidth = width*(_scenario.getMissedPercentage()/100);
float bonusWidth = width*(_scenario.getBonusPercentage()/100);
String scoreText = String.format("%1$.0f", _scenario.getHitTotalValue());
Rect scoreTextBounds = new Rect();
scorePaint.getTextBounds(scoreText, 0, scoreText.length(), scoreTextBounds);
canvas.drawText(scoreText, hitWidth, height*0.95f-scoreTextBounds.height()-5, scorePaint);
canvas.drawRect(0, height*0.95f, width, height, mainPaint);
float stepSize = width / _scenario.targets.size();
for(int i = _scenario.targets.size(); i > 0; i--) {
canvas.drawLine(stepSize*i, height*0.95f, stepSize*i, height, attrScoreLinePaint);
}
canvas.drawRect(0, height*0.95f, hitWidth, height, emoPaints.get(Emotion.JOY));
canvas.drawRect(0, height*0.95f, hitWidth, height, emoPaints.get(Emotion.JOY)); // paint: yellow
canvas.drawRect(hitWidth, height*0.95f, hitWidth+misWidth, height, attrScorePaint);
canvas.drawRect(0, height*0.95f, bonusWidth, height*0.975f, bonusBarPaint);
}
@ -271,7 +303,24 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// canvas has exact same size as surface :-)
mLeftTop = new Point((int) (width*0.2), height/2);
mRightTop = new Point((int) (width*0.8), height/2);
mLeftBot = new Point(0, height);
mRightBot = new Point(width, height);
matrix = new Matrix();
matrix.setPolyToPoly(new float[]{0, 0,
width - 1, 0,
0, height - 1,
width - 1, height - 1},
0,
new float[]{mLeftTop.x, mLeftTop.y,
mRightTop.x, mRightTop.y,
mLeftBot.x, mLeftBot.y,
mRightBot.x, mRightBot.y
}
, 0, 4);
}
@Override