123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462 |
- package me.hammerle.supersnuvi.gamelogic;
- import java.io.File;
- import java.util.HashMap;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.TreeSet;
- import java.util.stream.Collectors;
- import me.hammerle.supersnuvi.entity.Entity;
- import me.hammerle.supersnuvi.entity.EntityBuilder;
- import me.hammerle.supersnuvi.tiles.BottledSoulTile;
- import me.hammerle.supersnuvi.tiles.Location;
- import me.hammerle.supersnuvi.tiles.StartTile;
- import me.hammerle.supersnuvi.tiles.Tile;
- import me.hammerle.supersnuvi.util.CollisionBox;
- import me.hammerle.supersnuvi.rendering.IRenderer;
- public final class Level
- {
- private final StateRenderer state;
- private final IRenderer renderer;
-
- private final boolean worldLoaded;
- private final LevelData data;
-
- private final String name;
-
- private final HashMap<Integer, Entity> entities;
- private Entity hero;
- private int entityCounter;
-
- private boolean shouldReset;
- private boolean done;
-
- private int souls;
- private int maxSouls;
-
- private double time;
-
- private TreeSet<Point> spawns;
-
- public Level(StateRenderer state, File f)
- {
- this.state = state;
- this.renderer = state.getRenderer();
- this.data = new LevelData(f);
- this.worldLoaded = data.load();
- this.entities = new HashMap<>();
- this.entityCounter = 0;
- this.shouldReset = false;
- this.done = false;
- this.time = 0.0;
-
- this.spawns = new TreeSet<>();
-
- if(worldLoaded)
- {
- this.name = data.getString("name", "error");
- maxSouls = 0;
- data.forEachInteractTile((x, y, tile) ->
- {
- if(tile == BottledSoulTile.ID)
- {
- maxSouls++;
- }
- else if(tile == StartTile.ID)
- {
- spawns.add(new Point(x, y));
- }
- });
- }
- else
- {
- this.name = "error";
- maxSouls = 0;
- }
-
- // there must be at least one spawn
- if(spawns.isEmpty())
- {
- spawns.add(new Point(5, 5));
- }
-
- /*if(name.equals("00-Tech Demo"))
- {
- data.addLayer();
- int index = data.getLayers() - 1;
- data.clearLayer(index);
- int width = data.getWidth();
- int height = data.getHeight();
- for(int x = 10; x < width; x++)
- {
- for(int y = 0; y < height; y++)
- {
- data.setTile(index, x, y, 224 + Math.min(15, x - 10));
- }
- }
- }*/
-
- resetLevel();
-
- //Entity test = EntityBuilder.buildTest(this, 100, 100);
- //entities.put(entityCounter++, test);
- }
-
- // -------------------------------------------------------------------------
- // basic stuff
- // -------------------------------------------------------------------------
- public String getName()
- {
- return name;
- }
-
- public void finishLevel()
- {
- shouldReset = true;
- done = true;
- }
-
- public boolean shouldFinish()
- {
- return done;
- }
-
- public boolean shouldReset()
- {
- return shouldReset;
- }
-
- public void scheduleReset()
- {
- shouldReset = true;
- }
-
- public void resetLevel()
- {
- state.resetTiles();
- souls = 0;
- shouldReset = false;
- done = false;
- Entity h = spawnHero();
- hero = h;
- entities.clear();
- entities.put(entityCounter++, h);
- }
-
- public Entity spawnHero()
- {
- Entity h = hero;
- Point p;
- if(h == null || hero.getX() < 0)
- {
- // first spawn or out of map, use first spawn
- p = spawns.first();
- }
- else
- {
- // hero is somewhere in the map, getting last spawn
- p = spawns.floor(new Point(renderer.toBlock(hero.getX()), renderer.toBlock(hero.getY())));
- if(p == null)
- {
- p = spawns.first();
- }
- }
- return EntityBuilder.buildHero(this, renderer.toCoord(p.getX()), renderer.toCoord(p.getY()));
- }
-
- public void increaseSouls()
- {
- souls++;
- }
-
- public LevelData getData()
- {
- return data;
- }
-
- // -------------------------------------------------------------------------
- // tick
- // -------------------------------------------------------------------------
-
- public void update()
- {
- if(worldLoaded)
- {
- if(hero.getY() < 0)
- {
- resetLevel();
- return;
- }
-
- time += 0.0125;
-
- state.tickTiles();
-
- // doing entity logic first
- entities.values().forEach(entity ->
- {
- entity.tick();
- });
- }
- }
-
- public void render()
- {
- if(worldLoaded)
- {
- // setting the right view center
- double rWidth = renderer.getWidth();
- double rHeight = renderer.getHeight();
-
- double centerX = Math.min(Math.max(0, hero.getX() - rWidth / 2), data.getWidth() * 32 - rWidth);
- double centerY = Math.min(Math.max(0, hero.getY() - rHeight / 2), data.getHeight() * 32 - rHeight);
-
- renderer.setViewCenter(centerX, centerY);
-
- int startX = renderer.getFirstVisibleBlockX();
- int startY = renderer.getFirstVisibleBlockY();
- int endX = Math.min(renderer.getLastVisibleBlockX() + 1, data.getWidth());
- int endY = Math.min(renderer.getLastVisibleBlockY() + 1, data.getHeight());
-
- data.forEachBackground((x, y, tile) ->
- {
- if(tile != -1)
- {
- Tile t = state.getTile(tile);
- t.preRender(renderer, x, y);
- renderer.drawBlockImage(t.getImage(x, y), x, y, t.getRenderOffsetX(), t.getRenderOffsetY());
- t.postRender(renderer, x, y);
- }
- }, startX, endX, startY, endY);
-
- entities.values().forEach(en -> en.getAnimator().render(renderer));
-
- data.forEachForeground((x, y, tile) ->
- {
- if(tile != -1)
- {
- Tile t = state.getTile(tile);
- t.preRender(renderer, x, y);
- renderer.drawBlockImage(t.getImage(x, y), x, y, t.getRenderOffsetX(), t.getRenderOffsetY());
- t.postRender(renderer, x, y);
- }
- }, startX, endX, startY, endY);
-
- // menu rendering
- // |-------------------------------------|
- // | B00/00 | ENERGYENERGY | HPHP | TIME |
- // |-------------------------------------|
- renderer.prepareTextDrawing(255, 255, 255, 1.0, 40);
- {
- double baseLine = renderer.getTextHeight(1);
- double line = baseLine * 1.5;
- double y = baseLine * 0.25;
-
- renderer.save();
- {
- renderer.setFillColor(0, 0, 0, 0.5);
- renderer.fillRectangle(0, 0, renderer.getWidth(), line);
- }
- renderer.restore();
- // soul rendering
- char[] c = new char[5];
- if(souls <= 9)
- {
- c[0] = '0';
- c[1] = (char) (souls + '0');
- }
- else if(souls > 99)
- {
- c[0] = 'X';
- c[1] = 'X';
- }
- else
- {
- c[0] = (char) ((souls / 10) + '0');
- c[1] = (char) ((souls % 10) + '0');
- }
- c[2] = '/';
- if(maxSouls <= 9)
- {
- c[3] = '0';
- c[4] = (char) (maxSouls + '0');
- }
- else if(maxSouls > 99)
- {
- c[3] = 'X';
- c[4] = 'X';
- }
- else
- {
- c[3] = (char) ((maxSouls / 10) + '0');
- c[4] = (char) ((maxSouls % 10) + '0');
- }
- double x = 5;
- renderer.drawFixedImage(BottledSoulTile.IMAGE, x, 0, line, line);
- x += line;
- renderer.drawText(x, y, c);
- x += renderer.getTextWidth(5) + 10;
- // energy rendering
- double leftX = (renderer.getWidth() - 40.0 - renderer.getTextWidth(10) - line) * 0.5;
- //double energyWidth = renderer.getWidth() * 0.2;
- //double ex = (renderer.getWidth() / 2) - energyWidth;
- //energyWidth *= 2;
- renderer.save();
- {
- renderer.setFillColor(0, 0, 0, 1.0);
- renderer.fillRectangle(x, y, leftX, baseLine);
- renderer.setFillColor(0, 0, 150, 1.0);
- renderer.fillRectangle(x + 3, y + 3, (leftX * hero.getEnergy().getEnergyPercent()) - 6, baseLine - 6);
- }
- renderer.restore();
- x += leftX + 10;
-
- // hp rendering
- renderer.save();
- {
- renderer.setFillColor(0, 0, 0, 1.0);
- renderer.fillRectangle(x, y, leftX, baseLine);
- renderer.setFillColor(150, 0, 0, 1.0);
- renderer.fillRectangle(x + 3, y + 3, (leftX * hero.getHealth().getHealthPercent()) - 6, baseLine - 6);
- }
- renderer.restore();
- x += leftX + 10;
- // time rendering
- if(time >= 999.9)
- {
- c[0] = '9';
- c[1] = '9';
- c[2] = '9';
- c[3] = '.';
- c[4] = '9';
- renderer.drawText(x, y, c);
- }
- else
- {
- renderer.drawText(x, y, String.format("%05.1f", time).toCharArray());
- }
- }
- renderer.stopTextDrawing();
- }
- }
-
- // -------------------------------------------------------------------------
- // collision box, interaction layer
- // -------------------------------------------------------------------------
-
- public Tile getInteractionTile(int x, int y)
- {
- int i = data.getInteractionTile(x, y);
- if(i == -1)
- {
- return StateRenderer.FALLBACK_TILE;
- }
- return state.getInteractionTile(i);
- }
-
- public CollisionBox getTileMovementBox(int x, int y)
- {
- int i = data.getInteractionTile(x, y);
- if(i == -1)
- {
- return CollisionBox.NULL_BOX;
- }
- Tile tile = state.getInteractionTile(i);
- return tile.getMovementBox(x, y).reset().offset(renderer.toCoord(x), renderer.toCoord(y));
- }
-
- public LinkedList<Location> getTilesInMovementOf(CollisionBox cb)
- {
- LinkedList<Location> boxes = new LinkedList<>();
- int startX = renderer.toBlock(cb.getMinX());
- int endX = renderer.toBlock(cb.getMaxX());
- int startY = renderer.toBlock(cb.getMinY());
- int endY = renderer.toBlock(cb.getMaxY());
-
- for(int x = startX; x <= endX; x++)
- {
- for(int y = startY; y <= endY; y++)
- {
- if(getTileMovementBox(x, y).intersects(cb))
- {
- boxes.add(new Location(getInteractionTile(x, y), x, y));
- }
- }
- }
- return boxes;
- }
-
- public CollisionBox getTileCollisionBox(int x, int y)
- {
- int i = data.getInteractionTile(x, y);
- if(i == -1)
- {
- return CollisionBox.NULL_BOX;
- }
- Tile tile = state.getInteractionTile(i);
- return tile.getCollisionBox(x, y).reset().offset(renderer.toCoord(x), renderer.toCoord(y));
- }
-
- public LinkedList<Location> getTilesCollidingWith(CollisionBox cb)
- {
- LinkedList<Location> boxes = new LinkedList<>();
- int startX = renderer.toBlock(cb.getMinX());
- int endX = renderer.toBlock(cb.getMaxX());
- int startY = renderer.toBlock(cb.getMinY());
- int endY = renderer.toBlock(cb.getMaxY());
-
- for(int x = startX; x <= endX; x++)
- {
- for(int y = startY; y <= endY; y++)
- {
- if(getTileCollisionBox(x, y).intersects(cb))
- {
- boxes.add(new Location(getInteractionTile(x, y), x, y));
- }
- }
- }
- return boxes;
- }
-
- public List<Entity> getEntitiesCollidingWith(Entity not, CollisionBox cb)
- {
- return entities.values().stream().filter(ent -> ent != not && ent.getBox().intersects(cb)).collect(Collectors.toList());
- }
-
- public LinkedList<CollisionBox> getMovementBoxesAt(Entity not, CollisionBox cb)
- {
- LinkedList<CollisionBox> boxes = new LinkedList<>(/*entities.values().stream()
- .filter(ent -> ent != not && ent.getBox().intersects(cb))
- .map(ent -> ent.getBox())
- .collect(Collectors.toList())*/);
- int startX = renderer.toBlock(cb.getMinX());
- int endX = renderer.toBlock(cb.getMaxX());
- int startY = renderer.toBlock(cb.getMinY());
- int endY = renderer.toBlock(cb.getMaxY());
-
- CollisionBox box;
- for(int x = startX; x <= endX; x++)
- {
- for(int y = startY; y <= endY; y++)
- {
- box = getTileMovementBox(x, y);
- if(box.intersects(cb))
- {
- boxes.add(box.copy());
- }
- }
- }
- return boxes;
- }
-
- public Entity getHero()
- {
- return hero;
- }
- }
|