Visual Changes

mostly personal preferences though

Larger hit circles
Circle overlay after drawing circle
Fade in approach circles
Fade in sliders (I don't think it looks that bad)
Fade out hit lighting
Hit Error Bar
 Probably need an option for this.
Miss locations(I don't know)

Reverse Slider ball rotation on repeats
This commit is contained in:
fd 2015-02-14 13:45:14 -05:00
parent 54806303f4
commit 597c4bfb19
5 changed files with 151 additions and 23 deletions

View File

@ -153,6 +153,23 @@ public class GameData {
/** List of hit result objects associated with hit objects. */ /** List of hit result objects associated with hit objects. */
private LinkedList<OsuHitObjectResult> hitResultList; private LinkedList<OsuHitObjectResult> hitResultList;
class ErrorInfo {
int time, x, y, timeDiff;
public ErrorInfo(int time, int x, int y, int timeDiff) {
super();
this.time = time;
this.x = x;
this.y = y;
this.timeDiff = timeDiff;
}
}
private LinkedList<ErrorInfo> errorRateList = new LinkedList<ErrorInfo>();
private LinkedList<ErrorInfo> mouseMissList = new LinkedList<ErrorInfo>();
/** /**
* Hit result helper class. * Hit result helper class.
*/ */
@ -225,6 +242,10 @@ public class GameData {
/** Container dimensions. */ /** Container dimensions. */
private int width, height; private int width, height;
/** Time offsets for obtaining each hit result (indexed by HIT_* constants). */
private int[] hitResultOffset;
/** /**
* Constructor for gameplay. * Constructor for gameplay.
* @param width container width * @param width container width
@ -283,6 +304,8 @@ public class GameData {
comboEnd = 0; comboEnd = 0;
comboBurstIndex = -1; comboBurstIndex = -1;
scoreData = null; scoreData = null;
errorRateList.clear();
mouseMissList.clear();
} }
/** /**
@ -364,6 +387,10 @@ public class GameData {
public void setDifficulty(float difficulty) { this.difficulty = difficulty; } public void setDifficulty(float difficulty) { this.difficulty = difficulty; }
public float getDifficulty() { return difficulty; } public float getDifficulty() { return difficulty; }
/** Sets the HitResultOffset */
public void setHitResultOffset(int[] hitResultOffset) {this.hitResultOffset = hitResultOffset; }
/** /**
* Draws a number with defaultSymbols. * Draws a number with defaultSymbols.
* @param n the number to draw * @param n the number to draw
@ -528,6 +555,47 @@ public class GameData {
); );
} }
} }
//*
//Draw Error bar
final int fadeDelay = 5000;
int hitErrorY = 30;
Iterator<ErrorInfo> iter2 = errorRateList.iterator();
g.setColor(Color.black);
g.fillRect(width/2f-3-hitResultOffset[HIT_50], height-marginX-hitErrorY-10,hitResultOffset[HIT_50]*2,20);
g.setColor(Utils.COLOR_LIGHT_ORANGE);
g.fillRect(width/2f-3-hitResultOffset[HIT_50], height-marginX-hitErrorY-3,hitResultOffset[HIT_50]*2,6);
g.setColor(Utils.COLOR_LIGHT_GREEN);
g.fillRect(width/2f-3-hitResultOffset[HIT_100], height-marginX-hitErrorY-3,hitResultOffset[HIT_100]*2,6);
g.setColor(Utils.COLOR_LIGHT_BLUE);
g.fillRect(width/2f-3-hitResultOffset[HIT_300], height-marginX-hitErrorY-3,hitResultOffset[HIT_300]*2,6);
g.setColor(Color.white);
g.drawRect(width/2f-3, height-marginX-hitErrorY-10, 6, 20);
while (iter2.hasNext()) {
ErrorInfo info = iter2.next();
int time = info.time;
if (time + fadeDelay > trackPosition) {
float alpha = 1 - ((float) (trackPosition - time) / fadeDelay);
g.setColor(Color.white.scaleCopy(alpha));
g.fillRect(width/2 + info.timeDiff-1, height-marginX-hitErrorY-10, 2, 20);
}else{
iter2.remove();
}
}
iter2 = mouseMissList.iterator();
while (iter2.hasNext()) {
ErrorInfo info = iter2.next();
int time = info.time;
if (time + fadeDelay > trackPosition) {
//float alpha = 1 - ((float) (trackPosition - time) / fadeDelay);
//g.setColor(Color.green.scaleCopy(alpha));
//g.fillRect(info.x-5, info.y-5, 10, 10);
}else{
iter2.remove();
}
}//*/
} }
/** /**
@ -649,6 +717,9 @@ public class GameData {
float scale = 1f + ((trackPosition - hitResult.time) / (float) fadeDelay); float scale = 1f + ((trackPosition - hitResult.time) / (float) fadeDelay);
Image scaledLighting = GameImage.LIGHTING.getImage().getScaledCopy(scale); Image scaledLighting = GameImage.LIGHTING.getImage().getScaledCopy(scale);
Image scaledLighting1 = GameImage.LIGHTING1.getImage().getScaledCopy(scale); Image scaledLighting1 = GameImage.LIGHTING1.getImage().getScaledCopy(scale);
scaledLighting.setAlpha(hitResult.alpha);
scaledLighting1.setAlpha(hitResult.alpha);
scaledLighting.draw(hitResult.x - (scaledLighting.getWidth() / 2f), scaledLighting.draw(hitResult.x - (scaledLighting.getWidth() / 2f),
hitResult.y - (scaledLighting.getHeight() / 2f), hitResult.color); hitResult.y - (scaledLighting.getHeight() / 2f), hitResult.color);
scaledLighting1.draw(hitResult.x - (scaledLighting1.getWidth() / 2f), scaledLighting1.draw(hitResult.x - (scaledLighting1.getWidth() / 2f),
@ -1008,4 +1079,13 @@ public class GameData {
* @return true if gameplay, false if score viewing * @return true if gameplay, false if score viewing
*/ */
public boolean isGameplay() { return gameplay; } public boolean isGameplay() { return gameplay; }
public void addMouseMissPoint(int time, int x, int y, int button) {
mouseMissList.add(new ErrorInfo(time, x, y, 0));
}
public void addErrorRate(int time, int x, int y, int timeDiff) {
errorRateList.add(new ErrorInfo(time, x, y, timeDiff));
}
} }

View File

@ -79,7 +79,10 @@ public class Utils {
COLOR_YELLOW_ALPHA = new Color(255, 255, 0, 0.4f), COLOR_YELLOW_ALPHA = new Color(255, 255, 0, 0.4f),
COLOR_WHITE_FADE = new Color(255, 255, 255, 1f), COLOR_WHITE_FADE = new Color(255, 255, 255, 1f),
COLOR_RED_HOVER = new Color(255, 112, 112), COLOR_RED_HOVER = new Color(255, 112, 112),
COLOR_GREEN = new Color(137, 201, 79); COLOR_GREEN = new Color(137, 201, 79),
COLOR_LIGHT_ORANGE = new Color(255,192,128),
COLOR_LIGHT_GREEN = new Color(128,255,128),
COLOR_LIGHT_BLUE = new Color(128,128,255);
/** The default map colors, used when a map does not provide custom colors. */ /** The default map colors, used when a map does not provide custom colors. */
public static final Color[] DEFAULT_COMBO = { public static final Color[] DEFAULT_COMBO = {
@ -838,4 +841,20 @@ public class Utils {
list.add(str); list.add(str);
return list; return list;
} }
/**
* Clamps the value to be in between low and high
* @param val
* @param low
* @param high
* @return val clamped between low and high
* @author fluddokt (https://github.com/fluddokt)
*/
public static float clamp(float val, int low, int high) {
if(val < low)
return low;
if(val > high)
return high;
return val;
}
} }

View File

@ -55,7 +55,7 @@ public class Circle implements HitObject {
* @param circleSize the map's circleSize value * @param circleSize the map's circleSize value
*/ */
public static void init(GameContainer container, float circleSize) { public static void init(GameContainer container, float circleSize) {
int diameter = (int) (96 - (circleSize * 8)); int diameter = (int) (104 - (circleSize * 8));
diameter = (int) (diameter * OsuHitObject.getXMultiplier()); // convert from Osupixels (640x480) diameter = (int) (diameter * OsuHitObject.getXMultiplier()); // convert from Osupixels (640x480)
GameImage.HITCIRCLE.setImage(GameImage.HITCIRCLE.getImage().getScaledCopy(diameter, diameter)); GameImage.HITCIRCLE.setImage(GameImage.HITCIRCLE.getImage().getScaledCopy(diameter, diameter));
GameImage.HITCIRCLE_OVERLAY.setImage(GameImage.HITCIRCLE_OVERLAY.getImage().getScaledCopy(diameter, diameter)); GameImage.HITCIRCLE_OVERLAY.setImage(GameImage.HITCIRCLE_OVERLAY.getImage().getScaledCopy(diameter, diameter));
@ -83,15 +83,20 @@ public class Circle implements HitObject {
int timeDiff = hitObject.getTime() - trackPosition; int timeDiff = hitObject.getTime() - trackPosition;
if (timeDiff >= 0) { if (timeDiff >= 0) {
float x = hitObject.getX(), y = hitObject.getY();
float approachScale = 1 + (timeDiff * 2f / game.getApproachTime());
Utils.drawCentered(GameImage.APPROACHCIRCLE.getImage().getScaledCopy(approachScale), x, y, color);
float alpha = (approachScale > 3.3f) ? 0f : 1f - (approachScale - 1f) / 2.7f;
float oldAlpha = color.a; float oldAlpha = color.a;
float x = hitObject.getX(), y = hitObject.getY();
float scale = timeDiff / (float)game.getApproachTime();
float approachScale = 1 + scale * 3;
color.a = 1 - scale;
Utils.drawCentered(GameImage.APPROACHCIRCLE.getImage().getScaledCopy(approachScale), x, y, color);
float alpha = Utils.clamp((1 - scale) * 2, 0, 1);
color.a = alpha; color.a = alpha;
Utils.COLOR_WHITE_FADE.a = alpha; Utils.COLOR_WHITE_FADE.a = alpha;
Utils.drawCentered(GameImage.HITCIRCLE_OVERLAY.getImage(), x, y, Utils.COLOR_WHITE_FADE);
Utils.drawCentered(GameImage.HITCIRCLE.getImage(), x, y, color); Utils.drawCentered(GameImage.HITCIRCLE.getImage(), x, y, color);
Utils.drawCentered(GameImage.HITCIRCLE_OVERLAY.getImage(), x, y, Utils.COLOR_WHITE_FADE);
color.a = oldAlpha; color.a = oldAlpha;
Utils.COLOR_WHITE_FADE.a = 1f; Utils.COLOR_WHITE_FADE.a = 1f;
data.drawSymbolNumber(hitObject.getComboNumber(), x, y, data.drawSymbolNumber(hitObject.getComboNumber(), x, y,
@ -105,8 +110,7 @@ public class Circle implements HitObject {
* @return the hit result (GameData.HIT_* constants) * @return the hit result (GameData.HIT_* constants)
*/ */
private int hitResult(int time) { private int hitResult(int time) {
int trackPosition = MusicController.getPosition(); int timeDiff = Math.abs(time);
int timeDiff = Math.abs(trackPosition - time);
int[] hitResultOffset = game.getHitResultOffsets(); int[] hitResultOffset = game.getHitResultOffsets();
int result = -1; int result = -1;
@ -128,8 +132,12 @@ public class Circle implements HitObject {
double distance = Math.hypot(hitObject.getX() - x, hitObject.getY() - y); double distance = Math.hypot(hitObject.getX() - x, hitObject.getY() - y);
int circleRadius = GameImage.HITCIRCLE.getImage().getWidth() / 2; int circleRadius = GameImage.HITCIRCLE.getImage().getWidth() / 2;
if (distance < circleRadius) { if (distance < circleRadius) {
int result = hitResult(hitObject.getTime()); int trackPosition = MusicController.getPosition();
int timeDiff = trackPosition - hitObject.getTime();
int result = hitResult(timeDiff);
if (result > -1) { if (result > -1) {
data.addErrorRate(hitObject.getTime(), x, y, timeDiff);
data.hitResult( data.hitResult(
hitObject.getTime(), result, hitObject.getTime(), result,
hitObject.getX(), hitObject.getY(), hitObject.getX(), hitObject.getY(),

View File

@ -98,7 +98,7 @@ public class Slider implements HitObject {
* @param osu the associated OsuFile object * @param osu the associated OsuFile object
*/ */
public static void init(GameContainer container, float circleSize, OsuFile osu) { public static void init(GameContainer container, float circleSize, OsuFile osu) {
int diameter = (int) (96 - (circleSize * 8)); int diameter = (int) (104 - (circleSize * 8));
diameter = (int) (diameter * OsuHitObject.getXMultiplier()); // convert from Osupixels (640x480) diameter = (int) (diameter * OsuHitObject.getXMultiplier()); // convert from Osupixels (640x480)
// slider ball // slider ball
@ -110,7 +110,7 @@ public class Slider implements HitObject {
sliderBallImages = new Image[]{ GameImage.SLIDER_BALL.getImage() }; sliderBallImages = new Image[]{ GameImage.SLIDER_BALL.getImage() };
for (int i = 0; i < sliderBallImages.length; i++) for (int i = 0; i < sliderBallImages.length; i++)
sliderBallImages[i] = sliderBallImages[i].getScaledCopy(diameter * 118 / 128, diameter * 118 / 128); sliderBallImages[i] = sliderBallImages[i].getScaledCopy(diameter * 118 / 128, diameter * 118 / 128);
sliderBall = new Animation(sliderBallImages, 60); sliderBall = new Animation(sliderBallImages, 30);
GameImage.SLIDER_FOLLOWCIRCLE.setImage(GameImage.SLIDER_FOLLOWCIRCLE.getImage().getScaledCopy(diameter * 259 / 128, diameter * 259 / 128)); GameImage.SLIDER_FOLLOWCIRCLE.setImage(GameImage.SLIDER_FOLLOWCIRCLE.getImage().getScaledCopy(diameter * 259 / 128, diameter * 259 / 128));
GameImage.REVERSEARROW.setImage(GameImage.REVERSEARROW.getImage().getScaledCopy(diameter, diameter)); GameImage.REVERSEARROW.setImage(GameImage.REVERSEARROW.getImage().getScaledCopy(diameter, diameter));
@ -143,16 +143,21 @@ public class Slider implements HitObject {
@Override @Override
public void draw(int trackPosition, boolean currentObject, Graphics g) { public void draw(int trackPosition, boolean currentObject, Graphics g) {
float x = hitObject.getX(), y = hitObject.getY();
int timeDiff = hitObject.getTime() - trackPosition; int timeDiff = hitObject.getTime() - trackPosition;
float approachScale = (timeDiff >= 0) ? 1 + (timeDiff * 2f / game.getApproachTime()) : 1f;
float alpha = (approachScale > 3.3f) ? 0f : 1f - (approachScale - 1f) / 2.7f;
float oldAlpha = color.a; float oldAlpha = color.a;
float oldAlphaFade = Utils.COLOR_WHITE_FADE.a; float oldAlphaFade = Utils.COLOR_WHITE_FADE.a;
color.a = alpha;
float x = hitObject.getX(), y = hitObject.getY();
float scale = timeDiff / (float)game.getApproachTime();
float approachScale = 1 + scale*3 ;
float alpha = (1 - scale);//(approachScale > 3.3f) ? 0f : 1f - (approachScale - 1f) / 2.7f;
color.a = Utils.clamp(alpha* 0.5f, 0, 1);
alpha = Utils.clamp(alpha, 0, 1);
Utils.COLOR_WHITE_FADE.a = alpha; Utils.COLOR_WHITE_FADE.a = alpha;
// curve // curve
curve.draw(); curve.draw();
@ -164,6 +169,8 @@ public class Slider implements HitObject {
tick.drawCentered(c[0], c[1]); tick.drawCentered(c[0], c[1]);
} }
} }
color.a = alpha;
Image hitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage(); Image hitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage();
Image hitCircle = GameImage.HITCIRCLE.getImage(); Image hitCircle = GameImage.HITCIRCLE.getImage();
@ -174,8 +181,8 @@ public class Slider implements HitObject {
Utils.drawCentered(hitCircleOverlay, endPos[0], endPos[1], Utils.COLOR_WHITE_FADE); Utils.drawCentered(hitCircleOverlay, endPos[0], endPos[1], Utils.COLOR_WHITE_FADE);
// start circle // start circle
Utils.drawCentered(hitCircleOverlay, x, y, Utils.COLOR_WHITE_FADE);
Utils.drawCentered(hitCircle, x, y, color); Utils.drawCentered(hitCircle, x, y, color);
Utils.drawCentered(hitCircleOverlay, x, y, Utils.COLOR_WHITE_FADE);
if (sliderClicked) if (sliderClicked)
; // don't draw current combo number if already clicked ; // don't draw current combo number if already clicked
else else
@ -208,22 +215,29 @@ public class Slider implements HitObject {
if (timeDiff >= 0) { if (timeDiff >= 0) {
// approach circle // approach circle
color.a = 1 - scale;
Utils.drawCentered(GameImage.APPROACHCIRCLE.getImage().getScaledCopy(approachScale), x, y, color); Utils.drawCentered(GameImage.APPROACHCIRCLE.getImage().getScaledCopy(approachScale), x, y, color);
} else { } else {
float[] c = curve.pointAt(getT(trackPosition, false)); float[] c = curve.pointAt(getT(trackPosition, false));
float[] c2 = curve.pointAt(getT(trackPosition, false) + 0.01f); float[] c2 = curve.pointAt(getT(trackPosition, false) + 0.01f);
// slider ball // slider ball
sliderBall.updateNoDraw();//TODO ..... I can't thing of anything else
//It might be better to make your own animation class or something
//also it might be better to update the animation based on the distance traveled
Image sliderBallFrame = sliderBall.getCurrentFrame(); Image sliderBallFrame = sliderBall.getCurrentFrame();
float angle = (float) (Math.atan2(c2[1] - c[1], c2[0] - c[0]) * 180 / Math.PI); float angle = (float) (Math.atan2(c2[1] - c[1], c2[0] - c[0]) * 180 / Math.PI)
+ (currentRepeats % 2 == 1 ? 180 : 0);
sliderBallFrame.setRotation(angle); sliderBallFrame.setRotation(angle);
sliderBallFrame.drawCentered(c[0], c[1]); sliderBallFrame.drawCentered(c[0], c[1]);
// follow circle // follow circle
if (followCircleActive) if (followCircleActive)
GameImage.SLIDER_FOLLOWCIRCLE.getImage().drawCentered(c[0], c[1]); GameImage.SLIDER_FOLLOWCIRCLE.getImage().drawCentered(c[0], c[1]);
} }
} }
/** /**
* Calculates the slider hit result. * Calculates the slider hit result.
@ -275,6 +289,7 @@ public class Slider implements HitObject {
//else not a hit //else not a hit
if (result > -1) { if (result > -1) {
data.addErrorRate(hitObject.getTime(), x,y,trackPosition - hitObject.getTime());
sliderClicked = true; sliderClicked = true;
data.sliderTickResult(hitObject.getTime(), result, data.sliderTickResult(hitObject.getTime(), result,
hitObject.getX(), hitObject.getY(), hitObject.getHitSoundType()); hitObject.getX(), hitObject.getY(), hitObject.getHitSoundType());

View File

@ -664,8 +664,13 @@ public class Game extends BasicGameState {
objectIndex++; // circle hit objectIndex++; // circle hit
// sliders // sliders
else if (hitObject.isSlider()) else if (hitObject.isSlider() && hitObjects[objectIndex].mousePressed(x, y)){
hitObjects[objectIndex].mousePressed(x, y);
}
//Nothing hit
else
data.addMouseMissPoint(MusicController.getPosition(), x,y,button);
} }
@Override @Override
@ -878,6 +883,7 @@ public class Game extends BasicGameState {
// HPDrainRate (health change), overallDifficulty (scoring) // HPDrainRate (health change), overallDifficulty (scoring)
data.setDrainRate(HPDrainRate); data.setDrainRate(HPDrainRate);
data.setDifficulty(overallDifficulty); data.setDifficulty(overallDifficulty);
data.setHitResultOffset(hitResultOffset);
} }
/** /**