package toritools.entity; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Image; import java.awt.image.VolatileImage; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import toritools.debug.Debug; import toritools.entrypoint.Binary; import toritools.math.Vector2; import toritools.scripting.ScriptUtils; public class Level extends Entity { private HashMap<String, Entity> idMap = new HashMap<String, Entity>(); private List<List<Entity>> layers = new ArrayList<List<Entity>>(); /** * The entity lists. */ private List<Entity> solids = new ArrayList<Entity>(), nonSolids = new ArrayList<Entity>(); /** * The type map */ private HashMap<String, List<Entity>> typeMap = new HashMap<String, List<Entity>>(); private List<Entity> trash = new ArrayList<Entity>(); private List<Entity> newEntities = new ArrayList<Entity>(); private Entity viewPort; private void addEntityUnsafe(final Entity e) { layers.get(e.getLayer()).add(e); if (e.isSolid()) { solids.add(e); } else { nonSolids.add(e); } } private void removeEntityUnsafe(final Entity e) { e.setActive(false); layers.get(e.getLayer()).remove(e); if (e.isSolid()) solids.remove(e); else nonSolids.remove(e); String id; if ((id = e.getVariableCase().getVar("id")) != null) { idMap.remove(id); } typeMap.get(e.getType()).remove(e); } public void spawnEntity(final Entity entity) { getNewEntities().add(entity); String id; if ((id = entity.getVariableCase().getVar("id")) != null) { idMap.put(id, entity); } if (!typeMap.containsKey(entity.getType())) { typeMap.put(entity.getType(), new ArrayList<Entity>()); } typeMap.get(entity.getType()).add(entity); } public void despawnEntity(final Entity entity) { trash.add(entity); } private void spawnNewEntities() { List<Entity> tempList = new ArrayList<Entity>(getNewEntities()); getNewEntities().clear(); for (Entity e : tempList) { addEntityUnsafe(e); } for (Entity e : tempList) { e.onSpawn(this); } } private void takeOutTrash() { List<Entity> tempList = new ArrayList<Entity>(trash); trash.clear(); for (Entity e : tempList) { removeEntityUnsafe(e); } for (Entity e : tempList) { e.onDeath(this, false); } } @Override public void onSpawn(final Level level) { spawnNewEntities(); } public void onUpdate(final float time) { spawnNewEntities(); for (Entity e : solids) { e.onUpdate(time, this); } for (Entity e : nonSolids) { e.onUpdate(time, this); } takeOutTrash(); if (viewPort != null) { for (Entity e : solids) { e.setInView(ScriptUtils.isColliding(viewPort, e)); } for (Entity e : nonSolids) { e.setInView(ScriptUtils.isColliding(viewPort, e)); } } } public void onDeath(final boolean isRoomExit) { for (Entity e : solids) { e.onDeath(this, isRoomExit); } for (Entity e : nonSolids) { e.onDeath(this, isRoomExit); } } public Level() { super(); for (int i = 0; i < 10; i++) { layers.add(new ArrayList<Entity>()); } } public Entity getEntityWithId(final String id) { return idMap.get(id); } public List<Entity> getEntitiesWithType(final String type) { if (typeMap.containsKey(type)) return typeMap.get(type); return new ArrayList<Entity>(); } public void setViewportData(final Vector2 pos, final Vector2 dim) { if (viewPort == null) { viewPort = new Entity(); } viewPort.setPos(pos); viewPort.setDim(dim); } private Image baked; /** * Draw every BACKGROUND object to a large volatile image, and delete all * the objects. This speeds up performance by removing pointless iterations * and lookups, but prevents background objects from being in the * foreground. * * @return the baked image. */ public Image bakeBackground() { baked = Binary.gc.createCompatibleVolatileImage((int) dim.x, (int) dim.y, VolatileImage.TRANSLUCENT); ((VolatileImage) baked).validate(Binary.gc); Graphics2D gr = (Graphics2D) baked.getGraphics(); gr.setColor(new Color(0, 0, 0, 0)); gr.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OUT)); gr.fillRect(0, 0, (int) dim.x, (int) dim.y); for (Entity e : getEntitiesWithType(ReservedTypes.BACKGROUND.toString())) { despawnEntity(e); e.draw((Graphics2D) baked.getGraphics()); } Debug.print("Baking Backgrounds..."); return baked; } /** * Returns the baked background. Make sure you bake it first! * * @return the baked bg, or null if none exists. DO NOT BAKE WHILE DRAWING. */ public Image getBakedBackground() { return baked; } public List<List<Entity>> getLayers() { return layers; } public List<Entity> getSolids() { return solids; } public List<Entity> getNonSolids() { return nonSolids; } /** * Grab a highly volatile list of the entities queued for spawn. Avoid! */ public List<Entity> getNewEntities() { return newEntities; } }