Initial world system with tile rendering & ionization support.
This commit is contained in:
@@ -22,10 +22,12 @@ import mightypork.rogue.screens.main_menu.ScreenMainMenu;
|
||||
import mightypork.rogue.screens.test_bouncyboxes.ScreenTestBouncy;
|
||||
import mightypork.rogue.screens.test_cat_sound.ScreenTestCat;
|
||||
import mightypork.rogue.screens.test_render.ScreenTestRender;
|
||||
import mightypork.rogue.world.WorldMap;
|
||||
import mightypork.rogue.world.LocalPlayer;
|
||||
import mightypork.rogue.world.World;
|
||||
import mightypork.rogue.world.WorldPos;
|
||||
import mightypork.rogue.world.item.Item;
|
||||
import mightypork.rogue.world.map.LevelMap;
|
||||
import mightypork.rogue.world.tile.Tile;
|
||||
import mightypork.rogue.world.tile.TileItems;
|
||||
import mightypork.util.control.eventbus.EventBus;
|
||||
import mightypork.util.control.eventbus.events.Event;
|
||||
import mightypork.util.files.ion.Ion;
|
||||
@@ -107,10 +109,12 @@ public final class App extends BaseApp {
|
||||
@Override
|
||||
protected void preInit()
|
||||
{
|
||||
Ion.registerIonizable(Tile.ION_MARK, Tile.class);
|
||||
Ion.registerIonizable(Item.ION_MARK, Item.class);
|
||||
Ion.registerIonizable(WorldMap.ION_MARK, WorldMap.class);
|
||||
Ion.registerIonizable(TileItems.ION_MARK, TileItems.class); // used by tile to store contained items
|
||||
Ion.registerIonizable(LevelMap.ION_MARK, LevelMap.class);
|
||||
Ion.registerIonizable(LocalPlayer.ION_MARK, LocalPlayer.class);
|
||||
Ion.registerIonizable(Tile.ION_MARK, Tile.class);
|
||||
Ion.registerIonizable(World.ION_MARK, World.class);
|
||||
Ion.registerIonizable(WorldPos.ION_MARK, WorldPos.class);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -80,8 +80,16 @@ public final class Res {
|
||||
texture = textures.loadTexture("tiles", "/res/img/map_tiles.png", FilterMode.NEAREST, WrapMode.CLAMP);
|
||||
final QuadGrid tiles = texture.grid(32, 32);
|
||||
|
||||
textures.addSheet("tile.mossy_bricks.wall", tiles.makeSheet(4, 0, 7, 1));
|
||||
textures.addSheet("tile.mossy_bricks.floor", tiles.makeSheet(16, 5, 7, 1));
|
||||
textures.addSheet("tile.wall.mossy_bricks", tiles.makeSheet(4, 0, 7, 1));
|
||||
textures.addSheet("tile.wall.small_bricks", tiles.makeSheet(0, 0, 4, 1));
|
||||
textures.addSheet("tile.floor.mossy_bricks", tiles.makeSheet(16, 5, 7, 1));
|
||||
textures.addSheet("tile.floor.rect_bricks", tiles.makeSheet(23, 5, 4, 1));
|
||||
textures.addSheet("tile.wall.sandstone", tiles.makeSheet(0, 3, 10, 1));
|
||||
textures.addSheet("tile.floor.sandstone", tiles.makeSheet(0, 6, 10, 1));
|
||||
textures.addSheet("tile.wall.brown_cobble", tiles.makeSheet(0, 8, 8, 1));
|
||||
textures.addSheet("tile.floor.brown_cobble", tiles.makeSheet(0, 11, 9, 1));
|
||||
textures.addSheet("tile.floor.crystal", tiles.makeSheet(4, 5, 6, 1));
|
||||
textures.addSheet("tile.wall.crystal", tiles.makeSheet(12, 2, 14, 1));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -8,14 +8,17 @@ import mightypork.gamecore.gui.components.painters.ImagePainter;
|
||||
import mightypork.gamecore.gui.components.painters.QuadPainter;
|
||||
import mightypork.gamecore.gui.screens.Screen;
|
||||
import mightypork.gamecore.gui.screens.ScreenLayer;
|
||||
import mightypork.gamecore.render.Render;
|
||||
import mightypork.rogue.Res;
|
||||
import mightypork.util.constraints.num.Num;
|
||||
import mightypork.util.constraints.rect.Rect;
|
||||
import mightypork.util.math.color.PAL16;
|
||||
import mightypork.util.math.color.RGB;
|
||||
|
||||
|
||||
public class GameGui extends ScreenLayer {
|
||||
|
||||
|
||||
public GameGui(Screen screen)
|
||||
{
|
||||
super(screen);
|
||||
@@ -23,11 +26,7 @@ public class GameGui extends ScreenLayer {
|
||||
final Num h = root.height();
|
||||
final Num w = root.width();
|
||||
final Num minWH = w.min(h).max(700); // avoid too small shrinking
|
||||
|
||||
final Component qp = new QuadPainter(PAL16.VOID);
|
||||
qp.setRect(root);
|
||||
root.add(qp);
|
||||
|
||||
|
||||
final ImagePainter nav = new ImagePainter(Res.getTxQuad("panel"));
|
||||
nav.setRect(root.bottomEdge().growUp(minWH.perc(7)));
|
||||
root.add(nav);
|
||||
@@ -60,4 +59,12 @@ public class GameGui extends ScreenLayer {
|
||||
return 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render()
|
||||
{
|
||||
|
||||
|
||||
super.render();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ public class ScreenGame extends LayeredScreen {
|
||||
public ScreenGame(AppAccess app)
|
||||
{
|
||||
super(app);
|
||||
|
||||
|
||||
addLayer(new WorldLayer(this)); //TODO with provided world
|
||||
addLayer(new GameGui(this));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package mightypork.rogue.screens.ingame;
|
||||
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import mightypork.gamecore.gui.screens.Screen;
|
||||
import mightypork.gamecore.gui.screens.ScreenLayer;
|
||||
import mightypork.rogue.world.MapGenerator;
|
||||
import mightypork.rogue.world.World;
|
||||
|
||||
|
||||
public class WorldLayer extends ScreenLayer {
|
||||
|
||||
public WorldLayer(Screen screen)
|
||||
{
|
||||
super(screen);
|
||||
|
||||
Random rand = new Random();
|
||||
World w = MapGenerator.createWorld(rand.nextLong());
|
||||
|
||||
WorldRenderer wr = new WorldRenderer(w);
|
||||
wr.setRect(root);
|
||||
root.add(wr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package mightypork.rogue.screens.ingame;
|
||||
|
||||
|
||||
import mightypork.gamecore.control.events.MouseButtonEvent;
|
||||
import mightypork.gamecore.gui.components.InputComponent;
|
||||
import mightypork.gamecore.render.Render;
|
||||
import mightypork.rogue.world.World;
|
||||
import mightypork.util.constraints.num.Num;
|
||||
import mightypork.util.constraints.rect.Rect;
|
||||
import mightypork.util.control.timing.Updateable;
|
||||
import mightypork.util.math.color.PAL16;
|
||||
import mightypork.util.math.color.RGB;
|
||||
|
||||
|
||||
public class WorldRenderer extends InputComponent implements Updateable {
|
||||
|
||||
private final World world;
|
||||
private final Rect rightShadow;
|
||||
private final Rect leftShadow;
|
||||
private final Rect topShadow;
|
||||
private final Rect bottomShadow;
|
||||
|
||||
|
||||
public WorldRenderer(World world)
|
||||
{
|
||||
this.world = world;
|
||||
|
||||
final Num h = height();
|
||||
final Num w = width();
|
||||
final Num minWH = w.min(h).max(700);
|
||||
|
||||
Num grX = w.perc(30);
|
||||
Num grY = h.perc(20);
|
||||
|
||||
leftShadow = leftEdge().growRight(grX);
|
||||
rightShadow = rightEdge().growLeft(grX);
|
||||
topShadow = topEdge().growDown(grY);
|
||||
bottomShadow = bottomEdge().growUp(grY).moveY(minWH.perc(-6));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void receive(MouseButtonEvent event)
|
||||
{
|
||||
System.out.println("world clciked, yo");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void renderComponent()
|
||||
{
|
||||
world.render(this, 8, 6, 64);
|
||||
|
||||
Render.quadGradH(leftShadow, RGB.BLACK, RGB.NONE);
|
||||
Render.quadGradH(rightShadow, RGB.NONE, RGB.BLACK);
|
||||
|
||||
Render.quadGradV(topShadow, RGB.BLACK, RGB.NONE);
|
||||
Render.quadGradV(bottomShadow, RGB.NONE, RGB.BLACK);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void update(double delta)
|
||||
{
|
||||
world.update(delta);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package mightypork.rogue.world;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import mightypork.util.files.ion.Ion;
|
||||
import mightypork.util.files.ion.IonBundle;
|
||||
import mightypork.util.files.ion.IonConstructor;
|
||||
import mightypork.util.files.ion.Ionizable;
|
||||
|
||||
|
||||
/**
|
||||
* Player info
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class LocalPlayer implements Ionizable, MapObserver {
|
||||
|
||||
public static final short ION_MARK = 708;
|
||||
|
||||
public WorldPos position = new WorldPos();
|
||||
|
||||
|
||||
@IonConstructor
|
||||
public LocalPlayer()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public LocalPlayer(int x, int y, int floor)
|
||||
{
|
||||
this.position.setTo(x, y, floor);
|
||||
}
|
||||
|
||||
|
||||
public LocalPlayer(WorldPos pos)
|
||||
{
|
||||
this.position = pos;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void load(InputStream in) throws IOException
|
||||
{
|
||||
IonBundle ib = (IonBundle) Ion.readObject(in);
|
||||
|
||||
position = ib.get("pos", position);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void save(OutputStream out) throws IOException
|
||||
{
|
||||
IonBundle ib = new IonBundle();
|
||||
|
||||
ib.put("pos", position);
|
||||
|
||||
Ion.writeObject(out, ib);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public short getIonMark()
|
||||
{
|
||||
return ION_MARK;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public WorldPos getPosition()
|
||||
{
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getViewRange()
|
||||
{
|
||||
return 15;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package mightypork.rogue.world;
|
||||
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import mightypork.rogue.world.map.LevelMap;
|
||||
import mightypork.rogue.world.tile.Tiles;
|
||||
|
||||
|
||||
public class MapGenerator {
|
||||
|
||||
public static final Random rand = new Random();
|
||||
|
||||
|
||||
public static World createWorld(long seed)
|
||||
{
|
||||
synchronized (rand) {
|
||||
rand.setSeed(seed);
|
||||
|
||||
World w = new World();
|
||||
w.setSeed(seed);
|
||||
|
||||
int levels = 4 + rand.nextInt(6);
|
||||
|
||||
for (int i = 0; i < levels; i++) {
|
||||
w.addLevel(createLevel(rand.nextLong()));
|
||||
}
|
||||
|
||||
// TODO place on start position
|
||||
w.setPlayer(new LocalPlayer(10, 10, 0));
|
||||
return w;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static LevelMap createLevel(long seed)
|
||||
{
|
||||
// TODO
|
||||
|
||||
LevelMap lm = new LevelMap(20, 20);
|
||||
|
||||
lm.fill(Tiles.CRYSTAL_FLOOR);
|
||||
|
||||
Random rand = new Random();
|
||||
rand.setSeed(seed);
|
||||
|
||||
for (int i = 0; i < 150; i++) {
|
||||
lm.setTile(Tiles.CRYSTAL_WALL, rand.nextInt(20), rand.nextInt(20));
|
||||
}
|
||||
|
||||
return lm;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package mightypork.rogue.world;
|
||||
|
||||
|
||||
/**
|
||||
* Player observing a map represented by an observer.
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public interface MapObserver {
|
||||
|
||||
/**
|
||||
* @return observer's position
|
||||
*/
|
||||
public WorldPos getPosition();
|
||||
|
||||
|
||||
/**
|
||||
* @return observed range (in tiles)
|
||||
*/
|
||||
public int getViewRange();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
package mightypork.rogue.world;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import mightypork.gamecore.render.Render;
|
||||
import mightypork.rogue.world.map.LevelMap;
|
||||
import mightypork.rogue.world.map.TileRenderContext;
|
||||
import mightypork.rogue.world.structs.LevelList;
|
||||
import mightypork.util.constraints.rect.Rect;
|
||||
import mightypork.util.constraints.rect.RectConst;
|
||||
import mightypork.util.constraints.rect.proxy.RectBound;
|
||||
import mightypork.util.constraints.vect.Vect;
|
||||
import mightypork.util.constraints.vect.VectConst;
|
||||
import mightypork.util.control.timing.Updateable;
|
||||
import mightypork.util.error.CorruptedDataException;
|
||||
import mightypork.util.files.ion.Ion;
|
||||
import mightypork.util.files.ion.IonBundle;
|
||||
import mightypork.util.files.ion.Ionizable;
|
||||
import mightypork.util.math.color.RGB;
|
||||
|
||||
|
||||
public class World implements Ionizable, Updateable {
|
||||
|
||||
public static final short ION_MARK = 706;
|
||||
|
||||
private LevelList levels = new LevelList();
|
||||
|
||||
private LocalPlayer player = new LocalPlayer();
|
||||
|
||||
private transient final Set<MapObserver> observers = new HashSet<>();
|
||||
|
||||
private long seed;
|
||||
|
||||
|
||||
@Override
|
||||
public void load(InputStream in) throws IOException
|
||||
{
|
||||
// world data
|
||||
IonBundle ib = (IonBundle) Ion.readObject(in);
|
||||
player = ib.get("player", player);
|
||||
levels = ib.get("levels", levels);
|
||||
seed = ib.get("seed", seed);
|
||||
|
||||
// levels
|
||||
Ion.readSequence(in, levels);
|
||||
|
||||
if (player == null) throw new CorruptedDataException("Null player in world.");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void save(OutputStream out) throws IOException
|
||||
{
|
||||
IonBundle ib = new IonBundle();
|
||||
ib.put("player", player);
|
||||
ib.put("levels", levels);
|
||||
ib.put("seed", seed);
|
||||
}
|
||||
|
||||
|
||||
public void setPlayer(LocalPlayer player)
|
||||
{
|
||||
removeObserver(this.player);
|
||||
|
||||
this.player = player;
|
||||
|
||||
addObserver(player);
|
||||
}
|
||||
|
||||
|
||||
public void removeObserver(MapObserver observer)
|
||||
{
|
||||
observers.remove(observer);
|
||||
}
|
||||
|
||||
|
||||
public void addObserver(MapObserver observer)
|
||||
{
|
||||
observers.add(observer);
|
||||
}
|
||||
|
||||
|
||||
public void addLevel(LevelMap level)
|
||||
{
|
||||
levels.add(level);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public short getIonMark()
|
||||
{
|
||||
return ION_MARK;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void update(double delta)
|
||||
{
|
||||
for (int level = 0; level < levels.size(); level++) {
|
||||
for (MapObserver observer : observers) {
|
||||
if (observer.getPosition().floor == level) {
|
||||
levels.get(level).update(observer, delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public LevelMap getLevelForObserver(MapObserver observer)
|
||||
{
|
||||
return levels.get(observer.getPosition().floor);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Draw on screen
|
||||
*
|
||||
* @param viewport rendering area on screen
|
||||
* @param xTiles Desired nr of tiles horizontally
|
||||
* @param yTiles Desired nr of tiles vertically
|
||||
* @param minSize minimum tile size
|
||||
*/
|
||||
public void render(final RectBound viewport, final int yTiles, final int xTiles, final int minSize)
|
||||
{
|
||||
LevelMap floor = getLevelForObserver(player); // TODO fractional movement
|
||||
|
||||
Rect r = viewport.getRect();
|
||||
double vpH = r.height().value();
|
||||
double vpW = r.width().value();
|
||||
|
||||
// adjust tile size to fit desired amount of tiles
|
||||
|
||||
double allowedSizeW = vpW / xTiles;
|
||||
double allowedSizeH = vpH / yTiles;
|
||||
int tileSize = (int) Math.round(Math.max(Math.min(allowedSizeH, allowedSizeW), minSize));
|
||||
|
||||
tileSize -= tileSize % 16;
|
||||
|
||||
VectConst vpCenter = r.center().sub(tileSize * 0.5, tileSize).freeze(); // 0.5 to center, 1 to move up (down is teh navbar)
|
||||
|
||||
int playerX = player.getPosition().x;
|
||||
int playerY = player.getPosition().y;
|
||||
|
||||
// total map area
|
||||
//@formatter:off
|
||||
RectConst mapRect = vpCenter.startRect().grow(
|
||||
playerX*tileSize,
|
||||
playerY*tileSize,//
|
||||
(floor.getWidth() - playerX) * tileSize,
|
||||
(floor.getHeight() - playerY) * tileSize
|
||||
).freeze();
|
||||
//@formatter:on
|
||||
|
||||
// tiles to render
|
||||
int x1 = (int) Math.floor(playerX - (vpW / tileSize));
|
||||
int y1 = (int) Math.floor(playerY - (vpH / tileSize));
|
||||
int x2 = (int) Math.ceil(playerX + (vpW / tileSize));
|
||||
int y2 = (int) Math.ceil(playerY + (vpH / tileSize));
|
||||
|
||||
TileRenderContext trc = new TileRenderContext(floor, mapRect); //-tileSize*0.5
|
||||
for (trc.y = y1; trc.y <= y2; trc.y++) {
|
||||
for (trc.x = x1; trc.x <= x2; trc.x++) {
|
||||
trc.render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setSeed(long seed)
|
||||
{
|
||||
this.seed = seed;
|
||||
}
|
||||
|
||||
|
||||
public long getSeed()
|
||||
{
|
||||
return seed;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package mightypork.rogue.world;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import mightypork.util.files.ion.Ion;
|
||||
import mightypork.util.files.ion.IonConstructor;
|
||||
import mightypork.util.files.ion.Ionizable;
|
||||
|
||||
|
||||
/**
|
||||
* A simple dimension data object
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class WorldPos implements Ionizable {
|
||||
|
||||
public static final short ION_MARK = 707;
|
||||
|
||||
public int x, y, floor;
|
||||
|
||||
|
||||
public WorldPos(int x, int y, int z)
|
||||
{
|
||||
super();
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.floor = z;
|
||||
}
|
||||
|
||||
|
||||
@IonConstructor
|
||||
public WorldPos()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void load(InputStream in) throws IOException
|
||||
{
|
||||
x = Ion.readInt(in);
|
||||
y = Ion.readInt(in);
|
||||
floor = Ion.readInt(in);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void save(OutputStream out) throws IOException
|
||||
{
|
||||
Ion.writeInt(out, x);
|
||||
Ion.writeInt(out, y);
|
||||
Ion.writeInt(out, floor);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public short getIonMark()
|
||||
{
|
||||
return ION_MARK;
|
||||
}
|
||||
|
||||
|
||||
public void setTo(int x, int y, int z)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.floor = z;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import mightypork.rogue.world.tile.TileRenderContext;
|
||||
import mightypork.rogue.world.map.TileRenderContext;
|
||||
import mightypork.util.constraints.rect.proxy.RectBound;
|
||||
import mightypork.util.control.timing.Animator;
|
||||
import mightypork.util.control.timing.AnimatorBounce;
|
||||
@@ -75,9 +75,9 @@ public class Item implements Updateable, Ionizable {
|
||||
{
|
||||
final IonBundle ib = (IonBundle) Ion.readObject(in);
|
||||
|
||||
id = ib.get("id", id);
|
||||
flags = ib.get("flags", flags);
|
||||
numbers = ib.get("numbers", numbers);
|
||||
id = ib.get("id", 0);
|
||||
flags = ib.get("flags", null);
|
||||
numbers = ib.get("numbers", null);
|
||||
|
||||
if (id != model.id) {
|
||||
model = Items.get(id);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package mightypork.rogue.world.item;
|
||||
|
||||
|
||||
import mightypork.rogue.world.tile.TileRenderContext;
|
||||
import mightypork.rogue.world.map.TileRenderContext;
|
||||
import mightypork.util.annotations.DefaultImpl;
|
||||
import mightypork.util.constraints.num.proxy.NumBoundAdapter;
|
||||
import mightypork.util.constraints.rect.Rect;
|
||||
|
||||
+76
-6
@@ -1,19 +1,27 @@
|
||||
package mightypork.rogue.world;
|
||||
package mightypork.rogue.world.map;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import mightypork.rogue.world.MapObserver;
|
||||
import mightypork.rogue.world.WorldPos;
|
||||
import mightypork.rogue.world.tile.Tile;
|
||||
import mightypork.rogue.world.tile.TileGrid;
|
||||
import mightypork.rogue.world.tile.TileModel;
|
||||
import mightypork.rogue.world.tile.Tiles;
|
||||
import mightypork.util.files.ion.Ion;
|
||||
import mightypork.util.files.ion.IonConstructor;
|
||||
import mightypork.util.files.ion.Ionizable;
|
||||
import mightypork.util.logging.Log;
|
||||
|
||||
|
||||
public class WorldMap implements TileGrid, Ionizable {
|
||||
/**
|
||||
* One level of the dungeon
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class LevelMap implements MapAccess, Ionizable {
|
||||
|
||||
public static final int ION_MARK = 702;
|
||||
|
||||
@@ -22,14 +30,17 @@ public class WorldMap implements TileGrid, Ionizable {
|
||||
/** Array of tiles [y][x] */
|
||||
private Tile[][] tiles;
|
||||
|
||||
/** Level seed (used for generation and tile variation) */
|
||||
public long seed;
|
||||
|
||||
|
||||
@IonConstructor
|
||||
public WorldMap()
|
||||
public LevelMap()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public WorldMap(int width, int height)
|
||||
public LevelMap(int width, int height)
|
||||
{
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
@@ -41,9 +52,21 @@ public class WorldMap implements TileGrid, Ionizable {
|
||||
{
|
||||
this.tiles = new Tile[height][width];
|
||||
|
||||
fill(Tiles.NULL_EMPTY);
|
||||
}
|
||||
|
||||
|
||||
public void fill(int id)
|
||||
{
|
||||
fill(Tiles.get(id));
|
||||
}
|
||||
|
||||
|
||||
public void fill(TileModel model)
|
||||
{
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
tiles[y][x] = Tiles.NONE.create();
|
||||
tiles[y][x] = model.createTile();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,10 +75,18 @@ public class WorldMap implements TileGrid, Ionizable {
|
||||
@Override
|
||||
public final Tile getTile(int x, int y)
|
||||
{
|
||||
if (x < 0 || x >= width || y < 0 || y >= height) return Tiles.NULL_SOLID.createTile(); // out of range
|
||||
|
||||
return tiles[y][x];
|
||||
}
|
||||
|
||||
|
||||
public final void setTile(TileModel model, int x, int y)
|
||||
{
|
||||
setTile(model.createTile(), x, y);
|
||||
}
|
||||
|
||||
|
||||
public final void setTile(int tileId, int x, int y)
|
||||
{
|
||||
setTile(new Tile(tileId), x, y);
|
||||
@@ -64,6 +95,8 @@ public class WorldMap implements TileGrid, Ionizable {
|
||||
|
||||
public final void setTile(Tile tile, int x, int y)
|
||||
{
|
||||
if (x < 0 || x > width || y < 0 || y >= height) return; // out of range
|
||||
|
||||
tiles[y][x] = tile;
|
||||
}
|
||||
|
||||
@@ -82,6 +115,19 @@ public class WorldMap implements TileGrid, Ionizable {
|
||||
}
|
||||
|
||||
|
||||
public void setSeed(long seed)
|
||||
{
|
||||
this.seed = seed;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long getSeed()
|
||||
{
|
||||
return seed;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void load(InputStream in) throws IOException
|
||||
{
|
||||
@@ -132,4 +178,28 @@ public class WorldMap implements TileGrid, Ionizable {
|
||||
return ION_MARK;
|
||||
}
|
||||
|
||||
|
||||
public void update(MapObserver observer, double delta)
|
||||
{
|
||||
int viewRange = observer.getViewRange();
|
||||
WorldPos position = observer.getPosition();
|
||||
|
||||
int x1 = position.x - viewRange;
|
||||
int y1 = position.y - viewRange;
|
||||
|
||||
int x2 = x1 + viewRange * 2;
|
||||
int y2 = y1 + viewRange * 2;
|
||||
|
||||
x1 = Math.min(Math.max(0, x1), width);
|
||||
y1 = Math.min(Math.max(0, y1), height);
|
||||
x2 = Math.min(x2, width);
|
||||
y2 = Math.max(y2, height);
|
||||
|
||||
for (int y = y1; y <= y2; y++) {
|
||||
for (int x = x1; x <= x2; x++) {
|
||||
getTile(x, y).update(delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package mightypork.rogue.world.map;
|
||||
|
||||
|
||||
import mightypork.rogue.world.tile.Tile;
|
||||
|
||||
|
||||
/**
|
||||
* Access interface for a level map.
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public interface MapAccess {
|
||||
|
||||
/**
|
||||
* Ge tile at X,Y
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @return tile
|
||||
*/
|
||||
Tile getTile(int x, int y);
|
||||
|
||||
|
||||
/**
|
||||
* @return map width in tiles
|
||||
*/
|
||||
int getWidth();
|
||||
|
||||
|
||||
/**
|
||||
* @return map height in tiles
|
||||
*/
|
||||
int getHeight();
|
||||
|
||||
|
||||
/**
|
||||
* @return map seed
|
||||
*/
|
||||
long getSeed();
|
||||
}
|
||||
+27
-14
@@ -1,45 +1,65 @@
|
||||
package mightypork.rogue.world.tile;
|
||||
package mightypork.rogue.world.map;
|
||||
|
||||
|
||||
import mightypork.rogue.world.tile.Tile;
|
||||
import mightypork.util.constraints.rect.Rect;
|
||||
import mightypork.util.constraints.rect.builders.TiledRect;
|
||||
import mightypork.util.constraints.rect.proxy.RectBound;
|
||||
import mightypork.util.math.noise.NoiseGen;
|
||||
|
||||
|
||||
/**
|
||||
* Context for tile rendering. Provides tile rect, surrounding tiles, rendered
|
||||
* tile and random noise values for position-static tile variation.
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public final class TileRenderContext implements RectBound {
|
||||
|
||||
private final TileGrid map;
|
||||
private final MapAccess map;
|
||||
private final TiledRect tiler;
|
||||
private final NoiseGen noise;
|
||||
|
||||
public int x, y;
|
||||
|
||||
|
||||
public TileRenderContext(TileGrid map, Rect drawArea, long renderNoiseSeed)
|
||||
public TileRenderContext(MapAccess map, Rect drawArea)
|
||||
{
|
||||
this.map = map;
|
||||
this.tiler = drawArea.tiles(map.getWidth(), map.getHeight());
|
||||
this.noise = new NoiseGen(0.2, 0, 0.5, 1, renderNoiseSeed);
|
||||
this.noise = new NoiseGen(0.2, 0, 0.5, 1, map.getSeed());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the rendered tile.
|
||||
*/
|
||||
public Tile getTile()
|
||||
{
|
||||
return map.getTile(x, y);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a neighbor tile
|
||||
*
|
||||
* @param offsetX x offset (left-right)
|
||||
* @param offsetY y offset (up-down)
|
||||
* @return the tile at that position
|
||||
*/
|
||||
public Tile getAdjacentTile(int offsetX, int offsetY)
|
||||
{
|
||||
return map.getTile(x + offsetX, y + offsetY);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Rect of the current tile to draw
|
||||
*/
|
||||
@Override
|
||||
public Rect getRect()
|
||||
{
|
||||
return tiler.tile(x, y);
|
||||
return tiler.tile(x, y).grow(0.01); // important to avoid gaps b/w tiles when scaled.
|
||||
}
|
||||
|
||||
|
||||
@@ -52,15 +72,8 @@ public final class TileRenderContext implements RectBound {
|
||||
}
|
||||
|
||||
|
||||
public void setCoord(int x, int y)
|
||||
public void render()
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
|
||||
public void renderTile(Tile t)
|
||||
{
|
||||
t.render(this);
|
||||
map.getTile(x, y).render(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package mightypork.rogue.world.structs;
|
||||
|
||||
|
||||
import mightypork.rogue.world.item.Item;
|
||||
import mightypork.util.files.ion.templates.IonizableStack;
|
||||
|
||||
|
||||
public class ItemStack extends IonizableStack<Item> {
|
||||
|
||||
private static final short ION_MARK = 710;
|
||||
|
||||
|
||||
@Override
|
||||
public short getIonMark()
|
||||
{
|
||||
return ION_MARK;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package mightypork.rogue.world.structs;
|
||||
|
||||
|
||||
import mightypork.rogue.world.map.LevelMap;
|
||||
import mightypork.util.files.ion.templates.IonizableArrayList;
|
||||
|
||||
|
||||
public class LevelList extends IonizableArrayList<LevelMap> {
|
||||
|
||||
public static final short ION_MARK = 709;
|
||||
|
||||
@Override
|
||||
public short getIonMark()
|
||||
{
|
||||
return ION_MARK;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,7 +4,10 @@ package mightypork.rogue.world.tile;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Stack;
|
||||
|
||||
import mightypork.rogue.world.item.Item;
|
||||
import mightypork.rogue.world.map.TileRenderContext;
|
||||
import mightypork.util.control.timing.Animator;
|
||||
import mightypork.util.control.timing.Updateable;
|
||||
import mightypork.util.files.ion.Ion;
|
||||
@@ -23,7 +26,7 @@ public final class Tile implements Ionizable, Updateable {
|
||||
|
||||
public int id;
|
||||
|
||||
public TileItems items;
|
||||
public Stack<Item> items = new Stack<>();
|
||||
|
||||
public boolean[] flags;
|
||||
public int[] numbers;
|
||||
@@ -45,13 +48,12 @@ public final class Tile implements Ionizable, Updateable {
|
||||
{
|
||||
this.model = model;
|
||||
this.id = model.id;
|
||||
this.items = new TileItems();
|
||||
}
|
||||
|
||||
|
||||
public void render(TileRenderContext context)
|
||||
{
|
||||
model.render(this, context);
|
||||
model.render(context);
|
||||
|
||||
if (!items.isEmpty()) {
|
||||
items.peek().renderOnTile(context);
|
||||
@@ -69,7 +71,8 @@ public final class Tile implements Ionizable, Updateable {
|
||||
ib.put("id", id);
|
||||
ib.put("flags", flags);
|
||||
ib.put("numbers", numbers);
|
||||
ib.put("items", items);
|
||||
|
||||
Ion.writeSequence(out, items);
|
||||
|
||||
Ion.writeObject(out, ib);
|
||||
}
|
||||
@@ -78,12 +81,15 @@ public final class Tile implements Ionizable, Updateable {
|
||||
@Override
|
||||
public void load(InputStream in) throws IOException
|
||||
{
|
||||
// bundle of data
|
||||
final IonBundle ib = (IonBundle) Ion.readObject(in);
|
||||
|
||||
id = ib.get("id", id);
|
||||
flags = ib.get("flags", flags);
|
||||
numbers = ib.get("numbers", numbers);
|
||||
items = ib.get("items", items);
|
||||
|
||||
// stored items
|
||||
items.clear();
|
||||
Ion.readSequence(in, items);
|
||||
|
||||
// renew model
|
||||
if (model == null || id != model.id) {
|
||||
@@ -102,6 +108,7 @@ public final class Tile implements Ionizable, Updateable {
|
||||
@Override
|
||||
public void update(double delta)
|
||||
{
|
||||
model.update(this, delta);
|
||||
if (!items.isEmpty()) {
|
||||
items.peek().update(delta);
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
package mightypork.rogue.world.tile;
|
||||
|
||||
|
||||
public interface TileGrid {
|
||||
|
||||
Tile getTile(int x, int y);
|
||||
|
||||
|
||||
int getWidth();
|
||||
|
||||
|
||||
int getHeight();
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package mightypork.rogue.world.tile;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Stack;
|
||||
|
||||
import mightypork.rogue.world.item.Item;
|
||||
import mightypork.util.files.ion.Ion;
|
||||
import mightypork.util.files.ion.Ionizable;
|
||||
|
||||
|
||||
public class TileItems extends Stack<Item> implements Ionizable {
|
||||
|
||||
public static final short ION_MARK = 703;
|
||||
|
||||
|
||||
@Override
|
||||
public void load(InputStream in) throws IOException
|
||||
{
|
||||
Ion.readSequence(in, this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void save(OutputStream out) throws IOException
|
||||
{
|
||||
Ion.writeSequence(out, this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public short getIonMark()
|
||||
{
|
||||
return ION_MARK;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package mightypork.rogue.world.tile;
|
||||
|
||||
|
||||
import mightypork.rogue.world.map.TileRenderContext;
|
||||
import mightypork.util.annotations.DefaultImpl;
|
||||
|
||||
|
||||
@@ -23,10 +24,14 @@ public abstract class TileModel {
|
||||
|
||||
|
||||
/**
|
||||
* Create a tile. In case of null tiles / tiles with absolutely no
|
||||
* variability, the same instance can be returned over and over (created ie.
|
||||
* using lazy load)
|
||||
*
|
||||
* @return new tile with this model
|
||||
*/
|
||||
@DefaultImpl
|
||||
public Tile create()
|
||||
public Tile createTile()
|
||||
{
|
||||
return new Tile(this);
|
||||
}
|
||||
@@ -35,10 +40,9 @@ public abstract class TileModel {
|
||||
/**
|
||||
* Render the tile.
|
||||
*
|
||||
* @param tile
|
||||
* @param context
|
||||
*/
|
||||
public abstract void render(Tile tile, TileRenderContext context);
|
||||
public abstract void render(TileRenderContext context);
|
||||
|
||||
|
||||
/**
|
||||
@@ -49,7 +53,11 @@ public abstract class TileModel {
|
||||
|
||||
|
||||
/**
|
||||
* @return true if the tile can be walkable at some conditions
|
||||
* Check if the tile is walkable at some conditions. Used for world
|
||||
* generation to distinguish between doors etc and regular walls.<br>
|
||||
* Null tile should return true, if it can be replaced by a regular floor.
|
||||
*
|
||||
* @return if it's potentially walkable
|
||||
*/
|
||||
public abstract boolean isPotentiallyWalkable();
|
||||
|
||||
@@ -59,4 +67,13 @@ public abstract class TileModel {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update a tile
|
||||
*
|
||||
* @param tile tile
|
||||
* @param delta delta time
|
||||
*/
|
||||
public abstract void update(Tile tile, double delta);
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ package mightypork.rogue.world.tile;
|
||||
|
||||
|
||||
import mightypork.rogue.world.tile.models.Floor;
|
||||
import mightypork.rogue.world.tile.models.NullTile;
|
||||
import mightypork.rogue.world.tile.models.NullFloor;
|
||||
import mightypork.rogue.world.tile.models.NullWall;
|
||||
import mightypork.rogue.world.tile.models.Wall;
|
||||
|
||||
|
||||
/**
|
||||
@@ -14,14 +16,27 @@ public final class Tiles {
|
||||
|
||||
private static final TileModel[] tiles = new TileModel[256];
|
||||
|
||||
public static final TileModel NONE = new NullTile(0);
|
||||
public static final TileModel FLOOR_MOSSY = new Floor(1, "tile.mossy_bricks.floor");
|
||||
public static final TileModel WALL_MOSSY = new Floor(2, "tile.mossy_bricks.wall");
|
||||
public static final TileModel NULL_SOLID = new NullWall(0);
|
||||
public static final TileModel NULL_EMPTY = new NullFloor(1);
|
||||
public static final TileModel BRICK_FLOOR_VINES = new Floor(2, "tile.floor.mossy_bricks");
|
||||
public static final TileModel BRICK_WALL_VINES = new Wall(3, "tile.wall.mossy_bricks");
|
||||
public static final TileModel BRICK_FLOOR_RECT = new Floor(4, "tile.floor.rect_bricks");
|
||||
public static final TileModel BRICK_WALL_SMALL = new Wall(5, "tile.wall.small_bricks");
|
||||
public static final TileModel SANDSTONE_FLOOR = new Floor(6, "tile.floor.sandstone");
|
||||
public static final TileModel SANDSTONE_WALL = new Wall(7, "tile.wall.sandstone");
|
||||
public static final TileModel BRCOBBLE_FLOOR = new Floor(8, "tile.floor.brown_cobble");
|
||||
public static final TileModel BRCOBBLE_WALL = new Wall(9, "tile.wall.brown_cobble");
|
||||
public static final TileModel CRYSTAL_FLOOR = new Floor(10, "tile.floor.crystal");
|
||||
public static final TileModel CRYSTAL_WALL = new Wall(11, "tile.wall.crystal");
|
||||
|
||||
|
||||
static void register(int id, TileModel model)
|
||||
{
|
||||
if (id < 0 || id >= tiles.length) if (tiles[id] != null) {
|
||||
if (id < 0 || id >= tiles.length) {
|
||||
throw new IllegalArgumentException("Tile ID " + id + " is out of range.");
|
||||
}
|
||||
|
||||
if (tiles[id] != null) {
|
||||
throw new IllegalArgumentException("Tile ID " + id + " already in use.");
|
||||
}
|
||||
|
||||
|
||||
+17
-13
@@ -1,24 +1,35 @@
|
||||
package mightypork.rogue.world.tile.models;
|
||||
|
||||
|
||||
import mightypork.rogue.world.map.TileRenderContext;
|
||||
import mightypork.rogue.world.tile.Tile;
|
||||
import mightypork.rogue.world.tile.TileModel;
|
||||
import mightypork.rogue.world.tile.TileRenderContext;
|
||||
|
||||
|
||||
public class NullTile extends TileModel {
|
||||
/**
|
||||
* Null tile
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public abstract class AbstractNullTile extends TileModel {
|
||||
|
||||
private Tile inst;
|
||||
|
||||
|
||||
public NullTile(int id)
|
||||
public AbstractNullTile(int id)
|
||||
{
|
||||
super(id);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void render(Tile tile, TileRenderContext context)
|
||||
public void render(TileRenderContext context)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void update(Tile tile, double delta)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -26,14 +37,7 @@ public class NullTile extends TileModel {
|
||||
@Override
|
||||
public boolean isWalkable(Tile tile)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isPotentiallyWalkable()
|
||||
{
|
||||
return true;
|
||||
return isPotentiallyWalkable();
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +49,7 @@ public class NullTile extends TileModel {
|
||||
|
||||
|
||||
@Override
|
||||
public Tile create()
|
||||
public Tile createTile()
|
||||
{
|
||||
if (inst == null) {
|
||||
inst = new Tile(this);
|
||||
@@ -0,0 +1,18 @@
|
||||
package mightypork.rogue.world.tile.models;
|
||||
|
||||
|
||||
public class NullFloor extends AbstractNullTile {
|
||||
|
||||
public NullFloor(int id)
|
||||
{
|
||||
super(id);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isPotentiallyWalkable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package mightypork.rogue.world.tile.models;
|
||||
|
||||
|
||||
public class NullWall extends AbstractNullTile {
|
||||
|
||||
public NullWall(int id)
|
||||
{
|
||||
super(id);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isPotentiallyWalkable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +1,16 @@
|
||||
package mightypork.rogue.world.tile.models;
|
||||
|
||||
|
||||
import mightypork.gamecore.render.DisplaySystem;
|
||||
import mightypork.gamecore.render.Render;
|
||||
import mightypork.gamecore.render.textures.TxSheet;
|
||||
import mightypork.rogue.Res;
|
||||
import mightypork.rogue.world.map.TileRenderContext;
|
||||
import mightypork.rogue.world.tile.Tile;
|
||||
import mightypork.rogue.world.tile.TileModel;
|
||||
import mightypork.rogue.world.tile.TileRenderContext;
|
||||
import mightypork.util.annotations.DefaultImpl;
|
||||
import mightypork.util.constraints.vect.Vect;
|
||||
import mightypork.util.math.color.RGB;
|
||||
|
||||
|
||||
public abstract class SimpleTile extends TileModel {
|
||||
@@ -23,11 +26,17 @@ public abstract class SimpleTile extends TileModel {
|
||||
|
||||
|
||||
@Override
|
||||
public void render(Tile tile, TileRenderContext context)
|
||||
public void render(TileRenderContext context)
|
||||
{
|
||||
Render.quadTextured(context.getRect(), sheet.getRandomQuad(context.getTileNoise()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@DefaultImpl
|
||||
public void update(Tile tile, double delta)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@DefaultImpl
|
||||
|
||||
Reference in New Issue
Block a user