|
@@ -1,62 +1,54 @@
|
|
package me.hammerle.supersnuvi.rendering;
|
|
package me.hammerle.supersnuvi.rendering;
|
|
|
|
|
|
-import me.hammerle.supersnuvi.input.KeyHandler;
|
|
|
|
import java.util.HashMap;
|
|
import java.util.HashMap;
|
|
import java.util.LinkedList;
|
|
import java.util.LinkedList;
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Collectors;
|
|
-import javafx.scene.canvas.GraphicsContext;
|
|
|
|
import javafx.scene.image.Image;
|
|
import javafx.scene.image.Image;
|
|
import javafx.scene.image.WritableImage;
|
|
import javafx.scene.image.WritableImage;
|
|
import javafx.scene.paint.Color;
|
|
import javafx.scene.paint.Color;
|
|
import me.hammerle.supersnuvi.entity.Entity;
|
|
import me.hammerle.supersnuvi.entity.Entity;
|
|
import me.hammerle.supersnuvi.entity.Hero;
|
|
import me.hammerle.supersnuvi.entity.Hero;
|
|
|
|
+import me.hammerle.supersnuvi.input.IKeyHandler;
|
|
import me.hammerle.supersnuvi.tiles.Tile;
|
|
import me.hammerle.supersnuvi.tiles.Tile;
|
|
import me.hammerle.supersnuvi.util.CollisionBox;
|
|
import me.hammerle.supersnuvi.util.CollisionBox;
|
|
|
|
+import me.hammerle.supersnuvi.util.Utils;
|
|
|
|
|
|
-public class MapRenderer implements ITick
|
|
|
|
|
|
+public class WorldRenderer
|
|
{
|
|
{
|
|
|
|
+ // constants
|
|
private static final Image FALLBACK_IMAGE = new WritableImage(1, 1);
|
|
private static final Image FALLBACK_IMAGE = new WritableImage(1, 1);
|
|
|
|
|
|
- private GraphicsContext gc;
|
|
|
|
|
|
+ // rendering
|
|
|
|
+ private IGameRenderer renderer;
|
|
|
|
|
|
|
|
+ // world tiles
|
|
|
|
+ private boolean worldLoaded;
|
|
|
|
+ private int width;
|
|
|
|
+ private int height;
|
|
private int[][] background;
|
|
private int[][] background;
|
|
private int[][] background2;
|
|
private int[][] background2;
|
|
private int[][] foreground;
|
|
private int[][] foreground;
|
|
|
|
|
|
private HashMap<Integer, Entity> entities;
|
|
private HashMap<Integer, Entity> entities;
|
|
|
|
|
|
- private int mWidth;
|
|
|
|
- private int mHeight;
|
|
|
|
private HashMap<Integer, Tile> registeredTiles;
|
|
private HashMap<Integer, Tile> registeredTiles;
|
|
|
|
|
|
- private double cameraOffsetX;
|
|
|
|
- private double cameraWidth;
|
|
|
|
- private double cameraHeight;
|
|
|
|
-
|
|
|
|
- private double offsetY;
|
|
|
|
-
|
|
|
|
- private GameWindow w;
|
|
|
|
- private KeyHandler keyHandler;
|
|
|
|
-
|
|
|
|
- public MapRenderer(GameWindow w, GraphicsContext gc, double width, double height)
|
|
|
|
|
|
+ public WorldRenderer(IGameRenderer renderer)
|
|
{
|
|
{
|
|
- this.w = w;
|
|
|
|
- this.keyHandler = w.getKeyHandler();
|
|
|
|
- this.gc = gc;
|
|
|
|
|
|
+ this.renderer = renderer;
|
|
|
|
+
|
|
|
|
+ this.worldLoaded = false;
|
|
|
|
+ this.width = 0;
|
|
|
|
+ this.height = 0;
|
|
this.background = null;
|
|
this.background = null;
|
|
this.background2 = null;
|
|
this.background2 = null;
|
|
this.foreground = null;
|
|
this.foreground = null;
|
|
- this.mWidth = 0;
|
|
|
|
- this.mHeight = 0;
|
|
|
|
- this.cameraWidth = width;
|
|
|
|
- this.cameraHeight = height;
|
|
|
|
- this.cameraOffsetX = 0;
|
|
|
|
|
|
+
|
|
this.registeredTiles = new HashMap<>();
|
|
this.registeredTiles = new HashMap<>();
|
|
this.entities = new HashMap<>();
|
|
this.entities = new HashMap<>();
|
|
- this.offsetY = 0;
|
|
|
|
|
|
|
|
- Entity ent = new Entity(this, 48, 272, 32, 60);
|
|
|
|
- Hero hero = new Hero(this, 48, 0, 32, 60);
|
|
|
|
|
|
+ Entity ent = new Entity(this, 60, 240, 32, 60);
|
|
|
|
+ Hero hero = new Hero(this, 0, 160, 32, 60);
|
|
|
|
|
|
entities.put(1, ent);
|
|
entities.put(1, ent);
|
|
entities.put(2, hero);
|
|
entities.put(2, hero);
|
|
@@ -74,6 +66,7 @@ public class MapRenderer implements ITick
|
|
registeredTiles.put(1, new Tile("air"));
|
|
registeredTiles.put(1, new Tile("air"));
|
|
registeredTiles.put(2, new Tile("dirt").setDefaultCollisionBox());
|
|
registeredTiles.put(2, new Tile("dirt").setDefaultCollisionBox());
|
|
registeredTiles.put(3, new Tile("grass").setDefaultCollisionBox());
|
|
registeredTiles.put(3, new Tile("grass").setDefaultCollisionBox());
|
|
|
|
+
|
|
registerTile(4, 255, 0, 0, 255);
|
|
registerTile(4, 255, 0, 0, 255);
|
|
registeredTiles.get(4).setCollisionBox(CollisionBox.DEFAULT_BOX);
|
|
registeredTiles.get(4).setCollisionBox(CollisionBox.DEFAULT_BOX);
|
|
registerTile(5, 255, 0, 255, 255);
|
|
registerTile(5, 255, 0, 255, 255);
|
|
@@ -91,51 +84,52 @@ public class MapRenderer implements ITick
|
|
return tile.getImage();
|
|
return tile.getImage();
|
|
}
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
|
- public void tick(long delta)
|
|
|
|
|
|
+ public void tick(long delta, IKeyHandler keys)
|
|
{
|
|
{
|
|
- keyHandler.tick(delta);
|
|
|
|
- if(background != null)
|
|
|
|
|
|
+ if(worldLoaded)
|
|
{
|
|
{
|
|
// doing entity logic first
|
|
// doing entity logic first
|
|
entities.values().forEach(entity ->
|
|
entities.values().forEach(entity ->
|
|
{
|
|
{
|
|
- entity.controlTick(keyHandler);
|
|
|
|
|
|
+ entity.controlTick(keys);
|
|
entity.tick(delta);
|
|
entity.tick(delta);
|
|
});
|
|
});
|
|
|
|
|
|
- int startX = Math.max((int) (cameraOffsetX / Tile.TILE_SIZE), 0);
|
|
|
|
|
|
+ int startX = renderer.getFirstVisibleBlockX();
|
|
|
|
+ int startY = renderer.getFirstVisibleBlockY();
|
|
|
|
+ int endX = Math.min(renderer.getLastVisibleBlockX() + 1, width);
|
|
|
|
+ int endY = Math.min(renderer.getLastVisibleBlockY() + 1, height);
|
|
|
|
|
|
int id;
|
|
int id;
|
|
- for(int x = startX; x < mWidth; x++)
|
|
|
|
|
|
+ for(int x = startX; x < endX; x++)
|
|
{
|
|
{
|
|
- for(int y = 0; y < mHeight; y++)
|
|
|
|
|
|
+ for(int y = startY; y < endY; y++)
|
|
{
|
|
{
|
|
id = background[x][y];
|
|
id = background[x][y];
|
|
if(id != -1)
|
|
if(id != -1)
|
|
{
|
|
{
|
|
- gc.drawImage(getTile(id), x * Tile.TILE_SIZE - cameraOffsetX, y * Tile.TILE_SIZE + offsetY);
|
|
|
|
|
|
+ renderer.drawBlockImage(getTile(id), x, y);
|
|
}
|
|
}
|
|
id = background2[x][y];
|
|
id = background2[x][y];
|
|
if(id != -1)
|
|
if(id != -1)
|
|
{
|
|
{
|
|
- gc.drawImage(getTile(id), x * Tile.TILE_SIZE - cameraOffsetX, y * Tile.TILE_SIZE + offsetY);
|
|
|
|
|
|
+ renderer.drawBlockImage(getTile(id), x, y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// render entities here
|
|
// render entities here
|
|
- entities.values().forEach(en -> gc.drawImage(en.getImage(), en.getRenderX(), en.getRenderY()));
|
|
|
|
|
|
+ entities.values().forEach(en -> renderer.drawImage(en.getImage(), en.getRenderX(), en.getRenderY()));
|
|
// end entity rendering
|
|
// end entity rendering
|
|
|
|
|
|
- for(int x = startX; x < mWidth; x++)
|
|
|
|
|
|
+ for(int x = startX; x < endX; x++)
|
|
{
|
|
{
|
|
- for(int y = 0; y < mHeight; y++)
|
|
|
|
|
|
+ for(int y = startY; y < endY; y++)
|
|
{
|
|
{
|
|
id = foreground[x][y];
|
|
id = foreground[x][y];
|
|
if(id != -1)
|
|
if(id != -1)
|
|
{
|
|
{
|
|
- gc.drawImage(getTile(id), x * Tile.TILE_SIZE - cameraOffsetX, y * Tile.TILE_SIZE + offsetY);
|
|
|
|
|
|
+ renderer.drawBlockImage(getTile(id), x, y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -144,66 +138,72 @@ public class MapRenderer implements ITick
|
|
|
|
|
|
public Tile getInteractionTile(int x, int y)
|
|
public Tile getInteractionTile(int x, int y)
|
|
{
|
|
{
|
|
- if(x < 0 || y < 0 || x >= mWidth || y >= mHeight)
|
|
|
|
|
|
+ if(x < 0 || y < 0 || x >= width || y >= height)
|
|
{
|
|
{
|
|
return Tile.FALLBACK_TILE;
|
|
return Tile.FALLBACK_TILE;
|
|
}
|
|
}
|
|
return registeredTiles.get(background2[x][y]);
|
|
return registeredTiles.get(background2[x][y]);
|
|
}
|
|
}
|
|
|
|
|
|
- public void loadMap(int[][] background, int[][] background2, int[][] foreground)
|
|
|
|
- {
|
|
|
|
- this.background = background;
|
|
|
|
- this.background2 = background2;
|
|
|
|
- this.foreground = foreground;
|
|
|
|
- mWidth = background2.length;
|
|
|
|
- if(mWidth > 0)
|
|
|
|
- {
|
|
|
|
- mHeight = background2[0].length;
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- mHeight = 0;
|
|
|
|
- }
|
|
|
|
- offsetY = cameraHeight - mHeight * Tile.TILE_SIZE;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // -------------------------------------------------------------------------
|
|
|
|
- // coord utils
|
|
|
|
- // -------------------------------------------------------------------------
|
|
|
|
-
|
|
|
|
- public int getBlockX(double d)
|
|
|
|
- {
|
|
|
|
- return (int) (d / Tile.TILE_SIZE);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public int getBlockY(double d)
|
|
|
|
|
|
+ private void throwSameLayerSizeException()
|
|
{
|
|
{
|
|
- return (int) ((d - offsetY) / Tile.TILE_SIZE);
|
|
|
|
|
|
+ throw new IllegalArgumentException("world layers must be of same size");
|
|
}
|
|
}
|
|
|
|
|
|
- public double getCordX(int d)
|
|
|
|
|
|
+ private void validateArraySize(int[][] layer, int h)
|
|
{
|
|
{
|
|
- return d * Tile.TILE_SIZE;
|
|
|
|
|
|
+ for(int[] he : layer)
|
|
|
|
+ {
|
|
|
|
+ if(he.length != h)
|
|
|
|
+ {
|
|
|
|
+ throwSameLayerSizeException();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- public double getCordY(int d)
|
|
|
|
|
|
+ public void loadWorld(String path)
|
|
{
|
|
{
|
|
- return d * Tile.TILE_SIZE + offsetY;
|
|
|
|
|
|
+ int[][][] layers = Utils.loadMap(path);
|
|
|
|
+ int[][] back = layers[0];
|
|
|
|
+ int[][] back2 = layers[1];
|
|
|
|
+ int[][] fore = layers[2];
|
|
|
|
+ if(back.length > 0)
|
|
|
|
+ {
|
|
|
|
+ width = back.length;
|
|
|
|
+ if(back2.length != width || fore.length != width)
|
|
|
|
+ {
|
|
|
|
+ throwSameLayerSizeException();
|
|
|
|
+ }
|
|
|
|
+ height = back2[0].length;
|
|
|
|
+ validateArraySize(back, height);
|
|
|
|
+ validateArraySize(back2, height);
|
|
|
|
+ validateArraySize(fore, height);
|
|
|
|
+
|
|
|
|
+ this.background = back;
|
|
|
|
+ this.background2 = back2;
|
|
|
|
+ this.foreground = fore;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ this.background = new int[0][0];
|
|
|
|
+ this.background2 = new int[0][0];
|
|
|
|
+ this.foreground = new int[0][0];
|
|
|
|
+ }
|
|
|
|
+ worldLoaded = true;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
// -------------------------------------------------------------------------
|
|
// -------------------------------------------------------------------------
|
|
// collision box
|
|
// collision box
|
|
// -------------------------------------------------------------------------
|
|
// -------------------------------------------------------------------------
|
|
|
|
|
|
public CollisionBox getTileCollisionBox(int x, int y)
|
|
public CollisionBox getTileCollisionBox(int x, int y)
|
|
{
|
|
{
|
|
- if(x < 0 || y < 0 || x >= mWidth || y >= mHeight)
|
|
|
|
|
|
+ if(x < 0 || y < 0 || x >= width || y >= height)
|
|
{
|
|
{
|
|
return CollisionBox.NULL_BOX;
|
|
return CollisionBox.NULL_BOX;
|
|
}
|
|
}
|
|
Tile tile = registeredTiles.get(background2[x][y]);
|
|
Tile tile = registeredTiles.get(background2[x][y]);
|
|
- return tile.getCollisionBox().reset().offset(getCordX(x), getCordY(y));
|
|
|
|
|
|
+ return tile.getCollisionBox().reset().offset(renderer.toCoord(x), renderer.toCoord(y));
|
|
}
|
|
}
|
|
|
|
|
|
public LinkedList<CollisionBox> getCollisionBoxesAt(Entity not, CollisionBox cb)
|
|
public LinkedList<CollisionBox> getCollisionBoxesAt(Entity not, CollisionBox cb)
|
|
@@ -214,11 +214,10 @@ public class MapRenderer implements ITick
|
|
.map(ent -> ent.getBox())
|
|
.map(ent -> ent.getBox())
|
|
.collect(Collectors.toList()));
|
|
.collect(Collectors.toList()));
|
|
|
|
|
|
- int startX = getBlockX(cb.getMinX());
|
|
|
|
- int endX = getBlockX(cb.getMaxX());
|
|
|
|
- int startY = getBlockY(cb.getMinY());
|
|
|
|
- int endY = getBlockY(cb.getMaxY());
|
|
|
|
- //System.out.println("x = " + startX + " - " + endX + " y = " + startY + " - " + endY);
|
|
|
|
|
|
+ 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;
|
|
CollisionBox box;
|
|
for(int x = startX; x <= endX; x++)
|
|
for(int x = startX; x <= endX; x++)
|