Java tutorial
/******************************************************************************* * 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 }