Some code cleanup.

- Overhauled OsuTimingPoint class: parsing is done in the constructor, and fields are no longer public.
- Improved consistency of static/non-static fields in a couple of classes.

Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
Jeffrey Han 2014-07-09 13:36:42 -04:00
parent 50fb71e353
commit 5a1972a2bd
7 changed files with 172 additions and 64 deletions

View File

@ -336,35 +336,20 @@ public class OsuParser {
continue; continue;
if (line.charAt(0) == '[') if (line.charAt(0) == '[')
break; break;
tokens = line.split(",");
OsuTimingPoint timingPoint = new OsuTimingPoint(); // parse timing point
try { // newer file versions have many new fields OsuTimingPoint timingPoint = new OsuTimingPoint(line);
timingPoint.time = (int) Float.parseFloat(tokens[0]); //rare float
timingPoint.meter = Integer.parseInt(tokens[2]);
timingPoint.sampleType = Byte.parseByte(tokens[3]);
timingPoint.sampleTypeCustom = Byte.parseByte(tokens[4]);
timingPoint.sampleVolume = Integer.parseInt(tokens[5]);
timingPoint.inherited = (Integer.parseInt(tokens[6]) == 1);
timingPoint.kiai = (Integer.parseInt(tokens[7]) == 1);
} catch (ArrayIndexOutOfBoundsException e) {
// TODO: better support for old formats
// Log.error(String.format("Error while parsing TimingPoints, line: '%s'.", line), e);
}
// tokens[1] is either beatLength (positive) or velocity (negative) // calculate BPM
float beatLength = Float.parseFloat(tokens[1]); if (!timingPoint.isInherited()) {
if (beatLength > 0) { int bpm = Math.round(60000 / timingPoint.getBeatLength());
timingPoint.beatLength = beatLength;
int bpm = Math.round(60000 / beatLength);
if (osu.bpmMin == 0) if (osu.bpmMin == 0)
osu.bpmMin = osu.bpmMax = bpm; osu.bpmMin = osu.bpmMax = bpm;
else if (bpm < osu.bpmMin) else if (bpm < osu.bpmMin)
osu.bpmMin = bpm; osu.bpmMin = bpm;
else if (bpm > osu.bpmMax) else if (bpm > osu.bpmMax)
osu.bpmMax = bpm; osu.bpmMax = bpm;
} else }
timingPoint.velocity = (int) beatLength;
osu.timingPoints.add(timingPoint); osu.timingPoints.add(timingPoint);
} }

View File

@ -18,22 +18,145 @@
package itdelatrisu.opsu; package itdelatrisu.opsu;
import org.newdawn.slick.util.Log;
/** /**
* Data type representing a timing point. * Data type representing a timing point.
*/ */
public class OsuTimingPoint { public class OsuTimingPoint {
public int time; // start time/offset (in ms) /**
public float beatLength; // (non-inherited) ms per beat * Timing point start time/offset (in ms).
public int velocity = 0; // (inherited) slider multiplier = -100 / value */
public int meter; // beats per measure private int time = 0;
public byte sampleType; // sound samples (0:none, 1:normal, 2:soft, 3:drum)
public byte sampleTypeCustom; // custom samples (0:default, 1:custom1, 2:custom2) /**
public int sampleVolume; // volume of samples (0~100) * Time per beat (in ms). [NON-INHERITED]
public boolean inherited; // is this timing point inherited? */
public boolean kiai; // is Kiai Mode active? private float beatLength = 0f;
/**
* Slider multiplier. [INHERITED]
*/
private int velocity = 0;
/**
* Beats per measure.
*/
private int meter = 4;
/**
* Sound sample type.
*/
private byte sampleType = 1;
/**
* Custom sound sample type.
*/
private byte sampleTypeCustom = 0;
/**
* Volume of samples. [0, 100]
*/
private int sampleVolume = 100;
/**
* Whether or not this timing point is inherited.
*/
private boolean inherited = false;
/**
* Whether or not Kiai Mode is active.
*/
private boolean kiai = false;
/** /**
* Constructor. * Constructor.
* @param line the line to be parsed
*/ */
public OsuTimingPoint() {} public OsuTimingPoint(String line) {
// TODO: better support for old formats
String[] tokens = line.split(",");
try {
this.time = (int) Float.parseFloat(tokens[0]); // rare float
this.meter = Integer.parseInt(tokens[2]);
this.sampleType = Byte.parseByte(tokens[3]);
this.sampleTypeCustom = Byte.parseByte(tokens[4]);
this.sampleVolume = Integer.parseInt(tokens[5]);
// this.inherited = (Integer.parseInt(tokens[6]) == 1);
this.kiai = (Integer.parseInt(tokens[7]) == 1);
} catch (ArrayIndexOutOfBoundsException e) {
Log.debug(String.format("Error parsing timing point: '%s'", line));
}
// tokens[1] is either beatLength (positive) or velocity (negative)
float beatLength = Float.parseFloat(tokens[1]);
if (beatLength > 0)
this.beatLength = beatLength;
else {
this.velocity = (int) beatLength;
this.inherited = true;
}
}
/**
* Returns the timing point start time/offset.
* @return the start time (in ms)
*/
public int getTime() { return time; }
/**
* Returns the beat length. [NON-INHERITED]
* @return the time per beat (in ms)
*/
public float getBeatLength() { return beatLength; }
/**
* Returns the slider multiplier. [INHERITED]
*/
public float getSliderMultiplier() { return velocity / -100f; }
/**
* Returns the meter.
* @return the number of beats per measure
*/
public int getMeter() { return meter; }
/**
* Returns the sample type.
* <ul>
* <li>0: none
* <li>1: normal
* <li>2: soft
* <li>3: drum
* </ul>
*/
public byte getSampleType() { return sampleType; }
/**
* Returns the custom sample type.
* <ul>
* <li>0: default
* <li>1: custom 1
* <li>2: custom 2
* </ul>
*/
public byte getSampleTypeCustom() { return sampleTypeCustom; }
/**
* Returns the sample volume.
* @return the sample volume [0, 1]
*/
public float getSampleVolume() { return sampleVolume / 100f; }
/**
* Returns whether or not this timing point is inherited.
* @return the inherited
*/
public boolean isInherited() { return inherited; }
/**
* Returns whether or not Kiai Time is active.
* @return true if active
*/
public boolean isKiaiTimeActive() { return kiai; }
} }

View File

@ -231,11 +231,11 @@ public class SoundController {
/** /**
* Sets the sample volume (modifies the global sample volume). * Sets the sample volume (modifies the global sample volume).
* @param volume the sample volume [0, 100] * @param volume the sample volume [0, 1]
*/ */
public static void setSampleVolume(int volume) { public static void setSampleVolume(float volume) {
if (volume >= 0 && volume <= 100) if (volume >= 0f && volume <= 1f)
sampleVolumeMultiplier = volume / 100f; sampleVolumeMultiplier = volume;
} }
/** /**

View File

@ -71,7 +71,7 @@ public class Game extends BasicGameState {
/** /**
* The associated OsuFile object. * The associated OsuFile object.
*/ */
private static OsuFile osu; private OsuFile osu;
/** /**
* The associated GameScore object (holds all score data). * The associated GameScore object (holds all score data).
@ -101,7 +101,7 @@ public class Game extends BasicGameState {
/** /**
* Delay time, in milliseconds, before song starts. * Delay time, in milliseconds, before song starts.
*/ */
private static int leadInTime; private int leadInTime;
/** /**
* Hit object approach time, in milliseconds. * Hit object approach time, in milliseconds.
@ -141,7 +141,7 @@ 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 final int skipOffsetTime = 2000; private static final int SKIP_OFFSET = 2000;
/** /**
* Current timing point index in timingPoints ArrayList. * Current timing point index in timingPoints ArrayList.
@ -308,8 +308,8 @@ public class Game extends BasicGameState {
// skip beginning // skip beginning
if (objectIndex == 0 && if (objectIndex == 0 &&
osu.objects[0].time - skipOffsetTime > 5000 && osu.objects[0].time - SKIP_OFFSET > 5000 &&
trackPosition < osu.objects[0].time - skipOffsetTime) trackPosition < osu.objects[0].time - SKIP_OFFSET)
skipButton.draw(); skipButton.draw();
if (isLeadIn()) if (isLeadIn())
@ -456,13 +456,13 @@ public class Game extends BasicGameState {
// timing points // timing points
if (timingPointIndex < osu.timingPoints.size()) { if (timingPointIndex < osu.timingPoints.size()) {
OsuTimingPoint timingPoint = osu.timingPoints.get(timingPointIndex); OsuTimingPoint timingPoint = osu.timingPoints.get(timingPointIndex);
if (trackPosition >= timingPoint.time) { if (trackPosition >= timingPoint.getTime()) {
if (timingPoint.velocity >= 0) if (!timingPoint.isInherited())
beatLengthBase = beatLength = timingPoint.beatLength; beatLengthBase = beatLength = timingPoint.getBeatLength();
else else
beatLength = beatLengthBase * (timingPoint.velocity / -100f); beatLength = beatLengthBase * timingPoint.getSliderMultiplier();
SoundController.setSampleSet(timingPoint.sampleType); SoundController.setSampleSet(timingPoint.getSampleType());
SoundController.setSampleVolume(timingPoint.sampleVolume); SoundController.setSampleVolume(timingPoint.getSampleVolume());
timingPointIndex++; timingPointIndex++;
} }
} }
@ -644,7 +644,7 @@ public class Game extends BasicGameState {
pauseTime = -1; pauseTime = -1;
pausedMouseX = -1; pausedMouseX = -1;
pausedMouseY = -1; pausedMouseY = -1;
if (!Game.isLeadIn()) if (!isLeadIn())
MusicController.resume(); MusicController.resume();
} }
return; return;
@ -751,10 +751,10 @@ public class Game extends BasicGameState {
// load the first timingPoint // load the first timingPoint
if (!osu.timingPoints.isEmpty()) { if (!osu.timingPoints.isEmpty()) {
OsuTimingPoint timingPoint = osu.timingPoints.get(0); OsuTimingPoint timingPoint = osu.timingPoints.get(0);
if (timingPoint.velocity >= 0) { if (!timingPoint.isInherited()) {
beatLengthBase = beatLength = timingPoint.beatLength; beatLengthBase = beatLength = timingPoint.getBeatLength();
SoundController.setSampleSet(timingPoint.sampleType); SoundController.setSampleSet(timingPoint.getSampleType());
SoundController.setSampleVolume(timingPoint.sampleVolume); SoundController.setSampleVolume(timingPoint.getSampleVolume());
timingPointIndex++; timingPointIndex++;
} }
} }
@ -777,13 +777,13 @@ public class Game extends BasicGameState {
private boolean skipIntro() { private boolean skipIntro() {
int trackPosition = MusicController.getPosition(); int trackPosition = MusicController.getPosition();
if (objectIndex == 0 && if (objectIndex == 0 &&
osu.objects[0].time - skipOffsetTime > 4000 && osu.objects[0].time - SKIP_OFFSET > 4000 &&
trackPosition < osu.objects[0].time - skipOffsetTime) { trackPosition < osu.objects[0].time - SKIP_OFFSET) {
if (isLeadIn()) { if (isLeadIn()) {
leadInTime = 0; leadInTime = 0;
MusicController.resume(); MusicController.resume();
} }
MusicController.setPosition(osu.objects[0].time - skipOffsetTime); MusicController.setPosition(osu.objects[0].time - SKIP_OFFSET);
SoundController.playSound(SoundController.SOUND_MENUHIT); SoundController.playSound(SoundController.SOUND_MENUHIT);
return true; return true;
} }
@ -931,7 +931,7 @@ public class Game extends BasicGameState {
/** /**
* Returns whether or not the track is in the lead-in time state. * Returns whether or not the track is in the lead-in time state.
*/ */
public static boolean isLeadIn() { return leadInTime > 0; } public boolean isLeadIn() { return leadInTime > 0; }
/** /**
* Returns the object approach time, in milliseconds. * Returns the object approach time, in milliseconds.

View File

@ -50,7 +50,7 @@ public class GameRanking extends BasicGameState {
/** /**
* Associated GameScore object. * Associated GameScore object.
*/ */
private static GameScore score; private GameScore score;
/** /**
* "Retry" and "Exit" buttons. * "Retry" and "Exit" buttons.

View File

@ -209,9 +209,9 @@ public class MainMenu extends BasicGameState {
long time = System.currentTimeMillis() - osuStartTime; long time = System.currentTimeMillis() - osuStartTime;
g.drawString(String.format("opsu! has been running for %d minutes, %d seconds.", g.drawString(String.format("opsu! has been running for %d minutes, %d seconds.",
TimeUnit.MILLISECONDS.toMinutes(time), TimeUnit.MILLISECONDS.toMinutes(time),
TimeUnit.MILLISECONDS.toSeconds(time) - TimeUnit.MILLISECONDS.toSeconds(time) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(time))), TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(time))),
25, height - 25 - (lineHeight * 2)); 25, height - 25 - (lineHeight * 2));
g.drawString(String.format("The current time is %s.", g.drawString(String.format("The current time is %s.",
new SimpleDateFormat("h:mm a").format(new Date())), new SimpleDateFormat("h:mm a").format(new Date())),
25, height - 25 - lineHeight); 25, height - 25 - lineHeight);

View File

@ -118,7 +118,7 @@ public class Options extends BasicGameState {
/** /**
* Game options. * Game options.
*/ */
private enum GameOption { private static enum GameOption {
NULL, NULL,
SCREEN_RESOLUTION, SCREEN_RESOLUTION,
// FULLSCREEN, // FULLSCREEN,
@ -168,7 +168,7 @@ public class Options extends BasicGameState {
/** /**
* Option tab buttons. * Option tab buttons.
*/ */
private GUIMenuButton[] optionTabs = new GUIMenuButton[TAB_MAX]; private static GUIMenuButton[] optionTabs = new GUIMenuButton[TAB_MAX];
/** /**
* Current tab. * Current tab.
@ -870,7 +870,7 @@ public class Options extends BasicGameState {
drawOption(pos, "Track Checkpoint", drawOption(pos, "Track Checkpoint",
(checkpoint == 0) ? "Disabled" : String.format("%02d:%02d", (checkpoint == 0) ? "Disabled" : String.format("%02d:%02d",
TimeUnit.SECONDS.toMinutes(checkpoint), TimeUnit.SECONDS.toMinutes(checkpoint),
checkpoint - TimeUnit.MINUTES.toSeconds(TimeUnit.SECONDS.toMinutes(checkpoint))), checkpoint - TimeUnit.MINUTES.toSeconds(TimeUnit.SECONDS.toMinutes(checkpoint))),
"Press CTRL+L while playing to load a checkpoint, and CTRL+S to set one." "Press CTRL+L while playing to load a checkpoint, and CTRL+S to set one."
); );
break; break;
@ -975,8 +975,8 @@ public class Options extends BasicGameState {
public static float getEffectVolume() { return effectVolume / 100f; } public static float getEffectVolume() { return effectVolume / 100f; }
/** /**
* Returns the default sound effect volume. * Returns the default hit sound volume.
* @return the sound volume [0, 1] * @return the hit sound volume [0, 1]
*/ */
public static float getHitSoundVolume() { return hitSoundVolume / 100f; } public static float getHitSoundVolume() { return hitSoundVolume / 100f; }