finalize main menu with mouse controls
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
https://kenmi-art.itch.io/cute-fantasy-rpg
|
||||
https://yubatake.bandcamp.com/album/jrpg-collection
|
||||
https://crusenho.itch.io/complete-ui-essential-pack
|
||||
https://xdeviruchi.itch.io/8-bit-fantasy-adventure-music-pack
|
||||
|
||||
BIN
assets/audio/menu.ogg
Normal file
BIN
assets/audio/menu.ogg
Normal file
Binary file not shown.
BIN
assets/audio/sword_hit.wav
Normal file
BIN
assets/audio/sword_hit.wav
Normal file
Binary file not shown.
@@ -28,7 +28,7 @@ bar_frame
|
||||
index: -1
|
||||
button
|
||||
rotate: false
|
||||
xy: 141, 578
|
||||
xy: 644, 726
|
||||
size: 32, 16
|
||||
split: 5, 5, 8, 6
|
||||
orig: 32, 16
|
||||
@@ -42,3 +42,11 @@ frame
|
||||
orig: 129, 117
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
selection
|
||||
rotate: false
|
||||
xy: 141, 569
|
||||
size: 24, 25
|
||||
split: 8, 8, 9, 9
|
||||
orig: 24, 25
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 103 KiB |
BIN
assets_raw/ui/selection.9.png
Normal file
BIN
assets_raw/ui/selection.9.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 306 B |
@@ -4,6 +4,7 @@ import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.assets.AssetManager;
|
||||
import com.badlogic.gdx.assets.loaders.FileHandleResolver;
|
||||
import com.badlogic.gdx.audio.Music;
|
||||
import com.badlogic.gdx.audio.Sound;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||
import com.badlogic.gdx.maps.tiled.TiledMap;
|
||||
import com.badlogic.gdx.maps.tiled.TmxMapLoader;
|
||||
@@ -60,6 +61,14 @@ public class AssetService implements Disposable {
|
||||
return this.assetManager.get(skinAsset.getPath(), Skin.class);
|
||||
}
|
||||
|
||||
public void queue(SoundAsset soundAsset) {
|
||||
this.assetManager.load(soundAsset.getPath(), Sound.class);
|
||||
}
|
||||
|
||||
public Sound get(SoundAsset soundAsset) {
|
||||
return this.assetManager.get(soundAsset.getPath(), Sound.class);
|
||||
}
|
||||
|
||||
public boolean update() {
|
||||
return this.assetManager.update();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package io.github.com.quillraven.asset;
|
||||
|
||||
public enum MusicAsset {
|
||||
TOWN("town.ogg");
|
||||
TOWN("town.ogg"),
|
||||
MENU("menu.ogg");
|
||||
|
||||
private final String path;
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.github.com.quillraven.asset;
|
||||
|
||||
public enum SoundAsset {
|
||||
SWORD_HIT("sword_hit.wav");
|
||||
|
||||
private final String path;
|
||||
|
||||
SoundAsset(String musicFile) {
|
||||
this.path = "audio/" + musicFile;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import com.badlogic.gdx.maps.tiled.TiledMap;
|
||||
import com.badlogic.gdx.math.MathUtils;
|
||||
import io.github.com.quillraven.asset.AssetService;
|
||||
import io.github.com.quillraven.asset.MusicAsset;
|
||||
import io.github.com.quillraven.asset.SoundAsset;
|
||||
|
||||
public class AudioService {
|
||||
|
||||
@@ -57,6 +58,10 @@ public class AudioService {
|
||||
this.currentMusicAsset = musicAsset;
|
||||
}
|
||||
|
||||
public void playSound(SoundAsset soundAsset) {
|
||||
this.assetService.get(soundAsset).play(this.soundVolume);
|
||||
}
|
||||
|
||||
public void setMap(TiledMap tiledMap) {
|
||||
String musicAssetStr = tiledMap.getProperties().get("music", "", String.class);
|
||||
if (musicAssetStr.isBlank()) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import io.github.com.quillraven.GdxGame;
|
||||
import io.github.com.quillraven.asset.AssetService;
|
||||
import io.github.com.quillraven.asset.AtlasAsset;
|
||||
import io.github.com.quillraven.asset.SkinAsset;
|
||||
import io.github.com.quillraven.asset.SoundAsset;
|
||||
|
||||
public class LoadingScreen extends ScreenAdapter {
|
||||
|
||||
@@ -23,6 +24,9 @@ public class LoadingScreen extends ScreenAdapter {
|
||||
assetService.queue(atlasAsset);
|
||||
}
|
||||
assetService.queue(SkinAsset.DEFAULT);
|
||||
for (SoundAsset soundAsset : SoundAsset.values()) {
|
||||
assetService.queue(soundAsset);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Skin;
|
||||
import com.badlogic.gdx.utils.viewport.FitViewport;
|
||||
import com.badlogic.gdx.utils.viewport.Viewport;
|
||||
import io.github.com.quillraven.GdxGame;
|
||||
import io.github.com.quillraven.asset.MusicAsset;
|
||||
import io.github.com.quillraven.asset.SkinAsset;
|
||||
import io.github.com.quillraven.ui.model.MenuViewModel;
|
||||
import io.github.com.quillraven.ui.view.MenuView;
|
||||
@@ -38,6 +39,7 @@ public class MenuScreen extends ScreenAdapter {
|
||||
this.inputMultiplexer.addProcessor(stage);
|
||||
|
||||
this.stage.addActor(new MenuView(stage, skin, new MenuViewModel(game)));
|
||||
this.game.getAudioService().playMusic(MusicAsset.MENU);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
package io.github.com.quillraven.ui.model;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.utils.TimeUtils;
|
||||
import io.github.com.quillraven.GdxGame;
|
||||
import io.github.com.quillraven.asset.SoundAsset;
|
||||
import io.github.com.quillraven.audio.AudioService;
|
||||
import io.github.com.quillraven.screen.GameScreen;
|
||||
|
||||
public class MenuViewModel extends ViewModel {
|
||||
public static final String MUSIC_VOLUME_PROPERTY = "musicVolume";
|
||||
|
||||
private final AudioService audioService;
|
||||
private long lastSndPlayTime;
|
||||
|
||||
public MenuViewModel(GdxGame game) {
|
||||
super(game);
|
||||
this.audioService = game.getAudioService();
|
||||
this.lastSndPlayTime = 0L;
|
||||
}
|
||||
|
||||
public float getMusicVolume() {
|
||||
@@ -20,7 +23,6 @@ public class MenuViewModel extends ViewModel {
|
||||
}
|
||||
|
||||
public void setMusicVolume(float volume) {
|
||||
this.propertyChangeSupport.firePropertyChange(MUSIC_VOLUME_PROPERTY, getMusicVolume(), volume);
|
||||
this.audioService.setMusicVolume(volume);
|
||||
}
|
||||
|
||||
@@ -28,6 +30,14 @@ public class MenuViewModel extends ViewModel {
|
||||
return audioService.getSoundVolume();
|
||||
}
|
||||
|
||||
public void setSoundVolume(float soundVolume) {
|
||||
this.audioService.setSoundVolume(soundVolume);
|
||||
if (TimeUtils.timeSinceMillis(lastSndPlayTime) > 500L) {
|
||||
this.lastSndPlayTime = TimeUtils.millis();
|
||||
this.audioService.playSound(SoundAsset.SWORD_HIT);
|
||||
}
|
||||
}
|
||||
|
||||
public void startGame() {
|
||||
game.setScreen(GameScreen.class);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,53 @@
|
||||
package io.github.com.quillraven.ui.view;
|
||||
|
||||
import com.badlogic.gdx.math.Interpolation;
|
||||
import com.badlogic.gdx.scenes.scene2d.Group;
|
||||
import com.badlogic.gdx.scenes.scene2d.Stage;
|
||||
import com.badlogic.gdx.scenes.scene2d.Touchable;
|
||||
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Image;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Label;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.ProgressBar;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Slider;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import io.github.com.quillraven.ui.model.MenuViewModel;
|
||||
|
||||
public class MenuView extends View<MenuViewModel> {
|
||||
private final Image selectionImg;
|
||||
|
||||
public MenuView(Stage stage, Skin skin, MenuViewModel viewModel) {
|
||||
super(stage, skin, viewModel);
|
||||
|
||||
this.selectionImg = new Image(skin, "selection");
|
||||
this.selectionImg.setTouchable(Touchable.disabled);
|
||||
selectMenuItem(this.findActor("startGameBtn"));
|
||||
}
|
||||
|
||||
private void selectMenuItem(Group menuItem) {
|
||||
if (selectionImg.getParent() != null) {
|
||||
selectionImg.getParent().removeActor(selectionImg);
|
||||
}
|
||||
|
||||
float extraSize = 7f;
|
||||
float halfExtraSize = extraSize * 0.5f;
|
||||
float resizeTime = 0.2f;
|
||||
|
||||
menuItem.addActor(selectionImg);
|
||||
selectionImg.setPosition(-halfExtraSize, -halfExtraSize);
|
||||
selectionImg.setSize(menuItem.getWidth() + extraSize, menuItem.getHeight() + extraSize);
|
||||
selectionImg.clearActions();
|
||||
selectionImg.addAction(Actions.forever(Actions.sequence(
|
||||
Actions.parallel(
|
||||
Actions.sizeBy(extraSize, extraSize, resizeTime, Interpolation.linear),
|
||||
Actions.moveBy(-halfExtraSize, -halfExtraSize, resizeTime, Interpolation.linear)
|
||||
),
|
||||
Actions.parallel(
|
||||
Actions.sizeBy(-extraSize, -extraSize, resizeTime, Interpolation.linear),
|
||||
Actions.moveBy(halfExtraSize, halfExtraSize, resizeTime, Interpolation.linear)
|
||||
)
|
||||
)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -39,32 +73,37 @@ public class MenuView extends View<MenuViewModel> {
|
||||
contentTable.padBottom(20.0f);
|
||||
|
||||
TextButton textButton = new TextButton("Start Game", skin);
|
||||
onClick(textButton, ((event, x, y) -> viewModel.startGame()));
|
||||
textButton.setName("startGameBtn");
|
||||
onClick(textButton, viewModel::startGame);
|
||||
onEnter(textButton, this::selectMenuItem);
|
||||
contentTable.add(textButton).row();
|
||||
|
||||
ProgressBar musicBar = setupVolumeBar(contentTable, "Music Volume", viewModel.getMusicVolume());
|
||||
viewModel.addPropertyChangeListener(MenuViewModel.MUSIC_VOLUME_PROPERTY, (event) ->
|
||||
musicBar.setValue((Float) event.getNewValue())
|
||||
);
|
||||
setupVolumeBar(contentTable, "Sound Volume", viewModel.getSoundVolume());
|
||||
Slider musicSlider = setupVolumeSlider(contentTable, "Music Volume", viewModel.getMusicVolume());
|
||||
onChange(musicSlider, (slider) -> viewModel.setMusicVolume(slider.getValue()));
|
||||
|
||||
Slider soundSlider = setupVolumeSlider(contentTable, "Sound Volume", viewModel.getSoundVolume());
|
||||
onChange(soundSlider, (slider) -> viewModel.setSoundVolume(slider.getValue()));
|
||||
|
||||
textButton = new TextButton("Quit Game", skin);
|
||||
onClick(textButton, ((event, x, y) -> viewModel.quitGame()));
|
||||
onClick(textButton, viewModel::quitGame);
|
||||
onEnter(textButton, this::selectMenuItem);
|
||||
contentTable.add(textButton).padTop(10.0f);
|
||||
|
||||
add(contentTable).align(Align.top).expandY().padTop(20f).row();
|
||||
}
|
||||
|
||||
private ProgressBar setupVolumeBar(Table contentTable, String title, float initialValue) {
|
||||
private Slider setupVolumeSlider(Table contentTable, String title, float initialValue) {
|
||||
Table table = new Table();
|
||||
Label label = new Label(title, skin);
|
||||
label.setColor(skin.getColor("sand"));
|
||||
table.add(label).row();
|
||||
|
||||
ProgressBar progressBar = new ProgressBar(0.0f, 1f, 0.05f, false, skin);
|
||||
progressBar.setValue(initialValue);
|
||||
table.add(progressBar).fill();
|
||||
Slider slider = new Slider(0.0f, 1f, 0.05f, false, skin);
|
||||
slider.setValue(initialValue);
|
||||
table.add(slider);
|
||||
contentTable.add(table).padTop(10.0f).row();
|
||||
return progressBar;
|
||||
|
||||
onEnter(table, this::selectMenuItem);
|
||||
return slider;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@ package io.github.com.quillraven.ui.view;
|
||||
|
||||
import com.badlogic.gdx.scenes.scene2d.Actor;
|
||||
import com.badlogic.gdx.scenes.scene2d.InputEvent;
|
||||
import com.badlogic.gdx.scenes.scene2d.InputListener;
|
||||
import com.badlogic.gdx.scenes.scene2d.Stage;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table;
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
|
||||
import io.github.com.quillraven.ui.model.ViewModel;
|
||||
|
||||
@@ -24,17 +26,40 @@ public abstract class View<T extends ViewModel> extends Table {
|
||||
|
||||
protected abstract void setupUI();
|
||||
|
||||
public static void onClick(Actor actor, OnClickConsumer consumer) {
|
||||
public static void onClick(Actor actor, OnEventConsumer consumer) {
|
||||
actor.addListener(new ClickListener() {
|
||||
@Override
|
||||
public void clicked(InputEvent event, float x, float y) {
|
||||
consumer.onClick(event, x, y);
|
||||
consumer.onEvent();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static <T extends Actor> void onEnter(T actor, OnActorEvent<T> consumer) {
|
||||
actor.addListener(new InputListener() {
|
||||
@Override
|
||||
public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor) {
|
||||
consumer.onEvent(actor);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static <T extends Actor> void onChange(T actor, OnActorEvent<T> consumer) {
|
||||
actor.addListener(new ChangeListener() {
|
||||
@Override
|
||||
public void changed(ChangeEvent event, Actor eventActor) {
|
||||
consumer.onEvent(actor);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface OnClickConsumer {
|
||||
void onClick(InputEvent event, float x, float y);
|
||||
public interface OnEventConsumer {
|
||||
void onEvent();
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface OnActorEvent<T extends Actor> {
|
||||
void onEvent(T actor);
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user