Merge remote-tracking branch 'remotes/original/master' into upstream

# Conflicts:
#	src/itdelatrisu/opsu/Container.java
#	src/itdelatrisu/opsu/GameData.java
#	src/itdelatrisu/opsu/Options.java
#	src/itdelatrisu/opsu/audio/MusicController.java
#	src/itdelatrisu/opsu/objects/Circle.java
#	src/itdelatrisu/opsu/objects/Slider.java
#	src/itdelatrisu/opsu/render/CurveRenderState.java
#	src/itdelatrisu/opsu/states/Game.java
#	src/itdelatrisu/opsu/states/MainMenu.java
#	src/itdelatrisu/opsu/states/SongMenu.java
#	src/itdelatrisu/opsu/ui/Colors.java
#	src/itdelatrisu/opsu/ui/MenuButton.java
This commit is contained in:
yugecin
2016-12-24 14:35:20 +01:00
36 changed files with 1667 additions and 569 deletions

View File

@@ -33,6 +33,7 @@ public class Colors {
BLUE_BACKGROUND = new Color(74, 130, 255),
BLUE_BUTTON = new Color(40, 129, 237),
ORANGE_BUTTON = new Color(200, 90, 3),
PINK_BUTTON = new Color(223, 71, 147),
YELLOW_ALPHA = new Color(255, 255, 0, 0.4f),
WHITE_FADE = new Color(255, 255, 255, 1f),
RED_HOVER = new Color(255, 112, 112),
@@ -48,8 +49,7 @@ public class Colors {
BLACK_BG_NORMAL = new Color(0, 0, 0, 0.25f),
BLACK_BG_HOVER = new Color(0, 0, 0, 0.5f),
BLACK_BG_FOCUS = new Color(0, 0, 0, 0.75f),
GHOST_LOGO = new Color(1.0f, 1.0f, 1.0f, 0.25f);
GHOST_LOGO = new Color(1.0f, 1.0f, 1.0f, 0.25f);
// This class should not be instantiated.
private Colors() {}

View File

@@ -320,8 +320,6 @@ public class Cursor {
// reset angles
cursorAngle = 0f;
GameImage.CURSOR.getImage().setRotation(0f);
GameImage.CURSOR_TRAIL.getImage().setRotation(0f);
}
/**

View File

@@ -95,6 +95,9 @@ public class DropdownMenu<E> extends AbstractComponent {
/** The chevron images. */
private Image chevronDown, chevronRight;
/** Should the next click be blocked? */
private boolean blockClick = false;
/**
* Creates a new dropdown menu.
* @param container the container rendering this menu
@@ -327,6 +330,7 @@ public class DropdownMenu<E> extends AbstractComponent {
this.expanded = false;
this.lastUpdateTime = 0;
expandProgress.setTime(0);
blockClick = false;
}
@Override
@@ -349,9 +353,21 @@ public class DropdownMenu<E> extends AbstractComponent {
this.itemIndex = idx;
itemSelected(idx, items[idx]);
}
blockClick = true;
consumeEvent();
}
@Override
public void mouseClicked(int button, int x, int y, int clickCount) {
if (!active)
return;
if (blockClick) {
blockClick = false;
consumeEvent();
}
}
/**
* Notification that a new item was selected (via override).
* @param index the index of the item selected

View File

@@ -98,11 +98,8 @@ public class MenuButton {
/** The default max rotation angle of the button. */
private static final float DEFAULT_ANGLE_MAX = 30f;
private float currentScale = 1f;
public float getCurrentScale() {
return currentScale;
}
/** The last scale at which the button was drawn. */
private float lastScale = 1f;
/**
* Creates a new button from an Image.
@@ -172,6 +169,11 @@ public class MenuButton {
*/
public float getY() { return y; }
/**
* Returns the last scale at which the button was drawn.
*/
public float getLastScale() { return lastScale; }
/**
* Sets text to draw in the middle of the button.
* @param text the text to draw
@@ -197,21 +199,21 @@ public class MenuButton {
/**
* Draws the button.
*/
public void draw() { draw(Color.white, 1.0f); }
public void draw() { draw(Color.white, 1f); }
/**
* Draws the button with a color filter.
* @param filter the color to filter with when drawing
*/
public void draw(Color filter) { draw(filter, 1.0f); }
public void draw(Color filter) { draw(filter, 1f); }
/**
* Draw the button with a color filter and scale.
* @param filter the color to filter with when drawing
* @param scaleoverride the scale to use when drawing
* Draw the button with a color filter at the given scale.
* @param filter the color to filter with when drawing
* @param scaleOverride the scale to use when drawing (only works for normal images)
*/
@SuppressWarnings("deprecation")
public void draw(Color filter, float scaleoverride) {
public void draw(Color filter, float scaleOverride) {
// animations: get current frame
Image image = this.img;
if (image == null) {
@@ -219,20 +221,17 @@ public class MenuButton {
image = anim.getCurrentFrame();
}
currentScale = 1f;
// normal images
if (imgL == null) {
float scaleposmodx = 0;
float scaleposmody = 0;
if (scaleoverride != 1f) {
image = image.getScaledCopy(scaleoverride);
scaleposmodx = image.getWidth() / 2 - xRadius;
scaleposmody = image.getHeight() / 2 - yRadius;
currentScale = scaleoverride;
float xScaleOffset = 0f, yScaleOffset = 0f;
if (scaleOverride != 1f) {
image = image.getScaledCopy(scaleOverride);
xScaleOffset = image.getWidth() / 2f - xRadius;
yScaleOffset = image.getHeight() / 2f - yRadius;
}
lastScale = scaleOverride;
if (hoverEffect == 0)
image.draw(x - xRadius - scaleposmodx, y - yRadius - scaleposmody, filter);
image.draw(x - xRadius, y - yRadius, filter);
else {
float oldAlpha = image.getAlpha();
float oldAngle = image.getRotation();
@@ -240,16 +239,18 @@ public class MenuButton {
if (scale.getValue() != 1f) {
image = image.getScaledCopy(scale.getValue());
image.setAlpha(oldAlpha);
scaleposmodx = image.getWidth() / 2 - xRadius;
scaleposmody = image.getHeight() / 2 - yRadius;
currentScale *= scale.getValue();
if (scaleOverride != 1f) {
xScaleOffset = image.getWidth() / 2f - xRadius;
yScaleOffset = image.getHeight() / 2f - yRadius;
}
lastScale *= scale.getValue();
}
}
if ((hoverEffect & EFFECT_FADE) > 0)
image.setAlpha(alpha.getValue());
if ((hoverEffect & EFFECT_ROTATE) > 0)
image.setRotation(angle.getValue());
image.draw(x - xRadius - scaleposmodx, y - yRadius - scaleposmody, filter);
image.draw(x - xRadius - xScaleOffset, y - yRadius - yScaleOffset, filter);
if (image == this.img) {
image.setAlpha(oldAlpha);
image.setRotation(oldAngle);

View File

@@ -0,0 +1,143 @@
package itdelatrisu.opsu.ui;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.ui.animations.AnimatedValue;
import itdelatrisu.opsu.ui.animations.AnimationEquation;
import org.newdawn.slick.Image;
/**
* Star fountain consisting of two star streams.
*/
public class StarFountain {
/** The (approximate) number of stars in each burst. */
private static final int BURST_SIZE = 125;
/** Star streams. */
private final StarStream left, right;
/** Burst progress. */
private final AnimatedValue burstProgress = new AnimatedValue(1000, 0, 1, AnimationEquation.LINEAR);
/** The maximum direction offsets. */
private final float xDirection, yDirection;
/** Motion types. */
private enum Motion {
NONE {
@Override
public void init(StarFountain fountain) {
fountain.left.setDirection(0, fountain.yDirection);
fountain.right.setDirection(0, fountain.yDirection);
fountain.left.setDirectionSpread(20f);
fountain.right.setDirectionSpread(20f);
fountain.left.setDurationSpread(1000, 200);
fountain.right.setDurationSpread(1000, 200);
}
},
OUTWARD_SWEEP {
@Override
public void init(StarFountain fountain) {
fountain.left.setDirectionSpread(0f);
fountain.right.setDirectionSpread(0f);
fountain.left.setDurationSpread(850, 0);
fountain.right.setDurationSpread(850, 0);
}
@Override
public void update(StarFountain fountain) {
float t = fountain.burstProgress.getValue();
fountain.left.setDirection(fountain.xDirection - fountain.xDirection * 2f * t, fountain.yDirection);
fountain.right.setDirection(-fountain.xDirection + fountain.xDirection * 2f * t, fountain.yDirection);
}
},
INWARD_SWEEP {
@Override
public void init(StarFountain fountain) { OUTWARD_SWEEP.init(fountain); }
@Override
public void update(StarFountain fountain) {
float t = fountain.burstProgress.getValue();
fountain.left.setDirection(-fountain.xDirection + fountain.xDirection * 2f * t, fountain.yDirection);
fountain.right.setDirection(fountain.xDirection - fountain.xDirection * 2f * t, fountain.yDirection);
}
};
/** Initializes the streams in the fountain. */
public void init(StarFountain fountain) {}
/** Updates the streams in the fountain. */
public void update(StarFountain fountain) {}
}
/** The current motion. */
private Motion motion = Motion.NONE;
/**
* Initializes the star fountain.
* @param containerWidth the container width
* @param containerHeight the container height
*/
public StarFountain(int containerWidth, int containerHeight) {
Image img = GameImage.STAR2.getImage();
float xOffset = containerWidth * 0.125f;
this.xDirection = containerWidth / 2f - xOffset;
this.yDirection = -containerHeight * 0.85f;
this.left = new StarStream(xOffset - img.getWidth() / 2f, containerHeight, 0, yDirection, 0);
this.right = new StarStream(containerWidth - xOffset - img.getWidth() / 2f, containerHeight, 0, yDirection, 0);
left.setScaleSpread(1.1f, 0.2f);
right.setScaleSpread(1.1f, 0.2f);
}
/**
* Draws the star fountain.
*/
public void draw() {
left.draw();
right.draw();
}
/**
* Updates the stars in the fountain by a delta interval.
* @param delta the delta interval since the last call
*/
public void update(int delta) {
left.update(delta);
right.update(delta);
if (burstProgress.update(delta)) {
motion.update(this);
int size = Math.round((float) delta / burstProgress.getDuration() * BURST_SIZE);
left.burst(size);
right.burst(size);
}
}
/**
* Creates a burst of stars to be processed during the next {@link #update(int)} call.
* @param wait if {@code true}, will not burst if a previous burst is in progress
*/
public void burst(boolean wait) {
if (wait && (burstProgress.getTime() < burstProgress.getDuration() || !left.isEmpty() || !right.isEmpty()))
return; // previous burst in progress
burstProgress.setTime(0);
Motion lastMotion = motion;
motion = Motion.values()[(int) (Math.random() * Motion.values().length)];
if (motion == lastMotion) // don't do the same sweep twice
motion = Motion.NONE;
motion.init(this);
}
/**
* Clears the stars currently in the fountain.
*/
public void clear() {
left.clear();
right.clear();
burstProgress.setTime(burstProgress.getDuration());
motion = Motion.NONE;
motion.init(this);
}
}

View File

@@ -20,6 +20,7 @@ package itdelatrisu.opsu.ui;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.objects.curves.Vec2f;
import itdelatrisu.opsu.ui.animations.AnimatedValue;
import itdelatrisu.opsu.ui.animations.AnimationEquation;
@@ -31,11 +32,35 @@ import java.util.Random;
import org.newdawn.slick.Image;
/**
* Horizontal star stream.
* Star stream.
*/
public class StarStream {
/** The container dimensions. */
private final int containerWidth, containerHeight;
/** The origin of the star stream. */
private final Vec2f position;
/** The direction of the star stream. */
private final Vec2f direction;
/** The maximum number of stars to draw at once. */
private final int maxStars;
/** The spread of the stars' starting position. */
private float positionSpread = 0f;
/** The spread of the stars' direction. */
private float directionSpread = 0f;
/** The base (mean) duration for which stars are shown, in ms. */
private int durationBase = 1300;
/** The spread of the stars' duration, in ms. */
private int durationSpread = 300;
/** The base (mean) scale at which stars are drawn. */
private float scaleBase = 1f;
/** The spread of the stars' scale.*/
private float scaleSpread = 0f;
/** The star image. */
private final Image starImg;
@@ -43,33 +68,41 @@ public class StarStream {
/** The current list of stars. */
private final List<Star> stars;
/** The maximum number of stars to draw at once. */
private static final int MAX_STARS = 20;
/** Random number generator instance. */
private final Random random;
/** Contains data for a single star. */
private class Star {
/** The star position offset. */
private final Vec2f offset;
/** The star direction vector. */
private final Vec2f dir;
/** The star image rotation angle. */
private final int angle;
/** The star image scale. */
private final float scale;
/** The star animation progress. */
private final AnimatedValue animatedValue;
/** The star properties. */
private final int distance, yOffset, angle;
/**
* Creates a star with the given properties.
* @param offset the position offset vector
* @param direction the direction vector
* @param angle the image rotation angle
* @param scale the image scale
* @param duration the time, in milliseconds, to show the star
* @param distance the distance for the star to travel in {@code duration}
* @param yOffset the vertical offset from the center of the container
* @param angle the rotation angle
* @param eqn the animation equation to use
*/
public Star(int duration, int distance, int yOffset, int angle, AnimationEquation eqn) {
this.animatedValue = new AnimatedValue(duration, 0f, 1f, eqn);
this.distance = distance;
this.yOffset = yOffset;
public Star(Vec2f offset, Vec2f direction, int angle, float scale, int duration, AnimationEquation eqn) {
this.offset = offset;
this.dir = direction;
this.angle = angle;
this.scale = scale;
this.animatedValue = new AnimatedValue(duration, 0f, 1f, eqn);
}
/**
@@ -79,8 +112,9 @@ public class StarStream {
float t = animatedValue.getValue();
starImg.setImageColor(1f, 1f, 1f, Math.min((1 - t) * 5f, 1f));
starImg.drawEmbedded(
containerWidth - (distance * t), ((containerHeight - starImg.getHeight()) / 2) + yOffset,
starImg.getWidth(), starImg.getHeight(), angle);
offset.x + t * dir.x, offset.y + t * dir.y,
starImg.getWidth() * scale, starImg.getHeight() * scale, angle
);
}
/**
@@ -93,17 +127,60 @@ public class StarStream {
/**
* Initializes the star stream.
* @param width the container width
* @param height the container height
* @param x the x position
* @param y the y position
* @param dirX the x-axis direction
* @param dirY the y-axis direction
* @param k the maximum number of stars to draw at once (excluding bursts)
*/
public StarStream(int width, int height) {
this.containerWidth = width;
this.containerHeight = height;
public StarStream(float x, float y, float dirX, float dirY, int k) {
this.position = new Vec2f(x, y);
this.direction = new Vec2f(dirX, dirY);
this.maxStars = k;
this.starImg = GameImage.STAR2.getImage().copy();
this.stars = new ArrayList<Star>();
this.stars = new ArrayList<Star>(k);
this.random = new Random();
}
/**
* Set the direction spread of this star stream.
* @param spread the spread of the stars' starting position
*/
public void setPositionSpread(float spread) { this.positionSpread = spread; }
/**
* Sets the direction of this star stream.
* @param dirX the new x-axis direction
* @param dirY the new y-axis direction
*/
public void setDirection(float dirX, float dirY) { direction.set(dirX, dirY); }
/**
* Set the direction spread of this star stream.
* @param spread the spread of the stars' direction
*/
public void setDirectionSpread(float spread) { this.directionSpread = spread; }
/**
* Sets the duration base and spread of this star stream.
* @param base the base (mean) duration for which stars are shown, in ms
* @param spread the spread of the stars' duration, in ms
*/
public void setDurationSpread(int base, int spread) {
this.durationBase = base;
this.durationSpread = spread;
}
/**
* Sets the scale base and spread of this star stream.
* @param base the base (mean) scale at which stars are drawn
* @param spread the spread of the stars' scale
*/
public void setScaleSpread(float base, float spread) {
this.scaleBase = base;
this.scaleSpread = spread;
}
/**
* Draws the star stream.
*/
@@ -131,27 +208,48 @@ public class StarStream {
}
// create new stars
for (int i = stars.size(); i < MAX_STARS; i++) {
if (Math.random() < ((i < 5) ? 0.25 : 0.66))
break;
for (int i = stars.size(); i < maxStars; i++) {
if (Math.random() < ((i < maxStars / 4) ? 0.25 : 0.66))
break; // stagger spawning new stars
// generate star properties
float distanceRatio = Utils.clamp((float) getGaussian(0.65, 0.25), 0.2f, 0.925f);
int distance = (int) (containerWidth * distanceRatio);
int duration = (int) (distanceRatio * getGaussian(1300, 300));
int yOffset = (int) getGaussian(0, containerHeight / 20);
int angle = (int) getGaussian(0, 22.5);
AnimationEquation eqn = random.nextBoolean() ? AnimationEquation.IN_OUT_QUAD : AnimationEquation.OUT_QUAD;
stars.add(new Star(duration, distance, yOffset, angle, eqn));
stars.add(createStar());
}
}
/**
* Creates a new star with randomized properties.
*/
private Star createStar() {
float distanceRatio = Utils.clamp((float) getGaussian(0.65, 0.25), 0.2f, 0.925f);
Vec2f offset = position.cpy().add(direction.cpy().nor().normalize().scale((float) getGaussian(0, positionSpread)));
Vec2f dir = direction.cpy().scale(distanceRatio).add((float) getGaussian(0, directionSpread), (float) getGaussian(0, directionSpread));
int angle = (int) getGaussian(0, 22.5);
float scale = (float) getGaussian(scaleBase, scaleSpread);
int duration = Math.max(0, (int) (distanceRatio * getGaussian(durationBase, durationSpread)));
AnimationEquation eqn = random.nextBoolean() ? AnimationEquation.IN_OUT_QUAD : AnimationEquation.OUT_QUAD;
return new Star(offset, dir, angle, scale, duration, eqn);
}
/**
* Creates a burst of stars instantly.
* @param count the number of stars to create
*/
public void burst(int count) {
for (int i = 0; i < count; i++)
stars.add(createStar());
}
/**
* Clears the stars currently in the stream.
*/
public void clear() { stars.clear(); }
/**
* Returns whether there are any stars currently in this stream.
*/
public boolean isEmpty() { return stars.isEmpty(); }
/**
* Returns the next pseudorandom, Gaussian ("normally") distributed {@code double} value
* with the given mean and standard deviation.