Expand menu buttons when hovering.
Added hovering capabilities to GUIMenuButton. The max scale and direction to expand the image can be modified per object. Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
parent
ce8ae40f79
commit
33f5df030c
|
@ -25,6 +25,7 @@ import org.newdawn.slick.Image;
|
|||
/**
|
||||
* A convenience class for menu buttons.
|
||||
* Consists of an image or animation and coordinates.
|
||||
* Multi-part images and animations currently do not support hover updates.
|
||||
*/
|
||||
public class GUIMenuButton {
|
||||
/**
|
||||
|
@ -48,20 +49,37 @@ public class GUIMenuButton {
|
|||
private float x, y;
|
||||
|
||||
/**
|
||||
* The x and y radius of the button.
|
||||
* The x and y radius of the button (scaled).
|
||||
*/
|
||||
private float xRadius, yRadius;
|
||||
|
||||
/**
|
||||
* The current and max scale of the button (for hovering).
|
||||
*/
|
||||
private float scale, hoverScale = 1.25f;
|
||||
|
||||
/**
|
||||
* The scaled expansion direction for the botton (for hovering).
|
||||
*/
|
||||
private Expand dir = Expand.CENTER;
|
||||
|
||||
/**
|
||||
* Scaled expansion directions (for hovering).
|
||||
*/
|
||||
public enum Expand {
|
||||
CENTER, UP_RIGHT, UP_LEFT, DOWN_RIGHT, DOWN_LEFT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new button from an Image.
|
||||
*/
|
||||
public GUIMenuButton(Image img, float x, float y) {
|
||||
this.img = img;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
xRadius = img.getWidth() / 2f;
|
||||
yRadius = img.getHeight() / 2f;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.xRadius = img.getWidth() / 2f;
|
||||
this.yRadius = img.getHeight() / 2f;
|
||||
this.scale = 1f;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,11 +90,11 @@ public class GUIMenuButton {
|
|||
this.img = imgCenter;
|
||||
this.imgL = imgLeft;
|
||||
this.imgR = imgRight;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
xRadius = (img.getWidth() + imgL.getWidth() + imgR.getWidth()) / 2f;
|
||||
yRadius = img.getHeight() / 2f;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.xRadius = (img.getWidth() + imgL.getWidth() + imgR.getWidth()) / 2f;
|
||||
this.yRadius = img.getHeight() / 2f;
|
||||
this.scale = 1f;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,11 +102,11 @@ public class GUIMenuButton {
|
|||
*/
|
||||
public GUIMenuButton(Animation anim, float x, float y) {
|
||||
this.anim = anim;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
xRadius = anim.getWidth() / 2f;
|
||||
yRadius = anim.getHeight() / 2f;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.xRadius = anim.getWidth() / 2f;
|
||||
this.yRadius = anim.getHeight() / 2f;
|
||||
this.scale = 1f;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -110,9 +128,11 @@ public class GUIMenuButton {
|
|||
*/
|
||||
public void draw() {
|
||||
if (img != null) {
|
||||
if (imgL == null)
|
||||
img.draw(x - xRadius, y - yRadius);
|
||||
else {
|
||||
if (imgL == null) {
|
||||
Image imgScaled = img.getScaledCopy(scale);
|
||||
imgScaled.setAlpha(img.getAlpha());
|
||||
imgScaled.draw(x - xRadius, y - yRadius);
|
||||
} else {
|
||||
img.draw(x - xRadius + imgL.getWidth(), y - yRadius);
|
||||
imgL.draw(x - xRadius, y - yRadius);
|
||||
imgR.draw(x + xRadius - imgR.getWidth(), y - yRadius);
|
||||
|
@ -128,7 +148,7 @@ public class GUIMenuButton {
|
|||
public void draw(Color filter) {
|
||||
if (img != null) {
|
||||
if (imgL == null)
|
||||
img.draw(x - xRadius, y - yRadius, filter);
|
||||
img.getScaledCopy(scale).draw(x - xRadius, y - yRadius, filter);
|
||||
else {
|
||||
img.draw(x - xRadius + imgL.getWidth(), y - yRadius, filter);
|
||||
imgL.draw(x - xRadius, y - yRadius, filter);
|
||||
|
@ -140,9 +160,77 @@ public class GUIMenuButton {
|
|||
|
||||
/**
|
||||
* Returns true if the coordinates are within the button bounds.
|
||||
* @param cx the x coordinate
|
||||
* @param cy the y coordinate
|
||||
*/
|
||||
public boolean contains(float cx, float cy) {
|
||||
return ((cx > x - xRadius && cx < x + xRadius) &&
|
||||
(cy > y - yRadius && cy < y + yRadius));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current button scale (for hovering).
|
||||
* @param scale the new scale (default 1.0f)
|
||||
*/
|
||||
public void setScale(float scale) {
|
||||
this.scale = scale;
|
||||
setHoverRadius();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum scale factor for the button (for hovering).
|
||||
* @param scale the maximum scale factor (default 1.25f)
|
||||
*/
|
||||
public void setHoverScale(float scale) {
|
||||
this.hoverScale = scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expansion direction when hovering over the button.
|
||||
* @param dir the direction
|
||||
*/
|
||||
public void setHoverDir(Expand dir) {
|
||||
this.dir = dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the scale of the button depending on whether or not the cursor
|
||||
* is hovering over the button.
|
||||
* @param delta the delta interval
|
||||
* @param cx the x coordinate
|
||||
* @param cy the y coordinate
|
||||
*/
|
||||
public void hoverUpdate(int delta, float cx, float cy) {
|
||||
boolean isHover = contains(cx, cy);
|
||||
if (isHover && scale < hoverScale) {
|
||||
scale += (hoverScale - 1f) * delta / 100f;
|
||||
if (scale > hoverScale)
|
||||
scale = hoverScale;
|
||||
setHoverRadius();
|
||||
} else if (!isHover && scale > 1f) {
|
||||
scale -= (hoverScale - 1f) * delta / 100f;
|
||||
if (scale < 1f)
|
||||
scale = 1f;
|
||||
setHoverRadius();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set x and y radius of the button based on current scale factor
|
||||
* and expansion direction.
|
||||
*/
|
||||
private void setHoverRadius() {
|
||||
int xOffset = 0, yOffset = 0;
|
||||
if (dir != Expand.CENTER) {
|
||||
// offset by difference between normal/scaled image dimensions
|
||||
xOffset = (int) ((scale - 1f) * img.getWidth());
|
||||
yOffset = (int) ((scale - 1f) * img.getHeight());
|
||||
if (dir == Expand.DOWN_RIGHT || dir == Expand.UP_RIGHT)
|
||||
xOffset *= -1; // flip x for right
|
||||
if (dir == Expand.DOWN_LEFT || dir == Expand.DOWN_RIGHT)
|
||||
yOffset *= -1; // flip y for down
|
||||
}
|
||||
this.xRadius = ((img.getWidth() * scale) + xOffset) / 2f;
|
||||
this.yRadius = ((img.getHeight() * scale) + yOffset) / 2f;
|
||||
}
|
||||
}
|
|
@ -107,6 +107,7 @@ public enum GameMod {
|
|||
// create button
|
||||
img.setAlpha(0.5f);
|
||||
this.button = new GUIMenuButton(img, x + (offsetX * id), y);
|
||||
this.button.setHoverScale(1.15f);
|
||||
} catch (SlickException e) {
|
||||
Log.error(String.format("Failed to initialize game mod '%s'.", this), e);
|
||||
}
|
||||
|
@ -177,4 +178,19 @@ public enum GameMod {
|
|||
* @return true if within bounds
|
||||
*/
|
||||
public boolean contains(float x, float y) { return button.contains(x, y); }
|
||||
|
||||
/**
|
||||
* Sets the current button scale (for hovering).
|
||||
* @param scale the new scale (default 1.0f)
|
||||
*/
|
||||
public void setScale(float scale) { button.setScale(scale); }
|
||||
|
||||
/**
|
||||
* Updates the scale of the button depending on whether or not the cursor
|
||||
* is hovering over the button.
|
||||
* @param delta the delta interval
|
||||
* @param x the x coordinate
|
||||
* @param y the y coordinate
|
||||
*/
|
||||
public void hoverUpdate(int delta, float x, float y) { button.hoverUpdate(delta, x, y); }
|
||||
}
|
||||
|
|
|
@ -197,6 +197,7 @@ public class Utils {
|
|||
backButton = new GUIMenuButton(back,
|
||||
back.getWidth() / 2f,
|
||||
height - (back.getHeight() / 2f));
|
||||
backButton.setHoverDir(GUIMenuButton.Expand.UP_RIGHT);
|
||||
|
||||
// set default game images
|
||||
for (GameImage img : GameImage.values())
|
||||
|
|
|
@ -101,6 +101,10 @@ public class GamePauseMenu extends BasicGameState {
|
|||
public void update(GameContainer container, StateBasedGame game, int delta)
|
||||
throws SlickException {
|
||||
Utils.updateCursor(delta);
|
||||
int mouseX = input.getMouseX(), mouseY = input.getMouseY();
|
||||
continueButton.hoverUpdate(delta, mouseX, mouseY);
|
||||
retryButton.hoverUpdate(delta, mouseX, mouseY);
|
||||
backButton.hoverUpdate(delta, mouseX, mouseY);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -165,6 +169,9 @@ public class GamePauseMenu extends BasicGameState {
|
|||
SoundController.playSound(SoundController.SOUND_FAIL);
|
||||
} else
|
||||
MusicController.pause();
|
||||
continueButton.setScale(1f);
|
||||
retryButton.setScale(1f);
|
||||
backButton.setScale(1f);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -61,6 +61,7 @@ public class GameRanking extends BasicGameState {
|
|||
// game-related variables
|
||||
private StateBasedGame game;
|
||||
private int state;
|
||||
private Input input;
|
||||
|
||||
public GameRanking(int state) {
|
||||
this.state = state;
|
||||
|
@ -70,6 +71,7 @@ public class GameRanking extends BasicGameState {
|
|||
public void init(GameContainer container, StateBasedGame game)
|
||||
throws SlickException {
|
||||
this.game = game;
|
||||
this.input = container.getInput();
|
||||
|
||||
score = Game.getGameScore();
|
||||
|
||||
|
@ -138,6 +140,8 @@ public class GameRanking extends BasicGameState {
|
|||
public void update(GameContainer container, StateBasedGame game, int delta)
|
||||
throws SlickException {
|
||||
Utils.updateCursor(delta);
|
||||
int mouseX = input.getMouseX(), mouseY = input.getMouseY();
|
||||
Utils.getBackButton().hoverUpdate(delta, mouseX, mouseY);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -185,6 +189,7 @@ public class GameRanking extends BasicGameState {
|
|||
public void enter(GameContainer container, StateBasedGame game)
|
||||
throws SlickException {
|
||||
Display.setTitle(game.getTitle());
|
||||
Utils.getBackButton().setScale(1f);
|
||||
SoundController.playSound(SoundController.SOUND_APPLAUSE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,6 +103,7 @@ public class MainMenu extends BasicGameState {
|
|||
// game-related variables
|
||||
private GameContainer container;
|
||||
private StateBasedGame game;
|
||||
private Input input;
|
||||
private int state;
|
||||
|
||||
public MainMenu(int state) {
|
||||
|
@ -114,6 +115,7 @@ public class MainMenu extends BasicGameState {
|
|||
throws SlickException {
|
||||
this.container = container;
|
||||
this.game = game;
|
||||
this.input = container.getInput();
|
||||
|
||||
osuStartTime = System.currentTimeMillis();
|
||||
previous = new Stack<Integer>();
|
||||
|
@ -126,6 +128,7 @@ public class MainMenu extends BasicGameState {
|
|||
float buttonScale = (height / 1.2f) / logoImg.getHeight();
|
||||
Image logoImgScaled = logoImg.getScaledCopy(buttonScale);
|
||||
logo = new GUIMenuButton(logoImgScaled, width / 2f, height / 2f);
|
||||
logo.setHoverScale(1.05f);
|
||||
|
||||
Image playImg = new Image("menu-play.png");
|
||||
Image exitImg = new Image("menu-exit.png");
|
||||
|
@ -138,6 +141,8 @@ public class MainMenu extends BasicGameState {
|
|||
exitButton = new GUIMenuButton(exitImg.getScaledCopy(buttonScale),
|
||||
width * 0.75f - exitOffset, (height / 2) + (exitImg.getHeight() / 2f)
|
||||
);
|
||||
playButton.setHoverScale(1.05f);
|
||||
exitButton.setHoverScale(1.05f);
|
||||
|
||||
// initialize music buttons
|
||||
int musicWidth = 48;
|
||||
|
@ -146,6 +151,10 @@ public class MainMenu extends BasicGameState {
|
|||
musicPause = new GUIMenuButton(new Image("music-pause.png"), width - (2 * musicWidth), musicHeight);
|
||||
musicNext = new GUIMenuButton(new Image("music-next.png"), width - musicWidth, musicHeight);
|
||||
musicPrevious = new GUIMenuButton(new Image("music-previous.png"), width - (3 * musicWidth), musicHeight);
|
||||
musicPlay.setHoverScale(1.5f);
|
||||
musicPause.setHoverScale(1.5f);
|
||||
musicNext.setHoverScale(1.5f);
|
||||
musicPrevious.setHoverScale(1.5f);
|
||||
|
||||
// menu background
|
||||
try {
|
||||
|
@ -226,6 +235,14 @@ public class MainMenu extends BasicGameState {
|
|||
public void update(GameContainer container, StateBasedGame game, int delta)
|
||||
throws SlickException {
|
||||
Utils.updateCursor(delta);
|
||||
int mouseX = input.getMouseX(), mouseY = input.getMouseY();
|
||||
logo.hoverUpdate(delta, mouseX, mouseY);
|
||||
playButton.hoverUpdate(delta, mouseX, mouseY);
|
||||
exitButton.hoverUpdate(delta, mouseX, mouseY);
|
||||
musicPlay.hoverUpdate(delta, mouseX, mouseY);
|
||||
musicPause.hoverUpdate(delta, mouseX, mouseY);
|
||||
musicNext.hoverUpdate(delta, mouseX, mouseY);
|
||||
musicPrevious.hoverUpdate(delta, mouseX, mouseY);
|
||||
|
||||
// fade in background
|
||||
if (bgAlpha < 0.9f) {
|
||||
|
@ -280,6 +297,13 @@ public class MainMenu extends BasicGameState {
|
|||
logoClicked = false;
|
||||
logoTimer = 0;
|
||||
logo.setX(container.getWidth() / 2);
|
||||
logo.setScale(1f);
|
||||
playButton.setScale(1f);
|
||||
exitButton.setScale(1f);
|
||||
musicPlay.setScale(1f);
|
||||
musicPause.setScale(1f);
|
||||
musicNext.setScale(1f);
|
||||
musicPrevious.setScale(1f);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -525,6 +525,10 @@ public class Options extends BasicGameState {
|
|||
public void update(GameContainer container, StateBasedGame game, int delta)
|
||||
throws SlickException {
|
||||
Utils.updateCursor(delta);
|
||||
int mouseX = input.getMouseX(), mouseY = input.getMouseY();
|
||||
Utils.getBackButton().hoverUpdate(delta, mouseX, mouseY);
|
||||
for (GameMod mod : GameMod.values())
|
||||
mod.hoverUpdate(delta, mouseX, mouseY);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -782,6 +786,9 @@ public class Options extends BasicGameState {
|
|||
public void enter(GameContainer container, StateBasedGame game)
|
||||
throws SlickException {
|
||||
currentTab = TAB_DISPLAY;
|
||||
Utils.getBackButton().setScale(1f);
|
||||
for (GameMod mod : GameMod.values())
|
||||
mod.setScale(1f);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -180,6 +180,7 @@ public class SongMenu extends BasicGameState {
|
|||
// options button
|
||||
Image optionsIcon = new Image("options.png").getScaledCopy(iconScale);
|
||||
optionsButton = new GUIMenuButton(optionsIcon, search.getX() - (optionsIcon.getWidth() * 1.5f), search.getY());
|
||||
optionsButton.setHoverScale(1.75f);
|
||||
|
||||
// music note
|
||||
int musicNoteDim = (int) (Utils.FONT_LARGE.getLineHeight() * 0.75f + Utils.FONT_DEFAULT.getLineHeight());
|
||||
|
@ -281,6 +282,9 @@ public class SongMenu extends BasicGameState {
|
|||
public void update(GameContainer container, StateBasedGame game, int delta)
|
||||
throws SlickException {
|
||||
Utils.updateCursor(delta);
|
||||
int mouseX = input.getMouseX(), mouseY = input.getMouseY();
|
||||
Utils.getBackButton().hoverUpdate(delta, mouseX, mouseY);
|
||||
optionsButton.hoverUpdate(delta, mouseX, mouseY);
|
||||
|
||||
// search
|
||||
search.setFocus(true);
|
||||
|
@ -501,6 +505,8 @@ public class SongMenu extends BasicGameState {
|
|||
public void enter(GameContainer container, StateBasedGame game)
|
||||
throws SlickException {
|
||||
Display.setTitle(game.getTitle());
|
||||
Utils.getBackButton().setScale(1f);
|
||||
optionsButton.setScale(1f);
|
||||
|
||||
// stop playing the theme song
|
||||
if (MusicController.isThemePlaying() && focusNode != null)
|
||||
|
|
Loading…
Reference in New Issue
Block a user