diff --git a/engine/src/main/java/org/destinationsol/SolApplication.java b/engine/src/main/java/org/destinationsol/SolApplication.java index ab7632214..bb0b59af8 100644 --- a/engine/src/main/java/org/destinationsol/SolApplication.java +++ b/engine/src/main/java/org/destinationsol/SolApplication.java @@ -165,13 +165,14 @@ public void create() { musicManager.playMusic(OggMusicManager.MENU_MUSIC_SET, options); - menuBackgroundManager = new MenuBackgroundManager(displayDimensions); - menuScreens = new MenuScreens(layouts, isMobile(), options); - - inputManager.setScreen(this, menuScreens.main); parameterAdapterManager = ParameterAdapterManager.createCore(this); - nuiManager = new NUIManager(this, context, commonDrawer, options); + nuiManager = new NUIManager(this, context, commonDrawer, options, uiDrawer); + + menuBackgroundManager = new MenuBackgroundManager(displayDimensions); + menuScreens = new MenuScreens(layouts, isMobile(), options, nuiManager); + + nuiManager.pushScreen(menuScreens.main); } @Override @@ -359,6 +360,7 @@ public void play(boolean tut, String shipName, boolean isNewGame, WorldConfig wo } factionDisplay = new FactionDisplay(context.get(SolCam.class)); + nuiManager.removeScreen(menuScreens.loading); inputManager.setScreen(this, solGame.getScreens().mainGameScreen); } @@ -401,7 +403,9 @@ public SolLayouts getLayouts() { public void finishGame() { solGame.onGameEnd(context); solGame = null; - inputManager.setScreen(this, menuScreens.main); + // TODO: remove the following line when all screens have been ported to use NUI + inputManager.setScreen(this, null); + nuiManager.pushScreen(menuScreens.main); } public boolean isMobile() { diff --git a/engine/src/main/java/org/destinationsol/assets/AssetHelper.java b/engine/src/main/java/org/destinationsol/assets/AssetHelper.java index 07dc553cc..cfa83d89d 100644 --- a/engine/src/main/java/org/destinationsol/assets/AssetHelper.java +++ b/engine/src/main/java/org/destinationsol/assets/AssetHelper.java @@ -128,4 +128,8 @@ public void dispose() { logger.error("Error closing assetTypeManager", e); } } + + public boolean isAssetLoaded(ResourceUrn urn, Class> type) { + return assetTypeManager.getAssetManager().isLoaded(urn, type); + } } diff --git a/engine/src/main/java/org/destinationsol/assets/Assets.java b/engine/src/main/java/org/destinationsol/assets/Assets.java index 8dc70c850..92ceb4d8b 100644 --- a/engine/src/main/java/org/destinationsol/assets/Assets.java +++ b/engine/src/main/java/org/destinationsol/assets/Assets.java @@ -29,8 +29,10 @@ import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.terasology.gestalt.assets.Asset; import org.terasology.gestalt.assets.ResourceUrn; import org.terasology.gestalt.entitysystem.prefab.Prefab; +import org.terasology.nui.asset.UIElement; import org.terasology.nui.skin.UISkin; import org.terasology.nui.skin.UISkinAsset; @@ -267,6 +269,33 @@ public static Animation getAnimation(String texturePat return animation; } + /** + * Retrieves the specified UIElement asset, if it exists. Otherwise, throws a RuntimeException. + * NOTE: It is the caller's responsibility for initialising the retrieved element, if needed. + * @see org.destinationsol.ui.nui.NUIManager#createScreen + * @param path the asset path, in the {@link ResourceUrn} format. + * @return the retrieved asset + */ + public static UIElement getUIElement(String path) { + Optional optionalUIElement = assetHelper.get(new ResourceUrn(path), UIElement.class); + + if (optionalUIElement.isPresent()) { + return optionalUIElement.get(); + } + + throw new RuntimeException("UIElement " + path + " not found!"); + } + + /** + * Returns true if the asset specified has already been loaded. + * @param path the asset urn + * @param type the asset type + * @return true, if the asset has been loaded yet, otherwise false + */ + public static boolean isLoaded(String path, Class> type) { + return assetHelper.isAssetLoaded(new ResourceUrn(path), type); + } + public static void cacheLists() { textureList = assetHelper.list(DSTexture.class); } diff --git a/engine/src/main/java/org/destinationsol/assets/fonts/Font.java b/engine/src/main/java/org/destinationsol/assets/fonts/Font.java index b806e7d01..4f99d2e42 100644 --- a/engine/src/main/java/org/destinationsol/assets/fonts/Font.java +++ b/engine/src/main/java/org/destinationsol/assets/fonts/Font.java @@ -38,4 +38,8 @@ protected void doReload(FontData data) { public BitmapFont getBitmapFont() { return fontData.getBitmapFont(); } + + public FontData getFontData() { + return fontData; + } } diff --git a/engine/src/main/java/org/destinationsol/assets/fonts/ScaledFontProducer.java b/engine/src/main/java/org/destinationsol/assets/fonts/ScaledFontProducer.java index 9b6a5479b..ac9e3f8ad 100644 --- a/engine/src/main/java/org/destinationsol/assets/fonts/ScaledFontProducer.java +++ b/engine/src/main/java/org/destinationsol/assets/fonts/ScaledFontProducer.java @@ -70,16 +70,15 @@ public Optional getAssetData(ResourceUrn urn) throws IOException { return Optional.empty(); } - // The 1/scale value is due to the rendering scaling performed in UIFont.java, which uses the existing scale. - // Without this, large values would be displayed as smaller and smaller values as larger. - float scale = 1.0f / Float.parseFloat(urn.getFragmentName().toString()); + float scale = Float.parseFloat(urn.getFragmentName().toString()); Optional fontAsset = assetManager.getAsset(urn.getRootUrn(), Font.class); if (!fontAsset.isPresent()) { return Optional.empty(); } BitmapFont bitmapFont = fontAsset.get().getBitmapFont(); - BitmapFont.BitmapFontData fontData = new BitmapFont.BitmapFontData(bitmapFont.getData().getFontFile(), bitmapFont.getData().flipped); + // Invert the flip value because the original font may be already flipped. + BitmapFont.BitmapFontData fontData = new BitmapFont.BitmapFontData(bitmapFont.getData().getFontFile(), !bitmapFont.getData().flipped); fontData.setScale(scale); return Optional.of(new FontData(new BitmapFont(fontData, bitmapFont.getRegions(), bitmapFont.isFlipped()))); diff --git a/engine/src/main/java/org/destinationsol/assets/fonts/UIFont.java b/engine/src/main/java/org/destinationsol/assets/fonts/UIFont.java deleted file mode 100644 index ac1746086..000000000 --- a/engine/src/main/java/org/destinationsol/assets/fonts/UIFont.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2020 The Terasology Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.destinationsol.assets.fonts; - -import com.badlogic.gdx.graphics.g2d.BitmapFont; -import com.badlogic.gdx.graphics.g2d.GlyphLayout; -import org.joml.Vector2i; -import org.terasology.nui.backends.libgdx.LibGDXFont; - -import java.util.List; - -/** - * This class wraps a {@link Font} asset in order to adapt it to NUI's LibGDX back-end. It handles font scaling, - * so that NUI renders correctly. - */ -public class UIFont extends LibGDXFont { - private float fontScale; - private float previousFontScaleX; - private float previousFontScaleY; - private static final float FONT_SCALE = 8.0f; - - public UIFont(Font font) { - super(font.getBitmapFont()); - - fontScale = FONT_SCALE / super.getGdxFont().getData().xHeight; - } - - private void scale() { - scale(fontScale, fontScale); - } - - private void scale(float scaleX, float scaleY) { - previousFontScaleX = super.getGdxFont().getScaleX(); - previousFontScaleY = super.getGdxFont().getScaleY(); - super.getGdxFont().getData().setScale(scaleX, scaleY); - } - - private void reset() { - super.getGdxFont().getData().setScale(previousFontScaleX, previousFontScaleY); - } - - @Override - public Vector2i getSize(List lines) { - scale(); - Vector2i result = super.getSize(lines); - reset(); - return result; - } - - @Override - public int getWidth(Character c) { - scale(); - int result = super.getWidth(c); - reset(); - return result; - } - - @Override - public int getLineHeight() { - scale(); - int result = super.getLineHeight(); - reset(); - return result; - } - - @Override - public int getHeight(String text) { - scale(); - int result = super.getHeight(text); - reset(); - return result; - } - - @Override - public int getBaseHeight() { - scale(); - int result = super.getBaseHeight(); - reset(); - return result; - } - - @Override - public int getWidth(String text) { - scale(); - int result = super.getWidth(text); - reset(); - return result; - } - - @Override - public BitmapFont getGdxFont() { - super.getGdxFont().getData().setScale(fontScale, -fontScale); - return super.getGdxFont(); - } - - @Override - public GlyphLayout getGlyphLayout() { - super.getGdxFont().getData().setScale(fontScale, -fontScale); - return super.getGlyphLayout(); - } -} diff --git a/engine/src/main/java/org/destinationsol/assets/ui/UISkinFormat.java b/engine/src/main/java/org/destinationsol/assets/ui/UISkinFormat.java index a30d69fd5..27fcc4438 100644 --- a/engine/src/main/java/org/destinationsol/assets/ui/UISkinFormat.java +++ b/engine/src/main/java/org/destinationsol/assets/ui/UISkinFormat.java @@ -12,7 +12,6 @@ import com.google.gson.JsonSyntaxException; import com.google.gson.stream.JsonReader; import org.destinationsol.assets.Assets; -import org.destinationsol.assets.fonts.UIFont; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.gestalt.assets.ResourceUrn; @@ -210,7 +209,7 @@ public Font deserialize(JsonElement json, Type typeOfT, JsonDeserializationConte if (!name.contains(":")) { name = "engine:" + name; } - return new UIFont(Assets.getFont(name)); + return Assets.getFont(name).getFontData(); } } diff --git a/engine/src/main/java/org/destinationsol/game/SolGame.java b/engine/src/main/java/org/destinationsol/game/SolGame.java index 56b5eb266..a7524e82d 100644 --- a/engine/src/main/java/org/destinationsol/game/SolGame.java +++ b/engine/src/main/java/org/destinationsol/game/SolGame.java @@ -164,9 +164,9 @@ public SolGame(String shipName, boolean isTutorial, boolean isNewGame, CommonDra boolean isMobile = solApplication.isMobile(); if (!isMobile) { - mainGameScreen = (MainGameScreen) Assets.getAssetHelper().get(new ResourceUrn(NUI_MAIN_GAME_SCREEN_DESKTOP_URI), UIElement.class).get().getRootWidget(); + mainGameScreen = (MainGameScreen) solApplication.getNuiManager().createScreen(NUI_MAIN_GAME_SCREEN_DESKTOP_URI); } else { - mainGameScreen = (MainGameScreen) Assets.getAssetHelper().get(new ResourceUrn(NUI_MAIN_GAME_SCREEN_MOBILE_URI), UIElement.class).get().getRootWidget(); + mainGameScreen = (MainGameScreen) solApplication.getNuiManager().createScreen(NUI_MAIN_GAME_SCREEN_MOBILE_URI); } if (isTutorial) { diff --git a/engine/src/main/java/org/destinationsol/game/console/commands/ShowNUIScreenCommandHandler.java b/engine/src/main/java/org/destinationsol/game/console/commands/ShowNUIScreenCommandHandler.java index 02c9f7912..3a8955e3c 100644 --- a/engine/src/main/java/org/destinationsol/game/console/commands/ShowNUIScreenCommandHandler.java +++ b/engine/src/main/java/org/destinationsol/game/console/commands/ShowNUIScreenCommandHandler.java @@ -35,7 +35,7 @@ public class ShowNUIScreenCommandHandler { @Command(shortDescription = "Displays a NUI screen") public String showNUIScreen(@Game SolGame game, @CommandParam(value = "screen", suggester = NUIScreenSuggester.class) String screen) { NUIManager nuiManager = game.getSolApplication().getNuiManager(); - nuiManager.pushScreen((NUIScreenLayer) Assets.getAssetHelper().get(new ResourceUrn(screen), UIElement.class).get().getRootWidget()); + nuiManager.pushScreen(nuiManager.createScreen(screen)); return "Screen displayed."; } } diff --git a/engine/src/main/java/org/destinationsol/game/screens/MainGameScreen.java b/engine/src/main/java/org/destinationsol/game/screens/MainGameScreen.java index 258613675..f725a33c1 100644 --- a/engine/src/main/java/org/destinationsol/game/screens/MainGameScreen.java +++ b/engine/src/main/java/org/destinationsol/game/screens/MainGameScreen.java @@ -107,9 +107,7 @@ public class MainGameScreen extends SolUiBaseScreen { switch (gameOptions.controlType) { case KEYBOARD: UIShipControlsScreen shipControlsScreen = - (UIShipControlsScreen) Assets.getAssetHelper().get( - new ResourceUrn("engine:uiShipControlsScreen"), UIElement.class).get().getRootWidget(); - solApplication.getNuiManager().pushScreen(shipControlsScreen); + (UIShipControlsScreen) solApplication.getNuiManager().createScreen("engine:uiShipControlsScreen"); shipControl = shipControlsScreen; break; case MOUSE: @@ -162,6 +160,17 @@ public class MainGameScreen extends SolUiBaseScreen { myMoneyExcessTp = new TextPlace(SolColor.WHITE); } + @Override + public void onAdd(SolApplication solApplication) { + super.onAdd(solApplication); + if (solApplication.getOptions().controlType == GameOptions.ControlType.KEYBOARD) { + UIShipControlsScreen uiControls = (UIShipControlsScreen) shipControl; + if (!solApplication.getNuiManager().hasScreen(uiControls)) { + solApplication.getNuiManager().pushScreen(uiControls); + } + } + } + public static Rectangle btn(float x, float y, boolean halfHeight) { float gap = .01f; float cellH = CELL_SZ; diff --git a/engine/src/main/java/org/destinationsol/menu/InputMapControllerScreen.java b/engine/src/main/java/org/destinationsol/menu/InputMapControllerScreen.java index 45004bf82..b633eeff3 100644 --- a/engine/src/main/java/org/destinationsol/menu/InputMapControllerScreen.java +++ b/engine/src/main/java/org/destinationsol/menu/InputMapControllerScreen.java @@ -248,8 +248,9 @@ public void setEnterNewKey(boolean newKey) { Gdx.input.setInputProcessor(new InputAdapter() { @Override public boolean keyUp(int keycode) { - // Don't capture the escape key + // Don't capture the escape key - cancel the key input instead if (keycode == Input.Keys.ESCAPE) { + setEnterNewKey(false); return true; } @@ -359,6 +360,11 @@ public List getItems(GameOptions gameOptions) { return itemsList; } + @Override + public int getSelectedIndex() { + return selectedIndex; + } + @Override public void setSelectedIndex(int index) { selectedIndex = index; diff --git a/engine/src/main/java/org/destinationsol/menu/InputMapKeyboardScreen.java b/engine/src/main/java/org/destinationsol/menu/InputMapKeyboardScreen.java index 2f048edc6..91d0a9b1e 100644 --- a/engine/src/main/java/org/destinationsol/menu/InputMapKeyboardScreen.java +++ b/engine/src/main/java/org/destinationsol/menu/InputMapKeyboardScreen.java @@ -223,8 +223,9 @@ public void setEnterNewKey(boolean newKey) { Gdx.input.setInputProcessor(new InputAdapter() { @Override public boolean keyUp(int keycode) { - // Don't capture the escape key + // Don't capture the escape key - cancel the key input instead if (keycode == Input.Keys.ESCAPE) { + setEnterNewKey(false); return true; } @@ -255,6 +256,11 @@ public List getItems(GameOptions gameOptions) { return itemsList; } + @Override + public int getSelectedIndex() { + return selectedIndex; + } + @Override public void setSelectedIndex(int index) { selectedIndex = index; diff --git a/engine/src/main/java/org/destinationsol/menu/InputMapMixedScreen.java b/engine/src/main/java/org/destinationsol/menu/InputMapMixedScreen.java index 73a528dc2..91add46e7 100644 --- a/engine/src/main/java/org/destinationsol/menu/InputMapMixedScreen.java +++ b/engine/src/main/java/org/destinationsol/menu/InputMapMixedScreen.java @@ -195,8 +195,9 @@ public void setEnterNewKey(boolean newKey) { Gdx.input.setInputProcessor(new InputAdapter() { @Override public boolean keyUp(int keycode) { - // Don't capture the escape key + // Don't capture the escape key - cancel the key input instead if (keycode == Input.Keys.ESCAPE) { + setEnterNewKey(false); return true; } @@ -218,6 +219,11 @@ public List getItems(GameOptions gameOptions) { return itemsList; } + @Override + public int getSelectedIndex() { + return selectedIndex; + } + @Override public void setSelectedIndex(int index) { selectedIndex = index; diff --git a/engine/src/main/java/org/destinationsol/menu/InputMapOperations.java b/engine/src/main/java/org/destinationsol/menu/InputMapOperations.java index 107c902a6..60a3d877b 100644 --- a/engine/src/main/java/org/destinationsol/menu/InputMapOperations.java +++ b/engine/src/main/java/org/destinationsol/menu/InputMapOperations.java @@ -26,7 +26,7 @@ public abstract class InputMapOperations extends SolUiBaseScreen { * * @return String The header title */ - abstract String getHeader(); + public abstract String getHeader(); /** * Get the key mappings to display on the input mapping screen. @@ -34,47 +34,54 @@ public abstract class InputMapOperations extends SolUiBaseScreen { * @param gameOptions The options object that contains the key mapping * @return List<InputConfigItem> List of input config items */ - abstract List getItems(GameOptions gameOptions); + public abstract List getItems(GameOptions gameOptions); /** * Get the text to display in the detail are * * @return String The text to display */ - abstract String getDisplayDetail(); + public abstract String getDisplayDetail(); /** * Determines if the user is entering a new input key * * @return boolean True if user is entering a new key */ - abstract boolean isEnterNewKey(); + public abstract boolean isEnterNewKey(); /** * Enter a new input key * * @param newKey The value to set */ - abstract void setEnterNewKey(boolean newKey); + public abstract void setEnterNewKey(boolean newKey); /** * States which item in the list is currently selected * * @param index The index */ - abstract void setSelectedIndex(int index); + public abstract void setSelectedIndex(int index); + + /** + * Returns which item in the list is currently selected + * + * @return The index + */ + public abstract int getSelectedIndex(); /** * Save the new configuration settings * * @param gameOptions The options object that contains the key mapping */ - abstract void save(GameOptions gameOptions); + public abstract void save(GameOptions gameOptions); /** * Reset the input mappings back to the defaults * * @param gameOptions The options object that contains the key mapping */ - abstract void resetToDefaults(GameOptions gameOptions); + public abstract void resetToDefaults(GameOptions gameOptions); } diff --git a/engine/src/main/java/org/destinationsol/menu/InputMapScreen.java b/engine/src/main/java/org/destinationsol/menu/InputMapScreen.java deleted file mode 100644 index c97e7dad1..000000000 --- a/engine/src/main/java/org/destinationsol/menu/InputMapScreen.java +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.destinationsol.menu; - -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import com.badlogic.gdx.math.Rectangle; -import com.badlogic.gdx.math.Vector2; -import org.destinationsol.Const; -import org.destinationsol.GameOptions; -import org.destinationsol.SolApplication; -import org.destinationsol.assets.Assets; -import org.destinationsol.common.SolColor; -import org.destinationsol.ui.DisplayDimensions; -import org.destinationsol.ui.FontSize; -import org.destinationsol.ui.SolInputManager; -import org.destinationsol.ui.SolUiBaseScreen; -import org.destinationsol.ui.SolUiControl; -import org.destinationsol.ui.UiDrawer; - -import java.util.List; - -/** - *

Config Screen to Change Input Mapping

- * The input mapping screen is based on the inventory screen used within the game. - */ -public class InputMapScreen extends SolUiBaseScreen { - private static final float IMG_COL_PERC = .1f; - private static final float EQUI_COL_PERC = .1f; - private static final float PRICE_COL_PERC = .1f; - private static final float AMT_COL_PERC = .1f; - private static final float SMALL_GAP = .004f; - private static final float HEADER_TEXT_OFFSET = .005f; - private static final int BUTTON_ROWS = 4; - final InputMapKeyboardScreen inputMapKeyboardScreen; - final InputMapControllerScreen inputMapControllerScreen; - final InputMapMixedScreen inputMapMixedScreen; - private final TextureAtlas.AtlasRegion backgroundTexture; - private final SolUiControl[] itemControls; - private final SolUiControl previousControl; - private final SolUiControl nextControl; - private final SolUiControl cancelControl; - private final SolUiControl saveControl; - private final SolUiControl defaultsControl; - private final SolUiControl upControl; - private final SolUiControl downControl; - - private DisplayDimensions displayDimensions; - - private final Vector2 listHeaderPos; - private final Rectangle listArea; - private final Rectangle detailsArea; - private final Rectangle itemControlsArea; - private InputMapOperations operations; - private int page; - private int selectedIndex; - - InputMapScreen(GameOptions gameOptions) { - displayDimensions = SolApplication.displayDimensions; - - float contentW = .8f; - float col0 = displayDimensions.getRatio() / 2 - contentW / 2; - float row = 0.2f; - float bigGap = SMALL_GAP * 6; - float headerH = .03f; - - // List header & controls - listHeaderPos = new Vector2(col0 + HEADER_TEXT_OFFSET, row + HEADER_TEXT_OFFSET); // offset hack - float listCtrlW = contentW * .15f; - Rectangle nextArea = new Rectangle(col0 + contentW - listCtrlW, row, listCtrlW, headerH); - nextControl = new SolUiControl(nextArea, true, gameOptions.getKeyRight()); - nextControl.setDisplayName(">"); - controls.add(nextControl); - Rectangle prevArea = new Rectangle(nextArea.x - SMALL_GAP - listCtrlW, row, listCtrlW, headerH); - previousControl = new SolUiControl(prevArea, true, gameOptions.getKeyLeft()); - previousControl.setDisplayName("<"); - controls.add(previousControl); - row += headerH + SMALL_GAP; - - // List - float itemRowH = .04f; - float listRow0 = row; - itemControls = new SolUiControl[Const.ITEM_GROUPS_PER_PAGE]; - for (int i = 0; i < Const.ITEM_GROUPS_PER_PAGE; i++) { - Rectangle itemR = new Rectangle(col0, row, contentW, itemRowH); - SolUiControl itemCtrl = new SolUiControl(itemR, true); - itemControls[i] = itemCtrl; - controls.add(itemCtrl); - row += itemRowH + SMALL_GAP; - } - listArea = new Rectangle(col0, row, contentW, row - SMALL_GAP - listRow0); - row += bigGap; - - // Detail header & area - row += headerH + SMALL_GAP; - float itemCtrlAreaW = contentW * .4f; - itemControlsArea = new Rectangle(col0 + contentW - itemCtrlAreaW, row, itemCtrlAreaW, .2f); - detailsArea = new Rectangle(col0, row, contentW - itemCtrlAreaW - SMALL_GAP, itemControlsArea.height); - // row += detailsArea.height; - - // Add the buttons and controls - cancelControl = new SolUiControl(itemControlRectangle(3), true, gameOptions.getKeyClose()); - cancelControl.setDisplayName("Cancel"); - controls.add(cancelControl); - - saveControl = new SolUiControl(itemControlRectangle(2), true); - saveControl.setDisplayName("Save"); - controls.add(saveControl); - - defaultsControl = new SolUiControl(itemControlRectangle(1), true); - defaultsControl.setDisplayName("Defaults"); - controls.add(defaultsControl); - - upControl = new SolUiControl(null, true, gameOptions.getKeyUp()); - controls.add(upControl); - downControl = new SolUiControl(null, true, gameOptions.getKeyDown()); - controls.add(downControl); - - // Create the input screens - inputMapKeyboardScreen = new InputMapKeyboardScreen(); - inputMapControllerScreen = new InputMapControllerScreen(); - inputMapMixedScreen = new InputMapMixedScreen(); - - backgroundTexture = Assets.getAtlasRegion("engine:mainMenuBg", Texture.TextureFilter.Linear); - } - - @Override - public void updateCustom(SolApplication cmp, SolInputManager.InputPointer[] inputPointers, boolean clickedOutside) { - GameOptions gameOptions = cmp.getOptions(); - SolInputManager im = cmp.getInputManager(); - MenuScreens screens = cmp.getMenuScreens(); - - // Save - saves new settings and returns to the options screen - if (saveControl.isJustOff()) { - operations.save(gameOptions); - im.setScreen(cmp, screens.options); - } - - if (cancelControl.isJustOff()) { - if (operations.isEnterNewKey()) { - // Cancel - cancel the current key being entered - operations.setEnterNewKey(false); - } else { - // Cancel - return to options screen without saving - im.setScreen(cmp, screens.options); - } - } - - // Disable handling of key inputs while entering a new input key - if (operations.isEnterNewKey()) { - previousControl.setEnabled(false); - nextControl.setEnabled(false); - upControl.setEnabled(false); - downControl.setEnabled(false); - for (SolUiControl itemControl : itemControls) { - itemControl.setEnabled(false); - } - return; - } else { - upControl.setEnabled(true); - downControl.setEnabled(true); - for (SolUiControl itemControl : itemControls) { - itemControl.setEnabled(true); - } - } - - // Defaults - Reset the input keys back to their default values - if (defaultsControl.isJustOff()) { - operations.resetToDefaults(gameOptions); - } - - // Selected Item Control - List itemsList = operations.getItems(gameOptions); - int groupCount = itemsList.size(); - int pageCount = groupCount / Const.ITEM_GROUPS_PER_PAGE; - - // Select the item the mouse clicked - int offset = page * Const.ITEM_GROUPS_PER_PAGE; - for (int i = 0; i < itemControls.length; i++) { - SolUiControl itemCtrl = itemControls[i]; - if (itemCtrl.isJustOff()) { - selectedIndex = i + offset; - operations.setEnterNewKey(true); - } - } - - // Left and Right Page Control - if (previousControl.isJustOff()) { - page--; - } - if (nextControl.isJustOff()) { - page++; - } - if (pageCount == 0 || pageCount * Const.ITEM_GROUPS_PER_PAGE < groupCount) { - pageCount += 1; - } - if (page < 0) { - page = 0; - } - if (page >= pageCount) { - page = pageCount - 1; - } - previousControl.setEnabled(0 < page); - nextControl.setEnabled(page < pageCount - 1); - - // Ensure Selected item is on page - if (selectedIndex < offset || selectedIndex >= offset + Const.ITEM_GROUPS_PER_PAGE) { - selectedIndex = offset; - } - - // Up and Down Control - if (upControl.isJustOff()) { - selectedIndex--; - if (selectedIndex < 0) { - selectedIndex = 0; - } - if (selectedIndex < offset) { - page--; - } - } - if (downControl.isJustOff()) { - selectedIndex++; - if (selectedIndex >= groupCount) { - selectedIndex = groupCount - 1; - } - if (selectedIndex >= offset + Const.ITEM_GROUPS_PER_PAGE) { - page++; - } - if (page >= pageCount) { - page = pageCount - 1; - } - } - - // Inform the input screen which item is selected - operations.setSelectedIndex(selectedIndex); - - cmp.getMenuBackgroundManager().update(); - } - - public void drawBackground(UiDrawer uiDrawer, SolApplication solApplication) { - uiDrawer.draw(backgroundTexture, displayDimensions.getRatio(), 1, displayDimensions.getRatio() / 2, 0.5f, displayDimensions.getRatio() / 2, 0.5f, 0, SolColor.WHITE); - solApplication.getMenuBackgroundManager().draw(uiDrawer); - } - - @Override - public void drawText(UiDrawer uiDrawer, SolApplication solApplication) { - GameOptions gameOptions = solApplication.getOptions(); - List list = operations.getItems(gameOptions); - - float imgColW = listArea.width * IMG_COL_PERC; - float equiColW = listArea.width * EQUI_COL_PERC; - float priceWidth = listArea.width * PRICE_COL_PERC; - float amtWidth = listArea.width * AMT_COL_PERC; - float nameWidth = listArea.width - imgColW - equiColW - priceWidth - amtWidth; - - // Display the input mapping in the grid control - for (int i = 0; i < itemControls.length; i++) { - int groupIdx = page * Const.ITEM_GROUPS_PER_PAGE + i; - int groupCount = list.size(); - if (groupCount <= groupIdx) { - continue; - } - SolUiControl itemCtrl = itemControls[i]; - String displayName = list.get(groupIdx).getDisplayName(); - String inputKey = list.get(groupIdx).getInputKey(); - Rectangle rect = itemCtrl.getScreenArea(); - float rowCenterY = rect.y + rect.height / 2; - - // Draw the name of in the input and the key it is mapped to - uiDrawer.drawString(displayName, rect.x + equiColW + imgColW + nameWidth / 2, rowCenterY, FontSize.WINDOW, true, selectedIndex == groupIdx ? SolColor.WHITE : SolColor.G); - uiDrawer.drawString(inputKey, rect.x + rect.width - amtWidth - priceWidth / 2, rowCenterY, FontSize.WINDOW, true, SolColor.LG); - } - - // Draw the header title - uiDrawer.drawString(operations.getHeader(), listHeaderPos.x, listHeaderPos.y, FontSize.WINDOW, false, SolColor.WHITE); - - // Draw the detail text - uiDrawer.drawString(operations.getDisplayDetail(), detailsArea.x + .015f, detailsArea.y + .015f, FontSize.WINDOW, false, SolColor.WHITE); - } - - @Override - public void onAdd(SolApplication solApplication) { - // Add any extra screen information as required by the input screens. E.g. buttons - if (operations != null) { - solApplication.getInputManager().addScreen(solApplication, operations); - } - - page = 0; - selectedIndex = 0; - } - - private Rectangle itemControlRectangle(int row) { - float h = (itemControlsArea.height - SMALL_GAP * (BUTTON_ROWS - 1)) / BUTTON_ROWS; - return new Rectangle(itemControlsArea.x, itemControlsArea.y + (h + SMALL_GAP) * row, itemControlsArea.width, h); - } - - void setOperations(InputMapOperations operations) { - this.operations = operations; - } -} diff --git a/engine/src/main/java/org/destinationsol/menu/LoadingScreen.java b/engine/src/main/java/org/destinationsol/menu/LoadingScreen.java deleted file mode 100644 index 614547750..000000000 --- a/engine/src/main/java/org/destinationsol/menu/LoadingScreen.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.destinationsol.menu; - -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import org.destinationsol.SolApplication; -import org.destinationsol.assets.Assets; -import org.destinationsol.common.SolColor; -import org.destinationsol.game.WorldConfig; -import org.destinationsol.ui.DisplayDimensions; -import org.destinationsol.ui.FontSize; -import org.destinationsol.ui.SolInputManager; -import org.destinationsol.ui.SolUiBaseScreen; -import org.destinationsol.ui.UiDrawer; - -public class LoadingScreen extends SolUiBaseScreen { - private DisplayDimensions displayDimensions; - - private final TextureAtlas.AtlasRegion backgroundTexture; - - private boolean loadTutorial; - private boolean isNewGame; - private String shipName; - private WorldConfig worldConfig; - - LoadingScreen() { - displayDimensions = SolApplication.displayDimensions; - - backgroundTexture = Assets.getAtlasRegion("engine:mainMenuBg", Texture.TextureFilter.Linear); - } - - @Override - public void updateCustom(SolApplication solApplication, SolInputManager.InputPointer[] inputPointers, boolean clickedOutside) { - solApplication.play(loadTutorial, shipName, isNewGame, worldConfig); - } - - @Override - public void drawText(UiDrawer uiDrawer, SolApplication solApplication) { - uiDrawer.drawString("Loading...", displayDimensions.getRatio() / 2, .5f, FontSize.MENU, true, SolColor.WHITE); - } - - public void setMode(boolean loadTutorial, String shipName, boolean isNewGame, WorldConfig worldConfig) { - this.loadTutorial = loadTutorial; - this.shipName = shipName; - this.isNewGame = isNewGame; - this.worldConfig = worldConfig; - } - - @Override - public void drawBackground(UiDrawer uiDrawer, SolApplication solApplication) { - uiDrawer.draw(backgroundTexture, displayDimensions.getRatio(), 1, displayDimensions.getRatio() / 2, 0.5f, displayDimensions.getRatio() / 2, 0.5f, 0, SolColor.WHITE); - } -} diff --git a/engine/src/main/java/org/destinationsol/menu/MainMenuScreen.java b/engine/src/main/java/org/destinationsol/menu/MainMenuScreen.java deleted file mode 100644 index 60635ca31..000000000 --- a/engine/src/main/java/org/destinationsol/menu/MainMenuScreen.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.destinationsol.menu; - -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.Input; -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import org.destinationsol.GameOptions; -import org.destinationsol.SolApplication; -import org.destinationsol.assets.Assets; -import org.destinationsol.assets.music.OggMusicManager; -import org.destinationsol.common.SolColor; -import org.destinationsol.game.DebugOptions; -import org.destinationsol.game.WorldConfig; -import org.destinationsol.ui.DisplayDimensions; -import org.destinationsol.ui.SolInputManager; -import org.destinationsol.ui.SolUiBaseScreen; -import org.destinationsol.ui.SolUiControl; -import org.destinationsol.ui.UiDrawer; - -public class MainMenuScreen extends SolUiBaseScreen { - private final boolean isMobile; - private final GameOptions gameOptions; - - private final TextureAtlas.AtlasRegion logoTexture; - private final TextureAtlas.AtlasRegion backgroundTexture; - private DisplayDimensions displayDimensions; - - private final SolUiControl tutorialControl; - private final SolUiControl optionsControl; - private final SolUiControl exitControl; - private final SolUiControl newGameControl; - private final SolUiControl creditsControl; - - private final int buttonWidth = 300; - private final int buttonHeight = 75; - private final int buttonPadding = 10; - - MainMenuScreen(boolean isMobile, GameOptions gameOptions) { - this.isMobile = isMobile; - this.gameOptions = gameOptions; - - displayDimensions = SolApplication.displayDimensions; - - tutorialControl = new SolUiControl(buttonWidth, buttonHeight, UiDrawer.positions.get("bottom"), 0, calculateButtonOffsetFromBottom(3), true, Input.Keys.T); - tutorialControl.setDisplayName("Tutorial"); - controls.add(tutorialControl); - - newGameControl = new SolUiControl(buttonWidth, buttonHeight, UiDrawer.positions.get("bottom"), 0, calculateButtonOffsetFromBottom(2), true, gameOptions.getKeyShoot()); - newGameControl.setDisplayName("Play Game"); - controls.add(newGameControl); - - // TODO: Temporarily showing on mobile as well. Fix! - // optionsControl = new SolUiControl(isMobile ? null : menuLayout.buttonRect(-1, 3), true, Input.Keys.O); - optionsControl = new SolUiControl(buttonWidth, buttonHeight, UiDrawer.positions.get("bottom"), 0, calculateButtonOffsetFromBottom(1), true, Input.Keys.O); - optionsControl.setDisplayName("Options"); - controls.add(optionsControl); - - exitControl = new SolUiControl(buttonWidth, buttonHeight, UiDrawer.positions.get("bottom"), 0, calculateButtonOffsetFromBottom(0), true); - exitControl.setDisplayName("Exit"); - controls.add(exitControl); - - creditsControl = new SolUiControl(MenuLayout.bottomRightFloatingButton(displayDimensions), true, Input.Keys.C); - creditsControl.setDisplayName("Credits"); - controls.add(creditsControl); - - backgroundTexture = Assets.getAtlasRegion("engine:mainMenuBg", Texture.TextureFilter.Linear); - logoTexture = Assets.getAtlasRegion("engine:mainMenuLogo", Texture.TextureFilter.Linear); - } - - @Override - public void updateCustom(SolApplication solApplication, SolInputManager.InputPointer[] inputPointers, boolean clickedOutside) { - tutorialControl.setEnabled(solApplication.getOptions().controlType != GameOptions.ControlType.CONTROLLER); - - SolInputManager inputManager = solApplication.getInputManager(); - MenuScreens screens = solApplication.getMenuScreens(); - - if (tutorialControl.isJustOff()) { - inputManager.setScreen(solApplication, screens.loading); - screens.loading.setMode(true, "Imperial Small", true, new WorldConfig()); - return; - } - - if (newGameControl.isJustOff()) { - inputManager.setScreen(solApplication, screens.newGame); - return; - } - - if (optionsControl.isJustOff()) { - inputManager.setScreen(solApplication, screens.options); - return; - } - - if (exitControl.isJustOff()) { - // Save the settings on exit, but not on mobile as settings don't exist there. - if (!isMobile) { - solApplication.getOptions().save(); - } - Gdx.app.exit(); - return; - } - - if (creditsControl.isJustOff()) { - inputManager.setScreen(solApplication, screens.credits); - } - - solApplication.getMenuBackgroundManager().update(); - } - - @Override - public void onAdd(SolApplication solApplication) { - final OggMusicManager musicManager = solApplication.getMusicManager(); - if (!musicManager.getCurrentMusicSet().equals(OggMusicManager.MENU_MUSIC_SET)) { - musicManager.playMusic(OggMusicManager.MENU_MUSIC_SET, gameOptions); - } - } - - @Override - public void drawBackground(UiDrawer uiDrawer, SolApplication solApplication) { - uiDrawer.draw(backgroundTexture, displayDimensions.getRatio(), 1, displayDimensions.getRatio() / 2, 0.5f, displayDimensions.getRatio() / 2, 0.5f, 0, SolColor.WHITE); - solApplication.getMenuBackgroundManager().draw(uiDrawer); - } - - @Override - public void drawImages(UiDrawer uiDrawer, SolApplication solApplication) { - final float sy = .35f; - final float sx = sy * 400 / 218; - if (!DebugOptions.PRINT_BALANCE) { - uiDrawer.draw(logoTexture, sx, sy, sx / 2, sy / 2, displayDimensions.getRatio() / 2, 0.1f + sy / 2, 0, SolColor.WHITE); - } - } - - /** - * @param buttonIndex the index of the button, starting from 0 for the bottom-most button - * @return the number of pixels to go up from the bottom of the screen for the {@code buttonIndex}th button - */ - private int calculateButtonOffsetFromBottom(int buttonIndex) { - return -(buttonPadding + buttonHeight / 2) - (buttonIndex * (buttonPadding + buttonHeight)); - } -} diff --git a/engine/src/main/java/org/destinationsol/menu/MenuScreens.java b/engine/src/main/java/org/destinationsol/menu/MenuScreens.java index 6c50db735..38ac08815 100644 --- a/engine/src/main/java/org/destinationsol/menu/MenuScreens.java +++ b/engine/src/main/java/org/destinationsol/menu/MenuScreens.java @@ -17,6 +17,15 @@ import org.destinationsol.GameOptions; import org.destinationsol.ui.SolLayouts; +import org.destinationsol.ui.nui.NUIManager; +import org.destinationsol.ui.nui.screens.mainMenu.CreditsScreen; +import org.destinationsol.ui.nui.screens.mainMenu.InputMapScreen; +import org.destinationsol.ui.nui.screens.mainMenu.LoadingScreen; +import org.destinationsol.ui.nui.screens.mainMenu.MainMenuScreen; +import org.destinationsol.ui.nui.screens.mainMenu.NewGameScreen; +import org.destinationsol.ui.nui.screens.mainMenu.NewShipScreen; +import org.destinationsol.ui.nui.screens.mainMenu.OptionsScreen; +import org.destinationsol.ui.nui.screens.mainMenu.ResolutionScreen; public class MenuScreens { public final MainMenuScreen main; @@ -28,15 +37,15 @@ public class MenuScreens { public final NewGameScreen newGame; public final NewShipScreen newShip; - public MenuScreens(SolLayouts layouts, boolean mobile, GameOptions gameOptions) { + public MenuScreens(SolLayouts layouts, boolean mobile, GameOptions gameOptions, NUIManager nuiManager) { MenuLayout menuLayout = layouts.menuLayout; - main = new MainMenuScreen(mobile, gameOptions); - options = new OptionsScreen(mobile, menuLayout, gameOptions); - inputMapScreen = new InputMapScreen(gameOptions); - resolutionScreen = new ResolutionScreen(mobile, menuLayout, gameOptions); - credits = new CreditsScreen(gameOptions); - loading = new LoadingScreen(); - newGame = new NewGameScreen(menuLayout, gameOptions); - newShip = new NewShipScreen(menuLayout, gameOptions); + main = (MainMenuScreen) nuiManager.createScreen("engine:mainMenuScreen"); + options = (OptionsScreen) nuiManager.createScreen("engine:optionsScreen"); + inputMapScreen = (InputMapScreen) nuiManager.createScreen("engine:inputMapScreen"); + resolutionScreen = (ResolutionScreen) nuiManager.createScreen("engine:resolutionScreen"); + credits = (CreditsScreen) nuiManager.createScreen("engine:creditsScreen"); + loading = (LoadingScreen) nuiManager.createScreen("engine:loadingScreen"); + newGame = (NewGameScreen) nuiManager.createScreen("engine:newGameScreen"); + newShip = (NewShipScreen) nuiManager.createScreen("engine:newShipScreen"); } } diff --git a/engine/src/main/java/org/destinationsol/menu/NewGameScreen.java b/engine/src/main/java/org/destinationsol/menu/NewGameScreen.java deleted file mode 100644 index 508482f41..000000000 --- a/engine/src/main/java/org/destinationsol/menu/NewGameScreen.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.destinationsol.menu; - -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import org.destinationsol.GameOptions; -import org.destinationsol.SolApplication; -import org.destinationsol.assets.Assets; -import org.destinationsol.common.SolColor; -import org.destinationsol.game.SaveManager; -import org.destinationsol.game.WorldConfig; -import org.destinationsol.ui.DisplayDimensions; -import org.destinationsol.ui.SolInputManager; -import org.destinationsol.ui.SolUiBaseScreen; -import org.destinationsol.ui.SolUiControl; -import org.destinationsol.ui.UiDrawer; - -public class NewGameScreen extends SolUiBaseScreen { - private DisplayDimensions displayDimensions; - - private final TextureAtlas.AtlasRegion backgroundTexture; - - private final SolUiControl backControl; - private final SolUiControl continueControl; - private final SolUiControl newControl; - - NewGameScreen(MenuLayout menuLayout, GameOptions gameOptions) { - displayDimensions = SolApplication.displayDimensions; - - continueControl = new SolUiControl(menuLayout.buttonRect(-1, 1), true, gameOptions.getKeyShoot()); - continueControl.setDisplayName("Continue"); - controls.add(continueControl); - - newControl = new SolUiControl(menuLayout.buttonRect(-1, 2), true); - newControl.setDisplayName("New game"); - controls.add(newControl); - - backControl = new SolUiControl(menuLayout.buttonRect(-1, 4), true, gameOptions.getKeyEscape()); - backControl.setDisplayName("Cancel"); - controls.add(backControl); - - backgroundTexture = Assets.getAtlasRegion("engine:mainMenuBg", Texture.TextureFilter.Linear); - } - - @Override - public void onAdd(SolApplication solApplication) { - continueControl.setEnabled(SaveManager.hasPreviousCompatibleShip()); - } - - @Override - public void updateCustom(SolApplication solApplication, SolInputManager.InputPointer[] inputPointers, boolean clickedOutside) { - MenuScreens screens = solApplication.getMenuScreens(); - SolInputManager inputManager = solApplication.getInputManager(); - - if (backControl.isJustOff()) { - inputManager.setScreen(solApplication, screens.main); - return; - } - if (continueControl.isJustOff()) { - inputManager.setScreen(solApplication, screens.loading); - screens.loading.setMode(false, null, false, SaveManager.loadWorld().orElseGet(WorldConfig::new)); - return; - } - if (newControl.isJustOff()) { - inputManager.setScreen(solApplication, screens.newShip); - } - - solApplication.getMenuBackgroundManager().update(); - } - - @Override - public boolean isCursorOnBackground(SolInputManager.InputPointer inputPointer) { - return true; - } - - @Override - public void drawBackground(UiDrawer uiDrawer, SolApplication solApplication) { - uiDrawer.draw(backgroundTexture, displayDimensions.getRatio(), 1, displayDimensions.getRatio() / 2, 0.5f, displayDimensions.getRatio() / 2, 0.5f, 0, SolColor.WHITE); - solApplication.getMenuBackgroundManager().draw(uiDrawer); - } -} diff --git a/engine/src/main/java/org/destinationsol/menu/NewShipScreen.java b/engine/src/main/java/org/destinationsol/menu/NewShipScreen.java deleted file mode 100644 index 7b9f65477..000000000 --- a/engine/src/main/java/org/destinationsol/menu/NewShipScreen.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.destinationsol.menu; - -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import org.destinationsol.GameOptions; -import org.destinationsol.SolApplication; -import org.destinationsol.assets.Assets; -import org.destinationsol.assets.json.Json; -import org.destinationsol.assets.json.Validator; -import org.destinationsol.common.SolColor; -import org.destinationsol.game.WorldConfig; -import org.destinationsol.game.planet.SystemsBuilder; -import org.destinationsol.ui.DisplayDimensions; -import org.destinationsol.ui.FontSize; -import org.destinationsol.ui.SolInputManager; -import org.destinationsol.ui.SolUiBaseScreen; -import org.destinationsol.ui.SolUiControl; -import org.destinationsol.ui.UiDrawer; - -import java.util.ArrayList; -import java.util.List; - -public class NewShipScreen extends SolUiBaseScreen { - private final DisplayDimensions displayDimensions; - - private final TextureAtlas.AtlasRegion backgroundTexture; - - private final SolUiControl okControl; - private final SolUiControl cancelControl; - private final SolUiControl systemCountControl; - private final SolUiControl playerSpawnConfigControl; - private int playerSpawnConfigIndex = 0; - private final List playerSpawnConfigNames = new ArrayList<>(); - private int numberOfSystems = SystemsBuilder.DEFAULT_SYSTEM_COUNT; - - NewShipScreen(MenuLayout menuLayout, GameOptions gameOptions) { - displayDimensions = SolApplication.displayDimensions; - - // load player spawn configs - Assets.getAssetHelper().listAssets(Json.class, "playerSpawnConfig").forEach(configUrn -> - playerSpawnConfigNames.addAll(Validator.getValidatedJSON(configUrn.toString(), "engine:schemaPlayerSpawnConfig").keySet())); - - int row = 1; - systemCountControl = new SolUiControl(menuLayout.buttonRect(-1, row++), true); - systemCountControl.setDisplayName("Systems: " + numberOfSystems); - controls.add(systemCountControl); - - playerSpawnConfigControl = new SolUiControl(menuLayout.buttonRect(-1, row++), true); - playerSpawnConfigControl.setDisplayName("Starting Ship: " + playerSpawnConfigNames.get(playerSpawnConfigIndex)); - controls.add(playerSpawnConfigControl); - - okControl = new SolUiControl(menuLayout.buttonRect(-1, row++), true, gameOptions.getKeyEscape()); - okControl.setDisplayName("OK"); - controls.add(okControl); - - cancelControl = new SolUiControl(menuLayout.buttonRect(-1, row), true, gameOptions.getKeyEscape()); - cancelControl.setDisplayName("Cancel"); - controls.add(cancelControl); - - backgroundTexture = Assets.getAtlasRegion("engine:mainMenuBg", Texture.TextureFilter.Linear); - } - - @Override - public void updateCustom(SolApplication solApplication, SolInputManager.InputPointer[] inputPointers, boolean clickedOutside) { - MenuScreens screens = solApplication.getMenuScreens(); - SolInputManager inputManager = solApplication.getInputManager(); - - if (okControl.isJustOff()) { - WorldConfig worldConfig = new WorldConfig(); - worldConfig.setNumberOfSystems(numberOfSystems); - - inputManager.setScreen(solApplication, screens.loading); - screens.loading.setMode(false, playerSpawnConfigNames.get(playerSpawnConfigIndex), true, worldConfig); - return; - } - - if (cancelControl.isJustOff()) { - inputManager.setScreen(solApplication, screens.newGame); - return; - } - - if (systemCountControl.isJustOff()) { - int systemCount = (numberOfSystems + 1) % 10; - if (systemCount < 2) { - systemCount = 2; - } - numberOfSystems = systemCount; - systemCountControl.setDisplayName("Systems: " + numberOfSystems); - } - - if (playerSpawnConfigControl.isJustOff()) { - playerSpawnConfigIndex = (playerSpawnConfigIndex + 1) % playerSpawnConfigNames.size(); - playerSpawnConfigControl.setDisplayName("Starting Ship: " + playerSpawnConfigNames.get(playerSpawnConfigIndex)); - } - - solApplication.getMenuBackgroundManager().update(); - } - - @Override - public void drawText(UiDrawer uiDrawer, SolApplication solApplication) { - uiDrawer.drawString("Warning: This will erase any old ship you might have had!", .5f * displayDimensions.getRatio(), .3f, FontSize.MENU, true, SolColor.WHITE); - } - - @Override - public void drawBackground(UiDrawer uiDrawer, SolApplication solApplication) { - uiDrawer.draw(backgroundTexture, displayDimensions.getRatio(), 1, displayDimensions.getRatio() / 2, 0.5f, displayDimensions.getRatio() / 2, 0.5f, 0, SolColor.WHITE); - solApplication.getMenuBackgroundManager().draw(uiDrawer); - } -} diff --git a/engine/src/main/java/org/destinationsol/menu/OptionsScreen.java b/engine/src/main/java/org/destinationsol/menu/OptionsScreen.java deleted file mode 100644 index e8bf0d2a4..000000000 --- a/engine/src/main/java/org/destinationsol/menu/OptionsScreen.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2020 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.destinationsol.menu; - -import com.badlogic.gdx.Input; -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import org.destinationsol.GameOptions; -import org.destinationsol.SolApplication; -import org.destinationsol.assets.Assets; -import org.destinationsol.common.SolColor; -import org.destinationsol.ui.DisplayDimensions; -import org.destinationsol.ui.SolInputManager; -import org.destinationsol.ui.SolUiBaseScreen; -import org.destinationsol.ui.SolUiControl; -import org.destinationsol.ui.UiDrawer; - -public class OptionsScreen extends SolUiBaseScreen { - private DisplayDimensions displayDimensions; - - private final TextureAtlas.AtlasRegion backgroundTexture; - - private final SolUiControl backControl; - private final SolUiControl resolutionControl; - private final SolUiControl inputTypeControl; - private final SolUiControl inputMapControl; - private final SolUiControl soundVolumeControl; - private final SolUiControl musicVolumeControl; - private final SolUiControl mapScrollSpeedControl; - - OptionsScreen(boolean mobile, MenuLayout menuLayout, GameOptions gameOptions) { - displayDimensions = SolApplication.displayDimensions; - int rowNo = mobile ? -1 : -3; - musicVolumeControl = new SolUiControl(menuLayout.buttonRect(-1, rowNo++), true); - musicVolumeControl.setDisplayName("Music Volume"); - controls.add(musicVolumeControl); - - soundVolumeControl = new SolUiControl(menuLayout.buttonRect(-1, rowNo++), true); - soundVolumeControl.setDisplayName("Sound Volume"); - controls.add(soundVolumeControl); - - // Mobile platforms always run in fullscreen but the NUI UI scale can be changed - resolutionControl = new SolUiControl(menuLayout.buttonRect(-1, rowNo++), true); - resolutionControl.setDisplayName("Resolution"); - controls.add(resolutionControl); - - mapScrollSpeedControl = new SolUiControl(menuLayout.buttonRect(-1, rowNo++), true); - mapScrollSpeedControl.setDisplayName("Map Pan Speed"); - controls.add(mapScrollSpeedControl); - - // Mobile platforms always use the same input method: touchscreen controls - // TODO: Would portable keyboards be supported - inputTypeControl = new SolUiControl(mobile ? null : menuLayout.buttonRect(-1, rowNo++), true, Input.Keys.C); - inputTypeControl.setDisplayName("Control Type"); - controls.add(inputTypeControl); - - // The controls are not currently re-mappable on mobile platforms - inputMapControl = new SolUiControl(mobile ? null : menuLayout.buttonRect(-1, rowNo++), true, Input.Keys.M); - inputMapControl.setDisplayName("Controls"); - controls.add(inputMapControl); - - // Insert a space between the options and the back button - rowNo++; - backControl = new SolUiControl(menuLayout.buttonRect(-1, rowNo++), true, gameOptions.getKeyEscape()); - backControl.setDisplayName("Back"); - controls.add(backControl); - - backgroundTexture = Assets.getAtlasRegion("engine:mainMenuBg", Texture.TextureFilter.Linear); - } - - @Override - public void updateCustom(SolApplication solApplication, SolInputManager.InputPointer[] inputPointers, boolean clickedOutside) { - SolInputManager inputManager = solApplication.getInputManager(); - MenuScreens screens = solApplication.getMenuScreens(); - GameOptions options = solApplication.getOptions(); - if (resolutionControl.isJustOff()) { - inputManager.setScreen(solApplication, screens.resolutionScreen); - } - - String controlName = solApplication.getOptions().controlType.getHumanName(); - inputTypeControl.setDisplayName("Input: " + controlName); - if (inputTypeControl.isJustOff()) { - solApplication.getOptions().advanceControlType(false); - } - - if (backControl.isJustOff()) { - inputManager.setScreen(solApplication, screens.main); - } - - if (inputMapControl.isJustOff()) { - switch (solApplication.getOptions().controlType) { - case KEYBOARD: - screens.inputMapScreen.setOperations(screens.inputMapScreen.inputMapKeyboardScreen); - break; - case MIXED: - screens.inputMapScreen.setOperations(screens.inputMapScreen.inputMapMixedScreen); - break; - case CONTROLLER: - screens.inputMapScreen.setOperations(screens.inputMapScreen.inputMapControllerScreen); - } - inputManager.setScreen(solApplication, screens.inputMapScreen); - } - - soundVolumeControl.setDisplayName("Sound Volume: " + options.sfxVolume.getName()); - if (soundVolumeControl.isJustOff()) { - options.advanceSoundVolMul(); - } - - musicVolumeControl.setDisplayName("Music Volume: " + options.musicVolume.getName()); - if (musicVolumeControl.isJustOff()) { - options.advanceMusicVolMul(); - solApplication.getMusicManager().changeVolume(options); - } - - mapScrollSpeedControl.setDisplayName("Map Pan Speed: " + options.getMapScrollSpeed()); - if (mapScrollSpeedControl.isJustOff()) { - options.advanceMapScrollSpeed(); - } - - solApplication.getMenuBackgroundManager().update(); - } - - @Override - public void drawBackground(UiDrawer uiDrawer, SolApplication solApplication) { - uiDrawer.draw(backgroundTexture, displayDimensions.getRatio(), 1, displayDimensions.getRatio() / 2, 0.5f, displayDimensions.getRatio() / 2, 0.5f, 0, SolColor.WHITE); - solApplication.getMenuBackgroundManager().draw(uiDrawer); - } -} \ No newline at end of file diff --git a/engine/src/main/java/org/destinationsol/menu/ResolutionScreen.java b/engine/src/main/java/org/destinationsol/menu/ResolutionScreen.java deleted file mode 100644 index b9f24d5ad..000000000 --- a/engine/src/main/java/org/destinationsol/menu/ResolutionScreen.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.destinationsol.menu; - -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.Graphics; -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import org.destinationsol.GameOptions; -import org.destinationsol.SolApplication; -import org.destinationsol.assets.Assets; -import org.destinationsol.common.SolColor; -import org.destinationsol.ui.DisplayDimensions; -import org.destinationsol.ui.FontSize; -import org.destinationsol.ui.SolInputManager; -import org.destinationsol.ui.SolUiBaseScreen; -import org.destinationsol.ui.SolUiControl; -import org.destinationsol.ui.UiDrawer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ResolutionScreen extends SolUiBaseScreen { - private DisplayDimensions displayDimensions; - - private static final Logger logger = LoggerFactory.getLogger(ResolutionScreen.class); - private final TextureAtlas.AtlasRegion backgroundTexture; - - private final SolUiControl closeControl; - private final SolUiControl resolutionControl; - private final SolUiControl fullscreenControl; - private final SolUiControl nuiUIScaleControl; - - ResolutionScreen(boolean mobile, MenuLayout menuLayout, GameOptions gameOptions) { - displayDimensions = SolApplication.displayDimensions; - int rowNo = mobile ? 0 : 1; - - resolutionControl = new SolUiControl(mobile ? null : menuLayout.buttonRect(-1, rowNo++), true); - resolutionControl.setDisplayName("Resolution"); - controls.add(resolutionControl); - - fullscreenControl = new SolUiControl(mobile ? null : menuLayout.buttonRect(-1, rowNo++), true); - fullscreenControl.setDisplayName("Fullscreen"); - controls.add(fullscreenControl); - - nuiUIScaleControl = new SolUiControl(menuLayout.buttonRect(-1, rowNo++), true); - nuiUIScaleControl.setDisplayName("NUI UI scale"); - controls.add(nuiUIScaleControl); - - closeControl = new SolUiControl(menuLayout.buttonRect(-1, rowNo++), true, gameOptions.getKeyEscape()); - closeControl.setDisplayName("Back"); - controls.add(closeControl); - - backgroundTexture = Assets.getAtlasRegion("engine:mainMenuBg", Texture.TextureFilter.Linear); - } - - @Override - public void updateCustom(SolApplication solApplication, SolInputManager.InputPointer[] inputPointers, boolean clickedOutside) { - SolInputManager inputManager = solApplication.getInputManager(); - GameOptions options = solApplication.getOptions(); - - if (closeControl.isJustOff()) { - // Mobile only ever runs at one resolution: the entire screen. - // Changing the screen resolution does not work. - if (!solApplication.isMobile()) { - if (options.fullscreen) { - Graphics.DisplayMode mode = null; - //HACK: Gdx.graphics.getDisplayMode() always returns the native desktop resolution. - //See https://github.com/libgdx/libgdx/blob/5398d46aa082489052fccfaaaff7440e137ba5dc/backends/gdx-backend-lwjgl/src/com/badlogic/gdx/backends/lwjgl/LwjglGraphics.java#L555 - //and http://legacy.lwjgl.org/javadoc/org/lwjgl/opengl/Display.html#getDisplayMode() - //for more details. - for (Graphics.DisplayMode displayMode : Gdx.graphics.getDisplayModes()) { - if (displayMode.width == options.x && displayMode.height == options.y) { - mode = displayMode; - } - } - if (mode != null) { - Gdx.graphics.setFullscreenMode(mode); - solApplication.getNuiManager().resize(mode.width, mode.height); - } else { - logger.warn("The resolution {}x{} is not supported in fullscreen mode!", options.x, options.y); - } - } else { - Gdx.graphics.setWindowedMode(options.x, options.y); - solApplication.getNuiManager().resize(options.x, options.y); - } - } - inputManager.setScreen(solApplication, solApplication.getMenuScreens().options); - return; - } - - resolutionControl.setDisplayName(options.x + "x" + options.y); - if (resolutionControl.isJustOff()) { - options.advanceResolution(); - } - - fullscreenControl.setDisplayName(options.fullscreen ? "Fullscreen" : "Windowed"); - if (fullscreenControl.isJustOff()) { - options.advanceFullscreen(); - } - - nuiUIScaleControl.setDisplayName("NUI UI scale: " + options.getNuiUiScale()); - if (nuiUIScaleControl.isJustOff()) { - options.advanceNuiUiScale(); - solApplication.getNuiManager().setUiScale(options.getNuiUiScale()); - } - - solApplication.getMenuBackgroundManager().update(); - } - - @Override - public void drawBackground(UiDrawer uiDrawer, SolApplication solApplication) { - uiDrawer.draw(backgroundTexture, displayDimensions.getRatio(), 1, displayDimensions.getRatio() / 2, 0.5f, displayDimensions.getRatio() / 2, 0.5f, 0, SolColor.WHITE); - solApplication.getMenuBackgroundManager().draw(uiDrawer); - } - - @Override - public void drawText(UiDrawer uiDrawer, SolApplication solApplication) { - uiDrawer.drawString("Click 'Back' to apply changes", .5f * displayDimensions.getRatio(), .3f, FontSize.MENU, true, SolColor.WHITE); - } -} diff --git a/engine/src/main/java/org/destinationsol/ui/SolInputManager.java b/engine/src/main/java/org/destinationsol/ui/SolInputManager.java index ce6f11d84..849d1a514 100644 --- a/engine/src/main/java/org/destinationsol/ui/SolInputManager.java +++ b/engine/src/main/java/org/destinationsol/ui/SolInputManager.java @@ -152,11 +152,20 @@ void maybeTouchDragged(int x, int y) { lastTouchDragPosition.set(x, y); } + /** + * Sets the current UI screen, removing all other screens currently displayed. + * The screen value can be null, which represents clearing all screens. + * @param solApplication a {@link SolApplication} instance + * @param screen the screen to display, or null for no screen + */ public void setScreen(SolApplication solApplication, SolUiScreen screen) { for (SolUiScreen oldScreen : screens) { removeScreen(oldScreen, solApplication); } - addScreen(solApplication, screen); + + if (screen != null) { + addScreen(solApplication, screen); + } } public void addScreen(SolApplication solApplication, SolUiScreen screen) { diff --git a/engine/src/main/java/org/destinationsol/ui/nui/NUIManager.java b/engine/src/main/java/org/destinationsol/ui/nui/NUIManager.java index 47ae435fa..669c2702d 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/NUIManager.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/NUIManager.java @@ -23,6 +23,7 @@ import org.destinationsol.assets.Assets; import org.destinationsol.assets.sound.OggSound; import org.destinationsol.game.context.Context; +import org.destinationsol.ui.UiDrawer; import org.destinationsol.util.InjectionHelper; import org.terasology.joml.geom.Rectanglei; import org.joml.Vector2i; @@ -34,10 +35,13 @@ import org.terasology.input.device.KeyboardDevice; import org.terasology.input.device.MouseAction; import org.terasology.input.device.MouseDevice; +import org.terasology.nui.Canvas; import org.terasology.nui.FocusManager; import org.terasology.nui.FocusManagerImpl; import org.terasology.nui.TabbingManager; import org.terasology.nui.UITextureRegion; +import org.terasology.nui.UIWidget; +import org.terasology.nui.asset.UIElement; import org.terasology.nui.backends.libgdx.LibGDXCanvasRenderer; import org.terasology.nui.backends.libgdx.LibGDXKeyboardDevice; import org.terasology.nui.backends.libgdx.LibGDXMouseDevice; @@ -53,6 +57,7 @@ import org.terasology.nui.widgets.UIButton; import org.terasology.nui.widgets.UIText; +import java.io.Closeable; import java.util.Deque; import java.util.Iterator; import java.util.LinkedList; @@ -108,6 +113,11 @@ public class NUIManager { */ private Deque uiScreens = new LinkedList<>(); + /** + * An {@link UiDrawer} instance that can be used to interact with legacy UI screens that require it. + */ + private final UiDrawer uiDrawer; + private static final String WHITE_TEXTURE_URN = "engine:uiWhiteTex"; private static final String DEFAULT_SKIN_URN = "engine:default"; private static final String BUTTON_CLICK_URN = "engine:uiHover"; @@ -125,9 +135,10 @@ public class NUIManager { * @param commonDrawer used to directly access the game's LibGDX {@link com.badlogic.gdx.graphics.g2d.SpriteBatch} * @param options used to initialise the UI scale with its previously-saved value */ - public NUIManager(SolApplication solApplication, Context context, CommonDrawer commonDrawer, GameOptions options) { + public NUIManager(SolApplication solApplication, Context context, CommonDrawer commonDrawer, GameOptions options, UiDrawer uiDrawer) { NUIInputProcessor.CONSUME_INPUT = false; this.context = context; + this.uiDrawer = uiDrawer; // TODO: Re-enable tabbing when it works TabbingManager.tabForwardInput = Keyboard.Key.NONE; @@ -186,7 +197,10 @@ public void update(SolApplication solApplication) { focusManager.getFocus().onKeyEvent(event); } - for (NUIScreenLayer uiScreen : uiScreens) { + // Create a copy of the list, as screens may be removed in response to key events. + // This does not happen for most key events, however it may occur with KeyActivatedButton instances, + // which already have special handling in the NUIScreenLayer class. + for (NUIScreenLayer uiScreen : new LinkedList<>(uiScreens)) { if (uiScreen.onKeyEvent(event) || uiScreen.isBlockingInput() || event.isConsumed()) { break; } @@ -245,7 +259,8 @@ public void update(SolApplication solApplication) { } } - for (NUIScreenLayer uiScreen : uiScreens) { + // Create a copy of the list, as screens may be removed during update. + for (NUIScreenLayer uiScreen : new LinkedList<>(uiScreens)) { uiScreen.update(Gdx.graphics.getDeltaTime()); } } @@ -280,18 +295,57 @@ public NUIScreenLayer getTopScreen() { return uiScreens.peek(); } + /** + * Loads a UI screen from the specified asset and returns it. + * If the screen has not been previously loaded, then it is initialised. + * + * If the screen cannot be loaded, then the method may throw a RuntimeException. + * If the UI element loaded is not a UI screen itself, then the method may throw an IllegalArgumentException. + * @param uri the screen to load + * @return the loaded screen + */ + public NUIScreenLayer createScreen(String uri) { + boolean alreadyLoaded = Assets.isLoaded(uri, UIElement.class); + UIWidget rootWidget = Assets.getUIElement(uri).getRootWidget(); + if (rootWidget instanceof NUIScreenLayer) { + NUIScreenLayer screen = (NUIScreenLayer) rootWidget; + if (!alreadyLoaded) { + // Populate all @In annotated fields in the screen class with values from the context. + InjectionHelper.inject(screen, context); + screen.setFocusManager(focusManager); + screen.setNuiManager(this); + screen.initialise(); + } + return screen; + } else { + throw new IllegalArgumentException("Asset " + uri + " is not a UI screen!"); + } + } + /** * Pushes a screen onto the UI stack. * @param layer the screen to add */ public void pushScreen(NUIScreenLayer layer) { uiScreens.push(layer); + layer.onAdded(); + } - // Populate all @In annotated fields in the layer class with values from the context. - InjectionHelper.inject(layer, context); - layer.setFocusManager(focusManager); - layer.setNuiManager(this); - layer.initialise(); + /** + * Replaces the entire UI stack with the specified screen. + * + * This is generally not desirable behaviour, however, it can be useful for flows + * where only one screen is shown at a time, such as in the main menu. + * @param layer the screen to add + */ + public void setScreen(NUIScreenLayer layer) { + Iterator screenIterator = uiScreens.descendingIterator(); + while (screenIterator.hasNext()) { + screenIterator.next().onRemoved(); + screenIterator.remove(); + } + + pushScreen(layer); } /** @@ -408,6 +462,44 @@ public void setUiScale(float scale) { canvasRenderer.setUiScale(1.0f / actualScale); } + /** + * Returns a wrapper that allows safe usage of {@link UiDrawer} code with widget draw calls. + * @return a {@link UiDrawer} wrapper for accessing legacy UI screens + */ + public LegacyUiDrawerWrapper getLegacyUiDrawer() { + return new LegacyUiDrawerWrapper(uiDrawer, canvasRenderer); + } + + /** + * This class acts as a wrapper to safely allow {@link UiDrawer} code to be called in {@link org.terasology.nui.UIWidget#onDraw(Canvas)} methods. + * The wrapper must be closed after use and no NUI canvas methods can be used before closing the wrapper. + * Example usage: + * + * try (NUIManager.LegacyUiDrawerWrapper wrapper = nuiManager.getLegacyUiDrawer()) { + * legacyUiScreen.draw(wrapper.getUiDrawer()); + * } + * + */ + public static class LegacyUiDrawerWrapper implements Closeable { + private final UiDrawer uiDrawer; + private final CanvasRenderer canvasRenderer; + + public LegacyUiDrawerWrapper(UiDrawer uiDrawer, CanvasRenderer canvasRenderer) { + this.uiDrawer = uiDrawer; + this.canvasRenderer = canvasRenderer; + canvasRenderer.postRender(); + } + + public UiDrawer getUiDrawer() { + return uiDrawer; + } + + @Override + public void close() { + canvasRenderer.preRender(); + } + } + private class SolCanvas extends CanvasImpl { public SolCanvas(CanvasRenderer renderer, FocusManager focusManager, KeyboardDevice keyboard, MouseDevice mouse, UITextureRegion whiteTexture, UISkin defaultSkin, int uiScale) { super(renderer, focusManager, keyboard, mouse, whiteTexture, defaultSkin, uiScale); diff --git a/engine/src/main/java/org/destinationsol/ui/nui/NUIScreenLayer.java b/engine/src/main/java/org/destinationsol/ui/nui/NUIScreenLayer.java index e83a02b7b..84223b44e 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/NUIScreenLayer.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/NUIScreenLayer.java @@ -138,11 +138,18 @@ public boolean onKeyEvent(NUIKeyEvent event) { /** * Called to initialise the UI screen, allowing it to register widget callbacks and assign widget values - * programmatically. This is called whenever the UI screen becomes visible. + * programmatically. */ public void initialise() { } + /** + * Called when the UI screen is added to the UI stack. + * This method can be called multiple times, so initialisation should only occur in {@link #initialise()}. + */ + public void onAdded() { + } + /** * Called when the UI screen is removed from display. */ diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/ConsoleScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/ConsoleScreen.java index 8d3ccce37..7e4a4d7a6 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/screens/ConsoleScreen.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/ConsoleScreen.java @@ -55,50 +55,46 @@ public boolean onMouseClick(NUIMouseClickEvent event) { @Override public void initialise() { - screenClosed = false; + console = ConsoleImpl.instance; - if (!welcomePrinted) { - console = ConsoleImpl.instance; + final ScrollableArea scrollArea = find("scrollArea", ScrollableArea.class); + scrollArea.moveToBottom(); - final ScrollableArea scrollArea = find("scrollArea", ScrollableArea.class); + commandLine = find("commandLine", UICommandEntry.class); + commandLine.setTabCompletionEngine(new CyclingTabCompletionEngine(console)); + commandLine.bindCommandHistory(new ReadOnlyBinding>() { + @Override + public List get() { + return console.getPreviousCommands(); + } + }); + commandLine.subscribe(widget -> { + String text = commandLine.getText(); + if (!text.isEmpty()) { + console.execute(text); + } scrollArea.moveToBottom(); - - commandLine = find("commandLine", UICommandEntry.class); - commandLine.setTabCompletionEngine(new CyclingTabCompletionEngine(console)); - commandLine.bindCommandHistory(new ReadOnlyBinding>() { - @Override - public List get() { - return console.getPreviousCommands(); - } - }); - commandLine.subscribe(widget -> { - String text = commandLine.getText(); - if (!text.isEmpty()) { - console.execute(text); + }); + + final UIText history = find("messageHistory", UIText.class); + history.bindText(new ReadOnlyBinding() { + @Override + public String get() { + StringBuilder messageList = new StringBuilder(); + for (Message message : console.getMessages()) { + messageList.append(FontColor.getColored(message.getMessage(), new org.terasology.nui.Color(message.getType().getColor().toIntBits()))); + messageList.append(Console.NEW_LINE); } - scrollArea.moveToBottom(); - }); - - final UIText history = find("messageHistory", UIText.class); - history.bindText(new ReadOnlyBinding() { - @Override - public String get() { - StringBuilder messageList = new StringBuilder(); - for (Message message : console.getMessages()) { - messageList.append(FontColor.getColored(message.getMessage(), new org.terasology.nui.Color(message.getType().getColor().toIntBits()))); - messageList.append(Console.NEW_LINE); - } - return messageList.toString(); - } - }); - - onOpened(); - } + return messageList.toString(); + } + }); - focusManager.setFocus(commandLine); + welcomePrinted = false; } - public void onOpened() { + @Override + public void onAdded() { + screenClosed = false; if (!welcomePrinted) { console.addMessage("Welcome to the world of Destination Sol! Your journey begins!" + Console.NEW_LINE + "Type 'help' to see a list with available commands or 'help ' for command details." + Console.NEW_LINE + @@ -110,6 +106,11 @@ public void onOpened() { "gM + [tab] => 'godMode' (camel casing abbreviated commands)" + Console.NEW_LINE); welcomePrinted = true; } + + final ScrollableArea scrollArea = find("scrollArea", ScrollableArea.class); + scrollArea.moveToBottom(); + + focusManager.setFocus(commandLine); } @Override diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java index 0e4337470..b72049d1d 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java @@ -60,7 +60,7 @@ public class MainGameScreen extends NUIScreenLayer { @Override public void initialise() { - consoleScreen = (ConsoleScreen) Assets.getAssetHelper().get(new ResourceUrn("engine:console"), UIElement.class).get().getRootWidget(); + consoleScreen = (ConsoleScreen) nuiManager.createScreen("engine:console"); GameOptions gameOptions = solApplication.getOptions(); diff --git a/engine/src/main/java/org/destinationsol/menu/CreditsScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/CreditsScreen.java similarity index 60% rename from engine/src/main/java/org/destinationsol/menu/CreditsScreen.java rename to engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/CreditsScreen.java index 535e63ff0..07df92df9 100644 --- a/engine/src/main/java/org/destinationsol/menu/CreditsScreen.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/CreditsScreen.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 MovingBlocks + * Copyright 2021 The Terasology Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,47 +13,40 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.destinationsol.menu; +package org.destinationsol.ui.nui.screens.mainMenu; -import com.badlogic.gdx.graphics.Color; -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; import org.destinationsol.Const; -import org.destinationsol.GameOptions; import org.destinationsol.SolApplication; -import org.destinationsol.assets.Assets; -import org.destinationsol.common.SolColor; -import org.destinationsol.common.SolMath; -import org.destinationsol.ui.DisplayDimensions; -import org.destinationsol.ui.FontSize; -import org.destinationsol.ui.SolInputManager; -import org.destinationsol.ui.SolUiBaseScreen; -import org.destinationsol.ui.SolUiControl; -import org.destinationsol.ui.UiDrawer; +import org.destinationsol.common.In; +import org.destinationsol.ui.nui.NUIManager; +import org.destinationsol.ui.nui.NUIScreenLayer; +import org.destinationsol.ui.nui.widgets.KeyActivatedButton; +import org.joml.Math; +import org.terasology.nui.Canvas; +import org.terasology.nui.Color; +import org.terasology.nui.backends.libgdx.GDXInputUtil; +import org.terasology.nui.skin.UISkin; +import org.terasology.nui.skin.UISkinBuilder; +import org.terasology.nui.widgets.UILabel; import java.util.ArrayList; -public class CreditsScreen extends SolUiBaseScreen { +public class CreditsScreen extends NUIScreenLayer { private static final float MAX_AWAIT = 6f; - private final TextureAtlas.AtlasRegion backgroundTexture; - private final SolUiControl closeControl; - - private DisplayDimensions displayDimensions; - - private final ArrayList myPages = new ArrayList<>(); - private final Color myColor; + @In + private SolApplication solApplication; + private UILabel creditsText; + private ArrayList myPages = new ArrayList<>(); + private UISkin textSkin; + private Color textColor; private int pageIndex; private float pageProgressPercent; - CreditsScreen(GameOptions gameOptions) { - displayDimensions = SolApplication.displayDimensions; - - closeControl = new SolUiControl(MenuLayout.bottomRightFloatingButton(displayDimensions), true, gameOptions.getKeyEscape()); - closeControl.setDisplayName("Close"); - controls.add(closeControl); - myColor = SolColor.col(1, 1); + @Override + public void initialise() { + textColor = new Color(Color.white); - String[][] sss = { + String[][] creditsSections = { { "A game from", "", @@ -117,30 +110,44 @@ public class CreditsScreen extends SolUiBaseScreen { "Steveygos93", }, }; - for (String[] ss : sss) { + + for (String[] creditsSection : creditsSections) { StringBuilder page = new StringBuilder(); - for (String s : ss) { - page.append(s).append("\n"); + for (String creditsLine : creditsSection) { + page.append(creditsLine).append("\n"); } myPages.add(page.toString()); } - backgroundTexture = Assets.getAtlasRegion("engine:mainMenuBg", Texture.TextureFilter.Linear); + creditsText = find("creditsText", UILabel.class); + textSkin = new UISkinBuilder() + .setBaseSkin(getSkin()) + .setFamily(creditsText.getFamily()) + .setTextColor(textColor) + .setTextShadowColor(new Color(Color.transparent)) + .build(); + creditsText.setSkin(textSkin); + + KeyActivatedButton cancelButton = find("cancelButton", KeyActivatedButton.class); + cancelButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyEscape())); + cancelButton.subscribe(button -> { + nuiManager.setScreen(solApplication.getMenuScreens().main); + }); } @Override - public void onAdd(SolApplication solApplication) { + public void onAdded() { pageIndex = 0; pageProgressPercent = 0; - myColor.a = 0; + textColor.setAlpha(0.0f); + + creditsText.setText(myPages.get(pageIndex)); } @Override - public void updateCustom(SolApplication solApplication, SolInputManager.InputPointer[] inputPointers, boolean clickedOutside) { - if (closeControl.isJustOff()) { - solApplication.getInputManager().setScreen(solApplication, solApplication.getMenuScreens().main); - return; - } + public void update(float delta) { + super.update(delta); + pageProgressPercent += Const.REAL_TIME_STEP / MAX_AWAIT; if (pageProgressPercent > 1) { pageProgressPercent = 0; @@ -148,25 +155,31 @@ public void updateCustom(SolApplication solApplication, SolInputManager.InputPoi if (pageIndex >= myPages.size()) { pageIndex = 0; } + creditsText.setText(myPages.get(pageIndex)); } - float a = pageProgressPercent * 2; - if (a > 1) { - a = 2 - a; + float alpha = pageProgressPercent * 2; + if (alpha > 1) { + alpha = 2 - alpha; } - a *= 3; - myColor.a = SolMath.clamp(a); + alpha *= 3; + textColor.setAlpha(Math.clamp(0.0f, 1.0f, alpha)); + textSkin.getDefaultStyleFor(creditsText.getFamily()).setTextColor(textColor); solApplication.getMenuBackgroundManager().update(); } @Override - public void drawBackground(UiDrawer uiDrawer, SolApplication solApplication) { - uiDrawer.draw(backgroundTexture, displayDimensions.getRatio(), 1, displayDimensions.getRatio() / 2, 0.5f, displayDimensions.getRatio() / 2, 0.5f, 0, SolColor.WHITE); - solApplication.getMenuBackgroundManager().draw(uiDrawer); + public void onDraw(Canvas canvas) { + try (NUIManager.LegacyUiDrawerWrapper wrapper = nuiManager.getLegacyUiDrawer()) { + solApplication.getMenuBackgroundManager().draw(wrapper.getUiDrawer()); + } + + super.onDraw(canvas); } @Override - public void drawText(UiDrawer uiDrawer, SolApplication solApplication) { - uiDrawer.drawString(myPages.get(pageIndex), displayDimensions.getRatio() / 2, .5f, FontSize.MENU, true, myColor); + protected boolean escapeCloses() { + return false; } + } diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/InputMapScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/InputMapScreen.java new file mode 100644 index 000000000..c6250ca43 --- /dev/null +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/InputMapScreen.java @@ -0,0 +1,245 @@ +/* + * Copyright 2021 The Terasology Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.destinationsol.ui.nui.screens.mainMenu; + +import org.destinationsol.Const; +import org.destinationsol.SolApplication; +import org.destinationsol.common.In; +import org.destinationsol.menu.InputConfigItem; +import org.destinationsol.menu.InputMapControllerScreen; +import org.destinationsol.menu.InputMapKeyboardScreen; +import org.destinationsol.menu.InputMapMixedScreen; +import org.destinationsol.menu.InputMapOperations; +import org.destinationsol.ui.nui.NUIManager; +import org.destinationsol.ui.nui.NUIScreenLayer; +import org.destinationsol.ui.nui.widgets.KeyActivatedButton; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.terasology.nui.Canvas; +import org.terasology.nui.UIWidget; +import org.terasology.nui.backends.libgdx.GDXInputUtil; +import org.terasology.nui.layouts.ColumnLayout; +import org.terasology.nui.layouts.RowLayout; +import org.terasology.nui.layouts.RowLayoutHint; +import org.terasology.nui.layouts.relative.RelativeLayout; +import org.terasology.nui.widgets.UIBox; +import org.terasology.nui.widgets.UIButton; +import org.terasology.nui.widgets.UILabel; + +import java.util.Iterator; +import java.util.List; + +/** + * This screen allows the user to re-map the key bindings used for in-game controls. + * It is accessible via the {@link OptionsScreen}. + */ +public class InputMapScreen extends NUIScreenLayer { + private static final Logger logger = LoggerFactory.getLogger(InputMapScreen.class); + @In + private SolApplication solApplication; + private UILabel titleLabel; + private ColumnLayout inputMapRows; + private KeyActivatedButton nextButton; + private KeyActivatedButton previousButton; + private RelativeLayout keyPressOverlay; + private UILabel keyPressMessage; + private InputMapOperations inputOperations; + private InputMapKeyboardScreen inputMapKeyboardScreen; + private InputMapControllerScreen inputMapControllerScreen; + private InputMapMixedScreen inputMapMixedScreen; + private int selectedIndex; + private UIWidget selectedRow; + private int page; + + @Override + public void initialise() { + titleLabel = find("title", UILabel.class); + + inputMapRows = find("inputMapRows", ColumnLayout.class); + + nextButton = find("nextButton", KeyActivatedButton.class); + nextButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyRight())); + nextButton.subscribe(button -> { + int inputCount = inputOperations.getItems(solApplication.getOptions()).size(); + selectedIndex += Const.ITEM_GROUPS_PER_PAGE; + page++; + button.setEnabled((selectedIndex + Const.ITEM_GROUPS_PER_PAGE) < inputCount); + previousButton.setEnabled(true); + + updateInputRows(); + }); + + previousButton = find("previousButton", KeyActivatedButton.class); + previousButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyLeft())); + previousButton.subscribe(button -> { + selectedIndex -= Const.ITEM_GROUPS_PER_PAGE; + page--; + button.setEnabled(selectedIndex >= Const.ITEM_GROUPS_PER_PAGE); + nextButton.setEnabled(true); + + updateInputRows(); + }); + + for (int inputNo = selectedIndex; inputNo < Const.ITEM_GROUPS_PER_PAGE; inputNo++) { + inputMapRows.addWidget(createInputMapRow(inputNo)); + } + + UIButton resetButton = find("defaultsButton", UIButton.class); + resetButton.subscribe(button -> { + inputOperations.resetToDefaults(solApplication.getOptions()); + updateInputRows(); + }); + + UIButton saveButton = find("saveButton", UIButton.class); + saveButton.subscribe(button -> { + inputOperations.save(solApplication.getOptions()); + nuiManager.setScreen(solApplication.getMenuScreens().options); + }); + + KeyActivatedButton cancelButton = find("cancelButton", KeyActivatedButton.class); + cancelButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyEscape())); + cancelButton.subscribe(button -> { + if (inputOperations.isEnterNewKey()) { + // Cancel new input assignment if present (press escape to keep the current assignment) + inputOperations.setEnterNewKey(false); + return; + } + + nuiManager.setScreen(solApplication.getMenuScreens().options); + }); + + keyPressOverlay = find("keyPressOverlay", RelativeLayout.class); + keyPressMessage = keyPressOverlay.find("keyPressMessage", UILabel.class); + + inputMapKeyboardScreen = new InputMapKeyboardScreen(); + inputMapControllerScreen = new InputMapControllerScreen(); + inputMapMixedScreen = new InputMapMixedScreen(); + } + + @Override + public void onAdded() { + if (inputOperations == null) { + logger.error("You must call setOperations before adding InputMapScreen!"); + nuiManager.setScreen(solApplication.getMenuScreens().options); + return; + } + + titleLabel.setText(inputOperations.getHeader()); + + selectedIndex = 0; + selectedRow = null; + page = 0; + keyPressOverlay.setVisible(false); + inputOperations.onAdd(solApplication); + + List inputs = inputOperations.getItems(solApplication.getOptions()); + nextButton.setEnabled(Const.ITEM_GROUPS_PER_PAGE < inputs.size()); + previousButton.setEnabled(false); + + updateInputRows(); + } + + @Override + public void update(float delta) { + super.update(delta); + + if (selectedRow != null) { + UIButton assignButton = selectedRow.find("assignButton", UIButton.class); + assignButton.setActive(inputOperations.isEnterNewKey()); + if (!inputOperations.isEnterNewKey()) { + selectedRow = null; + assignButton.setText(inputOperations.getItems(solApplication.getOptions()).get(inputOperations.getSelectedIndex()).getInputKey()); + updateInputRows(); + keyPressOverlay.setVisible(false); + } + } + + solApplication.getMenuBackgroundManager().update(); + } + + @Override + public void onDraw(Canvas canvas) { + try (NUIManager.LegacyUiDrawerWrapper wrapper = nuiManager.getLegacyUiDrawer()) { + solApplication.getMenuBackgroundManager().draw(wrapper.getUiDrawer()); + } + + super.onDraw(canvas); + } + + public void setOperations(InputMapOperations operations) { + this.inputOperations = operations; + } + + public InputMapKeyboardScreen getInputMapKeyboardScreen() { + return inputMapKeyboardScreen; + } + + public InputMapControllerScreen getInputMapControllerScreen() { + return inputMapControllerScreen; + } + + public InputMapMixedScreen getInputMapMixedScreen() { + return inputMapMixedScreen; + } + + @Override + protected boolean escapeCloses() { + return false; + } + + private UIWidget createInputMapRow(int index) { + RowLayout rowLayout = new RowLayout(); + rowLayout.setFamily("inputMapRow"); + UIBox inputNameBox = new UIBox(); + inputNameBox.setContent(new UILabel("inputName", "Input")); + rowLayout.addWidget(inputNameBox, new RowLayoutHint().setRelativeWidth(0.6f)); + UIButton assignButton = new UIButton("assignButton", ""); + assignButton.subscribe(button -> { + inputOperations.setSelectedIndex(index + (page * Const.ITEM_GROUPS_PER_PAGE)); + inputOperations.setEnterNewKey(true); + selectedRow = button; + updateInputRows(); + keyPressMessage.setText(inputOperations.getDisplayDetail()); + keyPressOverlay.setVisible(true); + }); + rowLayout.addWidget(assignButton, new RowLayoutHint().setRelativeWidth(0.4f)); + return rowLayout; + } + + private void updateInputRows() { + List inputs = inputOperations.getItems(solApplication.getOptions()); + Iterator rowsIterator = inputMapRows.iterator(); + rowsIterator.next(); // Ignore the first row, since it's the header. + UIWidget row = rowsIterator.next(); + for (int inputNo = selectedIndex; inputNo < selectedIndex + Const.ITEM_GROUPS_PER_PAGE; inputNo++) { + boolean emptyRow = inputNo >= inputs.size(); + boolean enabled = !(inputOperations.isEnterNewKey() || emptyRow); + + UILabel inputNameLabel = row.find("inputName", UILabel.class); + inputNameLabel.setText(emptyRow ? "" : inputs.get(inputNo).getDisplayName()); + inputNameLabel.setEnabled(enabled); + + UIButton assignButton = row.find("assignButton", UIButton.class); + assignButton.setText(emptyRow ? "" : inputs.get(inputNo).getInputKey()); + assignButton.setActive(inputOperations.getSelectedIndex() == inputNo && inputOperations.isEnterNewKey()); + assignButton.setEnabled(assignButton.isActive() || enabled); + + if (rowsIterator.hasNext()) { + row = rowsIterator.next(); + } + } + } +} diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/LoadingScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/LoadingScreen.java new file mode 100644 index 000000000..ab9fb8818 --- /dev/null +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/LoadingScreen.java @@ -0,0 +1,58 @@ +/* + * Copyright 2021 The Terasology Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.destinationsol.ui.nui.screens.mainMenu; + +import org.destinationsol.SolApplication; +import org.destinationsol.common.In; +import org.destinationsol.game.WorldConfig; +import org.destinationsol.ui.nui.NUIScreenLayer; + +public class LoadingScreen extends NUIScreenLayer { + @In + private SolApplication solApplication; + private boolean loadTutorial; + private boolean isNewGame; + private String shipName; + private WorldConfig worldConfig; + private boolean firstUpdate; + + @Override + public void onAdded() { + firstUpdate = false; + } + + @Override + public void update(float delta) { + // Only start the long-running solApplication.play call after the first draw has been made. + if (!firstUpdate) { + firstUpdate = true; + } else { + solApplication.play(loadTutorial, shipName, isNewGame, worldConfig); + } + } + + public void setMode(boolean loadTutorial, String shipName, boolean isNewGame, WorldConfig worldConfig) { + this.loadTutorial = loadTutorial; + this.shipName = shipName; + this.isNewGame = isNewGame; + this.worldConfig = worldConfig; + } + + @Override + protected boolean escapeCloses() { + return false; + } +} diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/MainMenuScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/MainMenuScreen.java new file mode 100644 index 000000000..edd6666c6 --- /dev/null +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/MainMenuScreen.java @@ -0,0 +1,100 @@ +/* + * Copyright 2021 The Terasology Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.destinationsol.ui.nui.screens.mainMenu; + +import com.badlogic.gdx.Gdx; +import org.destinationsol.GameOptions; +import org.destinationsol.SolApplication; +import org.destinationsol.assets.music.OggMusicManager; +import org.destinationsol.common.In; +import org.destinationsol.game.WorldConfig; +import org.destinationsol.ui.nui.NUIManager; +import org.destinationsol.ui.nui.NUIScreenLayer; +import org.terasology.nui.Canvas; +import org.terasology.nui.widgets.UIButton; + +/** + * The main menu screen. This is the first screen shown when you open the game. + */ +public class MainMenuScreen extends NUIScreenLayer { + @In + private SolApplication solApplication; + private UIButton tutorialButton; + + @Override + public void initialise() { + tutorialButton = find("tutorialButton", UIButton.class); + tutorialButton.subscribe(button -> { + solApplication.getMenuScreens().loading.setMode(true, "Imperial Small", true, new WorldConfig()); + nuiManager.setScreen(solApplication.getMenuScreens().loading); + }); + + UIButton playGameButton = find("playGameButton", UIButton.class); + playGameButton.subscribe(button -> { + nuiManager.setScreen(solApplication.getMenuScreens().newGame); + }); + + UIButton optionsButton = find("optionsButton", UIButton.class); + optionsButton.subscribe(button -> { + nuiManager.pushScreen(solApplication.getMenuScreens().options); + nuiManager.removeScreen(this); + }); + + UIButton exitButton = find("exitButton", UIButton.class); + exitButton.subscribe(button -> { + if (!solApplication.isMobile()) { + solApplication.getOptions().save(); + } + Gdx.app.exit(); + nuiManager.removeScreen(this); + }); + + UIButton creditsButton = find("creditsButton", UIButton.class); + creditsButton.subscribe(button -> { + nuiManager.setScreen(solApplication.getMenuScreens().credits); + }); + } + + @Override + public void onAdded() { + final OggMusicManager musicManager = solApplication.getMusicManager(); + if (!musicManager.getCurrentMusicSet().equals(OggMusicManager.MENU_MUSIC_SET)) { + musicManager.playMusic(OggMusicManager.MENU_MUSIC_SET, solApplication.getOptions()); + } + + tutorialButton.setEnabled(solApplication.getOptions().controlType != GameOptions.ControlType.CONTROLLER); + } + + @Override + public void update(float delta) { + super.update(delta); + solApplication.getMenuBackgroundManager().update(); + } + + @Override + public void onDraw(Canvas canvas) { + try (NUIManager.LegacyUiDrawerWrapper wrapper = nuiManager.getLegacyUiDrawer()) { + solApplication.getMenuBackgroundManager().draw(wrapper.getUiDrawer()); + } + + super.onDraw(canvas); + } + + @Override + protected boolean escapeCloses() { + return false; + } +} diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/NewGameScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/NewGameScreen.java new file mode 100644 index 000000000..557325774 --- /dev/null +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/NewGameScreen.java @@ -0,0 +1,87 @@ +/* + * Copyright 2021 The Terasology Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.destinationsol.ui.nui.screens.mainMenu; + +import org.destinationsol.SolApplication; +import org.destinationsol.common.In; +import org.destinationsol.game.SaveManager; +import org.destinationsol.game.WorldConfig; +import org.destinationsol.ui.nui.NUIManager; +import org.destinationsol.ui.nui.NUIScreenLayer; +import org.destinationsol.ui.nui.widgets.KeyActivatedButton; +import org.terasology.input.Keyboard; +import org.terasology.nui.Canvas; +import org.terasology.nui.UIWidget; +import org.terasology.nui.backends.libgdx.GDXInputUtil; +import org.terasology.nui.widgets.UIButton; + +public class NewGameScreen extends NUIScreenLayer { + @In + private SolApplication solApplication; + private KeyActivatedButton continueButton; + private UIButton newGameButton; + private KeyActivatedButton cancelButton; + + @Override + public void initialise() { + super.initialise(); + + continueButton = find("continueButton", KeyActivatedButton.class); + continueButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyShoot())); + continueButton.setEnabled(SaveManager.hasPreviousCompatibleShip()); + continueButton.subscribe(button -> { + solApplication.getMenuScreens().loading.setMode(false, null, false, + SaveManager.loadWorld().orElseGet(WorldConfig::new)); + nuiManager.setScreen(solApplication.getMenuScreens().loading); + }); + + newGameButton = find("newGameButton", UIButton.class); + newGameButton.subscribe(button -> { + nuiManager.setScreen(solApplication.getMenuScreens().newShip); + }); + + cancelButton = find("cancelButton", KeyActivatedButton.class); + cancelButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyEscape())); + cancelButton.subscribe(button -> { + nuiManager.setScreen(solApplication.getMenuScreens().main); + }); + } + + @Override + public void onAdded() { + continueButton.setEnabled(SaveManager.hasPreviousCompatibleShip()); + } + + @Override + public void update(float delta) { + super.update(delta); + solApplication.getMenuBackgroundManager().update(); + } + + @Override + public void onDraw(Canvas canvas) { + try (NUIManager.LegacyUiDrawerWrapper wrapper = nuiManager.getLegacyUiDrawer()) { + solApplication.getMenuBackgroundManager().draw(wrapper.getUiDrawer()); + } + + super.onDraw(canvas); + } + + @Override + protected boolean escapeCloses() { + return false; + } +} diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/NewShipScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/NewShipScreen.java new file mode 100644 index 000000000..e67c58a2b --- /dev/null +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/NewShipScreen.java @@ -0,0 +1,105 @@ +/* + * Copyright 2021 The Terasology Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.destinationsol.ui.nui.screens.mainMenu; + +import org.destinationsol.SolApplication; +import org.destinationsol.assets.Assets; +import org.destinationsol.assets.json.Json; +import org.destinationsol.assets.json.Validator; +import org.destinationsol.common.In; +import org.destinationsol.game.WorldConfig; +import org.destinationsol.game.planet.SystemsBuilder; +import org.destinationsol.ui.nui.NUIManager; +import org.destinationsol.ui.nui.NUIScreenLayer; +import org.destinationsol.ui.nui.widgets.KeyActivatedButton; +import org.terasology.gestalt.assets.ResourceUrn; +import org.terasology.nui.Canvas; +import org.terasology.nui.backends.libgdx.GDXInputUtil; +import org.terasology.nui.widgets.UIButton; + +import java.util.ArrayList; +import java.util.List; + +public class NewShipScreen extends NUIScreenLayer { + @In + private SolApplication solApplication; + private int numberOfSystems = SystemsBuilder.DEFAULT_SYSTEM_COUNT; + private int playerSpawnConfigIndex = 0; + private List playerSpawnConfigNames = new ArrayList<>(); + + @Override + public void initialise() { + UIButton systemsButton = find("systemsButton", UIButton.class); + systemsButton.setText("Systems: " + numberOfSystems); + systemsButton.subscribe(button -> { + int systemCount = (numberOfSystems + 1) % 10; + if (systemCount < 2) { + systemCount = 2; + } + numberOfSystems = systemCount; + ((UIButton)button).setText("Systems: " + numberOfSystems); + }); + + for (ResourceUrn configUrn : Assets.getAssetHelper().listAssets(Json.class, "playerSpawnConfig")) { + playerSpawnConfigNames.addAll(Validator.getValidatedJSON(configUrn.toString(), "engine:schemaPlayerSpawnConfig").keySet()); + } + + UIButton startingShipButton = find("startingShipButton", UIButton.class); + startingShipButton.setText("Starting Ship: " + playerSpawnConfigNames.get(playerSpawnConfigIndex)); + startingShipButton.subscribe(button -> { + playerSpawnConfigIndex = (playerSpawnConfigIndex + 1) % playerSpawnConfigNames.size(); + ((UIButton)button).setText("Starting Ship: " + playerSpawnConfigNames.get(playerSpawnConfigIndex)); + }); + + // NOTE: The original code used getKeyEscape() for both the "OK" and "Cancel" buttons. This was probably a mistake. + KeyActivatedButton okButton = find("okButton", KeyActivatedButton.class); + okButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyShoot())); + okButton.subscribe(button -> { + WorldConfig worldConfig = new WorldConfig(); + worldConfig.setNumberOfSystems(numberOfSystems); + + LoadingScreen loadingScreen = solApplication.getMenuScreens().loading; + loadingScreen.setMode(false, playerSpawnConfigNames.get(playerSpawnConfigIndex), true, worldConfig); + nuiManager.setScreen(loadingScreen); + }); + + KeyActivatedButton cancelButton = find("cancelButton", KeyActivatedButton.class); + cancelButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyEscape())); + cancelButton.subscribe(button -> { + nuiManager.setScreen(solApplication.getMenuScreens().newGame); + }); + } + + @Override + public void update(float delta) { + super.update(delta); + solApplication.getMenuBackgroundManager().update(); + } + + @Override + public void onDraw(Canvas canvas) { + try (NUIManager.LegacyUiDrawerWrapper wrapper = nuiManager.getLegacyUiDrawer()) { + solApplication.getMenuBackgroundManager().draw(wrapper.getUiDrawer()); + } + + super.onDraw(canvas); + } + + @Override + protected boolean escapeCloses() { + return false; + } +} diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/OptionsScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/OptionsScreen.java new file mode 100644 index 000000000..314cbbd9a --- /dev/null +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/OptionsScreen.java @@ -0,0 +1,125 @@ +/* + * Copyright 2021 The Terasology Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.destinationsol.ui.nui.screens.mainMenu; + +import org.destinationsol.SolApplication; +import org.destinationsol.common.In; +import org.destinationsol.menu.MenuScreens; +import org.destinationsol.ui.nui.NUIManager; +import org.destinationsol.ui.nui.NUIScreenLayer; +import org.destinationsol.ui.nui.widgets.KeyActivatedButton; +import org.terasology.nui.Canvas; +import org.terasology.nui.backends.libgdx.GDXInputUtil; +import org.terasology.nui.layouts.ColumnLayout; +import org.terasology.nui.widgets.UIButton; + +/** + * The options screen allows the user to change configurable game settings through the UI. + * It is accessible via the {@link MainMenuScreen}. + */ +public class OptionsScreen extends NUIScreenLayer { + @In + private SolApplication solApplication; + + @Override + public void initialise() { + ColumnLayout menuButtonsLayout = find("menuButtons", ColumnLayout.class); + + UIButton musicVolumeButton = find("musicVolumeButton", UIButton.class); + musicVolumeButton.setText("Music Volume: " + solApplication.getOptions().musicVolume.getName()); + musicVolumeButton.subscribe(button -> { + solApplication.getOptions().advanceMusicVolMul(); + musicVolumeButton.setText("Music Volume: " + solApplication.getOptions().musicVolume.getName()); + solApplication.getMusicManager().changeVolume(solApplication.getOptions()); + }); + + UIButton soundVolumeButton = find("soundVolumeButton", UIButton.class); + soundVolumeButton.setText("Sound Volume: " + solApplication.getOptions().sfxVolume.getName()); + soundVolumeButton.subscribe(button -> { + solApplication.getOptions().advanceMusicVolMul(); + soundVolumeButton.setText("Sound Volume: " + solApplication.getOptions().sfxVolume.getName()); + }); + + UIButton resolutionButton = find("resolutionButton", UIButton.class); + resolutionButton.subscribe(button -> { + nuiManager.setScreen(solApplication.getMenuScreens().resolutionScreen); + }); + + UIButton mapPanSpeedButton = find("mapPanSpeedButton", UIButton.class); + mapPanSpeedButton.setText("Map Pan Speed: " + solApplication.getOptions().getMapScrollSpeed()); + mapPanSpeedButton.subscribe(button -> { + solApplication.getOptions().advanceMapScrollSpeed(); + mapPanSpeedButton.setText("Map Pan Speed: " + solApplication.getOptions().getMapScrollSpeed()); + }); + + KeyActivatedButton controlTypeButton = find("controlTypeButton", KeyActivatedButton.class); + if (solApplication.isMobile()) { + menuButtonsLayout.removeWidget(controlTypeButton); + } else { + controlTypeButton.setText("Input: " + solApplication.getOptions().controlType.getHumanName()); + controlTypeButton.subscribe(button -> { + solApplication.getOptions().advanceControlType(false); + controlTypeButton.setText("Input: " + solApplication.getOptions().controlType.getHumanName()); + }); + } + + KeyActivatedButton controlsButton = find("controlsButton", KeyActivatedButton.class); + if (solApplication.isMobile()) { + menuButtonsLayout.removeWidget(controlsButton); + } else { + controlsButton.subscribe(button -> { + InputMapScreen inputMapScreen = solApplication.getMenuScreens().inputMapScreen; + switch (solApplication.getOptions().controlType) { + case KEYBOARD: + inputMapScreen.setOperations(inputMapScreen.getInputMapKeyboardScreen()); + break; + case MIXED: + inputMapScreen.setOperations(inputMapScreen.getInputMapMixedScreen()); + break; + case CONTROLLER: + inputMapScreen.setOperations(inputMapScreen.getInputMapControllerScreen()); + } + nuiManager.setScreen(inputMapScreen); + }); + } + + KeyActivatedButton cancelButton = find("cancelButton", KeyActivatedButton.class); + cancelButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyEscape())); + cancelButton.subscribe(button -> { + nuiManager.setScreen(solApplication.getMenuScreens().main); + }); + } + + @Override + public void update(float delta) { + super.update(delta); + solApplication.getMenuBackgroundManager().update(); + } + + @Override + public void onDraw(Canvas canvas) { + try (NUIManager.LegacyUiDrawerWrapper wrapper = nuiManager.getLegacyUiDrawer()) { + solApplication.getMenuBackgroundManager().draw(wrapper.getUiDrawer()); + } + + super.onDraw(canvas); + } + + @Override + protected boolean escapeCloses() { + return false; + } +} diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/ResolutionScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/ResolutionScreen.java new file mode 100644 index 000000000..8bfbcf796 --- /dev/null +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/ResolutionScreen.java @@ -0,0 +1,129 @@ +/* + * Copyright 2021 The Terasology Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.destinationsol.ui.nui.screens.mainMenu; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Graphics; +import org.destinationsol.SolApplication; +import org.destinationsol.common.In; +import org.destinationsol.ui.nui.NUIManager; +import org.destinationsol.ui.nui.NUIScreenLayer; +import org.destinationsol.ui.nui.widgets.KeyActivatedButton; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.terasology.nui.Canvas; +import org.terasology.nui.backends.libgdx.GDXInputUtil; +import org.terasology.nui.layouts.ColumnLayout; +import org.terasology.nui.layouts.relative.RelativeLayout; +import org.terasology.nui.widgets.UIButton; + +/** + * The resolution screen allows the user to set the game's screen resolution, fullscreen modes and NUI scaling settings. + * It can be accessed via the {@link OptionsScreen}. + */ +public class ResolutionScreen extends NUIScreenLayer { + private static final Logger logger = LoggerFactory.getLogger(ResolutionScreen.class); + @In + private SolApplication solApplication; + + @Override + public void initialise() { + ColumnLayout menuButtonsLayout = find("menuButtons", ColumnLayout.class); + + UIButton resolutionButton = find("resolutionButton", UIButton.class); + if (solApplication.isMobile()) { + menuButtonsLayout.removeWidget(resolutionButton); + } else { + resolutionButton.setText(solApplication.getOptions().x + "x" + solApplication.getOptions().y); + resolutionButton.subscribe(button -> { + solApplication.getOptions().advanceResolution(); + resolutionButton.setText(solApplication.getOptions().x + "x" + solApplication.getOptions().y); + }); + } + + UIButton fullScreenButton = find("fullScreenButton", UIButton.class); + if (solApplication.isMobile()) { + menuButtonsLayout.removeWidget(fullScreenButton); + } else { + fullScreenButton.setText(solApplication.getOptions().fullscreen ? "Fullscreen" : "Windowed"); + fullScreenButton.subscribe(button -> { + solApplication.getOptions().advanceFullscreen(); + fullScreenButton.setText(solApplication.getOptions().fullscreen ? "Fullscreen" : "Windowed"); + }); + } + + UIButton nuiUIScaleButton = find("nuiUIScaleButton", UIButton.class); + nuiUIScaleButton.setText("NUI UI Scale: " + solApplication.getOptions().getNuiUiScale()); + nuiUIScaleButton.subscribe(button -> { + solApplication.getOptions().advanceNuiUiScale(); + nuiManager.setUiScale(solApplication.getOptions().getNuiUiScale()); + nuiUIScaleButton.setText("NUI UI Scale: " + solApplication.getOptions().getNuiUiScale()); + }); + + KeyActivatedButton cancelButton = find("cancelButton", KeyActivatedButton.class); + cancelButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyEscape())); + cancelButton.subscribe(button -> { + // Mobile only ever runs at one resolution: the entire screen. + // Changing the screen resolution does not work. + if (!solApplication.isMobile()) { + int width = solApplication.getOptions().x; + int height = solApplication.getOptions().y; + if (solApplication.getOptions().fullscreen) { + Graphics.DisplayMode mode = null; + // HACK: Gdx.graphics.getDisplayMode() always returns the native desktop resolution. + // See https://github.com/libgdx/libgdx/blob/5398d46aa082489052fccfaaaff7440e137ba5dc/backends/gdx-backend-lwjgl/src/com/badlogic/gdx/backends/lwjgl/LwjglGraphics.java#L555 + // and http://legacy.lwjgl.org/javadoc/org/lwjgl/opengl/Display.html#getDisplayMode() for more details. + for (Graphics.DisplayMode displayMode : Gdx.graphics.getDisplayModes()) { + if (displayMode.width == width && displayMode.height == height) { + mode = displayMode; + } + } + if (mode != null) { + Gdx.graphics.setFullscreenMode(mode); + nuiManager.resize(mode.width, mode.height); + } else { + logger.warn("The resolution {}x{} is not supported in fullscreen mode!", solApplication.getOptions().x, solApplication.getOptions().y); + } + } else { + Gdx.graphics.setWindowedMode(width, height); + nuiManager.resize(width, height); + } + } + + nuiManager.setScreen(solApplication.getMenuScreens().options); + }); + } + + @Override + public void update(float delta) { + super.update(delta); + solApplication.getMenuBackgroundManager().update(); + } + + @Override + public void onDraw(Canvas canvas) { + try (NUIManager.LegacyUiDrawerWrapper wrapper = nuiManager.getLegacyUiDrawer()) { + solApplication.getMenuBackgroundManager().draw(wrapper.getUiDrawer()); + } + + super.onDraw(canvas); + } + + @Override + protected boolean escapeCloses() { + return false; + } +} diff --git a/engine/src/main/resources/org/destinationsol/assets/skins/default.skin b/engine/src/main/resources/org/destinationsol/assets/skins/default.skin index 30e1c583e..d181c4f13 100644 --- a/engine/src/main/resources/org/destinationsol/assets/skins/default.skin +++ b/engine/src/main/resources/org/destinationsol/assets/skins/default.skin @@ -1,6 +1,6 @@ { "text-shadowed": true, - "font": "engine:main", + "font": "engine:main#0.42", "elements": { "UILabel": { "text-align-vertical": "top", @@ -286,6 +286,7 @@ } }, "UIButton": { + "font": "engine:main#1", "text-align-horizontal": "center", "text-align-vertical": "middle", "background": "button", diff --git a/engine/src/main/resources/org/destinationsol/assets/skins/mainGameScreen.skin b/engine/src/main/resources/org/destinationsol/assets/skins/mainGameScreen.skin index c7be7742e..b3b4d1619 100644 --- a/engine/src/main/resources/org/destinationsol/assets/skins/mainGameScreen.skin +++ b/engine/src/main/resources/org/destinationsol/assets/skins/mainGameScreen.skin @@ -8,10 +8,10 @@ "min-height": 64 } }, - "font": "engine:main#2" + "font": "engine:main#1" }, "controlsUIButton": { - "font": "engine:main#2" + "font": "engine:main#0.95" } } } diff --git a/engine/src/main/resources/org/destinationsol/assets/skins/mainMenu.skin b/engine/src/main/resources/org/destinationsol/assets/skins/mainMenu.skin new file mode 100644 index 000000000..685ba8726 --- /dev/null +++ b/engine/src/main/resources/org/destinationsol/assets/skins/mainMenu.skin @@ -0,0 +1,78 @@ +{ + "inherit": "engine:default", + "elements": { + "NUIScreenLayer": { + "background-scale-mode": "scale_fill", + "background": "engine:mainMenuBg" + } + }, + "families": { + "logo": { + "elements": { + "UIImage": { + "min-width": 200, + "min-height": 109, + "max-width": 400, + "max-height": 218 + } + } + }, + "menuButtons": { + "elements": { + "UIButton": { + "min-width": 400, + "min-height": 50, + "max-width": 800, + "max-height": 400 + } + }, + "font": "engine:main#1" + }, + "inputMapHeader": { + "elements": { + "UILabel": { + "min-height": 25, + "font": "engine:main#0.6", + "text-align-vertical": "middle", + "text-align-horizontal": "center" + }, + "UIButton": { + "min-width": 10, + "min-height": 25 + } + }, + "font": "engine:main#0.7" + }, + "inputMapRow": { + "font": "engine:main#0.675", + "text-align-vertical": "middle", + "text-align-horizontal": "center", + "min-height": 30 + }, + "inputMapOptions": { + "elements": { + "UIButton": { + "min-width": 200, + "min-height": 25 + } + }, + "font": "engine:main#0.7" + }, + "creditsButton": { + "font": "engine:main#0.60" + }, + "menuHeaderText": { + "font": "engine:main#1.0" + }, + "creditsText": { + "font": "engine:main#0.8", + "text-align-vertical": "middle", + "text-align-horizontal": "center" + }, + "keyPressMessage": { + "font": "engine:main#2", + "text-align-vertical": "middle", + "text-align-horizontal": "center" + } + } +} \ No newline at end of file diff --git a/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/creditsScreen.ui b/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/creditsScreen.ui new file mode 100644 index 000000000..181bb71c3 --- /dev/null +++ b/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/creditsScreen.ui @@ -0,0 +1,33 @@ +{ + "type": "CreditsScreen", + "skin": "engine:mainMenu", + "contents": { + "type": "RelativeLayout", + "contents": [ + { + "type": "UILabel", + "id": "creditsText", + "family": "creditsText", + "text": "[Credits go here...]", + "layoutInfo": { + "position-horizontal-center": {}, + "position-vertical-center": {}, + "use-content-width": true, + "use-content-height": true + } + }, + { + "type": "KeyActivatedButton", + "id": "cancelButton", + "family": "creditsButton", + "text": "Cancel", + "layoutInfo": { + "position-right": {}, + "position-bottom": {}, + "width": 100, + "height": 50 + } + } + ] + } +} \ No newline at end of file diff --git a/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/inputMapScreen.ui b/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/inputMapScreen.ui new file mode 100644 index 000000000..5b39efaba --- /dev/null +++ b/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/inputMapScreen.ui @@ -0,0 +1,141 @@ +{ + "type": "InputMapScreen", + "skin": "engine:mainMenu", + "contents": { + "type": "RelativeLayout", + "contents": [ + { + "type": "ColumnLayout", + "id": "inputMapRows", + "verticalSpacing": 8, + "contents": [ + { + "type": "RowLayout", + "id": "header", + "family": "inputMapHeader", + "horizontalSpacing": 8, + "contents": [ + { + "type": "UILabel", + "id": "title", + "text": "Keyboard and Mouse Inputs", + "layoutInfo": { + "relativeWidth": 0.6 + } + }, + { + "type": "KeyActivatedButton", + "id": "previousButton", + "text": "<" + }, + { + "type": "KeyActivatedButton", + "id": "nextButton", + "text": ">" + } + ] + } + ], + "layoutInfo": { + "position-horizontal-center": {}, + "position-top": { + "offset": 64 + }, + "position-bottom": { + "widget": "actionButtons", + "target": "TOP", + "offset": 16 + }, + "position-left": { + "offset": 64 + }, + "position-right": { + "offset": 64 + } + } + }, + { + "type": "ColumnLayout", + "id": "actionButtons", + "family": "inputMapOptions", + "verticalSpacing": 8, + "contents": [ + { + "type": "UIButton", + "id": "defaultsButton", + "text": "Defaults" + }, + { + "type": "UIButton", + "id": "saveButton", + "text": "Save" + }, + { + "type": "KeyActivatedButton", + "id": "cancelButton", + "text": "Cancel" + } + ], + "layoutInfo": { + "position-bottom": { + "offset": 32 + }, + "position-left": { + "offset": 64 + }, + "position-right": { + "offset": 64 + }, + "use-content-height": true + } + }, + { + "type": "RelativeLayout", + "id": "keyPressOverlay", + "contents": [ + { + "type": "UIImage", + "image": "engine:uiWhiteTex", + "tint": [0, 0, 0, 0.8], + "ignoreAspectRatio": true, + "layoutInfo": { + "position-top": {}, + "position-bottom": {}, + "position-left": {}, + "position-right": {} + } + }, + { + "type": "UIBox", + "content": { + "type": "UILabel", + "id": "keyPressMessage", + "family": "keyPressMessage", + "text": "Press Any Key" + }, + "layoutInfo": { + "position-top": { + "offset": 128 + }, + "position-bottom": { + "offset": 128 + }, + "position-left": { + "offset": 128 + }, + "position-right": { + "offset": 128 + } + } + } + ], + "layoutInfo": { + "position-top": {}, + "position-bottom": {}, + "position-left": {}, + "position-right": {} + } + } + ] + } +} \ No newline at end of file diff --git a/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/loadingScreen.ui b/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/loadingScreen.ui new file mode 100644 index 000000000..f62180b1a --- /dev/null +++ b/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/loadingScreen.ui @@ -0,0 +1,20 @@ +{ + "type": "LoadingScreen", + "skin": "engine:mainMenu", + "contents": { + "type": "RelativeLayout", + "contents": [ + { + "type": "UILabel", + "family": "menuHeaderText", + "text": "Loading...", + "layoutInfo": { + "position-horizontal-center": {}, + "position-vertical-center": {}, + "use-content-width": true, + "use-content-height": true + } + } + ] + } +} \ No newline at end of file diff --git a/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/mainMenuScreen.ui b/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/mainMenuScreen.ui new file mode 100644 index 000000000..c6a9ec5f4 --- /dev/null +++ b/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/mainMenuScreen.ui @@ -0,0 +1,85 @@ +{ + "type": "MainMenuScreen", + "skin": "engine:mainMenu", + "contents": { + "type": "RelativeLayout", + "contents": [ + { + "type": "UIImage", + "image": "engine:mainMenuLogo", + "ignoreAspectRatio": true, + "id": "mainMenuLogo", + "family": "logo", + "layoutInfo": { + "position-horizontal-center": {}, + "position-top": { + "offset": 32 + }, + "position-bottom": { + "widget": "menuButtons", + "target": "TOP" + }, + "position-left": { + "offset": 32 + }, + "position-right": { + "offset": 32 + } + } + }, + { + "type": "ColumnLayout", + "id": "menuButtons", + "family": "menuButtons", + "columns": 1, + "verticalSpacing": 10, + "contents": [ + { + "type": "UIButton", + "id": "tutorialButton", + "text": "Tutorial" + }, + { + "type": "UIButton", + "id": "playGameButton", + "text": "Play Game" + }, + { + "type": "UIButton", + "id": "optionsButton", + "text": "Options" + }, + { + "type": "UIButton", + "id": "exitButton", + "text": "Exit" + } + ], + "layoutInfo": { + "position-horizontal-center": {}, + "position-bottom": { + "offset": 32 + }, + "position-top": { + "target": "MIDDLE", + "offset": 64 + }, + "use-content-height": true, + "use-content-width": true + } + }, + { + "type": "UIButton", + "id": "creditsButton", + "family": "creditsButton", + "text": "Credits", + "layoutInfo": { + "position-right": {}, + "position-bottom": {}, + "width": 100, + "height": 50 + } + } + ] + } +} \ No newline at end of file diff --git a/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/newGameScreen.ui b/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/newGameScreen.ui new file mode 100644 index 000000000..6315a282d --- /dev/null +++ b/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/newGameScreen.ui @@ -0,0 +1,49 @@ +{ + "type": "NewGameScreen", + "skin": "engine:mainMenu", + "contents": { + "type": "RelativeLayout", + "contents": [ + { + "type": "ColumnLayout", + "id": "menuButtons", + "family": "menuButtons", + "columns": 1, + "verticalSpacing": 10, + "contents": [ + { + "type": "KeyActivatedButton", + "id": "continueButton", + "text": "Continue" + }, + { + "type": "UIButton", + "id": "newGameButton", + "text": "New Game" + }, + { + "type": "UISpace", + "size": [16, 16] + }, + { + "type": "KeyActivatedButton", + "id": "cancelButton", + "text": "Cancel" + } + ], + "layoutInfo": { + "position-horizontal-center": {}, + "position-bottom": { + "offset": 32 + }, + "position-top": { + "target": "MIDDLE", + "offset": 64 + }, + "use-content-height": true, + "use-content-width": true + } + } + ] + } +} \ No newline at end of file diff --git a/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/newShipScreen.ui b/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/newShipScreen.ui new file mode 100644 index 000000000..d0d730ca7 --- /dev/null +++ b/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/newShipScreen.ui @@ -0,0 +1,62 @@ +{ + "type": "NewShipScreen", + "skin": "engine:mainMenu", + "contents": { + "type": "RelativeLayout", + "contents": [ + { + "type": "UILabel", + "family": "menuHeaderText", + "text": "Warning: This will erase any old ship you might have had!", + "layoutInfo": { + "position-horizontal-center": {}, + "position-top": { + "target": "MIDDLE", + "offset": -64 + } + } + }, + { + "type": "ColumnLayout", + "id": "menuButtons", + "family": "menuButtons", + "columns": 1, + "verticalSpacing": 10, + "contents": [ + { + "type": "UIButton", + "id": "systemsButton", + "text": "Systems" + }, + { + "type": "UIButton", + "id": "startingShipButton", + "text": "Starting Ship" + }, + { + "type": "KeyActivatedButton", + "id": "okButton", + "text": "OK" + }, + { + "type": "KeyActivatedButton", + "id": "cancelButton", + "text": "Cancel" + } + ], + "layoutInfo": { + "position-horizontal-center": {}, + "position-bottom": { + "offset": 32 + }, + "position-top": { + "target": "MIDDLE", + "offset": 64 + }, + "use-content-height": true, + "use-content-width": true + } + } + ] + } +} \ No newline at end of file diff --git a/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/optionsScreen.ui b/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/optionsScreen.ui new file mode 100644 index 000000000..3de5a0df1 --- /dev/null +++ b/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/optionsScreen.ui @@ -0,0 +1,67 @@ +{ + "type": "OptionsScreen", + "skin": "engine:mainMenu", + "contents": { + "type": "RelativeLayout", + "contents": [ + { + "type": "ColumnLayout", + "id": "menuButtons", + "family": "menuButtons", + "columns": 1, + "verticalSpacing": 10, + "contents": [ + { + "type": "UIButton", + "id": "musicVolumeButton", + "text": "Music Volume" + }, + { + "type": "UIButton", + "id": "soundVolumeButton", + "text": "Sound Volume" + }, + { + "type": "UIButton", + "id": "resolutionButton", + "text": "Resolution" + }, + { + "type": "UIButton", + "id": "mapPanSpeedButton", + "text": "Map Pan Speed" + }, + { + "type": "KeyActivatedButton", + "id": "controlTypeButton", + "key": "c", + "text": "Control Type" + }, + { + "type": "KeyActivatedButton", + "id": "controlsButton", + "key": "m", + "text": "Controls" + }, + { + "type": "UISpace", + "size": [16, 16] + }, + { + "type": "KeyActivatedButton", + "id": "cancelButton", + "text": "Back" + } + ], + "layoutInfo": { + "position-horizontal-center": {}, + "position-bottom": { + "offset": 32 + }, + "use-content-height": true, + "use-content-width": true + } + } + ] + } +} \ No newline at end of file diff --git a/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/resolutionScreen.ui b/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/resolutionScreen.ui new file mode 100644 index 000000000..6eb7a5141 --- /dev/null +++ b/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/resolutionScreen.ui @@ -0,0 +1,58 @@ +{ + "type": "ResolutionScreen", + "skin": "engine:mainMenu", + "contents": { + "type": "RelativeLayout", + "contents": [ + { + "type": "UILabel", + "family": "menuHeaderText", + "text": "Click 'Back' to apply changes", + "layoutInfo": { + "position-horizontal-center": {}, + "position-top": { + "target": "MIDDLE", + "offset": -64 + } + } + }, + { + "type": "ColumnLayout", + "id": "menuButtons", + "family": "menuButtons", + "columns": 1, + "verticalSpacing": 10, + "contents": [ + { + "type": "UIButton", + "id": "resolutionButton", + "text": "Resolution" + }, + { + "type": "UIButton", + "id": "fullScreenButton", + "text": "Full Screen" + }, + { + "type": "UIButton", + "id": "nuiUIScaleButton", + "text": "NUI UI Scale" + }, + { + "type": "KeyActivatedButton", + "id": "cancelButton", + "text": "Back" + } + ], + "layoutInfo": { + "position-horizontal-center": {}, + "position-bottom": { + "offset": 32 + }, + "use-content-height": true, + "use-content-width": true + } + } + ] + } +} \ No newline at end of file