Replaced native cursors with skinnable ones.
- Added support for both the new (2013+) and old cursor styles. These can be toggled on/off in the configuration file. - Added cursor images by XinCrin (old style) and teinecthel (new style). Other changes: - Refactoring: Created a "Utils" module, containing methods and constants that didn't belong in the "Options" state and some duplicated drawing methods. - Mouse is now grabbed during gameplay. - Removed 'optionsChanged' switch, simplifying adding new options. Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
parent
0604a25822
commit
ab487c5e80
|
@ -17,6 +17,7 @@ The images included in opsu! belong to their respective authors.
|
|||
* pictuga - "osu! web"
|
||||
* sherrie__fay
|
||||
* kouyang
|
||||
* teinecthel
|
||||
|
||||
Projects
|
||||
--------
|
||||
|
|
BIN
res/cursor.png
BIN
res/cursor.png
Binary file not shown.
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 5.7 KiB |
BIN
res/cursor2.png
Normal file
BIN
res/cursor2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.3 KiB |
BIN
res/cursormiddle.png
Normal file
BIN
res/cursormiddle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 565 B |
BIN
res/cursortrail.png
Normal file
BIN
res/cursortrail.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
BIN
res/cursortrail2.png
Normal file
BIN
res/cursortrail2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
|
@ -509,7 +509,7 @@ public class GameScore {
|
|||
|
||||
// header & "Ranking" text
|
||||
float rankingHeight = (rankingImage.getHeight() * 0.75f) + 3;
|
||||
g.setColor(Options.COLOR_BLACK_ALPHA);
|
||||
g.setColor(Utils.COLOR_BLACK_ALPHA);
|
||||
g.fillRect(0, 0, width, rankingHeight);
|
||||
rankingImage.draw((width * 0.97f) - rankingImage.getWidth(), 0);
|
||||
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
|
||||
package itdelatrisu.opsu;
|
||||
|
||||
import itdelatrisu.opsu.states.Options;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
|
||||
|
@ -128,21 +126,21 @@ public class OsuGroupNode implements Comparable<OsuGroupNode> {
|
|||
textColor = Color.white;
|
||||
} else {
|
||||
xOffset = bg.getWidth() * 0.05f;
|
||||
bg.draw(x + xOffset, y, Options.COLOR_BLUE_BUTTON);
|
||||
bg.draw(x + xOffset, y, Utils.COLOR_BLUE_BUTTON);
|
||||
}
|
||||
osu = osuFiles.get(osuFileIndex);
|
||||
} else {
|
||||
bg.draw(x, y, Options.COLOR_ORANGE_BUTTON);
|
||||
bg.draw(x, y, Utils.COLOR_ORANGE_BUTTON);
|
||||
osu = osuFiles.get(0);
|
||||
}
|
||||
|
||||
float cx = x + (bg.getWidth() * 0.05f) + xOffset;
|
||||
float cy = y + (bg.getHeight() * 0.2f) - 3;
|
||||
|
||||
Options.FONT_MEDIUM.drawString(cx, cy, osu.title, textColor);
|
||||
Options.FONT_DEFAULT.drawString(cx, cy + Options.FONT_MEDIUM.getLineHeight() - 4, String.format("%s // %s", osu.artist, osu.creator), textColor);
|
||||
Utils.FONT_MEDIUM.drawString(cx, cy, osu.title, textColor);
|
||||
Utils.FONT_DEFAULT.drawString(cx, cy + Utils.FONT_MEDIUM.getLineHeight() - 4, String.format("%s // %s", osu.artist, osu.creator), textColor);
|
||||
if (expanded)
|
||||
Options.FONT_BOLD.drawString(cx, cy + Options.FONT_MEDIUM.getLineHeight() + Options.FONT_DEFAULT.getLineHeight() - 8, osu.version, textColor);
|
||||
Utils.FONT_BOLD.drawString(cx, cy + Utils.FONT_MEDIUM.getLineHeight() + Utils.FONT_DEFAULT.getLineHeight() - 8, osu.version, textColor);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,15 +18,12 @@
|
|||
|
||||
package itdelatrisu.opsu;
|
||||
|
||||
import itdelatrisu.opsu.states.Options;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
|
||||
|
@ -104,8 +101,6 @@ public class OsuParser {
|
|||
|
||||
try (BufferedReader in = new BufferedReader(new FileReader(file))) {
|
||||
|
||||
// copy the default combo colors
|
||||
osu.combo = Arrays.copyOf(Options.DEFAULT_COMBO, Options.DEFAULT_COMBO.length);
|
||||
// initialize timing point list
|
||||
osu.timingPoints = new ArrayList<OsuTimingPoint>();
|
||||
|
||||
|
@ -403,7 +398,7 @@ public class OsuParser {
|
|||
|
||||
// if no custom colors, use the default color scheme
|
||||
if (osu.combo == null)
|
||||
osu.combo = Options.DEFAULT_COMBO;
|
||||
osu.combo = Utils.DEFAULT_COMBO;
|
||||
|
||||
// add tags
|
||||
if (!tags.isEmpty()) {
|
||||
|
|
369
src/itdelatrisu/opsu/Utils.java
Normal file
369
src/itdelatrisu/opsu/Utils.java
Normal file
|
@ -0,0 +1,369 @@
|
|||
/*
|
||||
* 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.awt.Font;
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.LWJGLException;
|
||||
import org.lwjgl.input.Cursor;
|
||||
import org.newdawn.slick.Animation;
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.GameContainer;
|
||||
import org.newdawn.slick.Image;
|
||||
import org.newdawn.slick.Input;
|
||||
import org.newdawn.slick.SlickException;
|
||||
import org.newdawn.slick.TrueTypeFont;
|
||||
import org.newdawn.slick.imageout.ImageOut;
|
||||
import org.newdawn.slick.state.StateBasedGame;
|
||||
import org.newdawn.slick.util.Log;
|
||||
|
||||
/**
|
||||
* Contains miscellaneous utilities.
|
||||
*/
|
||||
public class Utils {
|
||||
/**
|
||||
* Game colors.
|
||||
*/
|
||||
public static final Color
|
||||
COLOR_BLACK_ALPHA = new Color(0, 0, 0, 0.5f),
|
||||
COLOR_BLUE_DIVIDER = new Color(49, 94, 237),
|
||||
COLOR_BLUE_BACKGROUND = new Color(74, 130, 255),
|
||||
COLOR_BLUE_BUTTON = new Color(50, 189, 237),
|
||||
COLOR_ORANGE_BUTTON = new Color(230, 151, 87),
|
||||
COLOR_GREEN_OBJECT = new Color(26, 207, 26),
|
||||
COLOR_BLUE_OBJECT = new Color(46, 136, 248),
|
||||
COLOR_RED_OBJECT = new Color(243, 48, 77),
|
||||
COLOR_ORANGE_OBJECT = new Color(255, 200, 32);
|
||||
|
||||
/**
|
||||
* The default map colors, used when a map does not provide custom colors.
|
||||
*/
|
||||
public static final Color[] DEFAULT_COMBO = {
|
||||
COLOR_GREEN_OBJECT, COLOR_BLUE_OBJECT,
|
||||
COLOR_RED_OBJECT, COLOR_ORANGE_OBJECT
|
||||
};
|
||||
|
||||
/**
|
||||
* Game fonts.
|
||||
*/
|
||||
public static TrueTypeFont
|
||||
FONT_DEFAULT, FONT_BOLD,
|
||||
FONT_XLARGE, FONT_LARGE, FONT_MEDIUM, FONT_SMALL;
|
||||
|
||||
/**
|
||||
* Back button (shared by other states).
|
||||
*/
|
||||
private static GUIMenuButton backButton;
|
||||
|
||||
/**
|
||||
* Cursor image and trail.
|
||||
*/
|
||||
private static Image cursor, cursorTrail, cursorMiddle;
|
||||
|
||||
/**
|
||||
* Last cursor coordinates.
|
||||
*/
|
||||
private static int lastX = -1, lastY = -1;
|
||||
|
||||
/**
|
||||
* Stores all previous cursor locations to display a trail.
|
||||
*/
|
||||
private static LinkedList<Integer>
|
||||
cursorX = new LinkedList<Integer>(),
|
||||
cursorY = new LinkedList<Integer>();
|
||||
|
||||
// game-related variables
|
||||
private static GameContainer container;
|
||||
// private static StateBasedGame game;
|
||||
private static Input input;
|
||||
|
||||
// This class should not be instantiated.
|
||||
private Utils() {}
|
||||
|
||||
/**
|
||||
* Initializes game settings and class data.
|
||||
* @param container the game container
|
||||
* @param game the game object
|
||||
* @throws SlickException
|
||||
*/
|
||||
public static void init(GameContainer container, StateBasedGame game)
|
||||
throws SlickException {
|
||||
Utils.container = container;
|
||||
// Utils.game = game;
|
||||
Utils.input = container.getInput();
|
||||
|
||||
// game settings
|
||||
container.setTargetFrameRate(Options.getTargetFPS());
|
||||
container.setMusicVolume(Options.getMusicVolume());
|
||||
container.setShowFPS(false);
|
||||
container.getInput().enableKeyRepeat();
|
||||
container.setAlwaysRender(true);
|
||||
|
||||
// hide the cursor
|
||||
try {
|
||||
Cursor emptyCursor = new Cursor(1, 1, 0, 0, 1, BufferUtils.createIntBuffer(1), null);
|
||||
container.setMouseCursor(emptyCursor, 0, 0);
|
||||
} catch (LWJGLException e) {
|
||||
Log.error("Failed to set the cursor.", e);
|
||||
}
|
||||
|
||||
// load cursor images
|
||||
if (Options.isNewCursorEnabled()) {
|
||||
// load new cursor type
|
||||
try {
|
||||
cursorMiddle = new Image("cursormiddle.png");
|
||||
cursor = new Image("cursor.png");
|
||||
cursorTrail = new Image("cursortrail.png");
|
||||
} catch (Exception e) {
|
||||
// optional
|
||||
}
|
||||
}
|
||||
if (cursorMiddle == null) {
|
||||
// load old cursor type
|
||||
cursor = new Image("cursor2.png");
|
||||
cursorTrail = new Image("cursortrail2.png");
|
||||
}
|
||||
|
||||
// create fonts
|
||||
int height = container.getHeight();
|
||||
float fontBase;
|
||||
if (height <= 600)
|
||||
fontBase = 9f;
|
||||
else if (height < 800)
|
||||
fontBase = 10f;
|
||||
else if (height <= 900)
|
||||
fontBase = 12f;
|
||||
else
|
||||
fontBase = 14f;
|
||||
|
||||
Font font = new Font("Lucida Sans Unicode", Font.PLAIN, (int) (fontBase * 4 / 3));
|
||||
FONT_DEFAULT = new TrueTypeFont(font, false);
|
||||
FONT_BOLD = new TrueTypeFont(font.deriveFont(Font.BOLD), false);
|
||||
FONT_XLARGE = new TrueTypeFont(font.deriveFont(fontBase * 4), false);
|
||||
FONT_LARGE = new TrueTypeFont(font.deriveFont(fontBase * 2), false);
|
||||
FONT_MEDIUM = new TrueTypeFont(font.deriveFont(fontBase * 3 / 2), false);
|
||||
FONT_SMALL = new TrueTypeFont(font.deriveFont(fontBase), false);
|
||||
|
||||
// back button
|
||||
Image back = new Image("menu-back.png");
|
||||
float scale = (height * 0.1f) / back.getHeight();
|
||||
back = back.getScaledCopy(scale);
|
||||
backButton = new GUIMenuButton(back,
|
||||
back.getWidth() / 2f,
|
||||
height - (back.getHeight() / 2f));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 'back' GUIMenuButton.
|
||||
*/
|
||||
public static GUIMenuButton getBackButton() { return backButton; }
|
||||
|
||||
/**
|
||||
* Draws an image based on its center with a color filter.
|
||||
* @param img the image to draw
|
||||
* @param x the center x coordinate
|
||||
* @param y the center y coordinate
|
||||
* @param color the color filter to apply
|
||||
*/
|
||||
public static void drawCentered(Image img, float x, float y, Color color) {
|
||||
img.draw(x - (img.getWidth() / 2f), y - (img.getHeight() / 2f), color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws an animation based on its center.
|
||||
* @param anim the animation to draw
|
||||
* @param x the center x coordinate
|
||||
* @param y the center y coordinate
|
||||
*/
|
||||
public static void drawCentered(Animation anim, float x, float y) {
|
||||
anim.draw(x - (anim.getWidth() / 2f), y - (anim.getHeight() / 2f));
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the cursor.
|
||||
*/
|
||||
public static void drawCursor() {
|
||||
// TODO: use an image buffer
|
||||
|
||||
int x = input.getMouseX();
|
||||
int y = input.getMouseY();
|
||||
|
||||
int removeCount = 0;
|
||||
int FPSmod = (Options.getTargetFPS() / 60);
|
||||
|
||||
// if middle exists, add all points between cursor movements
|
||||
if (cursorMiddle != null) {
|
||||
if (lastX < 0) {
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
return;
|
||||
}
|
||||
addCursorPoints(lastX, lastY, x, y);
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
|
||||
removeCount = (cursorX.size() / (6 * FPSmod)) + 1;
|
||||
}
|
||||
|
||||
// else, sample one point at a time
|
||||
else {
|
||||
cursorX.add(x);
|
||||
cursorY.add(y);
|
||||
|
||||
int max = 10 * FPSmod;
|
||||
if (cursorX.size() > max)
|
||||
removeCount = cursorX.size() - max;
|
||||
}
|
||||
|
||||
// remove points from the lists
|
||||
for (int i = 0; i < removeCount && !cursorX.isEmpty(); i++) {
|
||||
cursorX.remove();
|
||||
cursorY.remove();
|
||||
}
|
||||
|
||||
// draw a fading trail
|
||||
float alpha = 0f;
|
||||
float t = 2f / cursorX.size();
|
||||
Iterator<Integer> iterX = cursorX.iterator();
|
||||
Iterator<Integer> iterY = cursorY.iterator();
|
||||
while (iterX.hasNext()) {
|
||||
int cx = iterX.next();
|
||||
int cy = iterY.next();
|
||||
alpha += t;
|
||||
cursorTrail.setAlpha(alpha);
|
||||
// if (cx != x || cy != y)
|
||||
cursorTrail.drawCentered(cx, cy);
|
||||
}
|
||||
cursorTrail.drawCentered(x, y);
|
||||
|
||||
// draw the other components
|
||||
cursor.drawCentered(x, y);
|
||||
if (cursorMiddle != null)
|
||||
cursorMiddle.drawCentered(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all points between (x1, y1) and (x2, y2) to the cursor point lists.
|
||||
* @author http://rosettacode.org/wiki/Bitmap/Bresenham's_line_algorithm#Java
|
||||
*/
|
||||
private static void addCursorPoints(int x1, int y1, int x2, int y2) {
|
||||
// delta of exact value and rounded value of the dependent variable
|
||||
int d = 0;
|
||||
int dy = Math.abs(y2 - y1);
|
||||
int dx = Math.abs(x2 - x1);
|
||||
|
||||
int dy2 = (dy << 1); // slope scaling factors to avoid floating
|
||||
int dx2 = (dx << 1); // point
|
||||
int ix = x1 < x2 ? 1 : -1; // increment direction
|
||||
int iy = y1 < y2 ? 1 : -1;
|
||||
|
||||
int k = 5; // sample size
|
||||
if (dy <= dx) {
|
||||
for (int i = 0; ; i++) {
|
||||
if (i == k) {
|
||||
cursorX.add(x1);
|
||||
cursorY.add(y1);
|
||||
i = 0;
|
||||
}
|
||||
if (x1 == x2)
|
||||
break;
|
||||
x1 += ix;
|
||||
d += dy2;
|
||||
if (d > dx) {
|
||||
y1 += iy;
|
||||
d -= dx2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; ; i++) {
|
||||
if (i == k) {
|
||||
cursorX.add(x1);
|
||||
cursorY.add(y1);
|
||||
i = 0;
|
||||
}
|
||||
if (y1 == y2)
|
||||
break;
|
||||
y1 += iy;
|
||||
d += dx2;
|
||||
if (d > dy) {
|
||||
x1 += ix;
|
||||
d -= dy2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the FPS at the bottom-right corner of the game container.
|
||||
* If the option is not activated, this will do nothing.
|
||||
*/
|
||||
public static void drawFPS() {
|
||||
if (!Options.isFPSCounterEnabled())
|
||||
return;
|
||||
|
||||
String fps = String.format("FPS: %d", container.getFPS());
|
||||
FONT_DEFAULT.drawString(
|
||||
container.getWidth() - 15 - FONT_DEFAULT.getWidth(fps),
|
||||
container.getHeight() - 15 - FONT_DEFAULT.getHeight(fps),
|
||||
fps, Color.white
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a screenshot.
|
||||
* @return true if successful
|
||||
*/
|
||||
public static boolean takeScreenShot() {
|
||||
// TODO: should this be threaded?
|
||||
try {
|
||||
// create the screenshot directory
|
||||
if (!Options.SCREENSHOT_DIR.isDirectory()) {
|
||||
if (!Options.SCREENSHOT_DIR.mkdir())
|
||||
return false;
|
||||
}
|
||||
|
||||
// create file name
|
||||
SimpleDateFormat date = new SimpleDateFormat("yyyyMMdd_HHmmss");
|
||||
String file = date.format(new Date());
|
||||
|
||||
SoundController.playSound(SoundController.SOUND_SHUTTER);
|
||||
|
||||
// copy the screen
|
||||
Image screen = new Image(container.getWidth(), container.getHeight());
|
||||
container.getGraphics().copyArea(screen, 0, 0);
|
||||
ImageOut.write(screen, String.format("%s%sscreenshot_%s.%s",
|
||||
Options.SCREENSHOT_DIR.getName(), File.separator,
|
||||
file, Options.getScreenshotFormat()), false
|
||||
);
|
||||
screen.destroy();
|
||||
} catch (SlickException e) {
|
||||
Log.warn("Failed to take a screenshot.", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ package itdelatrisu.opsu.objects;
|
|||
import itdelatrisu.opsu.GameScore;
|
||||
import itdelatrisu.opsu.MusicController;
|
||||
import itdelatrisu.opsu.OsuHitObject;
|
||||
import itdelatrisu.opsu.Utils;
|
||||
import itdelatrisu.opsu.states.Game;
|
||||
import itdelatrisu.opsu.states.Options;
|
||||
|
||||
|
@ -120,21 +121,14 @@ public class Circle {
|
|||
|
||||
if (timeDiff >= 0) {
|
||||
float approachScale = 1 + (timeDiff * 2f / game.getApproachTime());
|
||||
drawCentered(approachCircle.getScaledCopy(approachScale), hitObject.x, hitObject.y, color);
|
||||
drawCentered(hitCircleOverlay, hitObject.x, hitObject.y, Color.white);
|
||||
drawCentered(hitCircle, hitObject.x, hitObject.y, color);
|
||||
Utils.drawCentered(approachCircle.getScaledCopy(approachScale), hitObject.x, hitObject.y, color);
|
||||
Utils.drawCentered(hitCircleOverlay, hitObject.x, hitObject.y, Color.white);
|
||||
Utils.drawCentered(hitCircle, hitObject.x, hitObject.y, color);
|
||||
score.drawSymbolNumber(hitObject.comboNumber, hitObject.x, hitObject.y,
|
||||
hitCircle.getWidth() * 0.40f / score.getDefaultSymbolImage(0).getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws an image based on its center with a color filter.
|
||||
*/
|
||||
private void drawCentered(Image img, float x, float y, Color color) {
|
||||
img.draw(x - (img.getWidth() / 2f), y - (img.getHeight() / 2f), color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the circle hit result.
|
||||
* @param time the hit object time (difference between track time)
|
||||
|
|
|
@ -22,6 +22,7 @@ import itdelatrisu.opsu.GameScore;
|
|||
import itdelatrisu.opsu.MusicController;
|
||||
import itdelatrisu.opsu.OsuFile;
|
||||
import itdelatrisu.opsu.OsuHitObject;
|
||||
import itdelatrisu.opsu.Utils;
|
||||
import itdelatrisu.opsu.states.Game;
|
||||
import itdelatrisu.opsu.states.Options;
|
||||
|
||||
|
@ -240,9 +241,9 @@ public class Slider {
|
|||
|
||||
// draw overlay and hit circle
|
||||
for (int i = curveX.length - 1; i >= 0; i--)
|
||||
drawCentered(hitCircleOverlay, curveX[i], curveY[i], Color.white);
|
||||
Utils.drawCentered(hitCircleOverlay, curveX[i], curveY[i], Color.white);
|
||||
for (int i = curveX.length - 1; i >= 0; i--)
|
||||
drawCentered(hitCircle, curveX[i], curveY[i], color);
|
||||
Utils.drawCentered(hitCircle, curveX[i], curveY[i], color);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,12 +313,12 @@ public class Slider {
|
|||
|
||||
// end circle
|
||||
int lastIndex = hitObject.sliderX.length - 1;
|
||||
drawCentered(hitCircleOverlay, hitObject.sliderX[lastIndex], hitObject.sliderY[lastIndex], Color.white);
|
||||
drawCentered(hitCircle, hitObject.sliderX[lastIndex], hitObject.sliderY[lastIndex], color);
|
||||
Utils.drawCentered(hitCircleOverlay, hitObject.sliderX[lastIndex], hitObject.sliderY[lastIndex], Color.white);
|
||||
Utils.drawCentered(hitCircle, hitObject.sliderX[lastIndex], hitObject.sliderY[lastIndex], color);
|
||||
|
||||
// start circle
|
||||
drawCentered(hitCircleOverlay, hitObject.x, hitObject.y, Color.white);
|
||||
drawCentered(hitCircle, hitObject.x, hitObject.y, color);
|
||||
Utils.drawCentered(hitCircleOverlay, hitObject.x, hitObject.y, Color.white);
|
||||
Utils.drawCentered(hitCircle, hitObject.x, hitObject.y, color);
|
||||
if (sliderClicked)
|
||||
; // don't draw current combo number if already clicked
|
||||
else
|
||||
|
@ -335,12 +336,13 @@ public class Slider {
|
|||
if (timeDiff >= 0) {
|
||||
// approach circle
|
||||
float approachScale = 1 + (timeDiff * 2f / game.getApproachTime());
|
||||
drawCentered(Circle.getApproachCircle().getScaledCopy(approachScale), hitObject.x, hitObject.y, color);
|
||||
Utils.drawCentered(Circle.getApproachCircle().getScaledCopy(approachScale),
|
||||
hitObject.x, hitObject.y, color);
|
||||
} else {
|
||||
float[] c = bezier.pointAt(getT(trackPosition, false));
|
||||
|
||||
// slider ball
|
||||
drawCentered(sliderBall, c[0], c[1]);
|
||||
Utils.drawCentered(sliderBall, c[0], c[1]);
|
||||
|
||||
// follow circle
|
||||
if (followCircleActive)
|
||||
|
@ -348,20 +350,6 @@ public class Slider {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws an image based on its center with a color filter.
|
||||
*/
|
||||
private void drawCentered(Image img, float x, float y, Color color) {
|
||||
img.draw(x - (img.getWidth() / 2f), y - (img.getHeight() / 2f), color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws an animation based on its center with a color filter.
|
||||
*/
|
||||
private static void drawCentered(Animation anim, float x, float y) {
|
||||
anim.draw(x - (anim.getWidth() / 2f), y - (anim.getHeight() / 2f));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the slider hit result.
|
||||
* @param time the hit object time (difference between track time)
|
||||
|
|
|
@ -22,6 +22,7 @@ import itdelatrisu.opsu.GameScore;
|
|||
import itdelatrisu.opsu.MusicController;
|
||||
import itdelatrisu.opsu.OsuHitObject;
|
||||
import itdelatrisu.opsu.SoundController;
|
||||
import itdelatrisu.opsu.Utils;
|
||||
import itdelatrisu.opsu.states.Game;
|
||||
import itdelatrisu.opsu.states.Options;
|
||||
|
||||
|
@ -127,7 +128,7 @@ public class Spinner {
|
|||
//spinnerOsuImage.drawCentered(width / 2, height / 4);
|
||||
|
||||
// darken screen
|
||||
g.setColor(Options.COLOR_BLACK_ALPHA);
|
||||
g.setColor(Utils.COLOR_BLACK_ALPHA);
|
||||
g.fillRect(0, 0, width, height);
|
||||
|
||||
if (timeDiff > 0)
|
||||
|
|
|
@ -26,6 +26,7 @@ import itdelatrisu.opsu.OsuFile;
|
|||
import itdelatrisu.opsu.OsuHitObject;
|
||||
import itdelatrisu.opsu.OsuTimingPoint;
|
||||
import itdelatrisu.opsu.SoundController;
|
||||
import itdelatrisu.opsu.Utils;
|
||||
import itdelatrisu.opsu.objects.Circle;
|
||||
import itdelatrisu.opsu.objects.Slider;
|
||||
import itdelatrisu.opsu.objects.Spinner;
|
||||
|
@ -264,8 +265,6 @@ public class Game extends BasicGameState {
|
|||
if (!osu.drawBG(width, height, 0.7f))
|
||||
g.setBackground(Color.black);
|
||||
|
||||
Options.drawFPS();
|
||||
|
||||
int trackPosition = MusicController.getPosition();
|
||||
if (pauseTime > -1) // returning from pause screen
|
||||
trackPosition = pauseTime;
|
||||
|
@ -313,6 +312,9 @@ public class Game extends BasicGameState {
|
|||
warningArrowL.draw(width * 0.75f, height * 0.75f);
|
||||
}
|
||||
}
|
||||
|
||||
Utils.drawFPS();
|
||||
Utils.drawCursor();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -413,7 +415,7 @@ public class Game extends BasicGameState {
|
|||
// returning from pause screen
|
||||
if (pauseTime > -1 && pausedMouseX > -1 && pausedMouseY > -1) {
|
||||
// darken the screen
|
||||
g.setColor(Options.COLOR_BLACK_ALPHA);
|
||||
g.setColor(Utils.COLOR_BLACK_ALPHA);
|
||||
g.fillRect(0, 0, width, height);
|
||||
|
||||
// draw glowing hit select circle and pulse effect
|
||||
|
@ -425,6 +427,9 @@ public class Game extends BasicGameState {
|
|||
cursorCirclePulse.setAlpha(1f - pausePulse);
|
||||
cursorCirclePulse.drawCentered(pausedMouseX, pausedMouseY);
|
||||
}
|
||||
|
||||
Utils.drawFPS();
|
||||
Utils.drawCursor();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -589,7 +594,7 @@ public class Game extends BasicGameState {
|
|||
mousePressed(Input.MOUSE_RIGHT_BUTTON, input.getMouseX(), input.getMouseY());
|
||||
break;
|
||||
case Input.KEY_F12:
|
||||
Options.takeScreenShot();
|
||||
Utils.takeScreenShot();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -647,6 +652,9 @@ public class Game extends BasicGameState {
|
|||
if (osu == null || osu.objects == null)
|
||||
throw new RuntimeException("Running game with no OsuFile loaded.");
|
||||
|
||||
// grab the mouse
|
||||
container.setMouseGrabbed(true);
|
||||
|
||||
// restart the game
|
||||
if (restart != RESTART_FALSE) {
|
||||
// new game
|
||||
|
@ -720,6 +728,12 @@ public class Game extends BasicGameState {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leave(GameContainer container, StateBasedGame game)
|
||||
throws SlickException {
|
||||
container.setMouseGrabbed(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips the beginning of a track.
|
||||
* @return true if skipped, false otherwise
|
||||
|
|
|
@ -22,6 +22,7 @@ import itdelatrisu.opsu.GUIMenuButton;
|
|||
import itdelatrisu.opsu.MusicController;
|
||||
import itdelatrisu.opsu.Opsu;
|
||||
import itdelatrisu.opsu.SoundController;
|
||||
import itdelatrisu.opsu.Utils;
|
||||
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.GameContainer;
|
||||
|
@ -117,13 +118,14 @@ public class GamePauseMenu extends BasicGameState {
|
|||
else
|
||||
g.setBackground(Color.black);
|
||||
|
||||
Options.drawFPS();
|
||||
|
||||
// draw buttons
|
||||
if (Game.getRestart() != Game.RESTART_LOSE)
|
||||
continueButton.draw();
|
||||
retryButton.draw();
|
||||
backButton.draw();
|
||||
|
||||
Utils.drawFPS();
|
||||
Utils.drawCursor();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -149,7 +151,7 @@ public class GamePauseMenu extends BasicGameState {
|
|||
unPause(Game.RESTART_FALSE);
|
||||
break;
|
||||
case Input.KEY_F12:
|
||||
Options.takeScreenShot();
|
||||
Utils.takeScreenShot();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import itdelatrisu.opsu.MusicController;
|
|||
import itdelatrisu.opsu.Opsu;
|
||||
import itdelatrisu.opsu.OsuFile;
|
||||
import itdelatrisu.opsu.SoundController;
|
||||
import itdelatrisu.opsu.Utils;
|
||||
|
||||
import org.lwjgl.opengl.Display;
|
||||
import org.newdawn.slick.Color;
|
||||
|
@ -100,7 +101,7 @@ public class GameRanking extends BasicGameState {
|
|||
|
||||
// background
|
||||
if (!osu.drawBG(width, height, 0.7f))
|
||||
g.setBackground(Options.COLOR_BLACK_ALPHA);
|
||||
g.setBackground(Utils.COLOR_BLACK_ALPHA);
|
||||
|
||||
// ranking screen elements
|
||||
score.drawRankingElements(g, width, height);
|
||||
|
@ -118,17 +119,18 @@ public class GameRanking extends BasicGameState {
|
|||
|
||||
// header text
|
||||
g.setColor(Color.white);
|
||||
Options.FONT_LARGE.drawString(10, 0,
|
||||
Utils.FONT_LARGE.drawString(10, 0,
|
||||
String.format("%s - %s [%s]", osu.artist, osu.title, osu.version));
|
||||
Options.FONT_MEDIUM.drawString(10, Options.FONT_LARGE.getLineHeight() - 6,
|
||||
Utils.FONT_MEDIUM.drawString(10, Utils.FONT_LARGE.getLineHeight() - 6,
|
||||
String.format("Beatmap by %s", osu.creator));
|
||||
|
||||
// buttons
|
||||
retryButton.draw();
|
||||
exitButton.draw();
|
||||
Options.getBackButton().draw();
|
||||
Utils.getBackButton().draw();
|
||||
|
||||
Options.drawFPS();
|
||||
Utils.drawFPS();
|
||||
Utils.drawCursor();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -150,7 +152,7 @@ public class GameRanking extends BasicGameState {
|
|||
game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
break;
|
||||
case Input.KEY_F12:
|
||||
Options.takeScreenShot();
|
||||
Utils.takeScreenShot();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -170,7 +172,7 @@ public class GameRanking extends BasicGameState {
|
|||
} else if (exitButton.contains(x, y)) {
|
||||
SoundController.playSound(SoundController.SOUND_MENUBACK);
|
||||
game.enterState(Opsu.STATE_MAINMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
} else if (Options.getBackButton().contains(x, y)) {
|
||||
} else if (Utils.getBackButton().contains(x, y)) {
|
||||
MusicController.pause();
|
||||
MusicController.playAt(Game.getOsuFile().previewTime, true);
|
||||
SoundController.playSound(SoundController.SOUND_MENUBACK);
|
||||
|
|
|
@ -23,6 +23,7 @@ import itdelatrisu.opsu.MusicController;
|
|||
import itdelatrisu.opsu.Opsu;
|
||||
import itdelatrisu.opsu.OsuGroupNode;
|
||||
import itdelatrisu.opsu.SoundController;
|
||||
import itdelatrisu.opsu.Utils;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
@ -153,8 +154,8 @@ public class MainMenu extends BasicGameState {
|
|||
if (backgroundImage != null)
|
||||
backgroundImage.draw();
|
||||
else
|
||||
g.setBackground(Options.COLOR_BLUE_BACKGROUND);
|
||||
g.setFont(Options.FONT_MEDIUM);
|
||||
g.setBackground(Utils.COLOR_BLUE_BACKGROUND);
|
||||
g.setFont(Utils.FONT_MEDIUM);
|
||||
|
||||
int width = container.getWidth();
|
||||
int height = container.getHeight();
|
||||
|
@ -173,7 +174,7 @@ public class MainMenu extends BasicGameState {
|
|||
musicPlay.draw();
|
||||
musicNext.draw();
|
||||
musicPrevious.draw();
|
||||
g.setColor(Options.COLOR_BLACK_ALPHA);
|
||||
g.setColor(Utils.COLOR_BLACK_ALPHA);
|
||||
g.fillRoundRect(width - 168, 54, 148, 5, 4);
|
||||
g.setColor(Color.white);
|
||||
if (!MusicController.isConverting())
|
||||
|
@ -181,7 +182,7 @@ public class MainMenu extends BasicGameState {
|
|||
148f * MusicController.getPosition() / MusicController.getTrackLength(), 5, 4);
|
||||
|
||||
// draw text
|
||||
int lineHeight = Options.FONT_MEDIUM.getLineHeight();
|
||||
int lineHeight = Utils.FONT_MEDIUM.getLineHeight();
|
||||
g.drawString(String.format("Loaded %d songs and %d beatmaps.",
|
||||
Opsu.groups.size(), Opsu.groups.getMapCount()), 25, 25);
|
||||
if (MusicController.isConverting())
|
||||
|
@ -203,7 +204,8 @@ public class MainMenu extends BasicGameState {
|
|||
new SimpleDateFormat("h:mm a").format(new Date())),
|
||||
25, height - 25 - lineHeight);
|
||||
|
||||
Options.drawFPS();
|
||||
Utils.drawFPS();
|
||||
Utils.drawCursor();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -317,7 +319,7 @@ public class MainMenu extends BasicGameState {
|
|||
game.enterState(Opsu.STATE_MAINMENUEXIT);
|
||||
break;
|
||||
case Input.KEY_F12:
|
||||
Options.takeScreenShot();
|
||||
Utils.takeScreenShot();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ package itdelatrisu.opsu.states;
|
|||
|
||||
import itdelatrisu.opsu.GUIMenuButton;
|
||||
import itdelatrisu.opsu.Opsu;
|
||||
import itdelatrisu.opsu.Utils;
|
||||
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.GameContainer;
|
||||
|
@ -90,22 +91,23 @@ public class MainMenuExit extends BasicGameState {
|
|||
|
||||
// draw text
|
||||
float c = container.getWidth() * 0.02f;
|
||||
Options.FONT_LARGE.drawString(c, c, "Are you sure you want to exit opsu!?");
|
||||
Utils.FONT_LARGE.drawString(c, c, "Are you sure you want to exit opsu!?");
|
||||
|
||||
// draw buttons
|
||||
yesButton.draw(Color.green);
|
||||
noButton.draw(Color.red);
|
||||
g.setFont(Options.FONT_XLARGE);
|
||||
g.setFont(Utils.FONT_XLARGE);
|
||||
g.drawString("1. Yes",
|
||||
yesButton.getX() - (Options.FONT_XLARGE.getWidth("1. Yes") / 2f),
|
||||
yesButton.getY() - (Options.FONT_XLARGE.getHeight() / 2f)
|
||||
yesButton.getX() - (Utils.FONT_XLARGE.getWidth("1. Yes") / 2f),
|
||||
yesButton.getY() - (Utils.FONT_XLARGE.getHeight() / 2f)
|
||||
);
|
||||
g.drawString("2. No",
|
||||
noButton.getX() - (Options.FONT_XLARGE.getWidth("2. No") / 2f),
|
||||
noButton.getY() - (Options.FONT_XLARGE.getHeight() / 2f)
|
||||
noButton.getX() - (Utils.FONT_XLARGE.getWidth("2. No") / 2f),
|
||||
noButton.getY() - (Utils.FONT_XLARGE.getHeight() / 2f)
|
||||
);
|
||||
|
||||
Options.drawFPS();
|
||||
Utils.drawFPS();
|
||||
Utils.drawCursor();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -150,7 +152,7 @@ public class MainMenuExit extends BasicGameState {
|
|||
game.enterState(Opsu.STATE_MAINMENU, new EmptyTransition(), new FadeInTransition(Color.black));
|
||||
break;
|
||||
case Input.KEY_F12:
|
||||
Options.takeScreenShot();
|
||||
Utils.takeScreenShot();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,9 +20,8 @@ package itdelatrisu.opsu.states;
|
|||
|
||||
import itdelatrisu.opsu.GUIMenuButton;
|
||||
import itdelatrisu.opsu.Opsu;
|
||||
import itdelatrisu.opsu.SoundController;
|
||||
import itdelatrisu.opsu.Utils;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
|
@ -39,8 +38,6 @@ import org.newdawn.slick.Graphics;
|
|||
import org.newdawn.slick.Image;
|
||||
import org.newdawn.slick.Input;
|
||||
import org.newdawn.slick.SlickException;
|
||||
import org.newdawn.slick.TrueTypeFont;
|
||||
import org.newdawn.slick.imageout.ImageOut;
|
||||
import org.newdawn.slick.state.BasicGameState;
|
||||
import org.newdawn.slick.state.StateBasedGame;
|
||||
import org.newdawn.slick.state.transition.EmptyTransition;
|
||||
|
@ -85,41 +82,6 @@ public class Options extends BasicGameState {
|
|||
*/
|
||||
private static final String OPTIONS_FILE = ".opsu.cfg";
|
||||
|
||||
/**
|
||||
* Whether or not any changes were made to options.
|
||||
* If false, the options file will not be modified.
|
||||
*/
|
||||
private static boolean optionsChanged = false;
|
||||
|
||||
/**
|
||||
* Game colors.
|
||||
*/
|
||||
public static final Color
|
||||
COLOR_BLACK_ALPHA = new Color(0, 0, 0, 0.5f),
|
||||
COLOR_BLUE_DIVIDER = new Color(49, 94, 237),
|
||||
COLOR_BLUE_BACKGROUND = new Color(74, 130, 255),
|
||||
COLOR_BLUE_BUTTON = new Color(50, 189, 237),
|
||||
COLOR_ORANGE_BUTTON = new Color(230, 151, 87),
|
||||
COLOR_GREEN_OBJECT = new Color(26, 207, 26),
|
||||
COLOR_BLUE_OBJECT = new Color(46, 136, 248),
|
||||
COLOR_RED_OBJECT = new Color(243, 48, 77),
|
||||
COLOR_ORANGE_OBJECT = new Color(255, 200, 32);
|
||||
|
||||
/**
|
||||
* The default map colors, used when a map does not provide custom colors.
|
||||
*/
|
||||
public static final Color[] DEFAULT_COMBO = {
|
||||
COLOR_GREEN_OBJECT, COLOR_BLUE_OBJECT,
|
||||
COLOR_RED_OBJECT, COLOR_ORANGE_OBJECT
|
||||
};
|
||||
|
||||
/**
|
||||
* Game fonts.
|
||||
*/
|
||||
public static TrueTypeFont
|
||||
FONT_DEFAULT, FONT_BOLD,
|
||||
FONT_XLARGE, FONT_LARGE, FONT_MEDIUM, FONT_SMALL;
|
||||
|
||||
/**
|
||||
* Game mods.
|
||||
*/
|
||||
|
@ -235,12 +197,12 @@ public class Options extends BasicGameState {
|
|||
/**
|
||||
* Port binding.
|
||||
*/
|
||||
private static int port = 0;
|
||||
private static int port = 49250;
|
||||
|
||||
/**
|
||||
* Back button (shared by other states).
|
||||
* Whether or not to use the new cursor type.
|
||||
*/
|
||||
private static GUIMenuButton backButton;
|
||||
private static boolean newCursor = true;
|
||||
|
||||
/**
|
||||
* Game option coordinate modifiers (for drawing).
|
||||
|
@ -248,8 +210,8 @@ public class Options extends BasicGameState {
|
|||
private int textY, offsetY;
|
||||
|
||||
// game-related variables
|
||||
private static GameContainer container;
|
||||
private static StateBasedGame game;
|
||||
private GameContainer container;
|
||||
private StateBasedGame game;
|
||||
private Input input;
|
||||
private int state;
|
||||
private boolean init = false;
|
||||
|
@ -261,42 +223,17 @@ public class Options extends BasicGameState {
|
|||
@Override
|
||||
public void init(GameContainer container, StateBasedGame game)
|
||||
throws SlickException {
|
||||
Options.container = container;
|
||||
Options.game = game;
|
||||
this.container = container;
|
||||
this.game = game;
|
||||
this.input = container.getInput();
|
||||
|
||||
// game settings
|
||||
container.setTargetFrameRate(targetFPS[targetFPSindex]);
|
||||
container.setMouseCursor("cursor.png", 16, 16);
|
||||
container.setMusicVolume(getMusicVolume());
|
||||
container.setShowFPS(false);
|
||||
container.getInput().enableKeyRepeat();
|
||||
container.setAlwaysRender(true);
|
||||
|
||||
// create fonts
|
||||
float fontBase;
|
||||
if (container.getHeight() <= 600)
|
||||
fontBase = 9f;
|
||||
else if (container.getHeight() < 800)
|
||||
fontBase = 10f;
|
||||
else if (container.getHeight() <= 900)
|
||||
fontBase = 12f;
|
||||
else
|
||||
fontBase = 14f;
|
||||
|
||||
Font font = new Font("Lucida Sans Unicode", Font.PLAIN, (int) (fontBase * 4 / 3));
|
||||
FONT_DEFAULT = new TrueTypeFont(font, false);
|
||||
FONT_BOLD = new TrueTypeFont(font.deriveFont(Font.BOLD), false);
|
||||
FONT_XLARGE = new TrueTypeFont(font.deriveFont(fontBase * 4), false);
|
||||
FONT_LARGE = new TrueTypeFont(font.deriveFont(fontBase * 2), false);
|
||||
FONT_MEDIUM = new TrueTypeFont(font.deriveFont(fontBase * 3 / 2), false);
|
||||
FONT_SMALL = new TrueTypeFont(font.deriveFont(fontBase), false);
|
||||
Utils.init(container, game);
|
||||
|
||||
int width = container.getWidth();
|
||||
int height = container.getHeight();
|
||||
|
||||
// game option coordinate modifiers
|
||||
textY = 10 + (FONT_XLARGE.getLineHeight() * 3 / 2);
|
||||
textY = 10 + (Utils.FONT_XLARGE.getLineHeight() * 3 / 2);
|
||||
offsetY = (int) (((height * 0.8f) - textY) / OPTIONS_MAX);
|
||||
|
||||
// game mods
|
||||
|
@ -330,14 +267,6 @@ public class Options extends BasicGameState {
|
|||
for (int i = 0; i < modButtons.length; i++)
|
||||
modButtons[i].getImage().setAlpha(0.5f);
|
||||
|
||||
// back button
|
||||
Image back = new Image("menu-back.png");
|
||||
float scale = (height * 0.1f) / back.getHeight();
|
||||
back = back.getScaledCopy(scale);
|
||||
backButton = new GUIMenuButton(back,
|
||||
back.getWidth() / 2f,
|
||||
height - (back.getHeight() / 2f));
|
||||
|
||||
game.enterState(Opsu.STATE_MAINMENU, new EmptyTransition(), new FadeInTransition(Color.black));
|
||||
}
|
||||
|
||||
|
@ -347,25 +276,25 @@ public class Options extends BasicGameState {
|
|||
if (!init)
|
||||
return;
|
||||
|
||||
g.setBackground(COLOR_BLACK_ALPHA);
|
||||
g.setBackground(Utils.COLOR_BLACK_ALPHA);
|
||||
g.setColor(Color.white);
|
||||
|
||||
int width = container.getWidth();
|
||||
int height = container.getHeight();
|
||||
|
||||
// title
|
||||
FONT_XLARGE.drawString(
|
||||
(width / 2) - (FONT_XLARGE.getWidth("GAME OPTIONS") / 2),
|
||||
Utils.FONT_XLARGE.drawString(
|
||||
(width / 2) - (Utils.FONT_XLARGE.getWidth("GAME OPTIONS") / 2),
|
||||
10, "GAME OPTIONS"
|
||||
);
|
||||
FONT_DEFAULT.drawString(
|
||||
(width / 2) - (FONT_DEFAULT.getWidth("Click or drag an option to change it.") / 2),
|
||||
10 + FONT_XLARGE.getHeight(), "Click or drag an option to change it."
|
||||
Utils.FONT_DEFAULT.drawString(
|
||||
(width / 2) - (Utils.FONT_DEFAULT.getWidth("Click or drag an option to change it.") / 2),
|
||||
10 + Utils.FONT_XLARGE.getHeight(), "Click or drag an option to change it."
|
||||
);
|
||||
|
||||
// game options
|
||||
g.setLineWidth(1f);
|
||||
g.setFont(FONT_LARGE);
|
||||
g.setFont(Utils.FONT_LARGE);
|
||||
this.drawOption(g, OPTIONS_SCREEN_RESOLUTION, "Screen Resolution",
|
||||
String.format("%dx%d", resolutions[resolutionIndex][0], resolutions[resolutionIndex][1]),
|
||||
"Restart to apply resolution changes."
|
||||
|
@ -375,7 +304,7 @@ public class Options extends BasicGameState {
|
|||
// "Restart to apply changes."
|
||||
// );
|
||||
this.drawOption(g, OPTIONS_TARGET_FPS, "Frame Limiter",
|
||||
String.format("%dfps", targetFPS[targetFPSindex]),
|
||||
String.format("%dfps", getTargetFPS()),
|
||||
"Higher values may cause high CPU usage."
|
||||
);
|
||||
this.drawOption(g, OPTIONS_MUSIC_VOLUME, "Music Volume",
|
||||
|
@ -408,13 +337,14 @@ public class Options extends BasicGameState {
|
|||
);
|
||||
|
||||
// game mods
|
||||
FONT_LARGE.drawString(width * 0.02f, height * 0.8f, "Game Mods:", Color.white);
|
||||
Utils.FONT_LARGE.drawString(width * 0.02f, height * 0.8f, "Game Mods:", Color.white);
|
||||
for (int i = 0; i < modButtons.length; i++)
|
||||
modButtons[i].draw();
|
||||
|
||||
backButton.draw();
|
||||
Utils.getBackButton().draw();
|
||||
|
||||
drawFPS();
|
||||
Utils.drawFPS();
|
||||
Utils.drawCursor();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -433,7 +363,7 @@ public class Options extends BasicGameState {
|
|||
return;
|
||||
|
||||
// back
|
||||
if (backButton.contains(x, y)) {
|
||||
if (Utils.getBackButton().contains(x, y)) {
|
||||
game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition(Color.black));
|
||||
return;
|
||||
}
|
||||
|
@ -472,7 +402,7 @@ public class Options extends BasicGameState {
|
|||
// }
|
||||
if (isOptionClicked(OPTIONS_TARGET_FPS, y)) {
|
||||
targetFPSindex = (targetFPSindex + 1) % targetFPS.length;
|
||||
container.setTargetFrameRate(targetFPS[targetFPSindex]);
|
||||
container.setTargetFrameRate(getTargetFPS());
|
||||
return;
|
||||
}
|
||||
if (isOptionClicked(OPTIONS_SCREENSHOT_FORMAT, y)) {
|
||||
|
@ -545,7 +475,7 @@ public class Options extends BasicGameState {
|
|||
game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition(Color.black));
|
||||
break;
|
||||
case Input.KEY_F12:
|
||||
Options.takeScreenShot();
|
||||
Utils.takeScreenShot();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -560,14 +490,14 @@ public class Options extends BasicGameState {
|
|||
*/
|
||||
private void drawOption(Graphics g, int pos, String label, String value, String notes) {
|
||||
int width = container.getWidth();
|
||||
int textHeight = FONT_LARGE.getHeight();
|
||||
int textHeight = Utils.FONT_LARGE.getHeight();
|
||||
float y = textY + (pos * offsetY);
|
||||
|
||||
g.drawString(label, width / 50, y);
|
||||
g.drawString(value, width / 2, y);
|
||||
g.drawLine(0, y + textHeight, width, y + textHeight);
|
||||
if (notes != null)
|
||||
FONT_SMALL.drawString(width / 50, y + textHeight, notes);
|
||||
Utils.FONT_SMALL.drawString(width / 50, y + textHeight, notes);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -577,12 +507,8 @@ public class Options extends BasicGameState {
|
|||
* @return true if clicked
|
||||
*/
|
||||
private boolean isOptionClicked(int pos, int y) {
|
||||
if (y > textY + (offsetY * pos) - FONT_LARGE.getHeight() &&
|
||||
y < textY + (offsetY * pos) + FONT_LARGE.getHeight()) {
|
||||
optionsChanged = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return (y > textY + (offsetY * pos) - Utils.FONT_LARGE.getHeight() &&
|
||||
y < textY + (offsetY * pos) + Utils.FONT_LARGE.getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -610,9 +536,10 @@ public class Options extends BasicGameState {
|
|||
public static Image getModImage(int mod) { return modButtons[mod].getImage(); }
|
||||
|
||||
/**
|
||||
* Returns the 'back' GUIMenuButton.
|
||||
* Returns the target frame rate.
|
||||
* @return the target FPS
|
||||
*/
|
||||
public static GUIMenuButton getBackButton() { return backButton; }
|
||||
public static int getTargetFPS() { return targetFPS[targetFPSindex]; }
|
||||
|
||||
/**
|
||||
* Returns the default music volume.
|
||||
|
@ -633,53 +560,10 @@ public class Options extends BasicGameState {
|
|||
public static int getMusicOffset() { return musicOffset; }
|
||||
|
||||
/**
|
||||
* Draws the FPS at the bottom-right corner of the game container.
|
||||
* If the option is not activated, this will do nothing.
|
||||
* Returns the screenshot file format.
|
||||
* @return the file extension ("png", "jpg", "bmp")
|
||||
*/
|
||||
public static void drawFPS() {
|
||||
if (showFPS) {
|
||||
String fps = String.format("FPS: %d", container.getFPS());
|
||||
FONT_DEFAULT.drawString(
|
||||
container.getWidth() - 15 - FONT_DEFAULT.getWidth(fps),
|
||||
container.getHeight() - 15 - FONT_DEFAULT.getHeight(fps),
|
||||
fps, Color.white
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a screenshot.
|
||||
* @return true if successful
|
||||
*/
|
||||
public static boolean takeScreenShot() {
|
||||
// TODO: should this be threaded?
|
||||
try {
|
||||
// create the screenshot directory
|
||||
if (!SCREENSHOT_DIR.isDirectory()) {
|
||||
if (!SCREENSHOT_DIR.mkdir())
|
||||
return false;
|
||||
}
|
||||
|
||||
// create file name
|
||||
SimpleDateFormat date = new SimpleDateFormat("yyyyMMdd_HHmmss");
|
||||
String file = date.format(new Date());
|
||||
|
||||
SoundController.playSound(SoundController.SOUND_SHUTTER);
|
||||
|
||||
// copy the screen
|
||||
Image screen = new Image(container.getWidth(), container.getHeight());
|
||||
container.getGraphics().copyArea(screen, 0, 0);
|
||||
ImageOut.write(screen, String.format("%s%sscreenshot_%s.%s",
|
||||
SCREENSHOT_DIR.getName(), File.separator,
|
||||
file, screenshotFormat[screenshotFormatIndex]), false
|
||||
);
|
||||
screen.destroy();
|
||||
} catch (SlickException e) {
|
||||
Log.warn("Failed to take a screenshot.", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public static String getScreenshotFormat() { return screenshotFormat[screenshotFormatIndex]; }
|
||||
|
||||
/**
|
||||
* Returns the screen resolution.
|
||||
|
@ -693,6 +577,12 @@ public class Options extends BasicGameState {
|
|||
// */
|
||||
// public static boolean isFullscreen() { return fullscreen; }
|
||||
|
||||
/**
|
||||
* Returns whether or not the FPS counter display is enabled.
|
||||
* @return true if enabled
|
||||
*/
|
||||
public static boolean isFPSCounterEnabled() { return showFPS; }
|
||||
|
||||
/**
|
||||
* Returns whether or not hit lighting effects are enabled.
|
||||
* @return true if enabled
|
||||
|
@ -709,14 +599,13 @@ public class Options extends BasicGameState {
|
|||
* Returns the port number to bind to.
|
||||
* @return the port
|
||||
*/
|
||||
public static int getPort() {
|
||||
if (port == 0) {
|
||||
// choose a random port
|
||||
port = 49250;
|
||||
optionsChanged = true; // force file creation
|
||||
}
|
||||
return port;
|
||||
}
|
||||
public static int getPort() { return port; }
|
||||
|
||||
/**
|
||||
* Returns whether or not the new cursor type is enabled.
|
||||
* @return true if enabled
|
||||
*/
|
||||
public static boolean isNewCursorEnabled() { return newCursor; }
|
||||
|
||||
/**
|
||||
* Returns the current beatmap directory.
|
||||
|
@ -730,15 +619,14 @@ public class Options extends BasicGameState {
|
|||
// search for directory
|
||||
for (int i = 0; i < BEATMAP_DIRS.length; i++) {
|
||||
beatmapDir = new File(BEATMAP_DIRS[i]);
|
||||
if (beatmapDir.isDirectory()) {
|
||||
optionsChanged = true; // force config file creation
|
||||
if (beatmapDir.isDirectory())
|
||||
return beatmapDir;
|
||||
}
|
||||
}
|
||||
beatmapDir.mkdir(); // none found, create new directory
|
||||
return beatmapDir;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads user options from the options file, if it exists.
|
||||
*/
|
||||
|
@ -746,9 +634,7 @@ public class Options extends BasicGameState {
|
|||
// if no config file, use default settings
|
||||
File file = new File(OPTIONS_FILE);
|
||||
if (!file.isFile()) {
|
||||
optionsChanged = true; // force file creation
|
||||
saveOptions();
|
||||
optionsChanged = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -816,6 +702,9 @@ public class Options extends BasicGameState {
|
|||
if (i > 0 && i <= 65535)
|
||||
port = i;
|
||||
break;
|
||||
case "NewCursor": // custom
|
||||
newCursor = Boolean.parseBoolean(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
|
@ -830,10 +719,6 @@ public class Options extends BasicGameState {
|
|||
* (Over)writes user options to a file.
|
||||
*/
|
||||
public static void saveOptions() {
|
||||
// only overwrite when needed
|
||||
if (!optionsChanged)
|
||||
return;
|
||||
|
||||
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
|
||||
new FileOutputStream(OPTIONS_FILE), "utf-8"))) {
|
||||
// header
|
||||
|
@ -873,6 +758,8 @@ public class Options extends BasicGameState {
|
|||
writer.newLine();
|
||||
writer.write(String.format("Port = %d", port));
|
||||
writer.newLine();
|
||||
writer.write(String.format("NewCursor = %b", newCursor)); // custom
|
||||
writer.newLine();
|
||||
writer.close();
|
||||
} catch (IOException e) {
|
||||
Log.error(String.format("Failed to write to file '%s'.", OPTIONS_FILE), e);
|
||||
|
|
|
@ -26,6 +26,7 @@ import itdelatrisu.opsu.OsuGroupList;
|
|||
import itdelatrisu.opsu.OsuGroupNode;
|
||||
import itdelatrisu.opsu.OsuParser;
|
||||
import itdelatrisu.opsu.SoundController;
|
||||
import itdelatrisu.opsu.Utils;
|
||||
|
||||
import org.lwjgl.opengl.Display;
|
||||
import org.newdawn.slick.Color;
|
||||
|
@ -170,13 +171,13 @@ public class SongMenu extends BasicGameState {
|
|||
searchResultString = "Type to search!";
|
||||
|
||||
searchIcon = new Image("search.png");
|
||||
float iconScale = Options.FONT_BOLD.getLineHeight() * 2f / searchIcon.getHeight();
|
||||
float iconScale = Utils.FONT_BOLD.getLineHeight() * 2f / searchIcon.getHeight();
|
||||
searchIcon = searchIcon.getScaledCopy(iconScale);
|
||||
|
||||
search = new TextField(
|
||||
container, Options.FONT_DEFAULT,
|
||||
container, Utils.FONT_DEFAULT,
|
||||
(int) tabX + searchIcon.getWidth(), (int) ((height * 0.15f) - (tab.getHeight() * 5 / 2f)),
|
||||
(int) (buttonWidth / 2), Options.FONT_DEFAULT.getHeight()
|
||||
(int) (buttonWidth / 2), Utils.FONT_DEFAULT.getHeight()
|
||||
);
|
||||
search.setBackgroundColor(Color.transparent);
|
||||
search.setBorderColor(Color.transparent);
|
||||
|
@ -205,9 +206,9 @@ public class SongMenu extends BasicGameState {
|
|||
|
||||
// header setup
|
||||
float lowerBound = height * 0.15f;
|
||||
g.setColor(Options.COLOR_BLACK_ALPHA);
|
||||
g.setColor(Utils.COLOR_BLACK_ALPHA);
|
||||
g.fillRect(0, 0, width, lowerBound);
|
||||
g.setColor(Options.COLOR_BLUE_DIVIDER);
|
||||
g.setColor(Utils.COLOR_BLUE_DIVIDER);
|
||||
g.setLineWidth(2f);
|
||||
g.drawLine(0, lowerBound, width, lowerBound);
|
||||
g.resetLineWidth();
|
||||
|
@ -220,17 +221,17 @@ public class SongMenu extends BasicGameState {
|
|||
|
||||
String[] info = focusNode.getInfo();
|
||||
g.setColor(Color.white);
|
||||
Options.FONT_LARGE.drawString(
|
||||
Utils.FONT_LARGE.drawString(
|
||||
musicNoteWidth + 5, -3, info[0]);
|
||||
float y1 = -3 + Options.FONT_LARGE.getHeight() * 0.75f;
|
||||
Options.FONT_DEFAULT.drawString(
|
||||
float y1 = -3 + Utils.FONT_LARGE.getHeight() * 0.75f;
|
||||
Utils.FONT_DEFAULT.drawString(
|
||||
musicNoteWidth + 5, y1, info[1]);
|
||||
Options.FONT_BOLD.drawString(
|
||||
Utils.FONT_BOLD.drawString(
|
||||
5, Math.max(y1 + 4, musicNoteHeight - 3), info[2]);
|
||||
Options.FONT_DEFAULT.drawString(
|
||||
5, musicNoteHeight + Options.FONT_BOLD.getLineHeight() - 9, info[3]);
|
||||
Options.FONT_SMALL.drawString(
|
||||
5, musicNoteHeight + Options.FONT_BOLD.getLineHeight() + Options.FONT_DEFAULT.getLineHeight() - 13, info[4]);
|
||||
Utils.FONT_DEFAULT.drawString(
|
||||
5, musicNoteHeight + Utils.FONT_BOLD.getLineHeight() - 9, info[3]);
|
||||
Utils.FONT_SMALL.drawString(
|
||||
5, musicNoteHeight + Utils.FONT_BOLD.getLineHeight() + Utils.FONT_DEFAULT.getLineHeight() - 13, info[4]);
|
||||
}
|
||||
|
||||
// song buttons
|
||||
|
@ -248,17 +249,17 @@ public class SongMenu extends BasicGameState {
|
|||
for (int i = sortTabs.length - 1; i >= 0; i--) {
|
||||
sortTabs[i].getImage().setAlpha((i == currentSort) ? 1.0f : 0.7f);
|
||||
sortTabs[i].draw();
|
||||
float tabTextX = sortTabs[i].getX() - (Options.FONT_MEDIUM.getWidth(OsuGroupList.SORT_NAMES[i]) / 2);
|
||||
Options.FONT_MEDIUM.drawString(tabTextX, tabTextY, OsuGroupList.SORT_NAMES[i], Color.white);
|
||||
float tabTextX = sortTabs[i].getX() - (Utils.FONT_MEDIUM.getWidth(OsuGroupList.SORT_NAMES[i]) / 2);
|
||||
Utils.FONT_MEDIUM.drawString(tabTextX, tabTextY, OsuGroupList.SORT_NAMES[i], Color.white);
|
||||
}
|
||||
|
||||
// search
|
||||
Options.FONT_BOLD.drawString(
|
||||
search.getX(), search.getY() - Options.FONT_BOLD.getLineHeight(),
|
||||
Utils.FONT_BOLD.drawString(
|
||||
search.getX(), search.getY() - Utils.FONT_BOLD.getLineHeight(),
|
||||
searchResultString, Color.white
|
||||
);
|
||||
searchIcon.draw(search.getX() - searchIcon.getWidth(),
|
||||
search.getY() - Options.FONT_DEFAULT.getLineHeight());
|
||||
search.getY() - Utils.FONT_DEFAULT.getLineHeight());
|
||||
g.setColor(Color.white);
|
||||
search.render(container, g);
|
||||
|
||||
|
@ -266,16 +267,17 @@ public class SongMenu extends BasicGameState {
|
|||
if (focusNode != null) {
|
||||
float scrollStartY = height * 0.16f;
|
||||
float scrollEndY = height * 0.82f;
|
||||
g.setColor(Options.COLOR_BLACK_ALPHA);
|
||||
g.setColor(Utils.COLOR_BLACK_ALPHA);
|
||||
g.fillRoundRect(width - 10, scrollStartY, 5, scrollEndY, 4);
|
||||
g.setColor(Color.white);
|
||||
g.fillRoundRect(width - 10, scrollStartY + (scrollEndY * startNode.index / Opsu.groups.size()), 5, 20, 4);
|
||||
}
|
||||
|
||||
// back button
|
||||
Options.getBackButton().draw();
|
||||
Utils.getBackButton().draw();
|
||||
|
||||
Options.drawFPS();
|
||||
Utils.drawFPS();
|
||||
Utils.drawCursor();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -343,7 +345,7 @@ public class SongMenu extends BasicGameState {
|
|||
return;
|
||||
|
||||
// back
|
||||
if (Options.getBackButton().contains(x, y)) {
|
||||
if (Utils.getBackButton().contains(x, y)) {
|
||||
SoundController.playSound(SoundController.SOUND_MENUBACK);
|
||||
game.enterState(Opsu.STATE_MAINMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
return;
|
||||
|
@ -436,7 +438,7 @@ public class SongMenu extends BasicGameState {
|
|||
setFocus(Opsu.groups.getRandomNode(), -1, true);
|
||||
break;
|
||||
case Input.KEY_F12:
|
||||
Options.takeScreenShot();
|
||||
Utils.takeScreenShot();
|
||||
break;
|
||||
case Input.KEY_ENTER:
|
||||
if (focusNode != null)
|
||||
|
|
Loading…
Reference in New Issue
Block a user