Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added hit animations, updated lighting & added InteliJ to gitignore #71

Merged
merged 7 commits into from
Apr 8, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,10 @@
.classpath
.project

# IntelliJ
.idea/
*.iml
*.iws

Thumbs.db
/target
Binary file modified res/lighting.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed res/lighting1.png
Binary file not shown.
198 changes: 168 additions & 30 deletions src/itdelatrisu/opsu/GameData.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.audio.SoundEffect;
import itdelatrisu.opsu.downloads.Updater;
import itdelatrisu.opsu.objects.HitResultType;
import itdelatrisu.opsu.objects.curves.Curve;
import itdelatrisu.opsu.replay.Replay;
import itdelatrisu.opsu.replay.ReplayFrame;

Expand All @@ -44,15 +46,33 @@ public class GameData {
/** Delta multiplier for steady HP drain. */
public static final float HP_DRAIN_MULTIPLIER = 1 / 200f;

/** Time, in milliseconds, for a hit result to remain existent. */
public static final int HITRESULT_TIME = 833;

/** Time, in milliseconds, for a hit result to fade. */
public static final int HITRESULT_FADE_TIME = 500;

/** Time, in milliseconds, for a hit circle to fade. */
public static final int HITCIRCLE_FADE_TIME = 300;

/** Duration, in milliseconds, of a combo pop effect. */
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;

/** Size of a hit circle at the end of the hit animation. */
private static final float HITCIRCLE_ANIM_SCALE = 1.38f;

/** Size of the hit result text at the end of its animation. */
private static final float HITCIRCLE_TEXT_ANIM_SCALE = 1.28f;

/** Time, in milliseconds, for the hit result text to bounce. */
private static final int HITCIRCLE_TEXT_BOUNCE_TIME = 100;

/** Time, in milliseconds, for the hit result text to fade. */
private static final int HITCIRCLE_TEXT_FADE_TIME = 833;

/** Letter grades. */
public enum Grade {
NULL (null, null),
Expand Down Expand Up @@ -221,28 +241,50 @@ private class OsuHitObjectResult {
/** Combo color. */
public Color color;

/** Whether the hit object was a spinner. */
public boolean isSpinner;
/** The type of the hit object. */
public HitResultType hitResultType;

/** Alpha level (for fading out). */
public float alpha = 1f;

/** Slider curve. */
public Curve curve;

/**
* Constructor.
* @param time the result's starting track position
* @param result the hit result (HIT_* constants)
* @param x the center x coordinate
* @param y the center y coordinate
* @param color the color of the hit object
* @param hitResultType the type of the hit object
*/
public OsuHitObjectResult(int time, int result, float x, float y, Color color, HitResultType hitResultType) {
this.time = time;
this.result = result;
this.x = x;
this.y = y;
this.color = color;
this.hitResultType = hitResultType;
}

/**
* Constructor.
* @param time the result's starting track position
* @param result the hit result (HIT_* constants)
* @param x the center x coordinate
* @param y the center y coordinate
* @param color the color of the hit object
* @param isSpinner whether the hit object was a spinner
* @param curve the slider curve
*/
public OsuHitObjectResult(int time, int result, float x, float y, Color color, boolean isSpinner) {
public OsuHitObjectResult(int time, int result, float x, float y, Color color, HitResultType hitResultType, Curve curve) {
this.time = time;
this.result = result;
this.x = x;
this.y = y;
this.color = color;
this.isSpinner = isSpinner;
this.hitResultType = hitResultType;
this.curve = curve;
}
}

Expand Down Expand Up @@ -822,14 +864,9 @@ public void drawHitResults(int trackPosition) {
Iterator<OsuHitObjectResult> iter = hitResultList.iterator();
while (iter.hasNext()) {
OsuHitObjectResult hitResult = iter.next();
if (hitResult.time + HITRESULT_FADE_TIME > trackPosition) {
// hit result
hitResults[hitResult.result].setAlpha(hitResult.alpha);
hitResults[hitResult.result].drawCentered(hitResult.x, hitResult.y);
hitResults[hitResult.result].setAlpha(1f);

if (hitResult.time + HITRESULT_TIME > trackPosition) {
// spinner
if (hitResult.isSpinner && hitResult.result != HIT_MISS) {
if (hitResult.hitResultType == HitResultType.SPINNER && hitResult.result != HIT_MISS) {
Image spinnerOsu = GameImage.SPINNER_OSU.getImage();
spinnerOsu.setAlpha(hitResult.alpha);
spinnerOsu.drawCentered(width / 2, height / 4);
Expand All @@ -839,16 +876,71 @@ public void drawHitResults(int trackPosition) {
// hit lighting
else if (Options.isHitLightingEnabled() && hitResult.result != HIT_MISS &&
hitResult.result != HIT_SLIDER30 && hitResult.result != HIT_SLIDER10) {
float scale = 1f + ((trackPosition - hitResult.time) / (float) HITRESULT_FADE_TIME);
Image scaledLighting = GameImage.LIGHTING.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),
hitResult.y - (scaledLighting.getHeight() / 2f), hitResult.color);
scaledLighting1.draw(hitResult.x - (scaledLighting1.getWidth() / 2f),
hitResult.y - (scaledLighting1.getHeight() / 2f), hitResult.color);
// soon add particle system to reflect original game
Image lighting = GameImage.LIGHTING.getImage();
lighting.setAlpha(hitResult.alpha);
lighting.drawCentered(hitResult.x, hitResult.y, hitResult.color);
}

// hit animation
if (hitResult.hitResultType == HitResultType.CIRCLE
|| hitResult.hitResultType == HitResultType.SLIDEREND
|| hitResult.hitResultType == HitResultType.SLIDEREND_FIRSTOBJECT) {
float scale = Utils.easeOut(
Utils.clamp(trackPosition - hitResult.time, 0, HITCIRCLE_FADE_TIME),
1f,
HITCIRCLE_ANIM_SCALE-1f,
HITCIRCLE_FADE_TIME
);

float alpha = Utils.easeOut(
Utils.clamp(trackPosition - hitResult.time, 0, HITCIRCLE_FADE_TIME),
1f,
-1f,
HITCIRCLE_FADE_TIME
);

if (hitResult.curve != null) {
float oldAlpha = Utils.COLOR_WHITE_FADE.a;

Curve curve = hitResult.curve;
Utils.COLOR_WHITE_FADE.a = alpha;
curve.color.a = alpha;
curve.draw();

Utils.COLOR_WHITE_FADE.a = oldAlpha;
}

Image scaledHitCircle = GameImage.HITCIRCLE.getImage().getScaledCopy(scale);
scaledHitCircle.setAlpha(alpha);
Image scaledHitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage().getScaledCopy(scale);
scaledHitCircleOverlay.setAlpha(alpha);

scaledHitCircle.drawCentered(hitResult.x, hitResult.y, hitResult.color);
scaledHitCircleOverlay.drawCentered(hitResult.x, hitResult.y);
}

// hit result
if (hitResult.hitResultType == HitResultType.CIRCLE
|| hitResult.hitResultType == HitResultType.SLIDEREND
|| hitResult.hitResultType == HitResultType.SPINNER) {
float scale = Utils.easeBounce(
Utils.clamp(trackPosition - hitResult.time, 0, HITCIRCLE_TEXT_BOUNCE_TIME),
1f,
HITCIRCLE_TEXT_ANIM_SCALE - 1f,
HITCIRCLE_TEXT_BOUNCE_TIME
);

float alpha = Utils.easeOut(
Utils.clamp((trackPosition - hitResult.time) - HITCIRCLE_FADE_TIME, 0, HITCIRCLE_TEXT_FADE_TIME),
1f,
-1f,
HITCIRCLE_TEXT_FADE_TIME
);

Image scaledHitResult = hitResults[hitResult.result].getScaledCopy(scale);
scaledHitResult.setAlpha(alpha);
scaledHitResult.drawCentered(hitResult.x, hitResult.y);
}

hitResult.alpha = 1 - ((float) (trackPosition - hitResult.time) / HITRESULT_FADE_TIME);
Expand Down Expand Up @@ -1115,7 +1207,7 @@ public void sliderTickResult(int time, int result, float x, float y, OsuHitObjec
if (!Options.isPerfectHitBurstEnabled())
; // hide perfect hit results
else
hitResultList.add(new OsuHitObjectResult(time, result, x, y, null, false));
hitResultList.add(new OsuHitObjectResult(time, result, x, y, null, HitResultType.SLIDERTICK));
}
}

Expand All @@ -1129,14 +1221,14 @@ public void sliderTickResult(int time, int result, float x, float y, OsuHitObjec
* @param end true if this is the last hit object in the combo
* @param hitObject the hit object
* @param repeat the current repeat number (for sliders, or 0 otherwise)
* @param hitResultType the type of hit object for the result
* @return the hit result (HIT_* constants)
*/
public void hitResult(int time, int result, float x, float y, Color color,
boolean end, OsuHitObject hitObject, int repeat) {
private int hitRes(int time, int result, float x, float y, Color color,
boolean end, OsuHitObject hitObject, int repeat, HitResultType hitResultType) {
int hitValue = 0;
boolean perfectHit = false;
switch (result) {
case HIT_300:
perfectHit = true;
hitValue = 300;
changeHealth(5f);
break;
Expand All @@ -1156,7 +1248,7 @@ public void hitResult(int time, int result, float x, float y, Color color,
resetComboStreak();
break;
default:
return;
return HIT_MISS;
}
if (hitValue > 0) {
SoundController.playHitSound(
Expand Down Expand Up @@ -1197,12 +1289,58 @@ public void hitResult(int time, int result, float x, float y, Color color,
comboEnd = 0;
}

if (perfectHit && !Options.isPerfectHitBurstEnabled())
return result;
}

/**
* Handles a hit result.
* @param time the object start time
* @param result the hit result (HIT_* constants)
* @param x the x coordinate
* @param y the y coordinate
* @param color the combo color
* @param end true if this is the last hit object in the combo
* @param hitObject the hit object
* @param repeat the current repeat number (for sliders, or 0 otherwise)
* @param hitResultType the type of hit object for the result
*/
public void hitResult(int time, int result, float x, float y, Color color,
boolean end, OsuHitObject hitObject, int repeat, HitResultType hitResultType) {
result = hitRes(time, result, x, y, color, end, hitObject, repeat, hitResultType);

if ((result == HIT_300 || result == HIT_300G || result == HIT_300K)
&& !Options.isPerfectHitBurstEnabled())
; // hide perfect hit results
else if (result == HIT_MISS && (GameMod.RELAX.isActive() || GameMod.AUTOPILOT.isActive()))
; // "relax" and "autopilot" mods: hide misses
else
hitResultList.add(new OsuHitObjectResult(time, result, x, y, color, hitResultType));
}

/**
* Handles a slider hit result.
* @param time the object start time
* @param result the hit result (HIT_* constants)
* @param x the x coordinate
* @param y the y coordinate
* @param color the combo color
* @param end true if this is the last hit object in the combo
* @param hitObject the hit object
* @param repeat the current repeat number (for sliders, or 0 otherwise)
* @param hitResultType the type of hit object for the result
* @param curve the slider curve
*/
public void hitResult(int time, int result, float x, float y, Color color,
boolean end, OsuHitObject hitObject, int repeat, HitResultType hitResultType, Curve curve) {
result = hitRes(time, result, x, y, color, end, hitObject, repeat, hitResultType);

if ((result == HIT_300 || result == HIT_300G || result == HIT_300K)
&& !Options.isPerfectHitBurstEnabled())
; // hide perfect hit results
else if (result == HIT_MISS && (GameMod.RELAX.isActive() || GameMod.AUTOPILOT.isActive()))
; // "relax" and "autopilot" mods: hide misses
else
hitResultList.add(new OsuHitObjectResult(time, result, x, y, color, hitObject.isSpinner()));
hitResultList.add(new OsuHitObjectResult(time, result, x, y, color, hitResultType, curve));
}

/**
Expand Down
1 change: 0 additions & 1 deletion src/itdelatrisu/opsu/GameImage.java
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,6 @@ protected Image process_sub(Image img, int w, int h) {
SCORE_PERCENT ("score-percent", "png"),
SCORE_X ("score-x", "png"),
LIGHTING ("lighting", "png"),
LIGHTING1 ("lighting1", "png"),

// Game Mods
MOD_EASY ("selection-mod-easy", "png", false, false),
Expand Down
26 changes: 26 additions & 0 deletions src/itdelatrisu/opsu/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -607,4 +607,30 @@ else if (seconds < 3600)
else
return String.format("%02d:%02d:%02d", seconds / 3600, (seconds / 60) % 60, seconds % 60);
}

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add Javadocs for these?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do.

/**
* Cubic ease out function
* @param t the current time
* @param a the starting position
* @param b the finishing position
* @param d the duration
* @return the eased float
*/
public static float easeOut(float t, float a, float b, float d) {
return b * ((t = t / d - 1f) * t * t + 1f) + a;
}

/**
* Fake bounce ease function
* @param t the current time
* @param a the starting position
* @param b the finishing position
* @param d the duration
* @return the eased float
*/
public static float easeBounce(float t, float a, float b, float d) {
if (t < d / 2)
return easeOut(t, a, b, d);
return easeOut(d-t, a, b, d);
}
}
8 changes: 4 additions & 4 deletions src/itdelatrisu/opsu/objects/Circle.java
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public boolean mousePressed(int x, int y, int trackPosition) {

if (result > -1) {
data.addHitError(hitObject.getTime(), x, y, timeDiff);
data.hitResult(hitObject.getTime(), result, this.x, this.y, color, comboEnd, hitObject, 0);
data.hitResult(hitObject.getTime(), result, this.x, this.y, color, comboEnd, hitObject, 0, HitResultType.CIRCLE);
return true;
}
}
Expand All @@ -154,17 +154,17 @@ public boolean update(boolean overlap, int delta, int mouseX, int mouseY, boolea

if (overlap || trackPosition > time + hitResultOffset[GameData.HIT_50]) {
if (isAutoMod) // "auto" mod: catch any missed notes due to lag
data.hitResult(time, GameData.HIT_300, x, y, color, comboEnd, hitObject, 0);
data.hitResult(time, GameData.HIT_300, x, y, color, comboEnd, hitObject, 0, HitResultType.CIRCLE);

else // no more points can be scored, so send a miss
data.hitResult(time, GameData.HIT_MISS, x, y, null, comboEnd, hitObject, 0);
data.hitResult(time, GameData.HIT_MISS, x, y, null, comboEnd, hitObject, 0, HitResultType.CIRCLE);
return true;
}

// "auto" mod: send a perfect hit result
else if (isAutoMod) {
if (Math.abs(trackPosition - time) < hitResultOffset[GameData.HIT_300]) {
data.hitResult(time, GameData.HIT_300, x, y, color, comboEnd, hitObject, 0);
data.hitResult(time, GameData.HIT_300, x, y, color, comboEnd, hitObject, 0, HitResultType.CIRCLE);
return true;
}
}
Expand Down
10 changes: 10 additions & 0 deletions src/itdelatrisu/opsu/objects/HitResultType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package itdelatrisu.opsu.objects;

public enum HitResultType {
CIRCLE,
//SLIDERSTART,
SLIDERTICK,
SLIDEREND,
SLIDEREND_FIRSTOBJECT,
SPINNER
}
Loading