Very minor follow-up to #61.

Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
Jeffrey Han 2015-03-30 23:06:52 -04:00
parent f63be81490
commit 4b91018b70
7 changed files with 117 additions and 118 deletions

View File

@ -72,27 +72,24 @@ public class OsuHitObject {
/** The container height. */ /** The container height. */
private static int containerHeight; private static int containerHeight;
/** The offset per stack. */
private static float stackOffset;
/** /**
* Return stack position modifier in pixels. * Returns the stack position modifier, in pixels.
* @return stack position modifier. * @return stack position modifier
*/ */
public static float getStackOffset() { return stackOffset; } public static float getStackOffset() { return stackOffset; }
/** /**
* Sets stack position modifier in pixels * Sets the stack position modifier.
* @param offset position modifier. * @param offset stack position modifier, in pixels
*/ */
public static void setStackOffset(float offset) { stackOffset = offset; } public static void setStackOffset(float offset) { stackOffset = offset; }
/** The offset per stack. */
private static float stackOffset;
/** Starting coordinates. */ /** Starting coordinates. */
private float x, y; private float x, y;
/** Hit object index in current stack. */
private int stack;
/** Start time (in ms). */ /** Start time (in ms). */
private int time; private int time;
@ -132,6 +129,9 @@ public class OsuHitObject {
/** Number to display in hit object. */ /** Number to display in hit object. */
private int comboNumber; private int comboNumber;
/** Hit object index in the current stack. */
private int stack;
/** /**
* Initializes the OsuHitObject data type with container dimensions. * Initializes the OsuHitObject data type with container dimensions.
* @param width the container width * @param width the container width
@ -279,18 +279,6 @@ public class OsuHitObject {
return (y - stack * stackOffset) * yMultiplier + yOffset; return (y - stack * stackOffset) * yMultiplier + yOffset;
} }
/**
* Sets the hit object index in current stack.
* @param stack index in stack
*/
public void setStack(int stack) { this.stack = stack; }
/**
* Returns hit object index in current stack.
* @return index in stack
*/
public int getStack() { return stack; }
/** /**
* Returns the start time. * Returns the start time.
* @return the start time (in ms) * @return the start time (in ms)
@ -481,6 +469,18 @@ public class OsuHitObject {
return 0; return 0;
} }
/**
* Sets the hit object index in the current stack.
* @param stack index in the stack
*/
public void setStack(int stack) { this.stack = stack; }
/**
* Returns the hit object index in the current stack.
* @return index in the stack
*/
public int getStack() { return stack; }
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();

View File

@ -251,12 +251,12 @@ public class Utils {
} }
/** /**
* * Returns the distance between two points.
* @param x1 The x-component of the first point * @param x1 the x-component of the first point
* @param y1 The y-component of the first point * @param y1 the y-component of the first point
* @param x2 The x-component of the second point * @param x2 the x-component of the second point
* @param y2 The y-component of the second point * @param y2 the y-component of the second point
* @return Euclidean distance between points (x1,y1) and (x2,y2) * @return the Euclidean distance between points (x1,y1) and (x2,y2)
*/ */
public static float distance(float x1, float y1, float x2, float y2) { public static float distance(float x1, float y1, float x2, float y2) {
float v1 = Math.abs(x1 - x2); float v1 = Math.abs(x1 - x2);

View File

@ -74,12 +74,11 @@ public class Circle implements HitObject {
*/ */
public Circle(OsuHitObject hitObject, Game game, GameData data, Color color, boolean comboEnd) { public Circle(OsuHitObject hitObject, Game game, GameData data, Color color, boolean comboEnd) {
this.hitObject = hitObject; this.hitObject = hitObject;
this.x = hitObject.getScaledX();
this.y = hitObject.getScaledY();
this.game = game; this.game = game;
this.data = data; this.data = data;
this.color = color; this.color = color;
this.comboEnd = comboEnd; this.comboEnd = comboEnd;
updatePosition();
} }
@Override @Override

View File

@ -38,8 +38,7 @@ public class DummyObject implements HitObject {
*/ */
public DummyObject(OsuHitObject hitObject) { public DummyObject(OsuHitObject hitObject) {
this.hitObject = hitObject; this.hitObject = hitObject;
this.x = hitObject.getScaledX(); updatePosition();
this.y = hitObject.getScaledY();
} }
@Override @Override
@ -53,15 +52,15 @@ public class DummyObject implements HitObject {
@Override @Override
public boolean mousePressed(int x, int y, int trackPosition) { return false; } public boolean mousePressed(int x, int y, int trackPosition) { return false; }
@Override
public void updatePosition() {
this.x = hitObject.getScaledX();
this.y = hitObject.getScaledY();
}
@Override @Override
public float[] getPointAt(int trackPosition) { return new float[] { x, y }; } public float[] getPointAt(int trackPosition) { return new float[] { x, y }; }
@Override @Override
public int getEndTime() { return hitObject.getTime(); } public int getEndTime() { return hitObject.getTime(); }
@Override
public void updatePosition() {
this.x = hitObject.getScaledX();
this.y = hitObject.getScaledY();
}
} }

View File

@ -18,7 +18,6 @@
package itdelatrisu.opsu.objects; package itdelatrisu.opsu.objects;
import itdelatrisu.opsu.OsuHitObject;
import org.newdawn.slick.Graphics; import org.newdawn.slick.Graphics;
/** /**
@ -67,7 +66,7 @@ public interface HitObject {
public int getEndTime(); public int getEndTime();
/** /**
* Updates position of hit object. * Updates the position of the hit object.
*/ */
public void updatePosition(); public void updatePosition();
} }

View File

@ -135,17 +135,11 @@ public class Slider implements HitObject {
*/ */
public Slider(OsuHitObject hitObject, Game game, GameData data, Color color, boolean comboEnd) { public Slider(OsuHitObject hitObject, Game game, GameData data, Color color, boolean comboEnd) {
this.hitObject = hitObject; this.hitObject = hitObject;
this.x = hitObject.getScaledX();
this.y = hitObject.getScaledY();
this.game = game; this.game = game;
this.data = data; this.data = data;
this.color = color; this.color = color;
this.comboEnd = comboEnd; this.comboEnd = comboEnd;
updatePosition();
if (hitObject.getSliderType() == OsuHitObject.SLIDER_PASSTHROUGH && hitObject.getSliderX().length == 2)
this.curve = new CircumscribedCircle(hitObject, color);
else
this.curve = new LinearBezier(hitObject, color);
// slider time calculations // slider time calculations
this.sliderTime = game.getBeatLength() * (hitObject.getPixelLength() / sliderMultiplier) / 100f; this.sliderTime = game.getBeatLength() * (hitObject.getPixelLength() / sliderMultiplier) / 100f;

View File

@ -86,10 +86,10 @@ public class Game extends BasicGameState {
/** Minimum time before start of song, in milliseconds, to process skip-related actions. */ /** Minimum time before start of song, in milliseconds, to process skip-related actions. */
private static final int SKIP_OFFSET = 2000; private static final int SKIP_OFFSET = 2000;
/** Tolerance in case if hit object is not snapped to the grid */ /** Tolerance in case if hit object is not snapped to the grid. */
private static final float STACK_LENIENCE = 3f; private static final float STACK_LENIENCE = 3f;
/** Stack time window of the previous object in ms. */ /** Stack time window of the previous object, in ms. */
private static final int STACK_TIMEOUT = 1000; private static final int STACK_TIMEOUT = 1000;
/** Stack position offset modifier. */ /** Stack position offset modifier. */
@ -1044,10 +1044,9 @@ public class Game extends BasicGameState {
int timingPointIndex = 0; int timingPointIndex = 0;
while (timingPointIndex < osu.timingPoints.size()) { while (timingPointIndex < osu.timingPoints.size()) {
OsuTimingPoint timingPoint = osu.timingPoints.get(timingPointIndex); OsuTimingPoint timingPoint = osu.timingPoints.get(timingPointIndex);
if (timingPoint.getTime() <= hitObjectTime) { if (timingPoint.getTime() > hitObjectTime)
setBeatLength(timingPoint);
} else
break; break;
setBeatLength(timingPoint);
timingPointIndex++; timingPointIndex++;
} }
@ -1067,72 +1066,8 @@ public class Game extends BasicGameState {
} }
} }
// stack calculation // stack calculations
// more info: https://gist.github.com/peppy/1167470 calculateStacks();
// @author peppy
for (int i = hitObjects.length - 1; i > 0; i--) {
OsuHitObject hitObjectI = osu.objects[i];
// already calculated
if (hitObjectI.getStack() != 0 || hitObjectI.isSpinner())
continue;
// search for hit objects in stack
for (int n = i -1; n >= 0; n--) {
OsuHitObject hitObjectN = osu.objects[n];
if (hitObjectN.isSpinner())
continue;
// check if in range stack calculation
float timeI = hitObjectI.getTime() - (STACK_TIMEOUT * osu.stackLeniency);
float timeN = hitObjectN.isSlider() ? hitObjects[n].getEndTime() : hitObjectN.getTime();
if (timeI > timeN)
break;
if (hitObjectN.isSlider()) {
// possible special case. if slider end in the stack, all next hit objects in stack moves right down
Slider slider = (Slider) hitObjects[n];
float x1 = hitObjects[i].getPointAt(hitObjectI.getTime())[0];
float y1 = hitObjects[i].getPointAt(hitObjectI.getTime())[1];
float x2 = slider.getPointAt(slider.getEndTime())[0];
float y2 = slider.getPointAt(slider.getEndTime())[1];
float distance = Utils.distance(x1, y1, x2, y2);
// check if hit object part of this stack
if (distance < STACK_LENIENCE * OsuHitObject.getXMultiplier()) {
int offset = hitObjectI.getStack() - hitObjectN.getStack() + 1;
for (int j = n + 1; j <= i; j++) {
OsuHitObject hitObjectJ = osu.objects[j];
x1 = hitObjects[j].getPointAt(hitObjectJ.getTime())[0];
y1 = hitObjects[j].getPointAt(hitObjectJ.getTime())[1];
distance = Utils.distance(x1, y1, x2, y2);
if (distance < STACK_LENIENCE * OsuHitObject.getXMultiplier()) {
// hit object below slider end
hitObjectJ.setStack(hitObjectJ.getStack() - offset);
}
}
// slider end always start of the stack. reset calculation
break;
}
}
// not a special case. stack moves up left
float distance = Utils.distance(hitObjectI.getX(), hitObjectI.getY(),
hitObjectN.getX(), hitObjectN.getY());
if (distance < STACK_LENIENCE) {
hitObjectN.setStack(hitObjectI.getStack() + 1);
hitObjectI = hitObjectN;
}
}
}
// update hit objects positions
for (int i = 0; i < hitObjects.length; i++) {
if(osu.objects[i].getStack() != 0) {
hitObjects[i].updatePosition();
}
}
// load the first timingPoint // load the first timingPoint
if (!osu.timingPoints.isEmpty()) { if (!osu.timingPoints.isEmpty()) {
@ -1670,4 +1605,77 @@ public class Game extends BasicGameState {
} }
} }
} }
/**
* Performs stacking calculations on all hit objects, and updates their
* positions if necessary.
* https://gist.github.com/peppy/1167470
* @author peppy
*/
private void calculateStacks() {
// reverse pass for stack calculation
for (int i = hitObjects.length - 1; i > 0; i--) {
OsuHitObject hitObjectI = osu.objects[i];
// already calculated
if (hitObjectI.getStack() != 0 || hitObjectI.isSpinner())
continue;
// search for hit objects in stack
for (int n = i -1; n >= 0; n--) {
OsuHitObject hitObjectN = osu.objects[n];
if (hitObjectN.isSpinner())
continue;
// check if in range stack calculation
float timeI = hitObjectI.getTime() - (STACK_TIMEOUT * osu.stackLeniency);
float timeN = hitObjectN.isSlider() ? hitObjects[n].getEndTime() : hitObjectN.getTime();
if (timeI > timeN)
break;
// possible special case: if slider end in the stack,
// all next hit objects in stack move right down
if (hitObjectN.isSlider()) {
Slider slider = (Slider) hitObjects[n];
float x1 = hitObjects[i].getPointAt(hitObjectI.getTime())[0];
float y1 = hitObjects[i].getPointAt(hitObjectI.getTime())[1];
float x2 = slider.getPointAt(slider.getEndTime())[0];
float y2 = slider.getPointAt(slider.getEndTime())[1];
float distance = Utils.distance(x1, y1, x2, y2);
// check if hit object part of this stack
if (distance < STACK_LENIENCE * OsuHitObject.getXMultiplier()) {
int offset = hitObjectI.getStack() - hitObjectN.getStack() + 1;
for (int j = n + 1; j <= i; j++) {
OsuHitObject hitObjectJ = osu.objects[j];
x1 = hitObjects[j].getPointAt(hitObjectJ.getTime())[0];
y1 = hitObjects[j].getPointAt(hitObjectJ.getTime())[1];
distance = Utils.distance(x1, y1, x2, y2);
// hit object below slider end
if (distance < STACK_LENIENCE * OsuHitObject.getXMultiplier())
hitObjectJ.setStack(hitObjectJ.getStack() - offset);
}
break; // slider end always start of the stack: reset calculation
}
}
// not a special case: stack moves up left
float distance = Utils.distance(
hitObjectI.getX(), hitObjectI.getY(),
hitObjectN.getX(), hitObjectN.getY()
);
if (distance < STACK_LENIENCE) {
hitObjectN.setStack(hitObjectI.getStack() + 1);
hitObjectI = hitObjectN;
}
}
}
// update hit object positions
for (int i = 0; i < hitObjects.length; i++) {
if (osu.objects[i].getStack() != 0)
hitObjects[i].updatePosition();
}
}
} }