diff --git a/src/itdelatrisu/opsu/GameData.java b/src/itdelatrisu/opsu/GameData.java
index f4387987..5bfb4796 100644
--- a/src/itdelatrisu/opsu/GameData.java
+++ b/src/itdelatrisu/opsu/GameData.java
@@ -42,6 +42,9 @@ public class GameData {
/** Time, in milliseconds, for a hit result to fade. */
public static final int HITRESULT_FADE_TIME = 500;
+ /** Time, in milliseconds, that a combo pops on the screen. */
+ private static final int COMBO_POP_TIME = 250;
+
/** Time, in milliseconds, for a hit error tick to fade. */
private static final int HIT_ERROR_FADE_TIME = 5000;
@@ -134,6 +137,9 @@ public class GameData {
/** The max combo streak obtained. */
private int comboMax;
+ /** The current combo pop timer, in milliseconds. */
+ private int comboPopTime;
+
/**
* Hit result types accumulated this streak (bitmask), for Katu/Geki status.
*
@@ -331,6 +337,7 @@ public class GameData {
fullObjectCount = 0;
combo = 0;
comboMax = 0;
+ comboPopTime = COMBO_POP_TIME;
comboEnd = 0;
comboBurstIndex = -1;
scoreData = null;
@@ -445,25 +452,30 @@ public class GameData {
* @param x the starting x coordinate
* @param y the y coordinate
* @param scale the scale to apply
+ * @param alpha the alpha level
* @param rightAlign align right (true) or left (false)
*/
- public void drawSymbolString(String str, int x, int y, float scale, boolean rightAlign) {
+ public void drawSymbolString(String str, float x, float y, float scale, float alpha, boolean rightAlign) {
char[] c = str.toCharArray();
- int cx = x;
+ float cx = x;
if (rightAlign) {
for (int i = c.length - 1; i >= 0; i--) {
Image digit = getScoreSymbolImage(c[i]);
if (scale != 1.0f)
digit = digit.getScaledCopy(scale);
cx -= digit.getWidth();
+ digit.setAlpha(alpha);
digit.draw(cx, y);
+ digit.setAlpha(1f);
}
} else {
for (int i = 0; i < c.length; i++) {
Image digit = getScoreSymbolImage(c[i]);
if (scale != 1.0f)
digit = digit.getScaledCopy(scale);
+ digit.setAlpha(alpha);
digit.draw(cx, y);
+ digit.setAlpha(1f);
cx += digit.getWidth();
}
}
@@ -478,9 +490,9 @@ public class GameData {
* @param fixedsize the width to use for all symbols
* @param rightAlign align right (true) or left (false)
*/
- public void drawFixedSizeSymbolString(String str, int x, int y, float scale, float fixedsize, boolean rightAlign) {
+ public void drawFixedSizeSymbolString(String str, float x, float y, float scale, float fixedsize, boolean rightAlign) {
char[] c = str.toCharArray();
- int cx = x;
+ float cx = x;
if (rightAlign) {
for (int i = c.length - 1; i >= 0; i--) {
Image digit = getScoreSymbolImage(c[i]);
@@ -510,24 +522,24 @@ public class GameData {
*/
@SuppressWarnings("deprecation")
public void drawGameElements(Graphics g, boolean breakPeriod, boolean firstObject) {
- int marginX = (int) (width * 0.008f);
+ int margin = (int) (width * 0.008f);
// score
drawFixedSizeSymbolString((scoreDisplay < 100000000) ? String.format("%08d", scoreDisplay) : Long.toString(scoreDisplay),
- width - marginX, 0, 1.0f, getScoreSymbolImage('0').getWidth() - 2, true);
+ width - margin, 0, 1.0f, getScoreSymbolImage('0').getWidth() - 2, true);
// score percentage
int symbolHeight = getScoreSymbolImage('0').getHeight();
drawSymbolString(
String.format((scorePercentDisplay < 10f) ? "0%.2f%%" : "%.2f%%", scorePercentDisplay),
- width - marginX, symbolHeight, 0.60f, true);
+ width - margin, symbolHeight, 0.60f, 1f, true);
// map progress circle
g.setAntiAlias(true);
g.setLineWidth(2f);
g.setColor(Color.white);
float circleDiameter = symbolHeight * 0.60f;
- int circleX = (int) (width - marginX - ( // max width: "100.00%"
+ int circleX = (int) (width - margin - ( // max width: "100.00%"
getScoreSymbolImage('1').getWidth() +
getScoreSymbolImage('0').getWidth() * 4 +
getScoreSymbolImage('.').getWidth() +
@@ -576,7 +588,7 @@ public class GameData {
hitErrorAlpha = (HIT_ERROR_FADE_TIME - (trackPosition - hitErrorList.getFirst().time)) / (HIT_ERROR_FADE_TIME * 0.1f);
// draw bar
- int hitErrorY = height - marginX - 30, hitErrorX = width / 2;
+ int hitErrorY = height - margin - 30, hitErrorX = width / 2;
float oldAlphaBlack = Utils.COLOR_BLACK_ALPHA.a;
Utils.COLOR_BLACK_ALPHA.a = hitErrorAlpha;
g.setColor(Utils.COLOR_BLACK_ALPHA);
@@ -650,8 +662,15 @@ public class GameData {
}
// combo count
- if (combo > 0) // 0 isn't a combo
- drawSymbolString(String.format("%dx", combo), 10, height - 10 - symbolHeight, 1.0f, false);
+ if (combo > 0) {
+ float comboPop = 1 - ((float) comboPopTime / COMBO_POP_TIME);
+ float comboPopBack = 1 + comboPop * 0.45f;
+ float comboPopFront = 1 + comboPop * 0.08f;
+ String comboString = String.format("%dx", combo);
+ if (comboPopTime != COMBO_POP_TIME)
+ drawSymbolString(comboString, margin, height - margin - (symbolHeight * comboPopBack), comboPopBack, 0.5f, false);
+ drawSymbolString(comboString, margin, height - margin - (symbolHeight * comboPopFront), comboPopFront, 1f, false);
+ }
} else {
// grade
Grade grade = getGrade();
@@ -713,11 +732,11 @@ public class GameData {
drawSymbolString(String.format("%dx", rankResultOrder[i]),
(int) (resultInitialX * GameImage.getUIscale()),
(int) ((resultInitialY + (resultOffsetY * (i / 2))) * GameImage.getUIscale()),
- symbolTextScale, false);
+ symbolTextScale, 1f, false);
drawSymbolString(String.format("%dx", rankResultOrder[i+1]),
(int) ((resultInitialX + resultOffsetX) * GameImage.getUIscale()),
(int) ((resultInitialY + (resultOffsetY * (i / 2))) * GameImage.getUIscale()),
- symbolTextScale, false);
+ symbolTextScale, 1f, false);
}
// combo and accuracy
@@ -726,10 +745,10 @@ public class GameData {
float numbersY = textY + 30;
drawSymbolString(String.format("%dx", comboMax),
(int) (25 * GameImage.getUIscale()),
- (int) (numbersY * GameImage.getUIscale()), symbolTextScale, false);
+ (int) (numbersY * GameImage.getUIscale()), symbolTextScale, 1f, false);
drawSymbolString(String.format("%02.2f%%", getScorePercent()),
(int) ((accuracyX + 20) * GameImage.getUIscale()),
- (int) (numbersY * GameImage.getUIscale()), symbolTextScale, false);
+ (int) (numbersY * GameImage.getUIscale()), symbolTextScale, 1f, false);
GameImage.RANKING_MAXCOMBO.getImage().draw(
(int) (10 * GameImage.getUIscale()),
(int) (textY * GameImage.getUIscale()));
@@ -978,6 +997,11 @@ public class GameData {
}
}
+ // combo pop
+ comboPopTime += delta;
+ if (comboPopTime > COMBO_POP_TIME)
+ comboPopTime = COMBO_POP_TIME;
+
// hit error bar
if (Options.isHitErrorBarEnabled()) {
int trackPosition = MusicController.getPosition();
@@ -996,6 +1020,7 @@ public class GameData {
*/
private void incrementComboStreak() {
combo++;
+ comboPopTime = 0;
if (combo > comboMax)
comboMax = combo;
diff --git a/src/itdelatrisu/opsu/objects/Spinner.java b/src/itdelatrisu/opsu/objects/Spinner.java
index a5605ab9..2c8b384c 100644
--- a/src/itdelatrisu/opsu/objects/Spinner.java
+++ b/src/itdelatrisu/opsu/objects/Spinner.java
@@ -118,7 +118,7 @@ public class Spinner implements HitObject {
Image rpmImg = GameImage.SPINNER_RPM.getImage();
rpmImg.drawCentered(width / 2f, height - rpmImg.getHeight() / 2f);
data.drawSymbolString(Integer.toString(rpm), (int) ((width + rpmImg.getWidth() * 0.95f) / 2f),
- (int) (height - data.getScoreSymbolImage('0').getHeight() * 1.025f), 1f, true);
+ (int) (height - data.getScoreSymbolImage('0').getHeight() * 1.025f), 1f, 1f, true);
// spinner meter (subimage)
Image spinnerMetre = GameImage.SPINNER_METRE.getImage();