Added initial support for loading beatmap skins.
- Added a GameImage enum for more organized loading of image resources. - Game image loading now takes place directly before each beatmap is loaded. - Added option 'IGNORE_BEATMAP_SKINS' to disable this feature. Other changes: - Slight correction in readme file: apparently the JAR will not run in the osu! program folder. Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
parent
c72b9b955a
commit
16afcaf3e6
|
@ -17,10 +17,9 @@ opsu! also requires beatmaps to run, which are available for download on the
|
||||||
[osu!Mirror](https://osu.yas-online.net/) or [Bloodcat](http://bloodcat.com/osu/).
|
[osu!Mirror](https://osu.yas-online.net/) or [Bloodcat](http://bloodcat.com/osu/).
|
||||||
|
|
||||||
If osu! is already installed, this application will attempt to load songs
|
If osu! is already installed, this application will attempt to load songs
|
||||||
directly from the osu! program folder. Otherwise, run this application from
|
directly from the osu! program folder. Otherwise, place songs in the generated
|
||||||
one directory above the root song directory, or place songs in the generated
|
`Songs` folder or set the `BeatmapDirectory` value in the generated
|
||||||
`songs` folder. This path can be changed at any time by editing the
|
configuration file to the path of the root song directory.
|
||||||
`BeatmapDirectory` value in the generated configuration file.
|
|
||||||
|
|
||||||
### First Run
|
### First Run
|
||||||
The `Music Offset` value will likely need to be adjusted when playing for the
|
The `Music Offset` value will likely need to be adjusted when playing for the
|
||||||
|
|
178
src/itdelatrisu/opsu/GameImage.java
Normal file
178
src/itdelatrisu/opsu/GameImage.java
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
/*
|
||||||
|
* opsu! - an open-source osu! client
|
||||||
|
* Copyright (C) 2014 Jeffrey Han
|
||||||
|
*
|
||||||
|
* opsu! is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* opsu! is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with opsu!. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package itdelatrisu.opsu;
|
||||||
|
|
||||||
|
import itdelatrisu.opsu.states.Options;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import org.newdawn.slick.Image;
|
||||||
|
import org.newdawn.slick.SlickException;
|
||||||
|
import org.newdawn.slick.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Game images.
|
||||||
|
*/
|
||||||
|
public enum GameImage {
|
||||||
|
// Game
|
||||||
|
SECTION_PASS ("section-pass.png"),
|
||||||
|
SECTION_FAIL ("section-fail.png"),
|
||||||
|
WARNINGARROW ("play-warningarrow.png"),
|
||||||
|
SKIP ("play-skip.png"),
|
||||||
|
COUNTDOWN_READY ("ready.png"),
|
||||||
|
COUNTDOWN_3 ("count3.png"),
|
||||||
|
COUNTDOWN_2 ("count2.png"),
|
||||||
|
COUNTDOWN_1 ("count1.png"),
|
||||||
|
COUNTDOWN_GO ("go.png"),
|
||||||
|
HITCIRCLE_SELECT ("hitcircleselect.png"),
|
||||||
|
UNRANKED ("play-unranked.png"),
|
||||||
|
|
||||||
|
// Game Pause/Fail
|
||||||
|
PAUSE_CONTINUE ("pause-continue.png"),
|
||||||
|
PAUSE_RETRY ("pause-retry.png"),
|
||||||
|
PAUSE_BACK ("pause-back.png"),
|
||||||
|
PAUSE_OVERLAY ("pause-overlay.png"),
|
||||||
|
FAIL_BACKGROUND ("fail-background.png"),
|
||||||
|
|
||||||
|
// Circle
|
||||||
|
HITCIRCLE ("hitcircle.png"),
|
||||||
|
HITCIRCLE_OVERLAY ("hitcircleoverlay.png"),
|
||||||
|
APPROACHCIRCLE ("approachcircle.png"),
|
||||||
|
|
||||||
|
// Slider
|
||||||
|
SLIDER_FOLLOWCIRCLE ("sliderfollowcircle.png"),
|
||||||
|
REVERSEARROW ("reversearrow.png"),
|
||||||
|
SLIDER_TICK ("sliderscorepoint.png"),
|
||||||
|
|
||||||
|
// Spinner
|
||||||
|
SPINNER_CIRCLE ("spinner-circle.png"),
|
||||||
|
SPINNER_APPROACHCIRCLE ("spinner-approachcircle.png"),
|
||||||
|
SPINNER_METRE ("spinner-metre.png"),
|
||||||
|
SPINNER_SPIN ("spinner-spin.png"),
|
||||||
|
SPINNER_CLEAR ("spinner-clear.png"),
|
||||||
|
SPINNER_OSU ("spinner-osu.png"),
|
||||||
|
|
||||||
|
// Game Score
|
||||||
|
SCOREBAR_BG ("scorebar-bg.png"),
|
||||||
|
SCOREBAR_COLOUR ("scorebar-colour.png"),
|
||||||
|
SCOREBAR_KI ("scorebar-ki.png"),
|
||||||
|
SCOREBAR_KI_DANGER ("scorebar-kidanger.png"),
|
||||||
|
SCOREBAR_KI_DANGER2 ("scorebar-kidanger2.png"),
|
||||||
|
HIT_MISS ("hit0.png"),
|
||||||
|
HIT_50 ("hit50.png"),
|
||||||
|
HIT_100 ("hit100.png"),
|
||||||
|
HIT_300 ("hit300.png"),
|
||||||
|
HIT_100K ("hit100k.png"),
|
||||||
|
HIT_300K ("hit300k.png"),
|
||||||
|
HIT_300G ("hit300g.png"),
|
||||||
|
HIT_SLIDER10 ("sliderpoint10.png"),
|
||||||
|
HIT_SLIDER30 ("sliderpoint30.png"),
|
||||||
|
RANKING_SS ("ranking-X.png"),
|
||||||
|
RANKING_SS_SMALL ("ranking-X-small.png"),
|
||||||
|
RANKING_SSH ("ranking-XH.png"),
|
||||||
|
RANKING_SSH_SMALL ("ranking-XH-small.png"),
|
||||||
|
RANKING_S ("ranking-S.png"),
|
||||||
|
RANKING_S_SMALL ("ranking-S-small.png"),
|
||||||
|
RANKING_SH ("ranking-SH.png"),
|
||||||
|
RANKING_SH_SMALL ("ranking-SH-small.png"),
|
||||||
|
RANKING_A ("ranking-A.png"),
|
||||||
|
RANKING_A_SMALL ("ranking-A-small.png"),
|
||||||
|
RANKING_B ("ranking-B.png"),
|
||||||
|
RANKING_B_SMALL ("ranking-B-small.png"),
|
||||||
|
RANKING_C ("ranking-C.png"),
|
||||||
|
RANKING_C_SMALL ("ranking-C-small.png"),
|
||||||
|
RANKING_D ("ranking-D.png"),
|
||||||
|
RANKING_D_SMALL ("ranking-D-small.png"),
|
||||||
|
RANKING_PANEL ("ranking-panel.png"),
|
||||||
|
RANKING_PERFECT ("ranking-perfect.png"),
|
||||||
|
RANKING_TITLE ("ranking-title.png"),
|
||||||
|
RANKING_MAXCOMBO ("ranking-maxcombo.png"),
|
||||||
|
RANKING_ACCURACY ("ranking-accuracy.png"),
|
||||||
|
DEFAULT_0 ("default-0.png"),
|
||||||
|
DEFAULT_1 ("default-1.png"),
|
||||||
|
DEFAULT_2 ("default-2.png"),
|
||||||
|
DEFAULT_3 ("default-3.png"),
|
||||||
|
DEFAULT_4 ("default-4.png"),
|
||||||
|
DEFAULT_5 ("default-5.png"),
|
||||||
|
DEFAULT_6 ("default-6.png"),
|
||||||
|
DEFAULT_7 ("default-7.png"),
|
||||||
|
DEFAULT_8 ("default-8.png"),
|
||||||
|
DEFAULT_9 ("default-9.png"),
|
||||||
|
SCORE_0 ("score-0.png"),
|
||||||
|
SCORE_1 ("score-1.png"),
|
||||||
|
SCORE_2 ("score-2.png"),
|
||||||
|
SCORE_3 ("score-3.png"),
|
||||||
|
SCORE_4 ("score-4.png"),
|
||||||
|
SCORE_5 ("score-5.png"),
|
||||||
|
SCORE_6 ("score-6.png"),
|
||||||
|
SCORE_7 ("score-7.png"),
|
||||||
|
SCORE_8 ("score-8.png"),
|
||||||
|
SCORE_9 ("score-9.png"),
|
||||||
|
SCORE_COMMA ("score-comma.png"),
|
||||||
|
SCORE_DOT ("score-dot.png"),
|
||||||
|
SCORE_PERCENT ("score-percent.png"),
|
||||||
|
SCORE_X ("score-x.png");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file name.
|
||||||
|
*/
|
||||||
|
private String filename;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The associated image.
|
||||||
|
*/
|
||||||
|
private Image img;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*/
|
||||||
|
GameImage(String filename) {
|
||||||
|
this.filename = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the associated image.
|
||||||
|
*/
|
||||||
|
public Image getImage() { return img; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets an image.
|
||||||
|
*/
|
||||||
|
public void setImage(Image img) { this.img = img; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets an image.
|
||||||
|
* Scans the path for the image first, then uses the default image.
|
||||||
|
*/
|
||||||
|
public void setImage(File dir) {
|
||||||
|
try {
|
||||||
|
// destroy the existing image, if any
|
||||||
|
if (img != null && !img.isDestroyed())
|
||||||
|
img.destroy();
|
||||||
|
|
||||||
|
// set a new image
|
||||||
|
File file = new File(dir, filename);
|
||||||
|
if (file.isFile() && !Options.isBeatmapSkinIgnored())
|
||||||
|
img = new Image(file.getAbsolutePath());
|
||||||
|
else
|
||||||
|
img = new Image(filename);
|
||||||
|
} catch (SlickException e) {
|
||||||
|
Log.error(String.format("Failed to set image '%s'.", filename), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ package itdelatrisu.opsu;
|
||||||
|
|
||||||
import itdelatrisu.opsu.states.Options;
|
import itdelatrisu.opsu.states.Options;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
@ -28,7 +29,6 @@ import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.Graphics;
|
import org.newdawn.slick.Graphics;
|
||||||
import org.newdawn.slick.Image;
|
import org.newdawn.slick.Image;
|
||||||
import org.newdawn.slick.SlickException;
|
import org.newdawn.slick.SlickException;
|
||||||
import org.newdawn.slick.util.Log;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds score data and renders all score-related elements.
|
* Holds score data and renders all score-related elements.
|
||||||
|
@ -179,26 +179,6 @@ public class GameScore {
|
||||||
*/
|
*/
|
||||||
private float difficulty = 5f;
|
private float difficulty = 5f;
|
||||||
|
|
||||||
/**
|
|
||||||
* Scorebar-related images.
|
|
||||||
*/
|
|
||||||
private Image
|
|
||||||
bgImage, // background (always rendered)
|
|
||||||
colourImage, // health bar (cropped)
|
|
||||||
kiImage, // end image (50~100% health)
|
|
||||||
kiDangerImage, // end image (25~50% health)
|
|
||||||
kiDanger2Image; // end image (0~25% health)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ranking screen images.
|
|
||||||
*/
|
|
||||||
private Image
|
|
||||||
rankingPanel, // panel to display text in
|
|
||||||
perfectImage, // display if full combo
|
|
||||||
rankingImage, // styled text "Ranking"
|
|
||||||
comboImage, // styled text "Combo"
|
|
||||||
accuracyImage; // styled text "Accuracy"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default text symbol images.
|
* Default text symbol images.
|
||||||
*/
|
*/
|
||||||
|
@ -233,20 +213,7 @@ public class GameScore {
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
|
|
||||||
hitResults = new Image[HIT_MAX];
|
|
||||||
defaultSymbols = new Image[10];
|
|
||||||
scoreSymbols = new HashMap<Character, Image>(14);
|
|
||||||
gradesLarge = new Image[GRADE_MAX];
|
|
||||||
gradesSmall = new Image[GRADE_MAX];
|
|
||||||
comboBurstImages = new Image[4];
|
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
try {
|
|
||||||
initializeImages();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.error("Failed to initialize images.", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -267,100 +234,150 @@ public class GameScore {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize all images tied to this object.
|
* Loads all game score images.
|
||||||
* @throws SlickException
|
* @throws SlickException
|
||||||
*/
|
*/
|
||||||
private void initializeImages() throws SlickException {
|
public void loadImages() throws SlickException {
|
||||||
// scorebar
|
File dir = MusicController.getOsuFile().getFile().getParentFile();
|
||||||
setScorebarImage(
|
|
||||||
new Image("scorebar-bg.png"),
|
|
||||||
new Image("scorebar-colour.png"),
|
|
||||||
new Image("scorebar-ki.png"),
|
|
||||||
new Image("scorebar-kidanger.png"),
|
|
||||||
new Image("scorebar-kidanger2.png")
|
|
||||||
);
|
|
||||||
|
|
||||||
// text symbol images
|
|
||||||
for (int i = 0; i <= 9; i++) {
|
|
||||||
defaultSymbols[i] = new Image(String.format("default-%d.png", i));
|
|
||||||
scoreSymbols.put(Character.forDigit(i, 10), new Image(String.format("score-%d.png", i)));
|
|
||||||
}
|
|
||||||
scoreSymbols.put(',', new Image("score-comma.png"));
|
|
||||||
scoreSymbols.put('.', new Image("score-dot.png"));
|
|
||||||
scoreSymbols.put('%', new Image("score-percent.png"));
|
|
||||||
scoreSymbols.put('x', new Image("score-x.png"));
|
|
||||||
|
|
||||||
// hit result images
|
|
||||||
hitResults[HIT_MISS] = new Image("hit0.png");
|
|
||||||
hitResults[HIT_50] = new Image("hit50.png");
|
|
||||||
hitResults[HIT_100] = new Image("hit100.png");
|
|
||||||
hitResults[HIT_300] = new Image("hit300.png");
|
|
||||||
hitResults[HIT_100K] = new Image("hit100k.png");
|
|
||||||
hitResults[HIT_300K] = new Image("hit300k.png");
|
|
||||||
hitResults[HIT_300G] = new Image("hit300g.png");
|
|
||||||
hitResults[HIT_SLIDER10] = new Image("sliderpoint10.png");
|
|
||||||
hitResults[HIT_SLIDER30] = new Image("sliderpoint30.png");
|
|
||||||
|
|
||||||
// combo burst images
|
// combo burst images
|
||||||
for (int i = 0; i <= 3; i++)
|
if (comboBurstImages != null) {
|
||||||
comboBurstImages[i] = new Image(String.format("comboburst-%d.png", i));
|
for (int i = 0; i < comboBurstImages.length; i++) {
|
||||||
|
if (!comboBurstImages[i].isDestroyed())
|
||||||
|
comboBurstImages[i].destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LinkedList<Image> comboBurst = new LinkedList<Image>();
|
||||||
|
String comboFormat = "comboburst-%d.png";
|
||||||
|
int comboIndex = 0;
|
||||||
|
File comboFile = new File(dir, "comboburst.png");
|
||||||
|
File comboFileN = new File(dir, String.format(comboFormat, comboIndex));
|
||||||
|
if (comboFileN.isFile()) { // beatmap provides images
|
||||||
|
do {
|
||||||
|
comboBurst.add(new Image(comboFileN.getAbsolutePath()));
|
||||||
|
comboFileN = new File(dir, String.format(comboFormat, ++comboIndex));
|
||||||
|
} while (comboFileN.isFile());
|
||||||
|
} else if (comboFile.isFile()) // beatmap provides single image
|
||||||
|
comboBurst.add(new Image(comboFile.getAbsolutePath()));
|
||||||
|
else { // load default images
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
Image comboImage = new Image(String.format(comboFormat, comboIndex++));
|
||||||
|
comboBurst.add(comboImage);
|
||||||
|
} catch (Exception e) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
comboBurstImages = comboBurst.toArray(new Image[comboBurst.size()]);
|
||||||
|
|
||||||
// lighting image
|
// lighting image
|
||||||
try {
|
if (lighting != null && !lighting.isDestroyed()) {
|
||||||
lighting = new Image("lighting.png");
|
lighting.destroy();
|
||||||
lighting1 = new Image("lighting1.png");
|
lighting = null;
|
||||||
} catch (Exception e) {
|
|
||||||
// optional
|
|
||||||
}
|
}
|
||||||
|
if (lighting1 != null && !lighting1.isDestroyed()) {
|
||||||
|
lighting1.destroy();
|
||||||
|
lighting1 = null;
|
||||||
|
}
|
||||||
|
File lightingFile = new File(dir, "lighting.png");
|
||||||
|
File lighting1File = new File(dir, "lighting1.png");
|
||||||
|
if (lightingFile.isFile()) { // beatmap provides images
|
||||||
|
try {
|
||||||
|
lighting = new Image(lightingFile.getAbsolutePath());
|
||||||
|
lighting1 = new Image(lighting1File.getAbsolutePath());
|
||||||
|
} catch (Exception e) {
|
||||||
|
// optional
|
||||||
|
}
|
||||||
|
} else { // load default image
|
||||||
|
try {
|
||||||
|
lighting = new Image("lighting.png");
|
||||||
|
lighting1 = new Image("lighting1.png");
|
||||||
|
} catch (Exception e) {
|
||||||
|
// optional
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// scorebar
|
||||||
|
Image bg = GameImage.SCOREBAR_BG.getImage();
|
||||||
|
Image colour = GameImage.SCOREBAR_COLOUR.getImage();
|
||||||
|
int bgWidth = width / 2;
|
||||||
|
GameImage.SCOREBAR_BG.setImage(bg.getScaledCopy(bgWidth, bg.getHeight()));
|
||||||
|
GameImage.SCOREBAR_COLOUR.setImage(colour.getScaledCopy(bgWidth, colour.getHeight()));
|
||||||
|
|
||||||
|
// default symbol images
|
||||||
|
defaultSymbols = new Image[10];
|
||||||
|
defaultSymbols[0] = GameImage.DEFAULT_0.getImage();
|
||||||
|
defaultSymbols[1] = GameImage.DEFAULT_1.getImage();
|
||||||
|
defaultSymbols[2] = GameImage.DEFAULT_2.getImage();
|
||||||
|
defaultSymbols[3] = GameImage.DEFAULT_3.getImage();
|
||||||
|
defaultSymbols[4] = GameImage.DEFAULT_4.getImage();
|
||||||
|
defaultSymbols[5] = GameImage.DEFAULT_5.getImage();
|
||||||
|
defaultSymbols[6] = GameImage.DEFAULT_6.getImage();
|
||||||
|
defaultSymbols[7] = GameImage.DEFAULT_7.getImage();
|
||||||
|
defaultSymbols[8] = GameImage.DEFAULT_8.getImage();
|
||||||
|
defaultSymbols[9] = GameImage.DEFAULT_9.getImage();
|
||||||
|
|
||||||
|
// score symbol images
|
||||||
|
scoreSymbols = new HashMap<Character, Image>(14);
|
||||||
|
scoreSymbols.put('0', GameImage.SCORE_0.getImage());
|
||||||
|
scoreSymbols.put('1', GameImage.SCORE_1.getImage());
|
||||||
|
scoreSymbols.put('2', GameImage.SCORE_2.getImage());
|
||||||
|
scoreSymbols.put('3', GameImage.SCORE_3.getImage());
|
||||||
|
scoreSymbols.put('4', GameImage.SCORE_4.getImage());
|
||||||
|
scoreSymbols.put('5', GameImage.SCORE_5.getImage());
|
||||||
|
scoreSymbols.put('6', GameImage.SCORE_6.getImage());
|
||||||
|
scoreSymbols.put('7', GameImage.SCORE_7.getImage());
|
||||||
|
scoreSymbols.put('8', GameImage.SCORE_8.getImage());
|
||||||
|
scoreSymbols.put('9', GameImage.SCORE_9.getImage());
|
||||||
|
scoreSymbols.put(',', GameImage.SCORE_COMMA.getImage());
|
||||||
|
scoreSymbols.put('.', GameImage.SCORE_DOT.getImage());
|
||||||
|
scoreSymbols.put('%', GameImage.SCORE_PERCENT.getImage());
|
||||||
|
scoreSymbols.put('x', GameImage.SCORE_X.getImage());
|
||||||
|
|
||||||
|
// hit result images
|
||||||
|
hitResults = new Image[HIT_MAX];
|
||||||
|
hitResults[HIT_MISS] = GameImage.HIT_MISS.getImage();
|
||||||
|
hitResults[HIT_50] = GameImage.HIT_50.getImage();
|
||||||
|
hitResults[HIT_100] = GameImage.HIT_100.getImage();
|
||||||
|
hitResults[HIT_300] = GameImage.HIT_300.getImage();
|
||||||
|
hitResults[HIT_100K] = GameImage.HIT_100K.getImage();
|
||||||
|
hitResults[HIT_300K] = GameImage.HIT_300K.getImage();
|
||||||
|
hitResults[HIT_300G] = GameImage.HIT_300G.getImage();
|
||||||
|
hitResults[HIT_SLIDER10] = GameImage.HIT_SLIDER10.getImage();
|
||||||
|
hitResults[HIT_SLIDER30] = GameImage.HIT_SLIDER30.getImage();
|
||||||
|
|
||||||
// letter grade images
|
// letter grade images
|
||||||
String[] grades = { "X", "XH", "S", "SH", "A", "B", "C", "D" };
|
gradesLarge = new Image[GRADE_MAX];
|
||||||
for (int i = 0; i < grades.length; i++) {
|
gradesSmall = new Image[GRADE_MAX];
|
||||||
gradesLarge[i] = new Image(String.format("ranking-%s.png", grades[i]));
|
gradesLarge[GRADE_SS] = GameImage.RANKING_SS.getImage();
|
||||||
gradesSmall[i] = new Image(String.format("ranking-%s-small.png", grades[i]));
|
gradesSmall[GRADE_SS] = GameImage.RANKING_SS_SMALL.getImage();
|
||||||
}
|
gradesLarge[GRADE_SSH] = GameImage.RANKING_SSH.getImage();
|
||||||
|
gradesSmall[GRADE_SSH] = GameImage.RANKING_SSH_SMALL.getImage();
|
||||||
|
gradesLarge[GRADE_S] = GameImage.RANKING_S.getImage();
|
||||||
|
gradesSmall[GRADE_S] = GameImage.RANKING_S_SMALL.getImage();
|
||||||
|
gradesLarge[GRADE_SH] = GameImage.RANKING_SH.getImage();
|
||||||
|
gradesSmall[GRADE_SH] = GameImage.RANKING_SH_SMALL.getImage();
|
||||||
|
gradesLarge[GRADE_A] = GameImage.RANKING_A.getImage();
|
||||||
|
gradesSmall[GRADE_A] = GameImage.RANKING_A_SMALL.getImage();
|
||||||
|
gradesLarge[GRADE_B] = GameImage.RANKING_B.getImage();
|
||||||
|
gradesSmall[GRADE_B] = GameImage.RANKING_B_SMALL.getImage();
|
||||||
|
gradesLarge[GRADE_C] = GameImage.RANKING_C.getImage();
|
||||||
|
gradesSmall[GRADE_C] = GameImage.RANKING_C_SMALL.getImage();
|
||||||
|
gradesLarge[GRADE_D] = GameImage.RANKING_D.getImage();
|
||||||
|
gradesSmall[GRADE_D] = GameImage.RANKING_D_SMALL.getImage();
|
||||||
|
|
||||||
// ranking screen elements
|
// ranking screen elements
|
||||||
setRankingImage(
|
Image rankingPanel = GameImage.RANKING_PANEL.getImage();
|
||||||
new Image("ranking-panel.png"),
|
Image rankingPerfect = GameImage.RANKING_PERFECT.getImage();
|
||||||
new Image("ranking-perfect.png"),
|
Image rankingTitle = GameImage.RANKING_TITLE.getImage();
|
||||||
new Image("ranking-title.png"),
|
Image rankingMaxCombo = GameImage.RANKING_MAXCOMBO.getImage();
|
||||||
new Image("ranking-maxcombo.png"),
|
Image rankingAccuracy = GameImage.RANKING_ACCURACY.getImage();
|
||||||
new Image("ranking-accuracy.png")
|
GameImage.RANKING_PANEL.setImage(rankingPanel.getScaledCopy((height * 0.63f) / rankingPanel.getHeight()));
|
||||||
);
|
GameImage.RANKING_PERFECT.setImage(rankingPerfect.getScaledCopy((height * 0.16f) / rankingPerfect.getHeight()));
|
||||||
}
|
GameImage.RANKING_TITLE.setImage(rankingTitle.getScaledCopy((height * 0.15f) / rankingTitle.getHeight()));
|
||||||
|
GameImage.RANKING_MAXCOMBO.setImage(rankingMaxCombo.getScaledCopy((height * 0.05f) / rankingMaxCombo.getHeight()));
|
||||||
/**
|
GameImage.RANKING_ACCURACY.setImage(rankingAccuracy.getScaledCopy((height * 0.05f) / rankingAccuracy.getHeight()));
|
||||||
* Sets a background, health bar, and end image.
|
|
||||||
* @param bgImage background image
|
|
||||||
* @param colourImage health bar image
|
|
||||||
* @param kiImage end image
|
|
||||||
*/
|
|
||||||
public void setScorebarImage(Image bg, Image colour,
|
|
||||||
Image ki, Image kiDanger, Image kiDanger2) {
|
|
||||||
int bgWidth = width / 2;
|
|
||||||
this.bgImage = bg.getScaledCopy(bgWidth, bg.getHeight());
|
|
||||||
this.colourImage = colour.getScaledCopy(bgWidth, colour.getHeight());
|
|
||||||
this.kiImage = ki;
|
|
||||||
this.kiDangerImage = kiDanger;
|
|
||||||
this.kiDanger2Image = kiDanger2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a ranking panel, full combo, and ranking/combo/accuracy text image.
|
|
||||||
* @param rankingPanel ranking panel image
|
|
||||||
* @param perfectImage full combo image
|
|
||||||
* @param rankingImage styled text "Ranking"
|
|
||||||
* @param comboImage styled text "Combo"
|
|
||||||
* @param accuracyImage styled text "Accuracy"
|
|
||||||
*/
|
|
||||||
public void setRankingImage(Image rankingPanel, Image perfectImage,
|
|
||||||
Image rankingImage, Image comboImage, Image accuracyImage) {
|
|
||||||
this.rankingPanel = rankingPanel.getScaledCopy((height * 0.63f) / rankingPanel.getHeight());
|
|
||||||
this.perfectImage = perfectImage.getScaledCopy((height * 0.16f) / perfectImage.getHeight());
|
|
||||||
this.rankingImage = rankingImage.getScaledCopy((height * 0.15f) / rankingImage.getHeight());
|
|
||||||
this.comboImage = comboImage.getScaledCopy((height * 0.05f) / comboImage.getHeight());
|
|
||||||
this.accuracyImage = accuracyImage.getScaledCopy((height * 0.05f) / accuracyImage.getHeight());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -469,15 +486,19 @@ public class GameScore {
|
||||||
if (firstObjectTime >= 1500 && trackPosition < firstObjectTime - 500)
|
if (firstObjectTime >= 1500 && trackPosition < firstObjectTime - 500)
|
||||||
healthRatio = (float) trackPosition / (firstObjectTime - 500);
|
healthRatio = (float) trackPosition / (firstObjectTime - 500);
|
||||||
}
|
}
|
||||||
bgImage.draw(0, 0);
|
GameImage.SCOREBAR_BG.getImage().draw(0, 0);
|
||||||
Image colourCropped = colourImage.getSubImage(0, 0, (int) (colourImage.getWidth() * healthRatio), colourImage.getHeight());
|
Image colour = GameImage.SCOREBAR_COLOUR.getImage();
|
||||||
colourCropped.draw(0, bgImage.getHeight() / 4f);
|
Image colourCropped = colour.getSubImage(0, 0, (int) (colour.getWidth() * healthRatio), colour.getHeight());
|
||||||
|
colourCropped.draw(0, GameImage.SCOREBAR_BG.getImage().getHeight() / 4f);
|
||||||
if (health >= 50f)
|
if (health >= 50f)
|
||||||
kiImage.drawCentered(colourCropped.getWidth(), kiImage.getHeight() / 2f);
|
GameImage.SCOREBAR_KI.getImage().drawCentered(
|
||||||
|
colourCropped.getWidth(), GameImage.SCOREBAR_KI.getImage().getHeight() / 2f);
|
||||||
else if (health >= 25f)
|
else if (health >= 25f)
|
||||||
kiDangerImage.drawCentered(colourCropped.getWidth(), kiDangerImage.getHeight() / 2f);
|
GameImage.SCOREBAR_KI_DANGER.getImage().drawCentered(
|
||||||
|
colourCropped.getWidth(), GameImage.SCOREBAR_KI_DANGER.getImage().getHeight() / 2f);
|
||||||
else
|
else
|
||||||
kiDanger2Image.drawCentered(colourCropped.getWidth(), kiDanger2Image.getHeight() / 2f);
|
GameImage.SCOREBAR_KI_DANGER2.getImage().drawCentered(
|
||||||
|
colourCropped.getWidth(), GameImage.SCOREBAR_KI_DANGER2.getImage().getHeight() / 2f);
|
||||||
|
|
||||||
// combo burst
|
// combo burst
|
||||||
if (comboBurstIndex != -1 && comboBurstAlpha > 0f) {
|
if (comboBurstIndex != -1 && comboBurstAlpha > 0f) {
|
||||||
|
@ -513,12 +534,14 @@ public class GameScore {
|
||||||
grade.draw(width - grade.getWidth(), height * 0.09f);
|
grade.draw(width - grade.getWidth(), height * 0.09f);
|
||||||
|
|
||||||
// header & "Ranking" text
|
// header & "Ranking" text
|
||||||
float rankingHeight = (rankingImage.getHeight() * 0.75f) + 3;
|
Image rankingTitle = GameImage.RANKING_TITLE.getImage();
|
||||||
|
float rankingHeight = (rankingTitle.getHeight() * 0.75f) + 3;
|
||||||
g.setColor(Utils.COLOR_BLACK_ALPHA);
|
g.setColor(Utils.COLOR_BLACK_ALPHA);
|
||||||
g.fillRect(0, 0, width, rankingHeight);
|
g.fillRect(0, 0, width, rankingHeight);
|
||||||
rankingImage.draw((width * 0.97f) - rankingImage.getWidth(), 0);
|
rankingTitle.draw((width * 0.97f) - rankingTitle.getWidth(), 0);
|
||||||
|
|
||||||
// ranking panel
|
// ranking panel
|
||||||
|
Image rankingPanel = GameImage.RANKING_PANEL.getImage();
|
||||||
int rankingPanelWidth = rankingPanel.getWidth();
|
int rankingPanelWidth = rankingPanel.getWidth();
|
||||||
int rankingPanelHeight = rankingPanel.getHeight();
|
int rankingPanelHeight = rankingPanel.getHeight();
|
||||||
rankingPanel.draw(0, rankingHeight - (rankingHeight / 10f));
|
rankingPanel.draw(0, rankingHeight - (rankingHeight / 10f));
|
||||||
|
@ -557,19 +580,25 @@ public class GameScore {
|
||||||
}
|
}
|
||||||
|
|
||||||
// combo and accuracy
|
// combo and accuracy
|
||||||
|
Image rankingMaxCombo = GameImage.RANKING_MAXCOMBO.getImage();
|
||||||
|
Image rankingAccuracy = GameImage.RANKING_ACCURACY.getImage();
|
||||||
float textY = rankingHeight + (rankingPanelHeight * 0.87f) - (rankingHeight / 10f);
|
float textY = rankingHeight + (rankingPanelHeight * 0.87f) - (rankingHeight / 10f);
|
||||||
float numbersX = comboImage.getWidth() * .07f;
|
float numbersX = rankingMaxCombo.getWidth() * .07f;
|
||||||
float numbersY = textY + comboImage.getHeight() * 0.7f;
|
float numbersY = textY + rankingMaxCombo.getHeight() * 0.7f;
|
||||||
comboImage.draw(width * 0.01f, textY);
|
rankingMaxCombo.draw(width * 0.01f, textY);
|
||||||
accuracyImage.draw(rankingPanelWidth / 2f, textY);
|
rankingAccuracy.draw(rankingPanelWidth / 2f, textY);
|
||||||
drawSymbolString(String.format("%dx", comboMax),
|
drawSymbolString(String.format("%dx", comboMax),
|
||||||
(int) (width * 0.01f + numbersX), (int) numbersY, symbolTextScale, false);
|
(int) (width * 0.01f + numbersX), (int) numbersY, symbolTextScale, false);
|
||||||
drawSymbolString(String.format("%02.2f%%", getScorePercent()),
|
drawSymbolString(String.format("%02.2f%%", getScorePercent()),
|
||||||
(int) (rankingPanelWidth / 2f + numbersX), (int) numbersY, symbolTextScale, false);
|
(int) (rankingPanelWidth / 2f + numbersX), (int) numbersY, symbolTextScale, false);
|
||||||
|
|
||||||
// full combo
|
// full combo
|
||||||
if (combo == fullObjectCount)
|
if (combo == fullObjectCount) {
|
||||||
perfectImage.draw(width * 0.08f, (height * 0.99f) - perfectImage.getHeight());
|
GameImage.RANKING_PERFECT.getImage().draw(
|
||||||
|
width * 0.08f,
|
||||||
|
(height * 0.99f) - GameImage.RANKING_PERFECT.getImage().getHeight()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -104,7 +104,6 @@ public class Utils {
|
||||||
|
|
||||||
// game-related variables
|
// game-related variables
|
||||||
private static GameContainer container;
|
private static GameContainer container;
|
||||||
// private static StateBasedGame game;
|
|
||||||
private static Input input;
|
private static Input input;
|
||||||
|
|
||||||
// This class should not be instantiated.
|
// This class should not be instantiated.
|
||||||
|
@ -119,7 +118,6 @@ public class Utils {
|
||||||
public static void init(GameContainer container, StateBasedGame game)
|
public static void init(GameContainer container, StateBasedGame game)
|
||||||
throws SlickException {
|
throws SlickException {
|
||||||
Utils.container = container;
|
Utils.container = container;
|
||||||
// Utils.game = game;
|
|
||||||
Utils.input = container.getInput();
|
Utils.input = container.getInput();
|
||||||
|
|
||||||
// game settings
|
// game settings
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
package itdelatrisu.opsu.objects;
|
package itdelatrisu.opsu.objects;
|
||||||
|
|
||||||
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.GameScore;
|
import itdelatrisu.opsu.GameScore;
|
||||||
import itdelatrisu.opsu.MusicController;
|
import itdelatrisu.opsu.MusicController;
|
||||||
import itdelatrisu.opsu.OsuHitObject;
|
import itdelatrisu.opsu.OsuHitObject;
|
||||||
|
@ -27,21 +28,12 @@ import itdelatrisu.opsu.states.Options;
|
||||||
|
|
||||||
import org.newdawn.slick.Color;
|
import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.GameContainer;
|
import org.newdawn.slick.GameContainer;
|
||||||
import org.newdawn.slick.Image;
|
|
||||||
import org.newdawn.slick.SlickException;
|
import org.newdawn.slick.SlickException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data type representing a circle object.
|
* Data type representing a circle object.
|
||||||
*/
|
*/
|
||||||
public class Circle {
|
public class Circle {
|
||||||
/**
|
|
||||||
* Images related to hit circles.
|
|
||||||
*/
|
|
||||||
private static Image
|
|
||||||
hitCircle, // hit circle
|
|
||||||
hitCircleOverlay, // hit circle overlay
|
|
||||||
approachCircle; // approach circle
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The associated OsuHitObject.
|
* The associated OsuHitObject.
|
||||||
*/
|
*/
|
||||||
|
@ -76,26 +68,11 @@ public class Circle {
|
||||||
public static void init(GameContainer container, float circleSize) throws SlickException {
|
public static void init(GameContainer container, float circleSize) throws SlickException {
|
||||||
int diameter = (int) (96 - (circleSize * 8));
|
int diameter = (int) (96 - (circleSize * 8));
|
||||||
diameter = diameter * container.getWidth() / 640; // convert from Osupixels (640x480)
|
diameter = diameter * container.getWidth() / 640; // convert from Osupixels (640x480)
|
||||||
hitCircle = new Image("hitcircle.png").getScaledCopy(diameter, diameter);
|
GameImage.HITCIRCLE.setImage(GameImage.HITCIRCLE.getImage().getScaledCopy(diameter, diameter));
|
||||||
hitCircleOverlay = new Image("hitcircleoverlay.png").getScaledCopy(diameter, diameter);
|
GameImage.HITCIRCLE_OVERLAY.setImage(GameImage.HITCIRCLE_OVERLAY.getImage().getScaledCopy(diameter, diameter));
|
||||||
approachCircle = new Image("approachcircle.png").getScaledCopy(diameter, diameter);
|
GameImage.APPROACHCIRCLE.setImage(GameImage.APPROACHCIRCLE.getImage().getScaledCopy(diameter, diameter));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the hit circle image.
|
|
||||||
*/
|
|
||||||
public static Image getHitCircle() { return hitCircle; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the hit circle overlay image.
|
|
||||||
*/
|
|
||||||
public static Image getHitCircleOverlay() { return hitCircleOverlay; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the approach circle image.
|
|
||||||
*/
|
|
||||||
public static Image getApproachCircle() { return approachCircle; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
* @param hitObject the associated OsuHitObject
|
* @param hitObject the associated OsuHitObject
|
||||||
|
@ -121,11 +98,12 @@ public class Circle {
|
||||||
|
|
||||||
if (timeDiff >= 0) {
|
if (timeDiff >= 0) {
|
||||||
float approachScale = 1 + (timeDiff * 2f / game.getApproachTime());
|
float approachScale = 1 + (timeDiff * 2f / game.getApproachTime());
|
||||||
Utils.drawCentered(approachCircle.getScaledCopy(approachScale), hitObject.x, hitObject.y, color);
|
Utils.drawCentered(GameImage.APPROACHCIRCLE.getImage().getScaledCopy(approachScale),
|
||||||
Utils.drawCentered(hitCircleOverlay, hitObject.x, hitObject.y, Color.white);
|
hitObject.x, hitObject.y, color);
|
||||||
Utils.drawCentered(hitCircle, hitObject.x, hitObject.y, color);
|
Utils.drawCentered(GameImage.HITCIRCLE_OVERLAY.getImage(), hitObject.x, hitObject.y, Color.white);
|
||||||
|
Utils.drawCentered(GameImage.HITCIRCLE.getImage(), hitObject.x, hitObject.y, color);
|
||||||
score.drawSymbolNumber(hitObject.comboNumber, hitObject.x, hitObject.y,
|
score.drawSymbolNumber(hitObject.comboNumber, hitObject.x, hitObject.y,
|
||||||
hitCircle.getWidth() * 0.40f / score.getDefaultSymbolImage(0).getHeight());
|
GameImage.HITCIRCLE.getImage().getWidth() * 0.40f / score.getDefaultSymbolImage(0).getHeight());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +140,7 @@ public class Circle {
|
||||||
*/
|
*/
|
||||||
public boolean mousePressed(int x, int y) {
|
public boolean mousePressed(int x, int y) {
|
||||||
double distance = Math.hypot(hitObject.x - x, hitObject.y - y);
|
double distance = Math.hypot(hitObject.x - x, hitObject.y - y);
|
||||||
int circleRadius = hitCircle.getWidth() / 2;
|
int circleRadius = GameImage.HITCIRCLE.getImage().getWidth() / 2;
|
||||||
if (distance < circleRadius) {
|
if (distance < circleRadius) {
|
||||||
int result = hitResult(hitObject.time);
|
int result = hitResult(hitObject.time);
|
||||||
if (result > -1) {
|
if (result > -1) {
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
package itdelatrisu.opsu.objects;
|
package itdelatrisu.opsu.objects;
|
||||||
|
|
||||||
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.GameScore;
|
import itdelatrisu.opsu.GameScore;
|
||||||
import itdelatrisu.opsu.MusicController;
|
import itdelatrisu.opsu.MusicController;
|
||||||
import itdelatrisu.opsu.OsuFile;
|
import itdelatrisu.opsu.OsuFile;
|
||||||
|
@ -26,6 +27,8 @@ import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.states.Game;
|
import itdelatrisu.opsu.states.Game;
|
||||||
import itdelatrisu.opsu.states.Options;
|
import itdelatrisu.opsu.states.Options;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
import org.newdawn.slick.Animation;
|
import org.newdawn.slick.Animation;
|
||||||
import org.newdawn.slick.Color;
|
import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.GameContainer;
|
import org.newdawn.slick.GameContainer;
|
||||||
|
@ -36,14 +39,6 @@ import org.newdawn.slick.SlickException;
|
||||||
* Data type representing a slider object.
|
* Data type representing a slider object.
|
||||||
*/
|
*/
|
||||||
public class Slider {
|
public class Slider {
|
||||||
/**
|
|
||||||
* Images related to sliders.
|
|
||||||
*/
|
|
||||||
private static Image
|
|
||||||
sliderFollowCircle, // slider follow circle
|
|
||||||
reverseArrow, // reverse arrow (for repeats)
|
|
||||||
sliderTick; // slider tick
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Slider ball animation.
|
* Slider ball animation.
|
||||||
*/
|
*/
|
||||||
|
@ -261,8 +256,8 @@ public class Slider {
|
||||||
* Draws the full Bezier curve to the graphics context.
|
* Draws the full Bezier curve to the graphics context.
|
||||||
*/
|
*/
|
||||||
public void draw() {
|
public void draw() {
|
||||||
Image hitCircle = Circle.getHitCircle();
|
Image hitCircle = GameImage.HITCIRCLE.getImage();
|
||||||
Image hitCircleOverlay = Circle.getHitCircleOverlay();
|
Image hitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage();
|
||||||
|
|
||||||
// draw overlay and hit circle
|
// draw overlay and hit circle
|
||||||
for (int i = curveX.length - 1; i >= 0; i--)
|
for (int i = curveX.length - 1; i >= 0; i--)
|
||||||
|
@ -283,12 +278,38 @@ public class Slider {
|
||||||
int diameter = (int) (96 - (circleSize * 8));
|
int diameter = (int) (96 - (circleSize * 8));
|
||||||
diameter = diameter * container.getWidth() / 640; // convert from Osupixels (640x480)
|
diameter = diameter * container.getWidth() / 640; // convert from Osupixels (640x480)
|
||||||
|
|
||||||
|
// slider ball
|
||||||
|
if (sliderBall != null) {
|
||||||
|
for (int i = 0; i < sliderBall.getFrameCount(); i++) {
|
||||||
|
Image img = sliderBall.getImage(i);
|
||||||
|
if (!img.isDestroyed())
|
||||||
|
img.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
sliderBall = new Animation();
|
sliderBall = new Animation();
|
||||||
for (int i = 0; i <= 9; i++)
|
String sliderFormat = "sliderb%d.png";
|
||||||
sliderBall.addFrame(new Image(String.format("sliderb%d.png", i)).getScaledCopy(diameter * 118 / 128, diameter * 118 / 128), 60);
|
int sliderIndex = 0;
|
||||||
sliderFollowCircle = new Image("sliderfollowcircle.png").getScaledCopy(diameter * 259 / 128, diameter * 259 / 128);
|
File dir = MusicController.getOsuFile().getFile().getParentFile();
|
||||||
reverseArrow = new Image("reversearrow.png").getScaledCopy(diameter, diameter);
|
File slider = new File(dir, String.format(sliderFormat, sliderIndex));
|
||||||
sliderTick = new Image("sliderscorepoint.png").getScaledCopy(diameter / 4, diameter / 4);
|
if (slider.isFile()) {
|
||||||
|
do {
|
||||||
|
sliderBall.addFrame(new Image(slider.getAbsolutePath()).getScaledCopy(diameter * 118 / 128, diameter * 118 / 128), 60);
|
||||||
|
slider = new File(dir, String.format(sliderFormat, ++sliderIndex));
|
||||||
|
} while (slider.isFile());
|
||||||
|
} else {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
Image sliderFrame = new Image(String.format(sliderFormat, sliderIndex++));
|
||||||
|
sliderBall.addFrame(sliderFrame.getScaledCopy(diameter * 118 / 128, diameter * 118 / 128), 60);
|
||||||
|
} catch (Exception e) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GameImage.SLIDER_FOLLOWCIRCLE.setImage(GameImage.SLIDER_FOLLOWCIRCLE.getImage().getScaledCopy(diameter * 259 / 128, diameter * 259 / 128));
|
||||||
|
GameImage.REVERSEARROW.setImage(GameImage.REVERSEARROW.getImage().getScaledCopy(diameter, diameter));
|
||||||
|
GameImage.SLIDER_TICK.setImage(GameImage.SLIDER_TICK.getImage().getScaledCopy(diameter / 4, diameter / 4));
|
||||||
|
|
||||||
sliderMultiplier = osu.sliderMultiplier;
|
sliderMultiplier = osu.sliderMultiplier;
|
||||||
sliderTickRate = osu.sliderTickRate;
|
sliderTickRate = osu.sliderTickRate;
|
||||||
|
@ -310,8 +331,6 @@ public class Slider {
|
||||||
this.comboEnd = comboEnd;
|
this.comboEnd = comboEnd;
|
||||||
|
|
||||||
this.bezier = new Bezier();
|
this.bezier = new Bezier();
|
||||||
|
|
||||||
// calculate slider time and ticks upon first update call
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -322,8 +341,8 @@ public class Slider {
|
||||||
public void draw(int trackPosition, boolean currentObject) {
|
public void draw(int trackPosition, boolean currentObject) {
|
||||||
int timeDiff = hitObject.time - trackPosition;
|
int timeDiff = hitObject.time - trackPosition;
|
||||||
|
|
||||||
Image hitCircleOverlay = Circle.getHitCircleOverlay();
|
Image hitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage();
|
||||||
Image hitCircle = Circle.getHitCircle();
|
Image hitCircle = GameImage.HITCIRCLE.getImage();
|
||||||
|
|
||||||
// bezier
|
// bezier
|
||||||
bezier.draw();
|
bezier.draw();
|
||||||
|
@ -332,7 +351,7 @@ public class Slider {
|
||||||
if (currentObject && ticksT != null) {
|
if (currentObject && ticksT != null) {
|
||||||
for (int i = 0; i < ticksT.length; i++) {
|
for (int i = 0; i < ticksT.length; i++) {
|
||||||
float[] c = bezier.pointAt(ticksT[i]);
|
float[] c = bezier.pointAt(ticksT[i]);
|
||||||
sliderTick.drawCentered(c[0], c[1]);
|
GameImage.SLIDER_TICK.getImage().drawCentered(c[0], c[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,19 +371,20 @@ public class Slider {
|
||||||
|
|
||||||
// repeats
|
// repeats
|
||||||
if (hitObject.repeat - 1 > currentRepeats) {
|
if (hitObject.repeat - 1 > currentRepeats) {
|
||||||
|
Image arrow = GameImage.REVERSEARROW.getImage();
|
||||||
if (currentRepeats % 2 == 0) { // last circle
|
if (currentRepeats % 2 == 0) { // last circle
|
||||||
reverseArrow.setRotation(bezier.getEndAngle());
|
arrow.setRotation(bezier.getEndAngle());
|
||||||
reverseArrow.drawCentered(hitObject.sliderX[lastIndex], hitObject.sliderY[lastIndex]);
|
arrow.drawCentered(hitObject.sliderX[lastIndex], hitObject.sliderY[lastIndex]);
|
||||||
} else { // first circle
|
} else { // first circle
|
||||||
reverseArrow.setRotation(bezier.getStartAngle());
|
arrow.setRotation(bezier.getStartAngle());
|
||||||
reverseArrow.drawCentered(hitObject.x, hitObject.y);
|
arrow.drawCentered(hitObject.x, hitObject.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeDiff >= 0) {
|
if (timeDiff >= 0) {
|
||||||
// approach circle
|
// approach circle
|
||||||
float approachScale = 1 + (timeDiff * 2f / game.getApproachTime());
|
float approachScale = 1 + (timeDiff * 2f / game.getApproachTime());
|
||||||
Utils.drawCentered(Circle.getApproachCircle().getScaledCopy(approachScale),
|
Utils.drawCentered(GameImage.APPROACHCIRCLE.getImage().getScaledCopy(approachScale),
|
||||||
hitObject.x, hitObject.y, color);
|
hitObject.x, hitObject.y, color);
|
||||||
} else {
|
} else {
|
||||||
float[] c = bezier.pointAt(getT(trackPosition, false));
|
float[] c = bezier.pointAt(getT(trackPosition, false));
|
||||||
|
@ -374,7 +394,7 @@ public class Slider {
|
||||||
|
|
||||||
// follow circle
|
// follow circle
|
||||||
if (followCircleActive)
|
if (followCircleActive)
|
||||||
sliderFollowCircle.drawCentered(c[0], c[1]);
|
GameImage.SLIDER_FOLLOWCIRCLE.getImage().drawCentered(c[0], c[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,7 +441,7 @@ public class Slider {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
double distance = Math.hypot(hitObject.x - x, hitObject.y - y);
|
double distance = Math.hypot(hitObject.x - x, hitObject.y - y);
|
||||||
int circleRadius = Circle.getHitCircle().getWidth() / 2;
|
int circleRadius = GameImage.HITCIRCLE.getImage().getWidth() / 2;
|
||||||
if (distance < circleRadius) {
|
if (distance < circleRadius) {
|
||||||
int trackPosition = MusicController.getPosition();
|
int trackPosition = MusicController.getPosition();
|
||||||
int timeDiff = Math.abs(trackPosition - hitObject.time);
|
int timeDiff = Math.abs(trackPosition - hitObject.time);
|
||||||
|
@ -513,7 +533,7 @@ public class Slider {
|
||||||
// check if cursor pressed and within end circle
|
// check if cursor pressed and within end circle
|
||||||
else if (game.isInputKeyPressed()) {
|
else if (game.isInputKeyPressed()) {
|
||||||
double distance = Math.hypot(hitObject.sliderX[lastIndex] - mouseX, hitObject.sliderY[lastIndex] - mouseY);
|
double distance = Math.hypot(hitObject.sliderX[lastIndex] - mouseX, hitObject.sliderY[lastIndex] - mouseY);
|
||||||
int followCircleRadius = sliderFollowCircle.getWidth() / 2;
|
int followCircleRadius = GameImage.SLIDER_FOLLOWCIRCLE.getImage().getWidth() / 2;
|
||||||
if (distance < followCircleRadius)
|
if (distance < followCircleRadius)
|
||||||
ticksHit++;
|
ticksHit++;
|
||||||
}
|
}
|
||||||
|
@ -550,7 +570,7 @@ public class Slider {
|
||||||
// holding slider...
|
// holding slider...
|
||||||
float[] c = bezier.pointAt(getT(trackPosition, false));
|
float[] c = bezier.pointAt(getT(trackPosition, false));
|
||||||
double distance = Math.hypot(c[0] - mouseX, c[1] - mouseY);
|
double distance = Math.hypot(c[0] - mouseX, c[1] - mouseY);
|
||||||
int followCircleRadius = sliderFollowCircle.getWidth() / 2;
|
int followCircleRadius = GameImage.SLIDER_FOLLOWCIRCLE.getImage().getWidth() / 2;
|
||||||
if ((game.isInputKeyPressed() && distance < followCircleRadius) || isAutoMod) {
|
if ((game.isInputKeyPressed() && distance < followCircleRadius) || isAutoMod) {
|
||||||
// mouse pressed and within follow circle
|
// mouse pressed and within follow circle
|
||||||
followCircleActive = true;
|
followCircleActive = true;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
package itdelatrisu.opsu.objects;
|
package itdelatrisu.opsu.objects;
|
||||||
|
|
||||||
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.GameScore;
|
import itdelatrisu.opsu.GameScore;
|
||||||
import itdelatrisu.opsu.MusicController;
|
import itdelatrisu.opsu.MusicController;
|
||||||
import itdelatrisu.opsu.OsuHitObject;
|
import itdelatrisu.opsu.OsuHitObject;
|
||||||
|
@ -36,17 +37,6 @@ import org.newdawn.slick.SlickException;
|
||||||
* Data type representing a spinner object.
|
* Data type representing a spinner object.
|
||||||
*/
|
*/
|
||||||
public class Spinner {
|
public class Spinner {
|
||||||
/**
|
|
||||||
* Images related to spinners.
|
|
||||||
*/
|
|
||||||
private static Image
|
|
||||||
spinnerCircle, // spinner
|
|
||||||
spinnerApproachCircle, // spinner approach circle (for end time)
|
|
||||||
spinnerMetre, // spinner meter (subimage based on completion ratio)
|
|
||||||
// spinnerOsuImage, // spinner "OSU!" text (complete)
|
|
||||||
spinnerSpinImage, // spinner "SPIN!" text (start)
|
|
||||||
spinnerClearImage; // spinner "CLEAR" text (passed)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Container dimensions.
|
* Container dimensions.
|
||||||
*/
|
*/
|
||||||
|
@ -91,12 +81,10 @@ public class Spinner {
|
||||||
width = container.getWidth();
|
width = container.getWidth();
|
||||||
height = container.getHeight();
|
height = container.getHeight();
|
||||||
|
|
||||||
spinnerCircle = new Image("spinner-circle.png").getScaledCopy(height * 9 / 10, height * 9 / 10);
|
Image spinnerCircle = GameImage.SPINNER_CIRCLE.getImage();
|
||||||
spinnerApproachCircle = new Image("spinner-approachcircle.png").getScaledCopy(spinnerCircle.getWidth(), spinnerCircle.getHeight());
|
GameImage.SPINNER_CIRCLE.setImage(spinnerCircle.getScaledCopy(height * 9 / 10, height * 9 / 10));
|
||||||
spinnerMetre = new Image("spinner-metre.png").getScaledCopy(width, height);
|
GameImage.SPINNER_APPROACHCIRCLE.setImage(GameImage.SPINNER_APPROACHCIRCLE.getImage().getScaledCopy(spinnerCircle.getWidth(), spinnerCircle.getHeight()));
|
||||||
spinnerSpinImage = new Image("spinner-spin.png");
|
GameImage.SPINNER_METRE.setImage(GameImage.SPINNER_METRE.getImage().getScaledCopy(width, height));
|
||||||
spinnerClearImage = new Image("spinner-clear.png");
|
|
||||||
// spinnerOsuImage = new Image("spinner-osu.png");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -135,6 +123,7 @@ public class Spinner {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// spinner meter (subimage)
|
// spinner meter (subimage)
|
||||||
|
Image spinnerMetre = GameImage.SPINNER_METRE.getImage();
|
||||||
int spinnerMetreY = (spinnerComplete) ? 0 : (int) (spinnerMetre.getHeight() * (1 - (rotations / rotationsNeeded)));
|
int spinnerMetreY = (spinnerComplete) ? 0 : (int) (spinnerMetre.getHeight() * (1 - (rotations / rotationsNeeded)));
|
||||||
Image spinnerMetreSub = spinnerMetre.getSubImage(
|
Image spinnerMetreSub = spinnerMetre.getSubImage(
|
||||||
0, spinnerMetreY,
|
0, spinnerMetreY,
|
||||||
|
@ -143,12 +132,12 @@ public class Spinner {
|
||||||
spinnerMetreSub.draw(0, height - spinnerMetreSub.getHeight());
|
spinnerMetreSub.draw(0, height - spinnerMetreSub.getHeight());
|
||||||
|
|
||||||
// main spinner elements
|
// main spinner elements
|
||||||
spinnerCircle.drawCentered(width / 2, height / 2);
|
GameImage.SPINNER_CIRCLE.getImage().drawCentered(width / 2, height / 2);
|
||||||
spinnerApproachCircle.getScaledCopy(1 - ((float) timeDiff / (hitObject.time - hitObject.endTime))).drawCentered(width / 2, height / 2);
|
GameImage.SPINNER_APPROACHCIRCLE.getImage().getScaledCopy(1 - ((float) timeDiff / (hitObject.time - hitObject.endTime))).drawCentered(width / 2, height / 2);
|
||||||
spinnerSpinImage.drawCentered(width / 2, height * 3 / 4);
|
GameImage.SPINNER_SPIN.getImage().drawCentered(width / 2, height * 3 / 4);
|
||||||
|
|
||||||
if (spinnerComplete) {
|
if (spinnerComplete) {
|
||||||
spinnerClearImage.drawCentered(width / 2, height / 4);
|
GameImage.SPINNER_CLEAR.getImage().drawCentered(width / 2, height / 4);
|
||||||
int extraRotations = (int) (rotations - rotationsNeeded);
|
int extraRotations = (int) (rotations - rotationsNeeded);
|
||||||
if (extraRotations > 0)
|
if (extraRotations > 0)
|
||||||
score.drawSymbolNumber(extraRotations * 1000, width / 2, height * 2 / 3, 1.0f);
|
score.drawSymbolNumber(extraRotations * 1000, width / 2, height * 2 / 3, 1.0f);
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
package itdelatrisu.opsu.states;
|
package itdelatrisu.opsu.states;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GUIMenuButton;
|
import itdelatrisu.opsu.GUIMenuButton;
|
||||||
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.GameScore;
|
import itdelatrisu.opsu.GameScore;
|
||||||
import itdelatrisu.opsu.MusicController;
|
import itdelatrisu.opsu.MusicController;
|
||||||
import itdelatrisu.opsu.Opsu;
|
import itdelatrisu.opsu.Opsu;
|
||||||
|
@ -31,6 +32,7 @@ import itdelatrisu.opsu.objects.Circle;
|
||||||
import itdelatrisu.opsu.objects.Slider;
|
import itdelatrisu.opsu.objects.Slider;
|
||||||
import itdelatrisu.opsu.objects.Spinner;
|
import itdelatrisu.opsu.objects.Spinner;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
|
||||||
|
@ -121,16 +123,6 @@ public class Game extends BasicGameState {
|
||||||
*/
|
*/
|
||||||
private int breakIndex;
|
private int breakIndex;
|
||||||
|
|
||||||
/**
|
|
||||||
* Warning arrows, pointing right and left.
|
|
||||||
*/
|
|
||||||
private Image warningArrowR, warningArrowL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Section pass and fail images (displayed at start of break, when necessary).
|
|
||||||
*/
|
|
||||||
private Image breakStartPass, breakStartFail;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Break start time (0 if not in break).
|
* Break start time (0 if not in break).
|
||||||
*/
|
*/
|
||||||
|
@ -161,16 +153,6 @@ public class Game extends BasicGameState {
|
||||||
*/
|
*/
|
||||||
private float beatLengthBase, beatLength;
|
private float beatLengthBase, beatLength;
|
||||||
|
|
||||||
/**
|
|
||||||
* Countdown-related images.
|
|
||||||
*/
|
|
||||||
private Image
|
|
||||||
countdownReady, // "READY?" text
|
|
||||||
countdown3, // "3" text
|
|
||||||
countdown1, // "2" text
|
|
||||||
countdown2, // "1" text
|
|
||||||
countdownGo; // "GO!" text
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the countdown sound has been played.
|
* Whether the countdown sound has been played.
|
||||||
*/
|
*/
|
||||||
|
@ -178,11 +160,6 @@ public class Game extends BasicGameState {
|
||||||
countdownReadySound, countdown3Sound, countdown1Sound,
|
countdownReadySound, countdown3Sound, countdown1Sound,
|
||||||
countdown2Sound, countdownGoSound;
|
countdown2Sound, countdownGoSound;
|
||||||
|
|
||||||
/**
|
|
||||||
* Glowing hit circle outline which must be clicked when returning from pause menu.
|
|
||||||
*/
|
|
||||||
private Image hitCircleSelect;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mouse coordinates before game paused.
|
* Mouse coordinates before game paused.
|
||||||
*/
|
*/
|
||||||
|
@ -204,11 +181,6 @@ public class Game extends BasicGameState {
|
||||||
*/
|
*/
|
||||||
private Image playfield;
|
private Image playfield;
|
||||||
|
|
||||||
/**
|
|
||||||
* Image displayed during unranked plays.
|
|
||||||
*/
|
|
||||||
private Image unrankedImage;
|
|
||||||
|
|
||||||
// game-related variables
|
// game-related variables
|
||||||
private GameContainer container;
|
private GameContainer container;
|
||||||
private StateBasedGame game;
|
private StateBasedGame game;
|
||||||
|
@ -229,41 +201,8 @@ public class Game extends BasicGameState {
|
||||||
int width = container.getWidth();
|
int width = container.getWidth();
|
||||||
int height = container.getHeight();
|
int height = container.getHeight();
|
||||||
|
|
||||||
// spinners have fixed properties, and only need to be initialized once
|
// create the associated GameScore object
|
||||||
Spinner.init(container);
|
score = new GameScore(width, height);
|
||||||
|
|
||||||
// breaks
|
|
||||||
breakStartPass = new Image("section-pass.png");
|
|
||||||
breakStartFail = new Image("section-fail.png");
|
|
||||||
warningArrowR = new Image("play-warningarrow.png");
|
|
||||||
warningArrowL = warningArrowR.getFlippedCopy(true, false);
|
|
||||||
|
|
||||||
// skip button
|
|
||||||
Image skip = new Image("play-skip.png");
|
|
||||||
float skipScale = (height * 0.1f) / skip.getHeight();
|
|
||||||
skip = skip.getScaledCopy(skipScale);
|
|
||||||
skipButton = new GUIMenuButton(skip,
|
|
||||||
width - (skip.getWidth() / 2f),
|
|
||||||
height - (skip.getHeight() / 2f));
|
|
||||||
|
|
||||||
// countdown
|
|
||||||
float countdownHeight = height / 3f;
|
|
||||||
countdownReady = new Image("ready.png");
|
|
||||||
countdownReady = countdownReady.getScaledCopy(countdownHeight / countdownReady.getHeight());
|
|
||||||
countdown3 = new Image("count3.png");
|
|
||||||
countdown3 = countdown3.getScaledCopy(countdownHeight / countdown3.getHeight());
|
|
||||||
countdown2 = new Image("count2.png");
|
|
||||||
countdown2 = countdown2.getScaledCopy(countdownHeight / countdown2.getHeight());
|
|
||||||
countdown1 = new Image("count1.png");
|
|
||||||
countdown1 = countdown1.getScaledCopy(countdownHeight / countdown1.getHeight());
|
|
||||||
countdownGo = new Image("go.png");
|
|
||||||
countdownGo = countdownGo.getScaledCopy(countdownHeight / countdownGo.getHeight());
|
|
||||||
|
|
||||||
// hit circle select
|
|
||||||
hitCircleSelect = new Image("hitcircleselect.png");
|
|
||||||
|
|
||||||
// "unranked" image
|
|
||||||
unrankedImage = new Image("play-unranked.png");
|
|
||||||
|
|
||||||
// playfield background
|
// playfield background
|
||||||
try {
|
try {
|
||||||
|
@ -271,9 +210,6 @@ public class Game extends BasicGameState {
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// optional
|
// optional
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the associated GameScore object
|
|
||||||
score = new GameScore(width, height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -317,13 +253,13 @@ public class Game extends BasicGameState {
|
||||||
trackPosition - breakTime < 5000) {
|
trackPosition - breakTime < 5000) {
|
||||||
// show break start
|
// show break start
|
||||||
if (score.getHealth() >= 50) {
|
if (score.getHealth() >= 50) {
|
||||||
breakStartPass.drawCentered(width / 2f, height / 2f);
|
GameImage.SECTION_PASS.getImage().drawCentered(width / 2f, height / 2f);
|
||||||
if (!breakSound) {
|
if (!breakSound) {
|
||||||
SoundController.playSound(SoundController.SOUND_SECTIONPASS);
|
SoundController.playSound(SoundController.SOUND_SECTIONPASS);
|
||||||
breakSound = true;
|
breakSound = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
breakStartFail.drawCentered(width / 2f, height / 2f);
|
GameImage.SECTION_FAIL.getImage().drawCentered(width / 2f, height / 2f);
|
||||||
if (!breakSound) {
|
if (!breakSound) {
|
||||||
SoundController.playSound(SoundController.SOUND_SECTIONFAIL);
|
SoundController.playSound(SoundController.SOUND_SECTIONFAIL);
|
||||||
breakSound = true;
|
breakSound = true;
|
||||||
|
@ -334,15 +270,18 @@ public class Game extends BasicGameState {
|
||||||
int endTimeDiff = endTime - trackPosition;
|
int endTimeDiff = endTime - trackPosition;
|
||||||
if ((endTimeDiff > 1500 && endTimeDiff < 2000) ||
|
if ((endTimeDiff > 1500 && endTimeDiff < 2000) ||
|
||||||
(endTimeDiff > 500 && endTimeDiff < 1000)) {
|
(endTimeDiff > 500 && endTimeDiff < 1000)) {
|
||||||
warningArrowR.draw(width * 0.15f, height * 0.15f);
|
Image arrow = GameImage.WARNINGARROW.getImage();
|
||||||
warningArrowR.draw(width * 0.15f, height * 0.75f);
|
arrow.setRotation(0);
|
||||||
warningArrowL.draw(width * 0.75f, height * 0.15f);
|
arrow.draw(width * 0.15f, height * 0.15f);
|
||||||
warningArrowL.draw(width * 0.75f, height * 0.75f);
|
arrow.draw(width * 0.15f, height * 0.75f);
|
||||||
|
arrow.setRotation(180);
|
||||||
|
arrow.draw(width * 0.75f, height * 0.15f);
|
||||||
|
arrow.draw(width * 0.75f, height * 0.75f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Options.isModActive(Options.MOD_AUTO))
|
if (Options.isModActive(Options.MOD_AUTO))
|
||||||
unrankedImage.drawCentered(width / 2, height * 0.077f);
|
GameImage.UNRANKED.getImage().drawCentered(width / 2, height * 0.077f);
|
||||||
Utils.drawFPS();
|
Utils.drawFPS();
|
||||||
Utils.drawCursor();
|
Utils.drawCursor();
|
||||||
return;
|
return;
|
||||||
|
@ -380,36 +319,37 @@ public class Game extends BasicGameState {
|
||||||
int timeDiff = osu.objects[0].time - trackPosition;
|
int timeDiff = osu.objects[0].time - trackPosition;
|
||||||
if (timeDiff >= 500 && timeDiff < 3000) {
|
if (timeDiff >= 500 && timeDiff < 3000) {
|
||||||
if (timeDiff >= 1500) {
|
if (timeDiff >= 1500) {
|
||||||
countdownReady.drawCentered(width / 2, height / 2);
|
GameImage.COUNTDOWN_READY.getImage().drawCentered(width / 2, height / 2);
|
||||||
if (!countdownReadySound) {
|
if (!countdownReadySound) {
|
||||||
SoundController.playSound(SoundController.SOUND_READY);
|
SoundController.playSound(SoundController.SOUND_READY);
|
||||||
countdownReadySound = true;
|
countdownReadySound = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (timeDiff < 2000) {
|
if (timeDiff < 2000) {
|
||||||
countdown3.draw(0, 0);
|
GameImage.COUNTDOWN_3.getImage().draw(0, 0);
|
||||||
if (!countdown3Sound) {
|
if (!countdown3Sound) {
|
||||||
SoundController.playSound(SoundController.SOUND_COUNT3);
|
SoundController.playSound(SoundController.SOUND_COUNT3);
|
||||||
countdown3Sound = true;
|
countdown3Sound = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (timeDiff < 1500) {
|
if (timeDiff < 1500) {
|
||||||
countdown2.draw(width - countdown2.getWidth(), 0);
|
GameImage.COUNTDOWN_2.getImage().draw(width - GameImage.COUNTDOWN_2.getImage().getWidth(), 0);
|
||||||
if (!countdown2Sound) {
|
if (!countdown2Sound) {
|
||||||
SoundController.playSound(SoundController.SOUND_COUNT2);
|
SoundController.playSound(SoundController.SOUND_COUNT2);
|
||||||
countdown2Sound = true;
|
countdown2Sound = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (timeDiff < 1000) {
|
if (timeDiff < 1000) {
|
||||||
countdown1.drawCentered(width / 2, height / 2);
|
GameImage.COUNTDOWN_1.getImage().drawCentered(width / 2, height / 2);
|
||||||
if (!countdown1Sound) {
|
if (!countdown1Sound) {
|
||||||
SoundController.playSound(SoundController.SOUND_COUNT1);
|
SoundController.playSound(SoundController.SOUND_COUNT1);
|
||||||
countdown1Sound = true;
|
countdown1Sound = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (timeDiff >= -500 && timeDiff < 500) {
|
} else if (timeDiff >= -500 && timeDiff < 500) {
|
||||||
countdownGo.setAlpha((timeDiff < 0) ? 1 - (timeDiff / -1000f) : 1);
|
Image go = GameImage.COUNTDOWN_GO.getImage();
|
||||||
countdownGo.drawCentered(width / 2, height / 2);
|
go.setAlpha((timeDiff < 0) ? 1 - (timeDiff / -1000f) : 1);
|
||||||
|
go.drawCentered(width / 2, height / 2);
|
||||||
if (!countdownGoSound) {
|
if (!countdownGoSound) {
|
||||||
SoundController.playSound(SoundController.SOUND_GO);
|
SoundController.playSound(SoundController.SOUND_GO);
|
||||||
countdownGoSound = true;
|
countdownGoSound = true;
|
||||||
|
@ -442,7 +382,7 @@ public class Game extends BasicGameState {
|
||||||
score.drawHitResults(trackPosition);
|
score.drawHitResults(trackPosition);
|
||||||
|
|
||||||
if (Options.isModActive(Options.MOD_AUTO))
|
if (Options.isModActive(Options.MOD_AUTO))
|
||||||
unrankedImage.drawCentered(width / 2, height * 0.077f);
|
GameImage.UNRANKED.getImage().drawCentered(width / 2, height * 0.077f);
|
||||||
|
|
||||||
// returning from pause screen
|
// returning from pause screen
|
||||||
if (pauseTime > -1 && pausedMouseX > -1 && pausedMouseY > -1) {
|
if (pauseTime > -1 && pausedMouseX > -1 && pausedMouseY > -1) {
|
||||||
|
@ -451,8 +391,8 @@ public class Game extends BasicGameState {
|
||||||
g.fillRect(0, 0, width, height);
|
g.fillRect(0, 0, width, height);
|
||||||
|
|
||||||
// draw glowing hit select circle and pulse effect
|
// draw glowing hit select circle and pulse effect
|
||||||
int circleRadius = Circle.getHitCircle().getWidth();
|
int circleRadius = GameImage.HITCIRCLE.getImage().getWidth();
|
||||||
Image cursorCircle = hitCircleSelect.getScaledCopy(circleRadius, circleRadius);
|
Image cursorCircle = GameImage.HITCIRCLE_SELECT.getImage().getScaledCopy(circleRadius, circleRadius);
|
||||||
cursorCircle.setAlpha(1.0f);
|
cursorCircle.setAlpha(1.0f);
|
||||||
cursorCircle.drawCentered(pausedMouseX, pausedMouseY);
|
cursorCircle.drawCentered(pausedMouseX, pausedMouseY);
|
||||||
Image cursorCirclePulse = cursorCircle.getScaledCopy(1f + pausePulse);
|
Image cursorCirclePulse = cursorCircle.getScaledCopy(1f + pausePulse);
|
||||||
|
@ -643,7 +583,7 @@ public class Game extends BasicGameState {
|
||||||
// returning from pause screen
|
// returning from pause screen
|
||||||
if (pauseTime > -1) {
|
if (pauseTime > -1) {
|
||||||
double distance = Math.hypot(pausedMouseX - x, pausedMouseY - y);
|
double distance = Math.hypot(pausedMouseX - x, pausedMouseY - y);
|
||||||
int circleRadius = Circle.getHitCircle().getWidth() / 2;
|
int circleRadius = GameImage.HITCIRCLE.getImage().getWidth() / 2;
|
||||||
if (distance < circleRadius) {
|
if (distance < circleRadius) {
|
||||||
// unpause the game
|
// unpause the game
|
||||||
pauseTime = -1;
|
pauseTime = -1;
|
||||||
|
@ -698,6 +638,7 @@ public class Game extends BasicGameState {
|
||||||
if (restart != RESTART_FALSE) {
|
if (restart != RESTART_FALSE) {
|
||||||
// new game
|
// new game
|
||||||
if (restart == RESTART_NEW) {
|
if (restart == RESTART_NEW) {
|
||||||
|
loadImages();
|
||||||
setMapModifiers();
|
setMapModifiers();
|
||||||
|
|
||||||
// calculate map length (TODO: end on slider?)
|
// calculate map length (TODO: end on slider?)
|
||||||
|
@ -802,6 +743,49 @@ public class Game extends BasicGameState {
|
||||||
input.isKeyDown(Input.KEY_Z) || input.isKeyDown(Input.KEY_X));
|
input.isKeyDown(Input.KEY_Z) || input.isKeyDown(Input.KEY_X));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads all game images.
|
||||||
|
* @throws SlickException
|
||||||
|
*/
|
||||||
|
private void loadImages() throws SlickException {
|
||||||
|
int width = container.getWidth();
|
||||||
|
int height = container.getHeight();
|
||||||
|
|
||||||
|
// set images
|
||||||
|
File parent = osu.getFile().getParentFile();
|
||||||
|
for (GameImage o : GameImage.values())
|
||||||
|
o.setImage(parent);
|
||||||
|
|
||||||
|
// skip button
|
||||||
|
Image skip = GameImage.SKIP.getImage();
|
||||||
|
float skipScale = (height * 0.1f) / skip.getHeight();
|
||||||
|
skip = skip.getScaledCopy(skipScale);
|
||||||
|
skipButton = new GUIMenuButton(skip,
|
||||||
|
width - (skip.getWidth() / 2f),
|
||||||
|
height - (skip.getHeight() / 2f));
|
||||||
|
|
||||||
|
// countdown
|
||||||
|
Image countdownReady = GameImage.COUNTDOWN_READY.getImage();
|
||||||
|
Image countdown3 = GameImage.COUNTDOWN_3.getImage();
|
||||||
|
Image countdown2 = GameImage.COUNTDOWN_2.getImage();
|
||||||
|
Image countdown1 = GameImage.COUNTDOWN_1.getImage();
|
||||||
|
Image countdownGo = GameImage.COUNTDOWN_GO.getImage();
|
||||||
|
float countdownHeight = height / 3f;
|
||||||
|
GameImage.COUNTDOWN_READY.setImage(
|
||||||
|
countdownReady.getScaledCopy(countdownHeight / countdownReady.getHeight()));
|
||||||
|
GameImage.COUNTDOWN_3.setImage(
|
||||||
|
countdown3.getScaledCopy(countdownHeight / countdown3.getHeight()));
|
||||||
|
GameImage.COUNTDOWN_2.setImage(
|
||||||
|
countdown2.getScaledCopy(countdownHeight / countdown2.getHeight()));
|
||||||
|
GameImage.COUNTDOWN_1.setImage(
|
||||||
|
countdown1.getScaledCopy(countdownHeight / countdown1.getHeight()));
|
||||||
|
GameImage.COUNTDOWN_GO.setImage(
|
||||||
|
countdownGo.getScaledCopy(countdownHeight / countdownGo.getHeight()));
|
||||||
|
|
||||||
|
((GamePauseMenu) game.getState(Opsu.STATE_GAMEPAUSEMENU)).loadImages();
|
||||||
|
score.loadImages();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set map modifiers.
|
* Set map modifiers.
|
||||||
*/
|
*/
|
||||||
|
@ -821,6 +805,7 @@ public class Game extends BasicGameState {
|
||||||
|
|
||||||
Circle.init(container, circleSize);
|
Circle.init(container, circleSize);
|
||||||
Slider.init(container, circleSize, osu);
|
Slider.init(container, circleSize, osu);
|
||||||
|
Spinner.init(container);
|
||||||
|
|
||||||
// approachRate (hit object approach time)
|
// approachRate (hit object approach time)
|
||||||
if (approachRate < 5)
|
if (approachRate < 5)
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
package itdelatrisu.opsu.states;
|
package itdelatrisu.opsu.states;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GUIMenuButton;
|
import itdelatrisu.opsu.GUIMenuButton;
|
||||||
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.MusicController;
|
import itdelatrisu.opsu.MusicController;
|
||||||
import itdelatrisu.opsu.Opsu;
|
import itdelatrisu.opsu.Opsu;
|
||||||
import itdelatrisu.opsu.SoundController;
|
import itdelatrisu.opsu.SoundController;
|
||||||
|
@ -27,7 +28,6 @@ import itdelatrisu.opsu.Utils;
|
||||||
import org.newdawn.slick.Color;
|
import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.GameContainer;
|
import org.newdawn.slick.GameContainer;
|
||||||
import org.newdawn.slick.Graphics;
|
import org.newdawn.slick.Graphics;
|
||||||
import org.newdawn.slick.Image;
|
|
||||||
import org.newdawn.slick.Input;
|
import org.newdawn.slick.Input;
|
||||||
import org.newdawn.slick.SlickException;
|
import org.newdawn.slick.SlickException;
|
||||||
import org.newdawn.slick.state.BasicGameState;
|
import org.newdawn.slick.state.BasicGameState;
|
||||||
|
@ -36,7 +36,7 @@ import org.newdawn.slick.state.transition.FadeInTransition;
|
||||||
import org.newdawn.slick.state.transition.FadeOutTransition;
|
import org.newdawn.slick.state.transition.FadeOutTransition;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Game Paused" state.
|
* "Game Pause/Fail" state.
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>[Continue] - unpause game (return to game state)
|
* <li>[Continue] - unpause game (return to game state)
|
||||||
* <li>[Retry] - restart game (return to game state)
|
* <li>[Retry] - restart game (return to game state)
|
||||||
|
@ -59,18 +59,9 @@ public class GamePauseMenu extends BasicGameState {
|
||||||
*/
|
*/
|
||||||
private GUIMenuButton continueButton, retryButton, backButton;
|
private GUIMenuButton continueButton, retryButton, backButton;
|
||||||
|
|
||||||
/**
|
|
||||||
* Background image for pause menu (optional).
|
|
||||||
*/
|
|
||||||
private Image backgroundImage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Background image for fail menu (optional).
|
|
||||||
*/
|
|
||||||
private Image failImage;
|
|
||||||
|
|
||||||
// game-related variables
|
// game-related variables
|
||||||
private StateBasedGame game;
|
private StateBasedGame game;
|
||||||
|
private GameContainer container;
|
||||||
private int state;
|
private int state;
|
||||||
|
|
||||||
public GamePauseMenu(int state) {
|
public GamePauseMenu(int state) {
|
||||||
|
@ -80,43 +71,18 @@ public class GamePauseMenu extends BasicGameState {
|
||||||
@Override
|
@Override
|
||||||
public void init(GameContainer container, StateBasedGame game)
|
public void init(GameContainer container, StateBasedGame game)
|
||||||
throws SlickException {
|
throws SlickException {
|
||||||
|
this.container = container;
|
||||||
this.game = game;
|
this.game = game;
|
||||||
|
|
||||||
int width = container.getWidth();
|
|
||||||
int height = container.getHeight();
|
|
||||||
|
|
||||||
// initialize buttons
|
|
||||||
continueButton = new GUIMenuButton(new Image("pause-continue.png"), width / 2f, height * 0.25f);
|
|
||||||
retryButton = new GUIMenuButton(new Image("pause-retry.png"), width / 2f, height * 0.5f);
|
|
||||||
backButton = new GUIMenuButton(new Image("pause-back.png"), width / 2f, height * 0.75f);
|
|
||||||
|
|
||||||
// pause background image
|
|
||||||
try {
|
|
||||||
backgroundImage = new Image("pause-overlay.png").getScaledCopy(width, height);
|
|
||||||
backgroundImage.setAlpha(0.7f);
|
|
||||||
} catch (Exception e) {
|
|
||||||
// optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// fail image
|
|
||||||
try {
|
|
||||||
failImage = new Image("fail-background.png").getScaledCopy(width, height);
|
|
||||||
failImage.setAlpha(0.7f);
|
|
||||||
} catch (Exception e) {
|
|
||||||
// optional
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(GameContainer container, StateBasedGame game, Graphics g)
|
public void render(GameContainer container, StateBasedGame game, Graphics g)
|
||||||
throws SlickException {
|
throws SlickException {
|
||||||
// background
|
// background
|
||||||
if (backgroundImage != null && Game.getRestart() != Game.RESTART_LOSE)
|
if (Game.getRestart() != Game.RESTART_LOSE)
|
||||||
backgroundImage.draw();
|
GameImage.PAUSE_OVERLAY.getImage().draw();
|
||||||
else if (failImage != null && Game.getRestart() == Game.RESTART_LOSE)
|
|
||||||
failImage.draw();
|
|
||||||
else
|
else
|
||||||
g.setBackground(Color.black);
|
GameImage.FAIL_BACKGROUND.getImage().draw();
|
||||||
|
|
||||||
// draw buttons
|
// draw buttons
|
||||||
if (Game.getRestart() != Game.RESTART_LOSE)
|
if (Game.getRestart() != Game.RESTART_LOSE)
|
||||||
|
@ -202,4 +168,25 @@ public class GamePauseMenu extends BasicGameState {
|
||||||
Game.setRestart(restart);
|
Game.setRestart(restart);
|
||||||
game.enterState(Opsu.STATE_GAME);
|
game.enterState(Opsu.STATE_GAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads all game pause/fail menu images.
|
||||||
|
*/
|
||||||
|
public void loadImages() {
|
||||||
|
int width = container.getWidth();
|
||||||
|
int height = container.getHeight();
|
||||||
|
|
||||||
|
// initialize buttons
|
||||||
|
continueButton = new GUIMenuButton(GameImage.PAUSE_CONTINUE.getImage(), width / 2f, height * 0.25f);
|
||||||
|
retryButton = new GUIMenuButton(GameImage.PAUSE_RETRY.getImage(), width / 2f, height * 0.5f);
|
||||||
|
backButton = new GUIMenuButton(GameImage.PAUSE_BACK.getImage(), width / 2f, height * 0.75f);
|
||||||
|
|
||||||
|
// pause background image
|
||||||
|
GameImage.PAUSE_OVERLAY.setImage(GameImage.PAUSE_OVERLAY.getImage().getScaledCopy(width, height));
|
||||||
|
GameImage.PAUSE_OVERLAY.getImage().setAlpha(0.7f);
|
||||||
|
|
||||||
|
// fail image
|
||||||
|
GameImage.FAIL_BACKGROUND.setImage(GameImage.FAIL_BACKGROUND.getImage().getScaledCopy(width, height));
|
||||||
|
GameImage.FAIL_BACKGROUND.getImage().setAlpha(0.7f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,7 +129,8 @@ public class Options extends BasicGameState {
|
||||||
DYNAMIC_BACKGROUND,
|
DYNAMIC_BACKGROUND,
|
||||||
SHOW_PERFECT_HIT,
|
SHOW_PERFECT_HIT,
|
||||||
BACKGROUND_DIM,
|
BACKGROUND_DIM,
|
||||||
FORCE_DEFAULT_PLAYFIELD;
|
FORCE_DEFAULT_PLAYFIELD,
|
||||||
|
IGNORE_BEATMAP_SKINS;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -189,6 +190,7 @@ public class Options extends BasicGameState {
|
||||||
private static final GameOption[] gameplayOptions = {
|
private static final GameOption[] gameplayOptions = {
|
||||||
GameOption.BACKGROUND_DIM,
|
GameOption.BACKGROUND_DIM,
|
||||||
GameOption.FORCE_DEFAULT_PLAYFIELD,
|
GameOption.FORCE_DEFAULT_PLAYFIELD,
|
||||||
|
GameOption.IGNORE_BEATMAP_SKINS,
|
||||||
GameOption.SHOW_HIT_LIGHTING,
|
GameOption.SHOW_HIT_LIGHTING,
|
||||||
GameOption.SHOW_COMBO_BURSTS,
|
GameOption.SHOW_COMBO_BURSTS,
|
||||||
GameOption.SHOW_PERFECT_HIT
|
GameOption.SHOW_PERFECT_HIT
|
||||||
|
@ -311,6 +313,11 @@ public class Options extends BasicGameState {
|
||||||
*/
|
*/
|
||||||
private static boolean forceDefaultPlayfield = false;
|
private static boolean forceDefaultPlayfield = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not to ignore resources in the beatmap folders.
|
||||||
|
*/
|
||||||
|
private static boolean ignoreBeatmapSkins = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Game option coordinate modifiers (for drawing).
|
* Game option coordinate modifiers (for drawing).
|
||||||
*/
|
*/
|
||||||
|
@ -545,6 +552,9 @@ public class Options extends BasicGameState {
|
||||||
case FORCE_DEFAULT_PLAYFIELD:
|
case FORCE_DEFAULT_PLAYFIELD:
|
||||||
forceDefaultPlayfield = !forceDefaultPlayfield;
|
forceDefaultPlayfield = !forceDefaultPlayfield;
|
||||||
break;
|
break;
|
||||||
|
case IGNORE_BEATMAP_SKINS:
|
||||||
|
ignoreBeatmapSkins = !ignoreBeatmapSkins;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -721,6 +731,12 @@ public class Options extends BasicGameState {
|
||||||
"Override the song background with the default playfield background."
|
"Override the song background with the default playfield background."
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case IGNORE_BEATMAP_SKINS:
|
||||||
|
drawOption(pos, "Ignore All Beatmap Skins",
|
||||||
|
ignoreBeatmapSkins ? "Yes" : "No",
|
||||||
|
"Never use skin element overrides provided by beatmaps."
|
||||||
|
);
|
||||||
|
break;
|
||||||
case SHOW_HIT_LIGHTING:
|
case SHOW_HIT_LIGHTING:
|
||||||
drawOption(pos, "Show Hit Lighting",
|
drawOption(pos, "Show Hit Lighting",
|
||||||
showHitLighting ? "Yes" : "No",
|
showHitLighting ? "Yes" : "No",
|
||||||
|
@ -920,6 +936,12 @@ public class Options extends BasicGameState {
|
||||||
*/
|
*/
|
||||||
public static boolean isDefaultPlayfieldForced() { return forceDefaultPlayfield; }
|
public static boolean isDefaultPlayfieldForced() { return forceDefaultPlayfield; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not beatmap skins are ignored.
|
||||||
|
* @return true if ignored
|
||||||
|
*/
|
||||||
|
public static boolean isBeatmapSkinIgnored() { return ignoreBeatmapSkins; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current beatmap directory.
|
* Returns the current beatmap directory.
|
||||||
* If invalid, this will attempt to search for the directory,
|
* If invalid, this will attempt to search for the directory,
|
||||||
|
@ -1044,6 +1066,9 @@ public class Options extends BasicGameState {
|
||||||
case "ForceDefaultPlayfield":
|
case "ForceDefaultPlayfield":
|
||||||
forceDefaultPlayfield = Boolean.parseBoolean(value);
|
forceDefaultPlayfield = Boolean.parseBoolean(value);
|
||||||
break;
|
break;
|
||||||
|
case "IgnoreBeatmapSkins":
|
||||||
|
ignoreBeatmapSkins = Boolean.parseBoolean(value);
|
||||||
|
break;
|
||||||
case "HitLighting":
|
case "HitLighting":
|
||||||
showHitLighting = Boolean.parseBoolean(value);
|
showHitLighting = Boolean.parseBoolean(value);
|
||||||
break;
|
break;
|
||||||
|
@ -1112,6 +1137,8 @@ public class Options extends BasicGameState {
|
||||||
writer.newLine();
|
writer.newLine();
|
||||||
writer.write(String.format("ForceDefaultPlayfield = %b", forceDefaultPlayfield));
|
writer.write(String.format("ForceDefaultPlayfield = %b", forceDefaultPlayfield));
|
||||||
writer.newLine();
|
writer.newLine();
|
||||||
|
writer.write(String.format("IgnoreBeatmapSkins = %b", ignoreBeatmapSkins));
|
||||||
|
writer.newLine();
|
||||||
writer.write(String.format("HitLighting = %b", showHitLighting));
|
writer.write(String.format("HitLighting = %b", showHitLighting));
|
||||||
writer.newLine();
|
writer.newLine();
|
||||||
writer.write(String.format("ComboBurst = %b", showComboBursts));
|
writer.write(String.format("ComboBurst = %b", showComboBursts));
|
||||||
|
|
Loading…
Reference in New Issue
Block a user