@2x size images.
ComboBurst speed scaling. CircumscribedCircle drawing optimization.
This commit is contained in:
parent
356772b6b6
commit
aeaaa9af4f
|
@ -164,7 +164,7 @@ public class GameData {
|
||||||
private float comboBurstAlpha;
|
private float comboBurstAlpha;
|
||||||
|
|
||||||
/** Current x coordinate of the combo burst image (for sliding animation). */
|
/** Current x coordinate of the combo burst image (for sliding animation). */
|
||||||
private int comboBurstX;
|
private float comboBurstX;
|
||||||
|
|
||||||
/** Time offsets for obtaining each hit result (indexed by HIT_* constants). */
|
/** Time offsets for obtaining each hit result (indexed by HIT_* constants). */
|
||||||
private int[] hitResultOffset;
|
private int[] hitResultOffset;
|
||||||
|
@ -999,11 +999,11 @@ public class GameData {
|
||||||
int leftX = 0;
|
int leftX = 0;
|
||||||
int rightX = width - comboBurstImages[comboBurstIndex].getWidth();
|
int rightX = width - comboBurstImages[comboBurstIndex].getWidth();
|
||||||
if (comboBurstX < leftX) {
|
if (comboBurstX < leftX) {
|
||||||
comboBurstX += (delta / 2f);
|
comboBurstX += (delta / 2f) * GameImage.getUIscale();
|
||||||
if (comboBurstX > leftX)
|
if (comboBurstX > leftX)
|
||||||
comboBurstX = leftX;
|
comboBurstX = leftX;
|
||||||
} else if (comboBurstX > rightX) {
|
} else if (comboBurstX > rightX) {
|
||||||
comboBurstX -= (delta / 2f);
|
comboBurstX -= (delta / 2f) * GameImage.getUIscale();
|
||||||
if (comboBurstX < rightX)
|
if (comboBurstX < rightX)
|
||||||
comboBurstX = rightX;
|
comboBurstX = rightX;
|
||||||
} else if (comboBurstAlpha > 0f) {
|
} else if (comboBurstAlpha > 0f) {
|
||||||
|
|
|
@ -373,6 +373,9 @@ public enum GameImage {
|
||||||
/** The unscaled container height that uiscale is based on. */
|
/** The unscaled container height that uiscale is based on. */
|
||||||
private static final int UNSCALED_HEIGHT = 768;
|
private static final int UNSCALED_HEIGHT = 768;
|
||||||
|
|
||||||
|
/** Image Sizes suffixes to try to load images with */
|
||||||
|
private static String[] imageSizeSuffix;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the GameImage class with container dimensions.
|
* Initializes the GameImage class with container dimensions.
|
||||||
* @param width the container width
|
* @param width the container width
|
||||||
|
@ -382,6 +385,11 @@ public enum GameImage {
|
||||||
containerWidth = width;
|
containerWidth = width;
|
||||||
containerHeight = height;
|
containerHeight = height;
|
||||||
uiscale = (float) containerHeight / UNSCALED_HEIGHT;
|
uiscale = (float) containerHeight / UNSCALED_HEIGHT;
|
||||||
|
if (Options.is2xImagesEnabled() && uiscale >= 1) {
|
||||||
|
imageSizeSuffix = new String[]{"@2x",""};
|
||||||
|
} else {
|
||||||
|
imageSizeSuffix = new String[]{""};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -564,51 +572,32 @@ public enum GameImage {
|
||||||
if (defaultImage != null || defaultImages != null)
|
if (defaultImage != null || defaultImages != null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// load image array
|
|
||||||
if (filenameFormat != null) {
|
if (filenameFormat != null) {
|
||||||
List<Image> list = new ArrayList<Image>();
|
defaultImages = getMutliImages(Options.getSkinDir());
|
||||||
File dir = Options.getSkinDir();
|
if (defaultImages != null) {
|
||||||
int i = 0;
|
process();
|
||||||
while (true) {
|
return;
|
||||||
// look for next image
|
|
||||||
String filenameFormatted = String.format(filenameFormat, i++);
|
|
||||||
String name = getImageFileName(filenameFormatted, dir, type, true);
|
|
||||||
if (i == 1 && name == null) { // first image: check other location
|
|
||||||
dir = null;
|
|
||||||
name = getImageFileName(filenameFormatted, dir, type, true);
|
|
||||||
}
|
}
|
||||||
if (name == null)
|
defaultImages = getMutliImages(null);
|
||||||
break;
|
if (defaultImages != null) {
|
||||||
|
|
||||||
// add image to list
|
|
||||||
try {
|
|
||||||
Image img = new Image(name);
|
|
||||||
list.add(img);
|
|
||||||
} catch (SlickException e) {
|
|
||||||
ErrorHandler.error(String.format("Failed to set default image '%s'.", name), null, false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!list.isEmpty()) {
|
|
||||||
this.defaultImages = list.toArray(new Image[list.size()]);
|
|
||||||
process();
|
process();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// load single image
|
defaultImage = getSingleImage(Options.getSkinDir());
|
||||||
String name = getImageFileName(filename, Options.getSkinDir(), type, false);
|
if (defaultImage != null) {
|
||||||
if (name == null) {
|
process();
|
||||||
ErrorHandler.error(String.format("Could not find image '%s'.", filename), null, false);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
Image img = new Image(name);
|
defaultImage = getSingleImage(null);
|
||||||
this.defaultImage = img;
|
if (defaultImage != null) {
|
||||||
process();
|
process();
|
||||||
} catch (SlickException e) {
|
return;
|
||||||
ErrorHandler.error(String.format("Failed to set default image '%s'.", filename), null, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ErrorHandler.error(String.format("Could not find default image '%s'.", filename), null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -627,47 +616,79 @@ public enum GameImage {
|
||||||
if (Options.isBeatmapSkinIgnored())
|
if (Options.isBeatmapSkinIgnored())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// look for multiple skin images
|
skinImages = getMutliImages(dir);
|
||||||
|
if (skinImages != null) {
|
||||||
|
process();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
skinImage = getSingleImage(dir);
|
||||||
|
if (skinImage != null) {
|
||||||
|
process();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to load GameImage with multiple images.
|
||||||
|
* @return an array of images or null if not found.
|
||||||
|
*/
|
||||||
|
public Image[] getMutliImages(File dir){
|
||||||
|
// load image array
|
||||||
if (filenameFormat != null) {
|
if (filenameFormat != null) {
|
||||||
|
for (String suf : imageSizeSuffix) {
|
||||||
List<Image> list = new ArrayList<Image>();
|
List<Image> list = new ArrayList<Image>();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
// look for next image
|
// look for next image
|
||||||
String filenameFormatted = String.format(filenameFormat, i++);
|
String filenameFormatted = String.format(filenameFormat+suf, i++);
|
||||||
String name = getImageFileName(filenameFormatted, dir, type, true);
|
String name = getImageFileName(filenameFormatted, dir, type, true);
|
||||||
if (name == null)
|
if (name == null)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// add image to list
|
// add image to list
|
||||||
try {
|
try {
|
||||||
|
System.out.println(name);
|
||||||
Image img = new Image(name);
|
Image img = new Image(name);
|
||||||
|
if(suf.equals("@2x"))
|
||||||
|
img = img.getScaledCopy(0.5f);
|
||||||
list.add(img);
|
list.add(img);
|
||||||
} catch (SlickException e) {
|
} catch (SlickException e) {
|
||||||
ErrorHandler.error(String.format("Failed to set skin image '%s'.", name), null, false);
|
ErrorHandler.error(String.format("Failed to set image '%s'.", name), null, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!list.isEmpty()) {
|
if (!list.isEmpty()) {
|
||||||
this.skinImages = list.toArray(new Image[list.size()]);
|
return list.toArray(new Image[list.size()]);
|
||||||
process();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// look for a skin image
|
/**
|
||||||
String name = getImageFileName(filename, dir, type, true);
|
* Attempts to load GameImage with a single image.
|
||||||
if (name == null)
|
* @return an image or null if not found.
|
||||||
return false;
|
*/
|
||||||
|
public Image getSingleImage(File dir){
|
||||||
|
for (String suf : imageSizeSuffix) {
|
||||||
|
// load single image
|
||||||
|
String name = getImageFileName(filename+suf, dir, type, true);
|
||||||
|
if (name != null) {
|
||||||
try {
|
try {
|
||||||
Image img = new Image(name);
|
Image img = new Image(name);
|
||||||
this.skinImage = img;
|
System.out.println(name);
|
||||||
process();
|
if(suf.equals("@2x"))
|
||||||
return true;
|
img = img.getScaledCopy(0.5f);
|
||||||
|
return img;
|
||||||
} catch (SlickException e) {
|
} catch (SlickException e) {
|
||||||
skinImage = null;
|
ErrorHandler.error(String.format("Failed to set image '%s'.", filename), null, false);
|
||||||
ErrorHandler.error(String.format("Failed to set skin image '%s'.", name), null, false);
|
|
||||||
}
|
}
|
||||||
return false;
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -257,6 +257,7 @@ public class Options {
|
||||||
},
|
},
|
||||||
ENABLE_THEME_SONG ("Enable Theme Song", "Whether to play the theme song upon starting opsu!", true),
|
ENABLE_THEME_SONG ("Enable Theme Song", "Whether to play the theme song upon starting opsu!", true),
|
||||||
SHOW_HIT_ERROR_BAR ("Show Hit Error Bar", "Shows precisely how accurate you were with each hit.", false),
|
SHOW_HIT_ERROR_BAR ("Show Hit Error Bar", "Shows precisely how accurate you were with each hit.", false),
|
||||||
|
USE_2X_IMAGE ("Use @2x Images", "Uses @2x images if available.", true),
|
||||||
DISABLE_MOUSE_WHEEL ("Disable mouse wheel in play mode", "During play, you can use the mouse wheel to adjust the volume and pause the game.\nThis will disable that functionality.", false),
|
DISABLE_MOUSE_WHEEL ("Disable mouse wheel in play mode", "During play, you can use the mouse wheel to adjust the volume and pause the game.\nThis will disable that functionality.", false),
|
||||||
DISABLE_MOUSE_BUTTONS ("Disable mouse buttons in play mode", "This option will disable all mouse buttons.\nSpecifically for people who use their keyboard to click.", false);
|
DISABLE_MOUSE_BUTTONS ("Disable mouse buttons in play mode", "This option will disable all mouse buttons.\nSpecifically for people who use their keyboard to click.", false);
|
||||||
|
|
||||||
|
@ -694,6 +695,14 @@ public class Options {
|
||||||
*/
|
*/
|
||||||
public static boolean isHitErrorBarEnabled() { return GameOption.SHOW_HIT_ERROR_BAR.getBooleanValue(); }
|
public static boolean isHitErrorBarEnabled() { return GameOption.SHOW_HIT_ERROR_BAR.getBooleanValue(); }
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not to use 2x Images
|
||||||
|
* @return true if ignored
|
||||||
|
*/
|
||||||
|
public static boolean is2xImagesEnabled() { return GameOption.USE_2X_IMAGE.getBooleanValue(); }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether or not the mouse wheel is disabled during gameplay.
|
* Returns whether or not the mouse wheel is disabled during gameplay.
|
||||||
* @return true if disabled
|
* @return true if disabled
|
||||||
|
@ -1021,6 +1030,9 @@ public class Options {
|
||||||
case "ScoreMeter":
|
case "ScoreMeter":
|
||||||
GameOption.SHOW_HIT_ERROR_BAR.setValue(Boolean.parseBoolean(value));
|
GameOption.SHOW_HIT_ERROR_BAR.setValue(Boolean.parseBoolean(value));
|
||||||
break;
|
break;
|
||||||
|
case "Use2xImage":
|
||||||
|
GameOption.USE_2X_IMAGE.setValue(Boolean.parseBoolean(value));
|
||||||
|
break;
|
||||||
case "FixedCS":
|
case "FixedCS":
|
||||||
GameOption.FIXED_CS.setValue((int) (Float.parseFloat(value) * 10f));
|
GameOption.FIXED_CS.setValue((int) (Float.parseFloat(value) * 10f));
|
||||||
break;
|
break;
|
||||||
|
@ -1133,6 +1145,8 @@ public class Options {
|
||||||
writer.newLine();
|
writer.newLine();
|
||||||
writer.write(String.format("ScoreMeter = %b", isHitErrorBarEnabled()));
|
writer.write(String.format("ScoreMeter = %b", isHitErrorBarEnabled()));
|
||||||
writer.newLine();
|
writer.newLine();
|
||||||
|
writer.write(String.format("Use2xImage = %b", is2xImagesEnabled()));
|
||||||
|
writer.newLine();
|
||||||
writer.write(String.format(Locale.US, "FixedCS = %.1f", getFixedCS()));
|
writer.write(String.format(Locale.US, "FixedCS = %.1f", getFixedCS()));
|
||||||
writer.newLine();
|
writer.newLine();
|
||||||
writer.write(String.format(Locale.US, "FixedHP = %.1f", getFixedHP()));
|
writer.write(String.format(Locale.US, "FixedHP = %.1f", getFixedHP()));
|
||||||
|
|
|
@ -140,7 +140,7 @@ public class Slider implements HitObject {
|
||||||
this.color = color;
|
this.color = color;
|
||||||
this.comboEnd = comboEnd;
|
this.comboEnd = comboEnd;
|
||||||
|
|
||||||
if (hitObject.getSliderType() == 'P' && hitObject.getSliderX().length == 2)
|
if (hitObject.getSliderType() == OsuHitObject.SLIDER_PASSTHROUGH && hitObject.getSliderX().length == 2)
|
||||||
this.curve = new CircumscribedCircle(hitObject, color);
|
this.curve = new CircumscribedCircle(hitObject, color);
|
||||||
else
|
else
|
||||||
this.curve = new LinearBezier(hitObject, color);
|
this.curve = new LinearBezier(hitObject, color);
|
||||||
|
|
|
@ -56,6 +56,9 @@ public class CircumscribedCircle extends Curve {
|
||||||
/** The number of steps in the curve to draw. */
|
/** The number of steps in the curve to draw. */
|
||||||
private float step;
|
private float step;
|
||||||
|
|
||||||
|
/** Points along the curve. */
|
||||||
|
private Vec2f[] curve;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
* @param hitObject the associated OsuHitObject
|
* @param hitObject the associated OsuHitObject
|
||||||
|
@ -120,6 +123,12 @@ public class CircumscribedCircle extends Curve {
|
||||||
// finds the angles to draw for repeats
|
// finds the angles to draw for repeats
|
||||||
this.drawEndAngle = (float) ((endAng + (startAng > endAng ? HALF_PI : -HALF_PI)) * 180 / Math.PI);
|
this.drawEndAngle = (float) ((endAng + (startAng > endAng ? HALF_PI : -HALF_PI)) * 180 / Math.PI);
|
||||||
this.drawStartAngle = (float) ((startAng + (startAng > endAng ? -HALF_PI : HALF_PI)) * 180 / Math.PI);
|
this.drawStartAngle = (float) ((startAng + (startAng > endAng ? -HALF_PI : HALF_PI)) * 180 / Math.PI);
|
||||||
|
|
||||||
|
curve = new Vec2f[(int) step + 1];
|
||||||
|
for (int i = 0; i < curve.length; i++) {
|
||||||
|
float[] xy = pointAt(i / step);
|
||||||
|
curve[i] = new Vec2f(xy[0], xy[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -172,13 +181,11 @@ public class CircumscribedCircle extends Curve {
|
||||||
public void draw() {
|
public void draw() {
|
||||||
Image hitCircle = GameImage.HITCIRCLE.getImage();
|
Image hitCircle = GameImage.HITCIRCLE.getImage();
|
||||||
Image hitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage();
|
Image hitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage();
|
||||||
float[][] xy = new float[(int) step + 1][];
|
|
||||||
for (int i = 0; i < step; i++) {
|
for (int i = 0; i < step; i++) {
|
||||||
xy[i] = pointAt(i / step);
|
hitCircleOverlay.drawCentered(curve[i].x, curve[i].y, Utils.COLOR_WHITE_FADE);
|
||||||
hitCircleOverlay.drawCentered(xy[i][0], xy[i][1], Utils.COLOR_WHITE_FADE);
|
|
||||||
}
|
}
|
||||||
for (int i = 0; i < step; i++)
|
for (int i = 0; i < step; i++)
|
||||||
hitCircle.drawCentered(xy[i][0], xy[i][1], color);
|
hitCircle.drawCentered(curve[i].x, curve[i].y, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -89,7 +89,8 @@ public class OptionsMenu extends BasicGameState {
|
||||||
GameOption.FIXED_HP,
|
GameOption.FIXED_HP,
|
||||||
GameOption.FIXED_AR,
|
GameOption.FIXED_AR,
|
||||||
GameOption.FIXED_OD,
|
GameOption.FIXED_OD,
|
||||||
GameOption.CHECKPOINT
|
GameOption.CHECKPOINT,
|
||||||
|
GameOption.USE_2X_IMAGE
|
||||||
});
|
});
|
||||||
|
|
||||||
/** Total number of tabs. */
|
/** Total number of tabs. */
|
||||||
|
|
Loading…
Reference in New Issue
Block a user