/******************************************************************************* * Copyright 2014 Rafael Garcia Moreno. * * 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 com.bladecoder.engine.ui.defaults; import static com.badlogic.gdx.scenes.scene2d.actions.Actions.fadeOut; import static com.badlogic.gdx.scenes.scene2d.actions.Actions.sequence; import java.util.Locale; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input.Peripheral; import com.badlogic.gdx.InputMultiplexer; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.GlyphLayout; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.TextureAtlas; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import com.badlogic.gdx.input.GestureDetector; import com.badlogic.gdx.math.Interpolation; import com.badlogic.gdx.math.Polygon; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.actions.Actions; import com.badlogic.gdx.scenes.scene2d.ui.Button; import com.badlogic.gdx.scenes.scene2d.ui.Label; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.scenes.scene2d.utils.Drawable; import com.badlogic.gdx.scenes.scene2d.utils.TransformDrawable; import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.utils.GdxRuntimeException; import com.badlogic.gdx.utils.viewport.Viewport; import com.bladecoder.engine.assets.EngineAssetManager; import com.bladecoder.engine.i18n.I18N; import com.bladecoder.engine.model.AnchorActor; import com.bladecoder.engine.model.BaseActor; import com.bladecoder.engine.model.CharacterActor; import com.bladecoder.engine.model.InteractiveActor; import com.bladecoder.engine.model.Scene; import com.bladecoder.engine.model.Text; import com.bladecoder.engine.model.TextManager; import com.bladecoder.engine.model.Transition; import com.bladecoder.engine.model.Verb; import com.bladecoder.engine.model.World; import com.bladecoder.engine.model.World.AssetState; import com.bladecoder.engine.model.WorldListener; import com.bladecoder.engine.ui.AnimButton; import com.bladecoder.engine.ui.AnimationDrawable; import com.bladecoder.engine.ui.DialogUI; import com.bladecoder.engine.ui.ITextManagerUI; import com.bladecoder.engine.ui.InventoryButton; import com.bladecoder.engine.ui.InventoryUI; import com.bladecoder.engine.ui.PieMenu; import com.bladecoder.engine.ui.Recorder; import com.bladecoder.engine.ui.SceneExtendViewport; import com.bladecoder.engine.ui.SceneFitViewport; import com.bladecoder.engine.ui.SceneScreen; import com.bladecoder.engine.ui.TesterBot; import com.bladecoder.engine.ui.TextManagerUI; import com.bladecoder.engine.ui.UI; import com.bladecoder.engine.ui.UI.Screens; import com.bladecoder.engine.util.Config; import com.bladecoder.engine.util.DPIUtils; import com.bladecoder.engine.util.EngineLogger; import com.bladecoder.engine.util.RectangleRenderer; public class DefaultSceneScreen implements SceneScreen { private final static float LOADING_WAIT_TIME_MS = 400f; private UI ui; private Stage stage; private PieMenu pie; private InventoryUI inventoryUI; private Actor dialogUI; private Actor textManagerUI; private ShapeRenderer renderer; private InventoryButton inventoryButton; private Button menuButton; public static enum UIModes { TWO_BUTTONS, PIE, SINGLE_CLICK }; private UIModes uiMode = UIModes.TWO_BUTTONS; private Recorder recorder; private TesterBot testerBot; private final Viewport viewport; private final Vector3 unprojectTmp = new Vector3(); private final Vector2 unproject2Tmp = new Vector2(); private final StringBuilder sbTmp = new StringBuilder(); // Actor under the cursor private InteractiveActor currentActor = null; // Called by the input handlers to show/hide the hotspots. private boolean drawHotspots = false; // Configuration to enable/disable the 'drawHotspot' feature. private boolean showHotspotsFeature = true; private final boolean showDesc; private final boolean fastLeave; private float speed = 1.0f; private ScenePointer pointer; private boolean uiEnabled = true; private final GlyphLayout textLayout = new GlyphLayout(); private final GestureDetector inputProcessor = new SceneGestureDetector(this); private final WorldListener worldListener = new SceneWorldListener(this); public DefaultSceneScreen() { viewport = Config.getInstance().getProperty(Config.EXTEND_VIEWPORT_PROP, true) ? new SceneExtendViewport() : new SceneFitViewport(); showDesc = Config.getInstance().getProperty(Config.SHOW_DESC_PROP, true); fastLeave = Config.getInstance().getProperty(Config.FAST_LEAVE, false); showHotspotsFeature = Config.getInstance().getProperty(Config.SHOW_HOTSPOTS, true); } @Override public UI getUI() { return ui; } @Override public World getWorld() { return ui.getWorld(); } public boolean isUiEnabled() { return uiEnabled; } public PieMenu getPie() { return pie; } public InventoryButton getInventoryButton() { return inventoryButton; } public boolean getDrawHotspots() { return drawHotspots; } public void setDrawHotspots(boolean drawHotspots) { this.drawHotspots = drawHotspots && showHotspotsFeature; } public void setShowHotspotsFeature(boolean v) { showHotspotsFeature = v; } public UIModes getUIMode() { return uiMode; } void showUIText(Text t) { // Type UI texts will show at the same time that TextManagerUI texts. String style = t.style == null ? "ui-text" : t.style; Label msg = new Label(t.str, getUI().getSkin(), style); msg.setWrap(true); msg.setAlignment(Align.center, Align.center); if (t.color != null) msg.setColor(t.color); msg.setSize(msg.getWidth() + DPIUtils.getMarginSize() * 2, msg.getHeight() + DPIUtils.getMarginSize() * 2); stage.addActor(msg); unprojectTmp.set(t.x, t.y, 0); getWorld().getSceneCamera().scene2screen(getStage().getViewport(), unprojectTmp); float posx, posy; if (t.x == TextManager.POS_CENTER) { posx = (getStage().getViewport().getScreenWidth() - msg.getWidth()) / 2; } else if (t.x == TextManager.POS_SUBTITLE) { posx = DPIUtils.getMarginSize(); } else { posx = unprojectTmp.x; } if (t.y == TextManager.POS_CENTER) { posy = (getStage().getViewport().getScreenHeight() - msg.getHeight()) / 2; } else if (t.y == TextManager.POS_SUBTITLE) { posy = getStage().getViewport().getScreenHeight() - msg.getHeight() - DPIUtils.getMarginSize() * 3; } else { posy = unprojectTmp.y; } msg.setPosition(posx, posy); msg.getColor().a = 0; msg.addAction(sequence(Actions.fadeIn(0.4f, Interpolation.fade), Actions.delay(t.time, sequence(fadeOut(0.4f, Interpolation.fade), Actions.removeActor())))); } void updateUI() { World w = getWorld(); if (w.getAssetState() == null || w.getAssetState() == AssetState.LOAD_ASSETS || w.getAssetState() == AssetState.LOAD_ASSETS_AND_INIT_SCENE) return; if (uiMode == UIModes.PIE && pie.isVisible()) pie.hide(); currentActor = null; pointer.reset(); if (w.isPaused() || w.inCutMode() || testerBot.isEnabled() || recorder.isPlaying()) { // DISABLE UI inventoryUI.hide(); inventoryButton.setVisible(false); dialogUI.setVisible(false); inventoryUI.cancelDragging(); uiEnabled = false; EngineLogger.debug("Updating UI: DISABLED."); } else { if (getWorld().hasDialogOptions()) { inventoryUI.hide(); inventoryButton.setVisible(false); dialogUI.setVisible(true); inventoryUI.cancelDragging(); EngineLogger.debug("Updating UI: DIALOG OPTIONS."); } else { inventoryUI.hide(); dialogUI.setVisible(false); inventoryButton.setVisible(w.getInventory().isVisible()); EngineLogger.debug("Updating UI: ENABLED."); } uiEnabled = true; } } /** * Sets the game speed. Can be used to fastfordward * * @param s The multiplier speed. ej. 2.0 */ @Override public void setSpeed(float s) { speed = s; } @Override public float getSpeed() { return speed; } private void update(float delta) { final World world = getWorld(); float deltaScaled = delta * speed; if (!world.isDisposed()) { world.update(deltaScaled); // if the game ends returns if (world.isDisposed()) return; } if (world.getAssetState() != AssetState.LOADED) { // TRY TO LOAD THE ASSETS FOR LOADING_WAIT_TIME_MS TO AVOID // BLACK/LOADING SCREEN long t0 = System.currentTimeMillis(); long t = t0; while (EngineAssetManager.getInstance().isLoading() && t - t0 < LOADING_WAIT_TIME_MS) { t = System.currentTimeMillis(); } if (t - t0 >= LOADING_WAIT_TIME_MS) { // Sets loading screen if resources are not loaded yet ui.setCurrentScreen(Screens.LOADING_SCREEN); } else { updateUI(); world.resize(viewport.getWorldWidth(), viewport.getWorldHeight()); // update() to retrieve assets and exec init verb world.update(0); } return; } stage.act(delta); pointer.update(delta); if (drawHotspots) { Drawable hotspotDrawable = getUI().getSkin().getDrawable(Verb.LEAVE_VERB); Drawable leaveDrawable = getUI().getSkin().getDrawable("hotspot"); if (hotspotDrawable != null && hotspotDrawable instanceof AnimationDrawable) ((AnimationDrawable) hotspotDrawable).act(delta); if (leaveDrawable != null && leaveDrawable instanceof AnimationDrawable) ((AnimationDrawable) leaveDrawable).act(delta); } if (world.isPaused()) return; recorder.update(deltaScaled); testerBot.update(deltaScaled); InteractiveActor actorUnderCursor = null; if (uiEnabled && !world.hasDialogOptions()) { if (inventoryUI.isVisible()) { unproject2Tmp.set(Gdx.input.getX(), Gdx.input.getY()); inventoryUI.screenToLocalCoordinates(unproject2Tmp); actorUnderCursor = inventoryUI.getItemAt(unproject2Tmp.x, unproject2Tmp.y); } else { actorUnderCursor = getActorUnderCursor(); } // UPDATE POINTER if (!pie.isVisible() && actorUnderCursor != currentActor) { currentActor = actorUnderCursor; if (currentActor != null) { if (showDesc) pointer.setDesc(currentActor.getDesc()); Verb leaveVerb = currentActor.getVerb(Verb.LEAVE_VERB); Drawable r = null; if (leaveVerb != null) { if ((r = getDrawable(leaveVerb.getIcon())) != null) { pointer.setIcon(r); } else { pointer.setLeaveIcon(calcLeaveArrowRotation(currentActor)); } } else { Verb actionVerb = currentActor.getVerb(Verb.ACTION_VERB); if (actionVerb != null && (r = getDrawable(actionVerb.getIcon())) != null) { pointer.setIcon(r); } else { pointer.setHotspotIcon(); } } } else { pointer.setDefaultIcon(); } } else if (pie.isVisible()) { currentActor = actorUnderCursor; } } } private Drawable getDrawable(String name) { if (name == null) return null; try { return getUI().getSkin().getDrawable(name); } catch (GdxRuntimeException e) { return null; } } private InteractiveActor getActorUnderCursor() { final float tolerance; if (inventoryUI.isDragging()) tolerance = DPIUtils.getTouchMinSize(); else if (Gdx.input.isPeripheralAvailable(Peripheral.MultitouchScreen)) tolerance = DPIUtils.getTouchMinSize() / 2; else tolerance = 0; return getWorld().getInteractiveActorAtInput(viewport, tolerance); } /** * Calcs the rotation based in the actor screen position */ private float calcLeaveArrowRotation(InteractiveActor actor) { Verb verb = actor.getVerb(Verb.LEAVE_VERB); if (verb == null || verb.getIcon() == null) { actor.getBBox().getBoundingRectangle().getCenter(unproject2Tmp); if (unproject2Tmp.x < stage.getViewport().getWorldWidth() / 3f) { return 180; // LEFT } if (unproject2Tmp.x > stage.getViewport().getWorldWidth() / 3f * 2f) { return 0; // RIGHT } if (unproject2Tmp.y < stage.getViewport().getWorldHeight() / 5f) { return -90; // DOWN } return 90; // UP } else { String dir = verb.getIcon(); if (dir.equals("left")) { return 180; // LEFT } if (dir.equals("right")) { return 0; // RIGHT } if (dir.equals("down")) { return -90; // DOWN } return 90; // UP } } @Override public void render(float delta) { final World world = getWorld(); update(delta); if (world.getAssetState() != AssetState.LOADED) { return; } SpriteBatch batch = ui.getBatch(); Gdx.gl.glClearColor(0, 0, 0, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // WORLD CAMERA world.draw(); // DRAW DEBUG BBOXES if (EngineLogger.debugMode() && EngineLogger.getDebugLevel() == EngineLogger.DEBUG1) { renderer.setProjectionMatrix(world.getSceneCamera().combined); world.getCurrentScene().drawBBoxLines(renderer); renderer.end(); } // STAGE stage.draw(); // SCREEN CAMERA batch.setProjectionMatrix(viewport.getCamera().combined); batch.begin(); if (!world.inCutMode() && !recorder.isPlaying() && !testerBot.isEnabled()) { pointer.draw(batch, viewport); } Transition t = world.getTransition(); t.draw(batch, viewport.getScreenWidth(), viewport.getScreenHeight()); recorder.draw(batch); testerBot.draw(batch); if (drawHotspots) drawHotspots(batch); // DRAW DEBUG STRING if (EngineLogger.debugMode()) { drawDebugText(batch); } batch.end(); } private void drawDebugText(SpriteBatch batch) { World w = getWorld(); w.getSceneCamera().getInputUnProject(viewport, unprojectTmp); Color color; sbTmp.setLength(0); if (EngineLogger.lastError != null) { // sbTmp.append(EngineLogger.lastError); sbTmp.append(EngineLogger.errorBuffer); color = Color.RED; } else { // sbTmp.append(" Density:"); // sbTmp.append(Gdx.graphics.getDensity()); // sbTmp.append(" UI Multiplier:"); // sbTmp.append(DPIUtils.getSizeMultiplier()); sbTmp.append(" "); long millis = w.getTimeOfGame(); long second = (millis / 1000) % 60; long minute = (millis / (1000 * 60)) % 60; long hour = (millis / (1000 * 60 * 60)); String time = String.format("%02d:%02d:%02d", hour, minute, second); sbTmp.append(time); if (EngineLogger.getDebugLevel() == EngineLogger.DEBUG1) { if (w.inCutMode()) { sbTmp.append(" CUT_MODE "); } else if (w.hasDialogOptions()) { sbTmp.append(" DIALOG_MODE "); } else if (w.isPaused()) { sbTmp.append(" PAUSED "); } sbTmp.append(" ( "); sbTmp.append((int) unprojectTmp.x); sbTmp.append(", "); sbTmp.append((int) unprojectTmp.y); sbTmp.append(") FPS:"); sbTmp.append(Gdx.graphics.getFramesPerSecond()); if (w.getCurrentScene().getState() != null) { sbTmp.append(" Scn State: "); sbTmp.append(w.getCurrentScene().getState()); } if (w.getCurrentScene().getPlayer() != null) { sbTmp.append(" Depth Scl: "); sbTmp.append(w.getCurrentScene().getFakeDepthScale(unprojectTmp.y)); } } color = Color.WHITE; } String strDebug = sbTmp.toString(); textLayout.setText(ui.getSkin().getFont("debug"), strDebug, color, viewport.getScreenWidth(), Align.left, true); RectangleRenderer.draw(batch, 0, viewport.getScreenHeight() - textLayout.height - 10, textLayout.width, textLayout.height + 10, Color.BLACK); ui.getSkin().getFont("debug").draw(batch, textLayout, 0, viewport.getScreenHeight() - 5); // Draw actor states when debug if (EngineLogger.getDebugLevel() == EngineLogger.DEBUG1) { for (BaseActor a : w.getCurrentScene().getActors().values()) { if (a instanceof AnchorActor) continue; Rectangle r = a.getBBox().getBoundingRectangle(); sbTmp.setLength(0); sbTmp.append(a.getId()); if (a instanceof InteractiveActor && ((InteractiveActor) a).getState() != null) sbTmp.append(".").append(((InteractiveActor) a).getState()); unprojectTmp.set(r.getX(), r.getY(), 0); w.getSceneCamera().scene2screen(viewport, unprojectTmp); ui.getSkin().getFont("debug").draw(batch, sbTmp.toString(), unprojectTmp.x, unprojectTmp.y); } } } private void drawHotspots(SpriteBatch batch) { final World world = getWorld(); for (BaseActor a : world.getCurrentScene().getActors().values()) { if (!(a instanceof InteractiveActor) || !a.isVisible() || a == world.getCurrentScene().getPlayer()) continue; InteractiveActor ia = (InteractiveActor) a; if (!ia.canInteract()) continue; Polygon p = a.getBBox(); if (p == null) { EngineLogger.error("ERROR DRAWING HOTSPOT FOR: " + a.getId()); } Rectangle r = a.getBBox().getBoundingRectangle(); unprojectTmp.set(r.getX() + r.getWidth() / 2, r.getY() + r.getHeight() / 2, 0); world.getSceneCamera().scene2screen(viewport, unprojectTmp); if (!showDesc || ia.getDesc() == null) { float size = DPIUtils.ICON_SIZE * DPIUtils.getSizeMultiplier(); if (ia.getVerb(Verb.LEAVE_VERB) != null) { TransformDrawable drawable = (TransformDrawable) getUI().getSkin().getDrawable(Verb.LEAVE_VERB); drawable.draw(batch, unprojectTmp.x - size / 2, unprojectTmp.y - size / 2, size / 2, size / 2, size, size, 1.0f, 1.0f, calcLeaveArrowRotation(ia)); } else { Drawable drawable = getUI().getSkin().getDrawable("hotspot"); if (drawable != null) drawable.draw(batch, unprojectTmp.x - size / 2, unprojectTmp.y - size / 2, size, size); } } else { BitmapFont font = getUI().getSkin().getFont("desc"); String desc = ia.getDesc(); if (desc.charAt(0) == I18N.PREFIX) desc = getWorld().getI18N().getString(desc.substring(1)); textLayout.setText(font, desc); float textX = unprojectTmp.x - textLayout.width / 2; float textY = unprojectTmp.y + textLayout.height; RectangleRenderer.draw(batch, textX - 8, textY - textLayout.height - 8, textLayout.width + 16, textLayout.height + 16, Color.BLACK); font.draw(batch, textLayout, textX, textY); } } } @Override public void resize(int width, int height) { final World world = getWorld(); if (!world.isDisposed()) { viewport.setWorldSize(world.getWidth(), world.getHeight()); viewport.update(width, height, true); world.resize(viewport.getWorldWidth(), viewport.getWorldHeight()); } else { viewport.setWorldSize(width, height); viewport.update(width, height, true); } updateUI(); pie.resize(viewport.getScreenWidth(), viewport.getScreenHeight()); inventoryUI.resize(viewport.getScreenWidth(), viewport.getScreenHeight()); inventoryButton.resize(width, height); pointer.resize(width, height); float size = DPIUtils.getPrefButtonSize(); float margin = DPIUtils.getMarginSize(); menuButton.setSize(size, size); menuButton.setPosition(stage.getViewport().getScreenWidth() - menuButton.getWidth() - margin, stage.getViewport().getScreenHeight() - menuButton.getHeight() - margin); } @Override public void dispose() { renderer.dispose(); stage.dispose(); } private void retrieveAssets(TextureAtlas atlas) { renderer = new ShapeRenderer(); inventoryUI.retrieveAssets(atlas); } void sceneClick(int button, int count) { World w = getWorld(); w.getSceneCamera().getInputUnProject(viewport, unprojectTmp); Scene s = w.getCurrentScene(); CharacterActor player = s.getPlayer(); currentActor = getActorUnderCursor(); if (currentActor != null) { if (EngineLogger.debugMode()) { EngineLogger.debug(currentActor.toString()); } // DOUBLE CLICK: Fastwalk when leaving scene. if (count > 1) { if (count == 2 && fastLeave && !recorder.isRecording() && player != null && currentActor.getVerb(Verb.LEAVE_VERB) != null) { player.fastWalk(); } return; } actorClick(currentActor, button); } else if (player != null) { if (count > 1) return; if (s.getPlayer().getVerb(Verb.GOTO_VERB) != null) { runVerb(s.getPlayer(), Verb.GOTO_VERB, null); } else { Vector2 pos = new Vector2(unprojectTmp.x, unprojectTmp.y); if (recorder.isRecording()) { recorder.add(pos); } player.goTo(pos, null, false); } } } @Override public void actorClick(InteractiveActor a, int button) { final boolean lookatButton = button == 1; if (a.getVerb(Verb.LEAVE_VERB) != null) { runVerb(a, Verb.LEAVE_VERB, null); } else if (a.getVerb(Verb.ACTION_VERB) != null) { runVerb(a, Verb.ACTION_VERB, null); } else if (uiMode == UIModes.SINGLE_CLICK) { // SINGLE CLICK UI // Preference TALKTO, ACTION, PICKUP, LOOKAT String verb = Verb.TALKTO_VERB; if (a.getVerb(verb) == null) verb = Verb.PICKUP_VERB; if (a.getVerb(verb) == null) verb = Verb.LOOKAT_VERB; runVerb(a, verb, null); } else if (uiMode == UIModes.TWO_BUTTONS) { String verb = Verb.LOOKAT_VERB; if (!lookatButton) { verb = a.getVerb(Verb.TALKTO_VERB) != null ? Verb.TALKTO_VERB : Verb.PICKUP_VERB; } runVerb(a, verb, null); } else if (uiMode == UIModes.PIE) { getInputUnProject(unprojectTmp); pie.show(a, unprojectTmp.x, unprojectTmp.y); pointer.reset(); } } private void getInputUnProject(Vector3 out) { out.set(Gdx.input.getX(), Gdx.input.getY(), 0); viewport.unproject(out); } /** * Run actor verb and handles recording * * @param a * @param verb * @param target */ @Override public void runVerb(InteractiveActor a, String verb, String target) { if (recorder.isRecording()) { recorder.add(a.getId(), verb, target); } a.runVerb(verb, target); } void showMenu() { pause(); ui.setCurrentScreen(Screens.MENU_SCREEN); } public InventoryUI getInventoryUI() { return inventoryUI; } public Actor getTextManagerUI() { return textManagerUI; } public Actor getDialogUI() { return dialogUI; } public void setTextManagerUI(Actor a) { if (a instanceof ITextManagerUI) { textManagerUI.remove(); textManagerUI = a; stage.addActor(textManagerUI); } else { EngineLogger.error("ERROR setTextManagerUI: actor is not a ITextManagerUI"); dispose(); Gdx.app.exit(); } } public void setDialogUI(Actor a) { dialogUI.remove(); dialogUI = a; stage.addActor(dialogUI); } public Stage getStage() { return stage; } public Button getMenuButton() { return menuButton; } @Override public void show() { final InputMultiplexer multiplexer = new InputMultiplexer(); multiplexer.addProcessor(stage); multiplexer.addProcessor(inputProcessor); Gdx.input.setInputProcessor(multiplexer); if (getWorld().isDisposed()) { try { getWorld().load(); } catch (Exception e) { EngineLogger.error("ERROR LOADING GAME", e); dispose(); Gdx.app.exit(); } } getWorld().setListener(worldListener); getWorld().resume(); } @Override public void hide() { getWorld().pause(); } @Override public void pause() { getWorld().pause(); } @Override public void resume() { getWorld().resume(); // resets the error when continue if (EngineLogger.lastError != null && EngineLogger.debugMode()) { EngineLogger.lastError = null; EngineLogger.lastException = null; } } @Override public Viewport getViewport() { return viewport; } @Override public InteractiveActor getCurrentActor() { return currentActor; } @Override public void setUI(final UI ui) { this.ui = ui; recorder = ui.getRecorder(); testerBot = ui.getTesterBot(); pie = new PieMenu(this); textManagerUI = new TextManagerUI(ui.getSkin(), getWorld()); menuButton = new AnimButton(ui.getSkin(), "menu"); dialogUI = new DialogUI(ui.getSkin(), getWorld(), ui.getRecorder()); pointer = new ScenePointer(ui.getSkin(), getWorld()); inventoryUI = new InventoryUI(this, pointer); inventoryButton = new InventoryButton(ui.getSkin(), getWorld(), inventoryUI); uiMode = UIModes .valueOf(Config.getInstance().getProperty(Config.UI_MODE, "TWO_BUTTONS").toUpperCase(Locale.ENGLISH)); if (Gdx.input.isPeripheralAvailable(Peripheral.MultitouchScreen) && uiMode == UIModes.TWO_BUTTONS) { uiMode = UIModes.PIE; } pie.setVisible(false); menuButton.addListener(new ClickListener() { @Override public void clicked(InputEvent event, float x, float y) { ui.setCurrentScreen(Screens.MENU_SCREEN); } }); retrieveAssets(ui.getUIAtlas()); stage = new Stage(viewport); stage.addActor(textManagerUI); stage.addActor(dialogUI); stage.addActor(inventoryButton); stage.addActor(menuButton); stage.addActor(inventoryUI); stage.addActor(pie); } }