com.jmolina.orb.screens.BaseScreen.java Source code

Java tutorial

Introduction

Here is the source code for com.jmolina.orb.screens.BaseScreen.java

Source

/*
 * IMPULSE ORB
 * Copyright (C) 2016 Juan M. Molina
 *
 * This file is part of the IMPULSE ORB source code.
 *
 * IMPULSE ORB is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * IMPULSE ORB is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.jmolina.orb.screens;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputMultiplexer;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.ScreenAdapter;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.math.Interpolation;
import com.badlogic.gdx.scenes.scene2d.Action;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.actions.SequenceAction;
import com.badlogic.gdx.utils.viewport.FitViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.jmolina.orb.data.ScreenFlag;
import com.jmolina.orb.interfaces.Backable;
import com.jmolina.orb.interfaces.SuperManager;
import com.jmolina.orb.managers.AssetManager;
import com.jmolina.orb.managers.GameManager;
import com.jmolina.orb.managers.PrefsManager;
import com.jmolina.orb.managers.ScreenManager;
import com.jmolina.orb.stages.BackgroundStage;
import com.jmolina.orb.stages.MainStage;
import com.jmolina.orb.var.Var;

import static com.badlogic.gdx.scenes.scene2d.actions.Actions.alpha;
import static com.badlogic.gdx.scenes.scene2d.actions.Actions.fadeIn;
import static com.badlogic.gdx.scenes.scene2d.actions.Actions.fadeOut;
import static com.badlogic.gdx.scenes.scene2d.actions.Actions.parallel;
import static com.badlogic.gdx.scenes.scene2d.actions.Actions.run;
import static com.badlogic.gdx.scenes.scene2d.actions.Actions.scaleTo;
import static com.badlogic.gdx.scenes.scene2d.actions.Actions.sequence;

/**
 * Clase base para todas las pantallas de la aplicacin. Renderiza los elementos y se ocupa de las
 * transiciones entre pantallas.
 */
public class BaseScreen extends ScreenAdapter implements Backable {

    public static final float SIZE_LARGE = 1.35f;
    public static final float SIZE_SMALL = 1 / SIZE_LARGE;
    public static final float VIEWPORT_WIDTH = Var.SCREEN_WIDTH;
    public static final float VIEWPORT_HEIGHT = Var.SCREEN_HEIGHT;

    private final Interpolation INTERPOLATION_IN = Interpolation.pow2In;
    private final Interpolation INTERPOLATION_OUT = Interpolation.pow2Out;
    protected final float TRANSITION_DURATION = 0.3f;
    protected final float MIN_DELTA_TIME = Var.FPS;

    /** Jerarqua de esta pantalla respecto de la siguiente */
    public enum Hierarchy {
        LOWER, HIGHER
    }

    /** Flujo de navegacin de la pantalla */
    public enum Flow {
        ENTERING, LEAVING
    }

    private final float PERIODIC_TASK_TIME = 1f;

    private SuperManager superManager;

    /** Viewports de las stages Main y Background */
    private Viewport mainViewport, backgroundViewport;

    /** Stage principal */
    private MainStage mainStage;

    /** Stage del fondo estatico */
    private BackgroundStage backgroundStage;

    /** Jerarquia de la pantalla */
    private Hierarchy hierarchy;

    /** Multiplexor de procesador de entrada */
    private InputMultiplexer multiplexer;

    /** Claves de la pantalla anterior y esta*/
    private ScreenManager.Key previousKey, thisKey;

    /** Bandera de cambio de pantalla */
    private ScreenFlag screenFlag;

    /** Cronometro de eventos periodicos */
    private float periodicTimer;

    /**
     * Constructor
     */
    public BaseScreen(SuperManager sm) {
        superManager = sm;
        periodicTimer = 0f;
        screenFlag = new ScreenFlag();
        mainViewport = new FitViewport(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
        backgroundViewport = new FitViewport(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
        mainStage = new MainStage(mainViewport, getBackRunnable());
        backgroundStage = new BackgroundStage(getAssetManager(), backgroundViewport);
        multiplexer = new InputMultiplexer();

        mainStage.getRoot().setOrigin(VIEWPORT_WIDTH * 0.5f, VIEWPORT_HEIGHT * 0.5f);
        mainStage.getRoot().setSize(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
        mainStage.getRoot().setScale(1f);
        mainStage.getRoot().setPosition(0f, 0f);

        addProcessor(mainStage);
        hierarchy = Hierarchy.LOWER;
    }

    @Override
    public void show() {
        clearRootActions();
        unsetInputProcessor();
        addMainAction(sequence(getTransitionAction(Flow.ENTERING, getHierarchy()),
                run(getSetAsInputProcessorRunnable())));
    }

    @Override
    public void render(float delta) {
        clear();

        backgroundStage.act(Math.min(Gdx.graphics.getDeltaTime(), MIN_DELTA_TIME));
        backgroundStage.draw();
        mainStage.act(Math.min(Gdx.graphics.getDeltaTime(), MIN_DELTA_TIME));
        mainStage.draw();

        update();
        checkSwitching();
    }

    @Override
    public void resize(int width, int height) {
        mainViewport.update(width, height);
        backgroundViewport.update(width, height);
    }

    @Override
    public void hide() {
        clearRootActions();
    }

    @Override
    public void dispose() {
        mainStage.dispose();
        backgroundStage.dispose();
    }

    @Override
    public void back() {
        getGameManager().play(GameManager.Fx.Back);
        switchToScreen(this.previousKey, Hierarchy.HIGHER);
    }

    private void update() {
        periodicTimer += Gdx.graphics.getDeltaTime();
        if (periodicTimer > PERIODIC_TASK_TIME) {
            periodicTimer = 0;
            periodicTask();
        }
    }

    /**
     * Este mtodo permite a las clases derivadas ejecutar cualquier tarea con una periodicidad de
     * {@link #PERIODIC_TASK_TIME}.
     */
    protected void periodicTask() {
    }

    /**
     * Fija la clave de la pantalla
     *
     * @param key Clave de pantalla
     */
    public void setThisKey(ScreenManager.Key key) {
        thisKey = key;
    }

    /**
     * Devuelve la clave de la pantalla
     */
    public ScreenManager.Key getThisKey() {
        return thisKey;
    }

    /**
     * Limpia la pantalla (antes de dibujar)
     */
    protected void clear() {
        Gdx.gl.glClearColor(0.980392157f, 0.980392157f, 0.980392157f, 1.0f);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    }

    /**
     * Devuelve el SuperManager
     */
    protected SuperManager getSuperManager() {
        return this.superManager;
    }

    /**
     * Devuelve el PrefsManager
     */
    protected PrefsManager getPrefsManager() {
        return getSuperManager().getPrefsManager();
    }

    /**
     * Devuelve el AssetManager
     */
    public AssetManager getAssetManager() {
        return getSuperManager().getAssetManager();
    }

    /**
     * Devuelve un asset determinado
     *
     * @param fileName Descriptor de fichero del asset
     * @param type Tipo de asset
     */
    public synchronized <T> T getAsset(String fileName, Class<T> type) {
        return getAssetManager().get(fileName, type);
    }

    /**
     * Devuelve el ScreenManager
     */
    public ScreenManager getScreenManager() {
        return getSuperManager().getScreenManager();
    }

    /**
     * Fija la clave de la pantalla anterior
     *
     * @param key Clave de pantalla
     */
    protected void setPreviousScreen(ScreenManager.Key key) {
        this.previousKey = key;
    }

    /**
     * Devuelve la clave de la pantalla anterior
     */
    protected ScreenManager.Key getPreviousScreen() {
        return this.previousKey;
    }

    /**
     * Fija la jerarqua de la pantalla
     *
     * @param hierarchy Jerarquia
     */
    public void setHierarchy(Hierarchy hierarchy) {
        this.hierarchy = hierarchy;
    }

    /**
     * Devuelve la jerarquia de la pantalla
     */
    public Hierarchy getHierarchy() {
        return this.hierarchy;
    }

    /**
     * Configura esta pantalla como InputProcessor (solo puede haber un InputProcessor)
     */
    public void setAsInputProcessor() {
        Gdx.input.setInputProcessor(this.mainStage);
    }

    /**
     * Desconfigura el InputProcessor
     */
    public void unsetInputProcessor() {
        Gdx.input.setInputProcessor(null);
    }

    /**
     * Devuelve el multiplexor de procesadores de entradas (multiplexor)
     */
    protected InputProcessor getProcessor() {
        return this.multiplexer;
    }

    /**
     * Aade al multiplexor un procesador de entrada
     *
     * @param processor Procesador de entrada
     */
    protected void addProcessor(InputProcessor processor) {
        this.multiplexer.addProcessor(processor);
    }

    /**
     * Ejecuta la animacion de salida y cambia a otra pantalla
     *
     * @param screen Name Nombre de la siguiente pantalla
     * @param hierarchy Hierarchy Jerarqua de la siguiente pantalla respecto de la actual
     */
    public void switchToScreen(final ScreenManager.Key screen, final Hierarchy hierarchy) {
        clearRootActions();
        unsetInputProcessor();

        Runnable flagSwitch = new Runnable() {
            @Override
            public void run() {
                flagSwitch(screen, hierarchy);
            }
        };

        addMainAction(sequence(getTransitionAction(Flow.LEAVING, hierarchy), run(flagSwitch)));
    }

    /**
     * Sealiza un cambio de pantalla
     *
     * @param screen Pantalla destino
     * @param hierarchy Jerarquia de la pantalla destino respecto de la actual
     */
    protected void flagSwitch(ScreenManager.Key screen, Hierarchy hierarchy) {
        screenFlag.enable(screen, hierarchy);
    }

    /**
     * Ejecuta un cambio inmediato de pantalla. Este mtodo debe llamarse al final del
     * {@link #render(float)} para evitar excepciones de acceso a memoria. El cambio slo se
     * ejecutar si se ha marcado la {@link #screenFlag}.
     */
    protected void checkSwitching() {
        if (screenFlag.isEnabled())
            getScreenManager().switchToScreen(screenFlag.getScreen(), screenFlag.getHierarchy());
    }

    /**
     * Ejecuta la animacion de salida y termina la aplicacion
     */
    public void exitApplication() {
        clearRootActions();
        addMainAction(sequence(getTransitionAction(Flow.LEAVING, Hierarchy.HIGHER), run(getExitRunnable())));
    }

    /**
     * Devuelve el ejecutable de salida de la aplicacion
     */
    private Runnable getExitRunnable() {
        return new Runnable() {
            @Override
            public void run() {
                Gdx.app.exit();
            }
        };
    }

    /**
     * Devuelve el ejecutable de ir hacia atras
     */
    private Runnable getBackRunnable() {
        return new Runnable() {
            @Override
            public void run() {
                back();
            }
        };
    }

    /**
     * Devuelve el ejecutable de configurar esta pantalla como InputProcessor
     */
    protected Runnable getSetAsInputProcessorRunnable() {
        return new Runnable() {
            @Override
            public void run() {
                Gdx.input.setInputProcessor(getProcessor());
            }
        };
    }

    /**
     * Limpia las acciones de la stage principal
     */
    protected void clearRootActions() {
        mainStage.getRoot().clearActions();
    }

    /**
     * Aade una accion a la stage principal
     *
     * @param action Accion
     */
    private void addMainAction(Action action) {
        mainStage.getRoot().addAction(action);
    }

    /**
     * Devuelve una animacion de transicion
     *
     * @param flow Flow Flujo de la pantalla actual
     * @param hierarchy Hierarchy Jerarqua de la siguiente pantalla respecto de la actual
     */
    protected Action getTransitionAction(Flow flow, Hierarchy hierarchy) {
        switch (flow) {
        case ENTERING:
            return transitionEntering(hierarchy);
        case LEAVING:
            return transitionLeaving(hierarchy);
        default:
            return resetAction();
        }
    }

    /**
     * Devuelve una animacion de transicion de entrada
     *
     * @param hierarchy Jerarquia de la pantalla actual respecto de la anterior
     */
    private Action transitionEntering(Hierarchy hierarchy) {
        switch (hierarchy) {
        case LOWER:
            return fromInsideAction();
        case HIGHER:
            return fromOutsideAction();
        default:
            return appearAction();
        }
    }

    /**
     * Devuelve una animacion de transicion de salida
     *
     * @param hierarchy Jerarquia de la pantalla actual respecto de la siguiente
     */
    private Action transitionLeaving(Hierarchy hierarchy) {
        switch (hierarchy) {
        case LOWER:
            return toOutsideAction();
        case HIGHER:
            return toInsideAction();
        default:
            return disappearAction();
        }
    }

    /**
     * Devuelve una accion de transicion hacia afuera
     */
    private Action toOutsideAction() {
        return new SequenceAction(parallel(fadeOut(TRANSITION_DURATION, INTERPOLATION_IN),
                scaleTo(SIZE_LARGE, SIZE_LARGE, TRANSITION_DURATION, INTERPOLATION_IN)));
    }

    /**
     * Devuelve una accion de transicion hacia adentro
     */
    private Action toInsideAction() {
        return new SequenceAction(parallel(fadeOut(TRANSITION_DURATION, INTERPOLATION_IN),
                scaleTo(SIZE_SMALL, SIZE_SMALL, TRANSITION_DURATION, INTERPOLATION_IN)));
    }

    /**
     * Devuelve una accion de transicion desde dentro
     */
    private Action fromInsideAction() {
        return new SequenceAction(alpha(0f), scaleTo(SIZE_SMALL, SIZE_SMALL),
                parallel(fadeIn(TRANSITION_DURATION, INTERPOLATION_OUT),
                        scaleTo(1f, 1f, TRANSITION_DURATION, INTERPOLATION_OUT)));
    }

    /**
     * Devuelve una accion de transicion desde fuera
     */
    private Action fromOutsideAction() {
        return new SequenceAction(alpha(0f), scaleTo(SIZE_LARGE, SIZE_LARGE),
                parallel(fadeIn(TRANSITION_DURATION, INTERPOLATION_OUT),
                        scaleTo(1f, 1f, TRANSITION_DURATION, INTERPOLATION_OUT)));
    }

    /**
     * Devuelve una accion de aparicion (por defecto)
     */
    private Action appearAction() {
        return new SequenceAction(alpha(0f), scaleTo(SIZE_LARGE, SIZE_LARGE),
                fadeIn(TRANSITION_DURATION, INTERPOLATION_IN));
    }

    /**
     * Devuelve una accion de desaparicion (por defecto)
     */
    private Action disappearAction() {
        return new SequenceAction(alpha(1f), scaleTo(1f, 1f), fadeOut(TRANSITION_DURATION, INTERPOLATION_IN));
    }

    /**
     * Devuelve una accion de reseteo de escala y canal alpha
     */
    private Action resetAction() {
        return new SequenceAction(alpha(1f), scaleTo(1f, 1f));
    }

    /**
     * Aade un Actor a la Stage principal
     */
    public void addMainActor(Actor actor) {
        mainStage.addActor(actor);
    }

    /**
     * Devuelve la stage principal
     */
    protected Stage getMainStage() {
        return mainStage;
    }

    /**
     * Devuelve la stage de fondo estatico
     */
    protected Stage getBackgroundStage() {
        return backgroundStage;
    }

    /**
     * Devuelve el GameManager
     */
    protected GameManager getGameManager() {
        return getSuperManager().getGameManager();
    }

}