com.sidereal.dolphinoes.architecture.GameScene.java Source code

Java tutorial

Introduction

Here is the source code for com.sidereal.dolphinoes.architecture.GameScene.java

Source

/*******************************************************************************
 * Copyright 2014 See AUTHORS file.
 * 
 * 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.sidereal.dolphinoes.architecture;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;

/** Scene of the game. Handles updating all of the objects tied to the scene by
 * updating the {@link GameBatch} objects found in {@link #gameBatches}. The
 * gamebatches added to the scene are handled in {@link #createGameBatches()}
 * which can be overrided.
 * <p>
 * To set the current scene, initialise a scene and call {@link DolphinOES#setScreen(Screen)}. 
 * For passing objects from one scene to another, use
 * {@link #passListToNextScene(ArrayList)} or
 * {@link #passObjToNextScene(GameObject)}.
 * <p>
 * Pausing and unpausing can be easily customised from scene to scene through
 * the use of {@link #eventOnPause} and {@link #eventOnUnpause}.
 * <p>
 * The object also deals with drawing and clearing the rendering batches.
 * 
 * @see {@link GameBatch} for scene "layers"
 * @see {@link GameObject} for individual entities
 * 
 * @author Claudiu Bele */
public abstract class GameScene implements Screen {

    // region fields
    /** list of game batches created in {@link #createGameBatches()} */
    public ArrayList<GameBatch> gameBatches;

    /** The default game batch. The particle game batches use this game batche's
     * camera to properly render things where they should */
    public GameBatch defaultBatch;

    /** Color used for clearing the screen */
    protected Color bgColor;

    /** List in which we will put objects that we want to remove, removing them
     * at the end of the frame. */
    private ArrayList<GameObject> toRemove;
    /** List of objects that will not be disposed, and will be passed and updated
     * in the next scene, being added to {@link #objectsList} and
     * {@link #objectsMap} as well as having the {@link GameObject#gameBatch}
     * set to the one with the same tag in the new scene */
    private ArrayList<GameObject> toKeepForNextScene;
    /** List in which we will put objects that we want to add, adding them at the
     * end of the frame. */
    private ArrayList<GameObject> toAdd;

    /** Objects Organised in a map, by type, the value baing another map, where
     * the key is the name of the Object
     * <p>
     * To get a specific object you need his {@link GameObject#name} and
     * {@link GameObject#type} */
    public HashMap<String, HashMap<String, GameObject>> objectsMap;

    /** Comparator used for sorting the game batches. Used in
     * {@link GameScene#render(float) } , is assigned in
     * {@link GameScene#GameScene(Object[]...)} to sorting
     * based on {@link GameBatch#priorityLevel}. */
    protected Comparator<GameBatch> gameBatchComparator;

    // endregion

    // region Constructor
    public GameScene(Object... params) {

        this.gameBatches = new ArrayList<GameBatch>();
        this.gameBatchComparator = new Comparator<GameBatch>() {
            @Override
            public int compare(GameBatch o1, GameBatch o2) {

                return o1.priorityLevel - o2.priorityLevel;
            }
        };

        this.toAdd = new ArrayList<GameObject>();
        this.toRemove = new ArrayList<GameObject>();
        this.objectsMap = new HashMap<String, HashMap<String, GameObject>>();
        this.setToKeepForNextScene(new ArrayList<GameObject>());
        this.bgColor = new Color(1, 1, 1, 1);

    }

    /** Add all the wanted objects and the logic to them here.
     * <p>
     * This method is called in the constructor of the scene, and you have to
     * make all the objects and assign values to them here, after which you have
     * to add them to the objects list.
     * <p>
     * In the render method, we call the update of each update in the arraylist,
     * which calls the update of each of it's behavior.
     * 
     * @param params */
    public abstract void createScene();

    /** Called when the screen renders itself
     * <p>
     * This method shouldn't be changed, everything could be set up in the
     * createScene method. */
    // endregion

    // region methods
    @Override
    public final void render(float delta) {

        Gdx.gl.glClearColor(bgColor.r, bgColor.g, bgColor.b, bgColor.a);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        for (int i = 0; i < gameBatches.size(); i++) {
            gameBatches.get(i).run();
            if (gameBatches == null)
                return;
        }

        for (int i = 0; i < gameBatches.size(); i++) {
            // camera view is different from screen size => resize
            if ((Gdx.graphics.getWidth() != gameBatches.get(i).camera.viewportWidth
                    || Gdx.graphics.getHeight() != gameBatches.get(i).camera.viewportHeight)
                    && gameBatches.get(i).referencingBatch == null)

            {
                gameBatches.get(i).resize();
            }
        }

        addObjects();
        removeObjects();

    }

    /** Method for making the batches to use in the scene, their layer and
     * whether or not any of them is "in sync" with another one ( uses the same
     * camera ). */
    protected void createGameBatches() {

        defaultBatch = new GameBatch(this, "Default");
        defaultBatch.translateMousePosition = true;
        addGameBatch(defaultBatch);

        GameBatch UIBatch = new GameBatch(this, "UI");
        UIBatch.priorityLevel = 2;
        UIBatch.translateMousePosition = true;
        addGameBatch(UIBatch);

        GameBatch particlesBefore = new GameBatch(this, "Particle First", defaultBatch);
        particlesBefore.priorityLevel = -1;
        particlesBefore.setSort(false, null);
        addGameBatch(particlesBefore);

        GameBatch particlesAfter = new GameBatch(this, "Particle Last", defaultBatch);
        particlesAfter.priorityLevel = 1;
        particlesAfter.setSort(false, null);
        addGameBatch(particlesAfter);

    }

    // region adding and removing

    // region game batches
    /** Adds a gameBatch to {@link #gameBatches}, which is updated in
     * {@link #render(float)}.
     * <p>
     * The Gamebatch will be added if it is not already in the list.
     * 
     * @param batch
     *            The batch that you want to add */
    protected final void addGameBatch(GameBatch batch) {

        if (!gameBatches.contains(batch)) {
            gameBatches.add(batch);
            Collections.sort(gameBatches, gameBatchComparator);
        }
    }

    /** Attempts to remove a specific gameBatch from the list.
     * 
     * @param batch
     *            The batch that you want removed
     * @return Whether or not the batch was in {@link #gameBatches} */
    protected final boolean removeGameBatch(GameBatch batch) {

        return gameBatches.remove(batch);
    }

    /** Returns the game batch with the required name or null if not found in the
     * list
     * 
     * @param name
     *            The name of the gamebatch
     * @return */
    public final GameBatch getGameBatch(String name) {

        for (int i = 0; i < gameBatches.size(); i++) {
            if (gameBatches.get(i).name.equals(name)) {
                return gameBatches.get(i);
            }
        }
        return null;
    }

    // endregion
    // region end of frame objects add/remove
    /** Adds objects currently in a queue to be added to the scene. Called
     * every frame when the scene is the focused scene.*/
    private final void addObjects() {

        for (int i = 0; i < toAdd.size(); i++) {
            toAdd.get(i).inScene = true;

            if (objectsMap.containsKey(toAdd.get(i).getType())
                    && objectsMap.get(toAdd.get(i).getType()).containsValue(toAdd.get(i))) {
            } else {
                if (!objectsMap.containsKey(toAdd.get(i).getType())) {
                    objectsMap.put(toAdd.get(i).getType(), new HashMap<String, GameObject>());
                }
                objectsMap.get(toAdd.get(i).getType()).put(toAdd.get(i).getName(), toAdd.get(i));
            }

        }
        toAdd.clear();

    }

    /** Internally removes objects currently in a queue to be removed from the scene. Called
     * every frame when the scene is the focused scene, removing objects flagged
     * for removal.*/
    private final void removeObjects() {

        // handles removing objects that were to be removed during this
        // frame
        for (int i = 0; i < toRemove.size(); i++) {
            // Checks whether or not the object we want to remove exists
            if (objectsMap.containsKey(toRemove.get(i).getType())) {

                if (objectsMap.get(toRemove.get(i).getType()).containsKey(toRemove.get(i).getName())) {

                    objectsMap.get(toRemove.get(i).getType()).remove(toRemove.get(i).getName());

                }
            }

            if (toRemove.get(i).gameBatch.objects.contains(toRemove.get(i)))
                toRemove.get(i).gameBatch.objects.remove(toRemove.get(i));
            toRemove.get(i).disposeInternal();

        }
        if (toRemove.size() > 0)
            toRemove.clear();
    }

    // endregion
    // region object passing to next scene
    public final <T extends GameObject> void passObjToNextScene(T obj) {

        if (!getToKeepForNextScene().contains(obj)) {
            getToKeepForNextScene().add(obj);

            synchronized (obj.children) {
                if (obj.children != null) {
                    for (int i = 0; i < obj.children.size(); i++) {
                        passObjToNextScene(obj.children.get(i));
                    }
                }
            }
            return;
        }
    }

    public final <T extends GameObject> void passListToNextScene(ArrayList<T> objects) {

        for (int i = 0; i < objects.size(); i++) {
            passObjToNextScene(objects.get(i));
        }
    }

    public ArrayList<GameObject> getToKeepForNextScene() {

        return toKeepForNextScene;
    }

    public void setToKeepForNextScene(ArrayList<GameObject> toKeepForNextScene) {

        this.toKeepForNextScene = toKeepForNextScene;
    }

    // endregion

    // region single objects
    /** Puts an object in a queue to be added at the end of the frame
     * 
     * @param obj */
    public void add(GameObject obj) {

        toAdd.add(obj);
    }

    /** Puts the object in a queue to be removed at the end of the frame
     * 
     * @param obj */
    public void remove(GameObject obj) {

        obj.inScene = false;

        synchronized (toRemove) {
            toRemove.add(obj);
        }
    }

    /** Retrieves the object with the expected type and name , or if it can't be
     * found, returns null. This method is very expensive as it queries all objects (until 
     * the first one is found) in all gamebatches for a potential match. If no object 
     * is found, null will be returned.
     * 
     * @param type The type of the object to find
     * @param name The name of the object to find
     * @return the first object with the given type and name, otherwise null.*/
    public GameObject get(String type, String name) {

        for (int i = 0; i < gameBatches.size(); i++) {
            for (int j = 0; j < gameBatches.get(i).objects.size(); i++) {
                if (gameBatches.get(i).objects.get(j).getName().equals(name)
                        && gameBatches.get(i).objects.get(j).getType().equals(type))
                    return gameBatches.get(i).objects.get(j);
            }
        }

        return null;
    }

    // endregion

    // endregion

    // region inheritance methods
    @Override
    public void show() {

    }

    @Override
    public void resize(int width, int height) {

    }

    @Override
    public void hide() {

    }

    @Override
    public void pause() {

    }

    @Override
    public void resume() {

    }

    @Override
    public void dispose() {

        for (int i = 0; i < gameBatches.size(); i++) {
            gameBatches.get(i).spriteBatch.dispose();
            gameBatches.get(i).camera = null;
            gameBatches.get(i).objects.clear();
            gameBatches.get(i).objects = null;
        }
        gameBatches = null;
        gameBatchComparator = null;
        defaultBatch = null;
        objectsMap = null;

    }
    // endregion

    // endregion
}