From 62a7ee0f21b16414d10f49e60fb6a3d874f3d7aa Mon Sep 17 00:00:00 2001 From: yugecin Date: Sun, 18 Dec 2016 13:03:09 +0100 Subject: [PATCH 1/9] always fadeout slider curve --- src/itdelatrisu/opsu/GameData.java | 62 ++++++++++++------------ src/itdelatrisu/opsu/objects/Slider.java | 5 +- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/src/itdelatrisu/opsu/GameData.java b/src/itdelatrisu/opsu/GameData.java index 1dace8b6..3887469a 100644 --- a/src/itdelatrisu/opsu/GameData.java +++ b/src/itdelatrisu/opsu/GameData.java @@ -232,7 +232,7 @@ public class GameData { private LinkedBlockingDeque hitErrorList; /** Hit object types, used for drawing results. */ - public enum HitObjectType { CIRCLE, SLIDERTICK, SLIDER_FIRST, SLIDER_LAST, SPINNER } + public enum HitObjectType { CIRCLE, SLIDERTICK, SLIDER_FIRST, SLIDER_CURVE, SLIDER_LAST, SPINNER } /** Hit result helper class. */ private class HitObjectResult { @@ -892,7 +892,25 @@ public class GameData { lighting.drawCentered(hitResult.x, hitResult.y, hitResult.color); } - // hit animation + // slider done animation + + // hit animations + if (hitResult.hitResultType == HitObjectType.SLIDER_CURVE && hitResult.curve != null) { + float progress = AnimationEquation.OUT_CUBIC.calc( + (float) Utils.clamp(trackPosition - hitResult.time, 0, HITCIRCLE_FADE_TIME) / HITCIRCLE_FADE_TIME); + float alpha = 1f - progress; + + // slider curve + float oldWhiteAlpha = Colors.WHITE_FADE.a; + float oldColorAlpha = hitResult.color.a; + Colors.WHITE_FADE.a = alpha; + hitResult.color.a = alpha; + hitResult.curve.draw(hitResult.color); + Colors.WHITE_FADE.a = oldWhiteAlpha; + hitResult.color.a = oldColorAlpha; + } + + // circles if (hitResult.result != HIT_MISS && ( hitResult.hitResultType == HitObjectType.CIRCLE || hitResult.hitResultType == HitObjectType.SLIDER_FIRST || @@ -915,27 +933,13 @@ public class GameData { scaledRepeat.rotate(ang); scaledRepeat.drawCentered(hitResult.x, hitResult.y, hitResult.color); } - // "hidden" mod: circle and slider animations not drawn - else if (!GameMod.HIDDEN.isActive()) { - // slider curve - if (hitResult.curve != null) { - float oldWhiteAlpha = Colors.WHITE_FADE.a; - float oldColorAlpha = hitResult.color.a; - Colors.WHITE_FADE.a = alpha; - hitResult.color.a = alpha; - hitResult.curve.draw(hitResult.color); - Colors.WHITE_FADE.a = oldWhiteAlpha; - hitResult.color.a = oldColorAlpha; - } - - // hit circles - Image scaledHitCircle = GameImage.HITCIRCLE.getImage().getScaledCopy(scale); - Image scaledHitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage().getScaledCopy(scale); - scaledHitCircle.setAlpha(alpha); - scaledHitCircleOverlay.setAlpha(alpha); - scaledHitCircle.drawCentered(hitResult.x, hitResult.y, hitResult.color); - scaledHitCircleOverlay.drawCentered(hitResult.x, hitResult.y); - } + // hit circles + Image scaledHitCircle = GameImage.HITCIRCLE.getImage().getScaledCopy(scale); + Image scaledHitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage().getScaledCopy(scale); + scaledHitCircle.setAlpha(alpha); + scaledHitCircleOverlay.setAlpha(alpha); + scaledHitCircle.drawCentered(hitResult.x, hitResult.y, hitResult.color); + scaledHitCircleOverlay.drawCentered(hitResult.x, hitResult.y); } // hit result @@ -1195,6 +1199,10 @@ public class GameData { hitResultList.add(new HitObjectResult(time, HIT_SLIDER_REPEAT, x, y, color, type, curve, true, true)); } + public void sendSliderCurveResult(int time, Color color, Curve curve) { + hitResultList.add(new HitObjectResult(time, HIT_SLIDER_REPEAT, 0f, 0f, color, HitObjectType.SLIDER_CURVE, curve, true, true)); + } + /** * Handles a slider tick result. * @param time the tick start time @@ -1396,14 +1404,6 @@ public class GameData { boolean hideResult = (hitResult == HIT_300 || hitResult == HIT_300G || hitResult == HIT_300K) && !Options.isPerfectHitBurstEnabled(); hitResultList.add(new HitObjectResult(time, hitResult, x, y, color, hitResultType, curve, expand, hideResult)); - - // sliders: add the other curve endpoint for the hit animation - if (curve != null) { - boolean isFirst = (hitResultType == HitObjectType.SLIDER_FIRST); - Vec2f p = curve.pointAt((isFirst) ? 1f : 0f); - HitObjectType type = (isFirst) ? HitObjectType.SLIDER_LAST : HitObjectType.SLIDER_FIRST; - hitResultList.add(new HitObjectResult(time, hitResult, p.x, p.y, color, type, null, expand, hideResult)); - } } /** diff --git a/src/itdelatrisu/opsu/objects/Slider.java b/src/itdelatrisu/opsu/objects/Slider.java index 3830726f..f8d9a3ea 100644 --- a/src/itdelatrisu/opsu/objects/Slider.java +++ b/src/itdelatrisu/opsu/objects/Slider.java @@ -441,7 +441,7 @@ public class Slider implements GameObject { } data.hitResult(hitObject.getTime() + (int) sliderTimeTotal, result, cx, cy, color, comboEnd, hitObject, type, sliderHeldToEnd, - currentRepeats + 1, curve, sliderHeldToEnd); + currentRepeats + 1, null, sliderHeldToEnd); return result; } @@ -530,6 +530,9 @@ public class Slider implements GameObject { // calculate and send slider result hitResult(); + + // send 'curve fade out' hit result + data.sendSliderCurveResult(getEndTime(), color, curve); return true; } From 59ed2f9ee3b3a1f37486ba6f70275ab2da96fd39 Mon Sep 17 00:00:00 2001 From: yugecin Date: Sun, 18 Dec 2016 13:08:36 +0100 Subject: [PATCH 2/9] don't draw animations when hidden is enabled --- src/itdelatrisu/opsu/GameData.java | 106 ++++++++++++++++------------- 1 file changed, 57 insertions(+), 49 deletions(-) diff --git a/src/itdelatrisu/opsu/GameData.java b/src/itdelatrisu/opsu/GameData.java index 3887469a..d4ce3272 100644 --- a/src/itdelatrisu/opsu/GameData.java +++ b/src/itdelatrisu/opsu/GameData.java @@ -26,7 +26,6 @@ import itdelatrisu.opsu.beatmap.Beatmap; import itdelatrisu.opsu.beatmap.HitObject; import itdelatrisu.opsu.downloads.Updater; import itdelatrisu.opsu.objects.curves.Curve; -import itdelatrisu.opsu.objects.curves.Vec2f; import itdelatrisu.opsu.replay.Replay; import itdelatrisu.opsu.replay.ReplayFrame; import itdelatrisu.opsu.ui.Colors; @@ -892,54 +891,9 @@ public class GameData { lighting.drawCentered(hitResult.x, hitResult.y, hitResult.color); } - // slider done animation - - // hit animations - if (hitResult.hitResultType == HitObjectType.SLIDER_CURVE && hitResult.curve != null) { - float progress = AnimationEquation.OUT_CUBIC.calc( - (float) Utils.clamp(trackPosition - hitResult.time, 0, HITCIRCLE_FADE_TIME) / HITCIRCLE_FADE_TIME); - float alpha = 1f - progress; - - // slider curve - float oldWhiteAlpha = Colors.WHITE_FADE.a; - float oldColorAlpha = hitResult.color.a; - Colors.WHITE_FADE.a = alpha; - hitResult.color.a = alpha; - hitResult.curve.draw(hitResult.color); - Colors.WHITE_FADE.a = oldWhiteAlpha; - hitResult.color.a = oldColorAlpha; - } - - // circles - if (hitResult.result != HIT_MISS && ( - hitResult.hitResultType == HitObjectType.CIRCLE || - hitResult.hitResultType == HitObjectType.SLIDER_FIRST || - hitResult.hitResultType == HitObjectType.SLIDER_LAST)) { - float progress = AnimationEquation.OUT_CUBIC.calc( - (float) Utils.clamp(trackPosition - hitResult.time, 0, HITCIRCLE_FADE_TIME) / HITCIRCLE_FADE_TIME); - float scale = (!hitResult.expand) ? 1f : 1f + (HITCIRCLE_ANIM_SCALE - 1f) * progress; - float alpha = 1f - progress; - - if (hitResult.result == HIT_SLIDER_REPEAT) { - // repeats - Image scaledRepeat = GameImage.REVERSEARROW.getImage().getScaledCopy(scale); - scaledRepeat.setAlpha(alpha); - float ang; - if (hitResult.hitResultType == HitObjectType.SLIDER_FIRST) { - ang = hitResult.curve.getStartAngle(); - } else { - ang = hitResult.curve.getEndAngle(); - } - scaledRepeat.rotate(ang); - scaledRepeat.drawCentered(hitResult.x, hitResult.y, hitResult.color); - } - // hit circles - Image scaledHitCircle = GameImage.HITCIRCLE.getImage().getScaledCopy(scale); - Image scaledHitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage().getScaledCopy(scale); - scaledHitCircle.setAlpha(alpha); - scaledHitCircleOverlay.setAlpha(alpha); - scaledHitCircle.drawCentered(hitResult.x, hitResult.y, hitResult.color); - scaledHitCircleOverlay.drawCentered(hitResult.x, hitResult.y); + // hit animations, only draw when the 'hidden' mod is not enabled + if (!GameMod.HIDDEN.isActive()) { + drawHitAnimations(hitResult, trackPosition); } // hit result @@ -967,6 +921,60 @@ public class GameData { } } + /** + * Draw the hit animations: circles, reversearrows, slider curves fading out and/or expanding + * @param hitResult the hitresult which holds information about the kind of animation to draw + * @param trackPosition the current track position (in ms) + */ + private void drawHitAnimations(HitObjectResult hitResult, int trackPosition) { + if (hitResult.hitResultType == HitObjectType.SLIDER_CURVE && hitResult.curve != null) { + float progress = AnimationEquation.OUT_CUBIC.calc( + (float) Utils.clamp(trackPosition - hitResult.time, 0, HITCIRCLE_FADE_TIME) / HITCIRCLE_FADE_TIME); + float alpha = 1f - progress; + + // slider curve + float oldWhiteAlpha = Colors.WHITE_FADE.a; + float oldColorAlpha = hitResult.color.a; + Colors.WHITE_FADE.a = alpha; + hitResult.color.a = alpha; + hitResult.curve.draw(hitResult.color); + Colors.WHITE_FADE.a = oldWhiteAlpha; + hitResult.color.a = oldColorAlpha; + } + + // circles + if (hitResult.result != HIT_MISS && ( + hitResult.hitResultType == HitObjectType.CIRCLE || + hitResult.hitResultType == HitObjectType.SLIDER_FIRST || + hitResult.hitResultType == HitObjectType.SLIDER_LAST)) { + float progress = AnimationEquation.OUT_CUBIC.calc( + (float) Utils.clamp(trackPosition - hitResult.time, 0, HITCIRCLE_FADE_TIME) / HITCIRCLE_FADE_TIME); + float scale = (!hitResult.expand) ? 1f : 1f + (HITCIRCLE_ANIM_SCALE - 1f) * progress; + float alpha = 1f - progress; + + if (hitResult.result == HIT_SLIDER_REPEAT) { + // repeats + Image scaledRepeat = GameImage.REVERSEARROW.getImage().getScaledCopy(scale); + scaledRepeat.setAlpha(alpha); + float ang; + if (hitResult.hitResultType == HitObjectType.SLIDER_FIRST) { + ang = hitResult.curve.getStartAngle(); + } else { + ang = hitResult.curve.getEndAngle(); + } + scaledRepeat.rotate(ang); + scaledRepeat.drawCentered(hitResult.x, hitResult.y, hitResult.color); + } + // hit circles + Image scaledHitCircle = GameImage.HITCIRCLE.getImage().getScaledCopy(scale); + Image scaledHitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage().getScaledCopy(scale); + scaledHitCircle.setAlpha(alpha); + scaledHitCircleOverlay.setAlpha(alpha); + scaledHitCircle.drawCentered(hitResult.x, hitResult.y, hitResult.color); + scaledHitCircleOverlay.drawCentered(hitResult.x, hitResult.y); + } + } + /** * Changes health by a given percentage, modified by drainRate. * @param percent the health percentage From 3c6b20f4c812903ebcff1b1a0ec4c97c7afe4ce0 Mon Sep 17 00:00:00 2001 From: yugecin Date: Sun, 18 Dec 2016 14:46:02 +0100 Subject: [PATCH 3/9] adjust the animations on the first circle of the slider --- src/itdelatrisu/opsu/GameData.java | 7 +++- src/itdelatrisu/opsu/objects/Slider.java | 42 +++++++++++++++--------- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/itdelatrisu/opsu/GameData.java b/src/itdelatrisu/opsu/GameData.java index d4ce3272..92255902 100644 --- a/src/itdelatrisu/opsu/GameData.java +++ b/src/itdelatrisu/opsu/GameData.java @@ -150,7 +150,8 @@ public class GameData { HIT_SLIDER10 = 7, HIT_SLIDER30 = 8, HIT_MAX = 9, // not a hit result - HIT_SLIDER_REPEAT = 10; // not a hit result + HIT_SLIDER_REPEAT = 10, // not a hit result + HIT_ANIMATION_RESULT = 11; // not a hit result /** Hit result-related images (indexed by HIT_* constants). */ private Image[] hitResults; @@ -1211,6 +1212,10 @@ public class GameData { hitResultList.add(new HitObjectResult(time, HIT_SLIDER_REPEAT, 0f, 0f, color, HitObjectType.SLIDER_CURVE, curve, true, true)); } + public void sendAnimationResult(int time, float x, float y, Color color, boolean expand) { + hitResultList.add(new HitObjectResult(time, HIT_ANIMATION_RESULT, x, y, color, HitObjectType.CIRCLE, null, expand, true)); + } + /** * Handles a slider tick result. * @param time the tick start time diff --git a/src/itdelatrisu/opsu/objects/Slider.java b/src/itdelatrisu/opsu/objects/Slider.java index f8d9a3ea..062d8f16 100644 --- a/src/itdelatrisu/opsu/objects/Slider.java +++ b/src/itdelatrisu/opsu/objects/Slider.java @@ -210,10 +210,12 @@ public class Slider implements GameObject { hitCircle.drawCentered(endCircPos.x, endCircPos.y, color); hitCircleOverlay.drawCentered(endCircPos.x, endCircPos.y, Colors.WHITE_FADE); - // start circle - hitCircle.drawCentered(x, y, color); - if (!overlayAboveNumber) - hitCircleOverlay.drawCentered(x, y, Colors.WHITE_FADE); + // draw start circle when not clicked yet + if (!sliderClickedInitial) { + hitCircle.drawCentered(x, y, color); + if (!overlayAboveNumber) + hitCircleOverlay.drawCentered(x, y, Colors.WHITE_FADE); + } color.a = alpha; @@ -231,17 +233,18 @@ public class Slider implements GameObject { alpha = Math.min(alpha, hiddenAlpha); } } - if (sliderClickedInitial) - ; // don't draw current combo number if already clicked - else - data.drawSymbolNumber(hitObject.getComboNumber(), x, y, - hitCircle.getWidth() * 0.40f / data.getDefaultSymbolImage(0).getHeight(), alpha); - if (overlayAboveNumber) { - oldWhiteFadeAlpha = Colors.WHITE_FADE.a; - Colors.WHITE_FADE.a = sliderAlpha; - hitCircleOverlay.drawCentered(x, y, Colors.WHITE_FADE); - Colors.WHITE_FADE.a = oldWhiteFadeAlpha; + // draw combonumber and overlay if not initially clicked + if (!sliderClickedInitial) { + data.drawSymbolNumber(hitObject.getComboNumber(), x, y, + hitCircle.getWidth() * 0.40f / data.getDefaultSymbolImage(0).getHeight(), alpha); + + if (overlayAboveNumber) { + oldWhiteFadeAlpha = Colors.WHITE_FADE.a; + Colors.WHITE_FADE.a = sliderAlpha; + hitCircleOverlay.drawCentered(x, y, Colors.WHITE_FADE); + Colors.WHITE_FADE.a = oldWhiteFadeAlpha; + } } // repeats @@ -460,8 +463,11 @@ public class Slider implements GameObject { if (timeDiff < hitResultOffset[GameData.HIT_50]) { result = GameData.HIT_SLIDER30; ticksHit++; - } else if (timeDiff < hitResultOffset[GameData.HIT_MISS]) + data.sendAnimationResult(trackPosition, x, y, color, true); + } else if (timeDiff < hitResultOffset[GameData.HIT_MISS]) { result = GameData.HIT_MISS; + data.sendAnimationResult(trackPosition, x, y, color, false); + } //else not a hit if (result > -1) { @@ -489,8 +495,11 @@ public class Slider implements GameObject { if (isAutoMod) { // "auto" mod: catch any missed notes due to lag ticksHit++; data.sliderTickResult(time, GameData.HIT_SLIDER30, x, y, hitObject, currentRepeats); - } else + data.sendAnimationResult(time, x, y, color, true); + } else { data.sliderTickResult(time, GameData.HIT_MISS, x, y, hitObject, currentRepeats); + data.sendAnimationResult(trackPosition, x, y, color, false); + } } // "auto" mod: send a perfect hit result @@ -499,6 +508,7 @@ public class Slider implements GameObject { ticksHit++; sliderClickedInitial = true; data.sliderTickResult(time, GameData.HIT_SLIDER30, x, y, hitObject, currentRepeats); + data.sendAnimationResult(time, x, y, color, true); } } From 55fa6f4070372d15ab9a226394d8f3e0cb9507a0 Mon Sep 17 00:00:00 2001 From: yugecin Date: Sun, 18 Dec 2016 14:53:04 +0100 Subject: [PATCH 4/9] fix initial circle animation position --- src/itdelatrisu/opsu/objects/Slider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/itdelatrisu/opsu/objects/Slider.java b/src/itdelatrisu/opsu/objects/Slider.java index 062d8f16..1d0dbef4 100644 --- a/src/itdelatrisu/opsu/objects/Slider.java +++ b/src/itdelatrisu/opsu/objects/Slider.java @@ -463,10 +463,10 @@ public class Slider implements GameObject { if (timeDiff < hitResultOffset[GameData.HIT_50]) { result = GameData.HIT_SLIDER30; ticksHit++; - data.sendAnimationResult(trackPosition, x, y, color, true); + data.sendAnimationResult(trackPosition, this.x, this.y, color, true); } else if (timeDiff < hitResultOffset[GameData.HIT_MISS]) { result = GameData.HIT_MISS; - data.sendAnimationResult(trackPosition, x, y, color, false); + data.sendAnimationResult(trackPosition, this.x, this.y, color, false); } //else not a hit From 2260299c4b59ad09a728f553a3d26a6af3540007 Mon Sep 17 00:00:00 2001 From: yugecin Date: Sun, 18 Dec 2016 15:06:21 +0100 Subject: [PATCH 5/9] don't show reversearrow pop when slider wasn't held --- src/itdelatrisu/opsu/objects/Slider.java | 42 +++++++++++------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/src/itdelatrisu/opsu/objects/Slider.java b/src/itdelatrisu/opsu/objects/Slider.java index 1d0dbef4..414d5861 100644 --- a/src/itdelatrisu/opsu/objects/Slider.java +++ b/src/itdelatrisu/opsu/objects/Slider.java @@ -562,23 +562,6 @@ public class Slider implements GameObject { tickIndex = 0; isNewRepeat = true; tickExpandTime = TICK_EXPAND_TIME; - - // send hit result, to fade out reversearrow - HitObjectType type; - float posX, posY; - if (currentRepeats % 2 == 1) { - type = HitObjectType.SLIDER_LAST; - Vec2f endPos = curve.pointAt(1); - posX = endPos.x; - posY = endPos.y; - } else { - type = HitObjectType.SLIDER_FIRST; - posX = this.x; - posY = this.y; - } - float colorLuminance = 0.299f*color.r + 0.587f*color.g + 0.114f*color.b; - Color arrowColor = colorLuminance < 0.8f ? Color.white : Color.black; - data.sendRepeatSliderResult(trackPosition, posX, posY, arrowColor, curve, type); } } @@ -606,13 +589,26 @@ public class Slider implements GameObject { // held during new repeat if (isNewRepeat) { ticksHit++; + + HitObjectType type; + float posX, posY; if (currentRepeats % 2 > 0) { // last circle - int lastIndex = hitObject.getSliderX().length; - data.sliderTickResult(trackPosition, GameData.HIT_SLIDER30, - curve.getX(lastIndex), curve.getY(lastIndex), hitObject, currentRepeats); - } else // first circle - data.sliderTickResult(trackPosition, GameData.HIT_SLIDER30, - c.x, c.y, hitObject, currentRepeats); + type = HitObjectType.SLIDER_LAST; + Vec2f endPos = curve.pointAt(1f); + posX = endPos.x; + posY = endPos.y; + } else { // first circle + type = HitObjectType.SLIDER_FIRST; + posX = this.x; + posY = this.y; + } + data.sliderTickResult(trackPosition, GameData.HIT_SLIDER30, + posX, posY, hitObject, currentRepeats); + + // send hit result, to fade out reversearrow + float colorLuminance = 0.299f*color.r + 0.587f*color.g + 0.114f*color.b; + Color arrowColor = colorLuminance < 0.8f ? Color.white : Color.black; + data.sendRepeatSliderResult(trackPosition, posX, posY, arrowColor, curve, type); } // held during new tick From 5be3fdf1a323c1b7559855e04ccf347e87d99dec Mon Sep 17 00:00:00 2001 From: yugecin Date: Sun, 18 Dec 2016 16:18:51 +0100 Subject: [PATCH 6/9] fade in slider circles after repeats, hide them if ball does not need to go to them again --- src/itdelatrisu/opsu/objects/Slider.java | 64 +++++++++++++++++++----- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/src/itdelatrisu/opsu/objects/Slider.java b/src/itdelatrisu/opsu/objects/Slider.java index 414d5861..694724ee 100644 --- a/src/itdelatrisu/opsu/objects/Slider.java +++ b/src/itdelatrisu/opsu/objects/Slider.java @@ -180,6 +180,7 @@ public class Slider implements GameObject { @Override public void draw(Graphics g, int trackPosition) { int timeDiff = hitObject.getTime() - trackPosition; + final int repeats = hitObject.getRepeatCount(); final int approachTime = game.getApproachTime(); final int fadeInTime = game.getFadeInTime(); float scale = timeDiff / (float) approachTime; @@ -205,16 +206,37 @@ public class Slider implements GameObject { float curveInterval = Options.isSliderSnaking() ? alpha : 1f; curve.draw(color,curveInterval); - // end circle - Vec2f endCircPos = curve.pointAt(curveInterval); - hitCircle.drawCentered(endCircPos.x, endCircPos.y, color); - hitCircleOverlay.drawCentered(endCircPos.x, endCircPos.y, Colors.WHITE_FADE); + // end circle, only draw if ball still has to go there + if (curveInterval == 1f && currentRepeats < repeats - (repeats % 2 == 0 ? 1 : 0)) { + Color circleColor = new Color(color); + Color overlayColor = new Color(Colors.WHITE_FADE); + if (currentRepeats == 0) { + if (Options.isSliderSnaking()) { + // fade in end circle using decorationsAlpha when snaking sliders are enabled + circleColor.a = overlayColor.a = decorationsAlpha; + } + } else { + // fade in end circle after repeats + circleColor.a = overlayColor.a = getCircleAlphaAfterRepeat(trackPosition, true); + } + Vec2f endCircPos = curve.pointAt(curveInterval); + hitCircle.drawCentered(endCircPos.x, endCircPos.y, circleColor); + hitCircleOverlay.drawCentered(endCircPos.x, endCircPos.y, overlayColor); + } - // draw start circle when not clicked yet - if (!sliderClickedInitial) { - hitCircle.drawCentered(x, y, color); - if (!overlayAboveNumber) - hitCircleOverlay.drawCentered(x, y, Colors.WHITE_FADE); + // set first circle colors to fade in after repeats + Color firstCircleColor = new Color(color); + Color startCircleOverlayColor = new Color(Colors.WHITE_FADE); + if (sliderClickedInitial) { + // fade in first circle after repeats + firstCircleColor.a = startCircleOverlayColor.a = getCircleAlphaAfterRepeat(trackPosition, false); + } + + // start circle, only draw if ball still has to go there + if (!sliderClickedInitial || currentRepeats < repeats - (repeats % 2 == 1 ? 1 : 0)) { + hitCircle.drawCentered(x, y, firstCircleColor); + if (!overlayAboveNumber || sliderClickedInitial) + hitCircleOverlay.drawCentered(x, y, startCircleOverlayColor); } color.a = alpha; @@ -240,10 +262,8 @@ public class Slider implements GameObject { hitCircle.getWidth() * 0.40f / data.getDefaultSymbolImage(0).getHeight(), alpha); if (overlayAboveNumber) { - oldWhiteFadeAlpha = Colors.WHITE_FADE.a; - Colors.WHITE_FADE.a = sliderAlpha; - hitCircleOverlay.drawCentered(x, y, Colors.WHITE_FADE); - Colors.WHITE_FADE.a = oldWhiteFadeAlpha; + startCircleOverlayColor.a = sliderAlpha; + hitCircleOverlay.drawCentered(x, y, startCircleOverlayColor); } } @@ -366,6 +386,24 @@ public class Slider implements GameObject { } } + /** + * Get the alpha level used to fade in circles & reversearrows after repeat + * @param trackPosition current trackposition, in ms + * @param endCircle request alpha for end circle (true) or start circle (false)? + * @return alpha level as float in interval [0, 1] + */ + private float getCircleAlphaAfterRepeat(int trackPosition, boolean endCircle) { + int ticksN = ticksT == null ? 0 : ticksT.length; + float t = getT(trackPosition, false); + if (endCircle) { + t = 1f - t; + } + if (currentRepeats % 2 == (endCircle ? 0 : 1)) { + t = 1f; + } + return Utils.clamp(t * (ticksN + 1), 0f, 1f); + } + /** * Calculates the slider hit result. * @return the hit result (GameData.HIT_* constants) From b252f0ec4213b232817a9a5ac1ba6fa6e25e05dd Mon Sep 17 00:00:00 2001 From: yugecin Date: Sun, 18 Dec 2016 16:37:48 +0100 Subject: [PATCH 7/9] use the same fade for reversearrows as circles --- src/itdelatrisu/opsu/objects/Slider.java | 43 ++++++++++++------------ 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/itdelatrisu/opsu/objects/Slider.java b/src/itdelatrisu/opsu/objects/Slider.java index 694724ee..2d71421b 100644 --- a/src/itdelatrisu/opsu/objects/Slider.java +++ b/src/itdelatrisu/opsu/objects/Slider.java @@ -269,29 +269,28 @@ public class Slider implements GameObject { // repeats if (curveInterval == 1.0f) { - for (int tcurRepeat = currentRepeats; tcurRepeat <= currentRepeats + 1; tcurRepeat++) { - if (hitObject.getRepeatCount() - 1 > tcurRepeat) { - Image arrow = GameImage.REVERSEARROW.getImage(); - // bouncing animation - //arrow = arrow.getScaledCopy((float) (1 + 0.2d * ((trackPosition + sliderTime * tcurRepeat) % 292) / 292)); - float colorLuminance = 0.299f*color.r + 0.587f*color.g + 0.114f*color.b; - Color arrowColor = colorLuminance < 0.8f ? Color.white : Color.black; - if (tcurRepeat != currentRepeats) { - if (sliderTime == 0) - continue; - float t = Math.max(getT(trackPosition, true), 0); - arrow.setAlpha((float) (t - Math.floor(t))); - } else - arrow.setAlpha(Options.isSliderSnaking() ? decorationsAlpha : 1f); - if (tcurRepeat % 2 == 0) { - // last circle - arrow.setRotation(curve.getEndAngle()); - arrow.drawCentered(endPos.x, endPos.y, arrowColor); - } else { - // first circle - arrow.setRotation(curve.getStartAngle()); - arrow.drawCentered(x, y, arrowColor); + for (int tcurRepeat = currentRepeats; tcurRepeat <= currentRepeats + 1 && tcurRepeat < repeats - 1; tcurRepeat++) { + Image arrow = GameImage.REVERSEARROW.getImage(); + // bouncing animation + //arrow = arrow.getScaledCopy((float) (1 + 0.2d * ((trackPosition + sliderTime * tcurRepeat) % 292) / 292)); + float colorLuminance = 0.299f*color.r + 0.587f*color.g + 0.114f*color.b; + Color arrowColor = colorLuminance < 0.8f ? Color.white : Color.black; + if (tcurRepeat == 0) { + arrow.setAlpha(Options.isSliderSnaking() ? decorationsAlpha : 1f); + } else { + if (!sliderClickedInitial) { + continue; } + arrow.setAlpha(getCircleAlphaAfterRepeat(trackPosition, tcurRepeat % 2 == 0)); + } + if (tcurRepeat % 2 == 0) { + // last circle + arrow.setRotation(curve.getEndAngle()); + arrow.drawCentered(endPos.x, endPos.y, arrowColor); + } else { + // first circle + arrow.setRotation(curve.getStartAngle()); + arrow.drawCentered(x, y, arrowColor); } } } From 3ca26531976231d579b85d907562f964717fb280 Mon Sep 17 00:00:00 2001 From: yugecin Date: Sun, 18 Dec 2016 16:41:52 +0100 Subject: [PATCH 8/9] adjust the slider circles alpha when hidden mod is enabled --- src/itdelatrisu/opsu/objects/Slider.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/itdelatrisu/opsu/objects/Slider.java b/src/itdelatrisu/opsu/objects/Slider.java index 2d71421b..2258204c 100644 --- a/src/itdelatrisu/opsu/objects/Slider.java +++ b/src/itdelatrisu/opsu/objects/Slider.java @@ -213,11 +213,11 @@ public class Slider implements GameObject { if (currentRepeats == 0) { if (Options.isSliderSnaking()) { // fade in end circle using decorationsAlpha when snaking sliders are enabled - circleColor.a = overlayColor.a = decorationsAlpha; + circleColor.a = overlayColor.a = sliderAlpha * decorationsAlpha; } } else { // fade in end circle after repeats - circleColor.a = overlayColor.a = getCircleAlphaAfterRepeat(trackPosition, true); + circleColor.a = overlayColor.a = sliderAlpha * getCircleAlphaAfterRepeat(trackPosition, true); } Vec2f endCircPos = curve.pointAt(curveInterval); hitCircle.drawCentered(endCircPos.x, endCircPos.y, circleColor); @@ -229,7 +229,7 @@ public class Slider implements GameObject { Color startCircleOverlayColor = new Color(Colors.WHITE_FADE); if (sliderClickedInitial) { // fade in first circle after repeats - firstCircleColor.a = startCircleOverlayColor.a = getCircleAlphaAfterRepeat(trackPosition, false); + firstCircleColor.a = startCircleOverlayColor.a = sliderAlpha * getCircleAlphaAfterRepeat(trackPosition, false); } // start circle, only draw if ball still has to go there From 089ff7d0ded211ca7a890b36f6de9999aa813908 Mon Sep 17 00:00:00 2001 From: yugecin Date: Sun, 18 Dec 2016 16:47:55 +0100 Subject: [PATCH 9/9] minor cleanup --- src/itdelatrisu/opsu/GameData.java | 60 ++++++++++++++++-------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/src/itdelatrisu/opsu/GameData.java b/src/itdelatrisu/opsu/GameData.java index 92255902..e3c1f3f7 100644 --- a/src/itdelatrisu/opsu/GameData.java +++ b/src/itdelatrisu/opsu/GameData.java @@ -941,39 +941,45 @@ public class GameData { hitResult.curve.draw(hitResult.color); Colors.WHITE_FADE.a = oldWhiteAlpha; hitResult.color.a = oldColorAlpha; + return; + } + + if (hitResult.result == HIT_MISS) { + return; + } + + if (hitResult.hitResultType != HitObjectType.CIRCLE + && hitResult.hitResultType != HitObjectType.SLIDER_FIRST + && hitResult.hitResultType != HitObjectType.SLIDER_LAST) { + return; } // circles - if (hitResult.result != HIT_MISS && ( - hitResult.hitResultType == HitObjectType.CIRCLE || - hitResult.hitResultType == HitObjectType.SLIDER_FIRST || - hitResult.hitResultType == HitObjectType.SLIDER_LAST)) { - float progress = AnimationEquation.OUT_CUBIC.calc( - (float) Utils.clamp(trackPosition - hitResult.time, 0, HITCIRCLE_FADE_TIME) / HITCIRCLE_FADE_TIME); - float scale = (!hitResult.expand) ? 1f : 1f + (HITCIRCLE_ANIM_SCALE - 1f) * progress; - float alpha = 1f - progress; + float progress = AnimationEquation.OUT_CUBIC.calc( + (float) Utils.clamp(trackPosition - hitResult.time, 0, HITCIRCLE_FADE_TIME) / HITCIRCLE_FADE_TIME); + float scale = (!hitResult.expand) ? 1f : 1f + (HITCIRCLE_ANIM_SCALE - 1f) * progress; + float alpha = 1f - progress; - if (hitResult.result == HIT_SLIDER_REPEAT) { - // repeats - Image scaledRepeat = GameImage.REVERSEARROW.getImage().getScaledCopy(scale); - scaledRepeat.setAlpha(alpha); - float ang; - if (hitResult.hitResultType == HitObjectType.SLIDER_FIRST) { - ang = hitResult.curve.getStartAngle(); - } else { - ang = hitResult.curve.getEndAngle(); - } - scaledRepeat.rotate(ang); - scaledRepeat.drawCentered(hitResult.x, hitResult.y, hitResult.color); + if (hitResult.result == HIT_SLIDER_REPEAT) { + // repeats + Image scaledRepeat = GameImage.REVERSEARROW.getImage().getScaledCopy(scale); + scaledRepeat.setAlpha(alpha); + float ang; + if (hitResult.hitResultType == HitObjectType.SLIDER_FIRST) { + ang = hitResult.curve.getStartAngle(); + } else { + ang = hitResult.curve.getEndAngle(); } - // hit circles - Image scaledHitCircle = GameImage.HITCIRCLE.getImage().getScaledCopy(scale); - Image scaledHitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage().getScaledCopy(scale); - scaledHitCircle.setAlpha(alpha); - scaledHitCircleOverlay.setAlpha(alpha); - scaledHitCircle.drawCentered(hitResult.x, hitResult.y, hitResult.color); - scaledHitCircleOverlay.drawCentered(hitResult.x, hitResult.y); + scaledRepeat.rotate(ang); + scaledRepeat.drawCentered(hitResult.x, hitResult.y, hitResult.color); } + // hit circles + Image scaledHitCircle = GameImage.HITCIRCLE.getImage().getScaledCopy(scale); + Image scaledHitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage().getScaledCopy(scale); + scaledHitCircle.setAlpha(alpha); + scaledHitCircleOverlay.setAlpha(alpha); + scaledHitCircle.drawCentered(hitResult.x, hitResult.y, hitResult.color); + scaledHitCircleOverlay.drawCentered(hitResult.x, hitResult.y); } /**