fourmiz.engine.Engine.java Source code

Java tutorial

Introduction

Here is the source code for fourmiz.engine.Engine.java

Source

/*//////////////////////////////////////////////////////////////////////
   This file is part of Fourmiz, an simulation of ant live.
   Copyright (C) 2013  Nicolas Barranger <wicowyn@gmail.com>
              Jean-Baptiste Le Henaff <jb.le.henaff@gmail.com>
              Antoine Fouque <antoine.fqe@gmail.com>
              Julien Camenen <jcamenen@gmail.Com>
Fourmiz 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.
    
Fourmiz 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 Fourmiz.  If not, see <http://www.gnu.org/licenses/>.
*///////////////////////////////////////////////////////////////////////

package fourmiz.engine;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jdom2.DataConversionException;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.geom.Shape;
import org.newdawn.slick.geom.Vector2f;

import tools.RessourceManager;
import fourmiz.collision.CollisionManager;
import fourmiz.collision.Entity;

/**
 * Class to load level from xml files and handle cadence all entities
 * @author Nicolas
 */
public class Engine {
    public static int SIZE_CASE = 100;
    private int xCase, yCase;
    private float xScale, yScale;
    private List<EngineListener> listeners = new ArrayList<EngineListener>();
    private CollisionManager collisionManager = new CollisionManager();
    private List<Entity> entities = new ArrayList<Entity>();
    private List<Entity> entitiesAdd = new ArrayList<Entity>();
    private List<Entity> entitiesRemove = new ArrayList<Entity>();
    private Logger log = LogManager.getLogger(getClass());
    private boolean loaded = false;
    private static String renderSuffix = "-render.xml";
    private static String mapSuffix = "-map.xml";
    private static String resourcePath = "ressources/";
    private String currentGame;
    private RessourceManager ressources = new RessourceManager();

    public static Shape getDefaultShape() {
        return new Rectangle(0, 0, SIZE_CASE, SIZE_CASE);
    }

    public RessourceManager getRessources() {
        return ressources;
    }

    /**
    * Callback method called at each cycle, it call each {@link Entity#update(int)} of entity contained
    * @param delta time elapsed from last call
    */
    public void update(int delta) {
        for (Entity entity : entities)
            entity.update(delta);
        checkEntityBuff();
        collisionManager.performCollision();
        checkEntityBuff();
    }

    /**
     * Like we can't add or remove {@link Entity} during update phase we must add temporary this change to different
     * list. This method check is temporary {@link Entity} exist and if is the case, it add them to right mode.
     */
    public void checkEntityBuff() {
        entities.addAll(entitiesAdd);
        collisionManager.addEntity(entitiesAdd);

        entities.removeAll(entitiesRemove);
        collisionManager.removeEntity(entitiesRemove);

        for (Entity entity : this.entitiesAdd)
            notifyEntityAdded(entity);
        for (Entity entity : this.entitiesRemove)
            notifyEntityRemoved(entity);

        entitiesAdd.clear();
        entitiesRemove.clear();
    }

    /**
    * Return copy of {@link ArrayList} of all {@link Entity} contained
    * @return the list
    */
    public List<Entity> getEntities() {
        return this.entities;
    }

    public void addEntityToBuff(Entity entity) {
        this.entitiesAdd.add(entity);
        this.log.debug("add Entity: " + entity.getClass().getSimpleName() + ", ID: " + entity.getID()
                + ", position: " + entity.getPosition() + ", direction: " + entity.getDirection());
    }

    public void removeEntityToBuff(Entity entity) {
        this.entitiesRemove.add(entity);
        this.log.debug("remove Entity: " + entity.getClass().getSimpleName() + ", ID: " + entity.getID()
                + ", position: " + entity.getPosition() + ", direction: " + entity.getDirection());
    }

    public void addEntity(Entity entity) {
        this.entities.add(entity);

        this.collisionManager.addEntity(entity);
        notifyEntityAdded(entity);
        this.log.debug("add Entity: " + entity.getClass().getSimpleName() + ", ID: " + entity.getID()
                + ", position: " + entity.getPosition() + ", direction: " + entity.getDirection());
    }

    public void removeEntity(Entity entity) {
        this.entities.remove(entity);

        this.collisionManager.removeEntity(entity);

        notifyEntityRemoved(entity);
        this.log.debug("remove Entity: " + entity.getClass().getSimpleName() + ", ID: " + entity.getID()
                + ", position: " + entity.getPosition() + ", direction: " + entity.getDirection());
    }

    public List<? extends Entity> getListOf(Class<?> classType) {
        List<Entity> list = new ArrayList<Entity>();

        for (Entity entity : this.entities)
            if (entity.getClass().equals(classType))
                list.add(entity);

        return list;
    }

    /**
     * Return list of possible game to load
     * @return the list of game
     */
    public static List<String> getPossibleGame() {
        List<String> listMap = new ArrayList<String>();
        List<String> listRender = new ArrayList<String>();

        File[] files = (new File(resourcePath)).listFiles();

        for (File file : files) {
            String name = file.getName();
            if (name.endsWith(renderSuffix)) {
                listRender.add(name.substring(0, name.indexOf(renderSuffix)));
            }
            if (name.endsWith(mapSuffix)) {
                listMap.add(name.substring(0, name.indexOf(mapSuffix)));
            }
        }

        listMap.retainAll(listRender);

        return listMap;
    }

    /**
     * Load a specific game
     * @param name
     * @throws JDOMException
     * @throws IOException
     * @throws SlickException
     */
    public void loadLevel(String name) throws JDOMException, IOException, SlickException {
        currentGame = name;
        ressources.load(resourcePath + currentGame + renderSuffix);
        SAXBuilder sax = new SAXBuilder();
        Document doc = sax.build(new File(resourcePath + currentGame + mapSuffix));
        Element root = doc.getRootElement();
        List<Element> listElem = root.getChildren();

        for (Element elem : listElem) {
            switch (elem.getName()) {
            case "Config":
                loadConfig(elem.getChildren());
                break;
            case "Entity":
                loadEntity(elem.getChildren());
                break;
            default:
                log.warn("loadLevel: unknown type object -> " + elem.getName());
                continue;
            }
        }

        this.loaded = true;
    }

    /**
     * Parse configuration part of xml
     * @param configs
     */
    private void loadConfig(Collection<Element> configs) {
        for (Element elem : configs) {
            switch (elem.getName()) {
            case "Chart":
                setxCase(Integer.parseInt(elem.getAttributeValue("xCase")));
                setyCase(Integer.parseInt(elem.getAttributeValue("yCase")));
                setxScale(Float.parseFloat(elem.getAttributeValue("xScale")));
                setyScale(Float.parseFloat(elem.getAttributeValue("yScale")));
                break;
            default:
                log.warn("loadLevel: unknown type config -> " + elem.getName());
                continue;
            }

        }
    }

    /**
     * Parse entity part of xml
     * @param elems
     * @throws DataConversionException
     */
    private void loadEntity(Collection<Element> elems) throws DataConversionException {
        for (Element elem : elems) {
            Entity entity = null;
            switch (elem.getName()) {
            case "Anthill":
                entity = EntityFactory.createEntity(EntityName.Anthill, this);
                break;
            case "Egg":
                entity = EntityFactory.createEntity(EntityName.Egg, this);
                break;
            case "Larva":
                entity = EntityFactory.createEntity(EntityName.Larva, this);
                break;
            case "Nymph":
                entity = EntityFactory.createEntity(EntityName.Nymph, this);
                break;
            case "FourmizWorker":
                entity = EntityFactory.createEntity(EntityName.FourmizWorker, this);
                break;
            case "FourmizSoldier":
                entity = EntityFactory.createEntity(EntityName.FourmizSoldier, this);
                break;
            case "FourmizSex":
                entity = EntityFactory.createEntity(EntityName.FourmizSex, this);
                break;
            case "Queen":
                entity = EntityFactory.createEntity(EntityName.Queen, this);
                break;
            case "Prey":
                entity = EntityFactory.createEntity(EntityName.Prey, this);
                break;
            case "PopPrey":
                entity = EntityFactory.createEntity(EntityName.PopPrey, this);
                break;
            default:
                log.warn("loadLevel: unknown type entity -> " + elem.getName());
                continue;
            }

            Vector2f position = new Vector2f();
            position.x = elem.getAttribute("x").getIntValue() * SIZE_CASE;
            position.y = elem.getAttribute("y").getIntValue() * SIZE_CASE;
            entity.setPosition(position);

            entity.setDirection(elem.getAttribute("dir").getIntValue());

            addEntity(entity);
        }
    }

    public int getxCase() {
        return xCase;
    }

    public void setxCase(int xCase) {
        this.xCase = xCase;
    }

    public int getyCase() {
        return yCase;
    }

    public void setyCase(int yCase) {
        this.yCase = yCase;
    }

    public float getxScale() {
        return xScale;
    }

    public void setxScale(float xScale) {
        this.xScale = xScale;
    }

    public float getyScale() {
        return yScale;
    }

    public void setyScale(float yScale) {
        this.yScale = yScale;
    }

    /**
     * Unload the engine of all his entity and other
     */
    public void unLoad() {
        for (Entity entity : this.entities)
            entity.clear();

        this.entities.clear();
        this.entitiesAdd.clear();
        this.entitiesRemove.clear();
        this.collisionManager = new CollisionManager();

        this.loaded = false;
    }

    public boolean isLoad() {
        return this.loaded;
    }

    public boolean addListener(EngineListener listener) {
        return this.listeners.add(listener);
    }

    public boolean removeListener(EngineListener listener) {
        return this.listeners.remove(listener);
    }

    protected void notifyEntityAdded(Entity entity) {
        for (EngineListener listener : this.listeners)
            listener.entityAdded(entity);
    }

    protected void notifyEntityRemoved(Entity entity) {
        for (EngineListener listener : this.listeners)
            listener.entityRemoved(entity);
    }
}