parent
9e4a237192
commit
3e69505787
Before Width: | Height: | Size: 320 KiB After Width: | Height: | Size: 320 KiB |
@ -1,94 +0,0 @@ |
|||||||
package mightypork.rogue.world; |
|
||||||
|
|
||||||
|
|
||||||
import mightypork.rogue.world.map.Level; |
|
||||||
import mightypork.rogue.world.map.TileRenderContext; |
|
||||||
import mightypork.util.constraints.rect.Rect; |
|
||||||
import mightypork.util.constraints.rect.RectConst; |
|
||||||
import mightypork.util.constraints.rect.proxy.RectBound; |
|
||||||
import mightypork.util.constraints.vect.VectConst; |
|
||||||
import mightypork.util.control.timing.Updateable; |
|
||||||
|
|
||||||
|
|
||||||
public class ClientWorld implements Updateable, WorldAccess { |
|
||||||
|
|
||||||
private Level level = null; |
|
||||||
|
|
||||||
private final PlayerEntity player = null; |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void update(double delta) |
|
||||||
{ |
|
||||||
player.update(delta); |
|
||||||
|
|
||||||
level.updateVisual(player, delta); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* 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) |
|
||||||
{ |
|
||||||
final Rect r = viewport.getRect(); |
|
||||||
final double vpH = r.height().value(); |
|
||||||
final double vpW = r.width().value(); |
|
||||||
|
|
||||||
// adjust tile size to fit desired amount of tiles
|
|
||||||
|
|
||||||
final double allowedSizeW = vpW / xTiles; |
|
||||||
final double allowedSizeH = vpH / yTiles; |
|
||||||
int tileSize = (int) Math.round(Math.max(Math.min(allowedSizeH, allowedSizeW), minSize)); |
|
||||||
|
|
||||||
tileSize -= tileSize % 16; |
|
||||||
|
|
||||||
final VectConst vpCenter = r.center().sub(tileSize * 0.5, tileSize).freeze(); // 0.5 to center, 1 to move up (down is teh navbar)
|
|
||||||
|
|
||||||
final double playerX = player.getPosition().getVisualX(); |
|
||||||
final double playerY = player.getPosition().getVisualY(); |
|
||||||
|
|
||||||
// total map area
|
|
||||||
//@formatter:off
|
|
||||||
final RectConst mapRect = vpCenter.startRect().grow( |
|
||||||
playerX*tileSize, |
|
||||||
(level.getWidth() - playerX) * tileSize, |
|
||||||
playerY*tileSize, |
|
||||||
(level.getHeight() - playerY) * tileSize |
|
||||||
).freeze(); |
|
||||||
//@formatter:on
|
|
||||||
|
|
||||||
// tiles to render
|
|
||||||
final int x1 = (int) Math.floor(playerX - (vpW / tileSize)); |
|
||||||
final int y1 = (int) Math.floor(playerY - (vpH / tileSize)); |
|
||||||
final int x2 = (int) Math.ceil(playerX + (vpW / tileSize)); |
|
||||||
final int y2 = (int) Math.ceil(playerY + (vpH / tileSize)); |
|
||||||
|
|
||||||
final TileRenderContext trc = new TileRenderContext(level, 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 PlayerEntity getPlayer() |
|
||||||
{ |
|
||||||
return player; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean isServer() |
|
||||||
{ |
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,16 +0,0 @@ |
|||||||
package mightypork.rogue.world; |
|
||||||
|
|
||||||
import mightypork.rogue.world.map.Level; |
|
||||||
import mightypork.util.control.timing.Updateable; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Abstraction of client-server connection from the client's view |
|
||||||
* |
|
||||||
* @author MightyPork |
|
||||||
*/ |
|
||||||
public abstract class ClientWorldAccess implements Updateable { |
|
||||||
|
|
||||||
public abstract Level getLevel(); |
|
||||||
|
|
||||||
} |
|
@ -1,64 +0,0 @@ |
|||||||
package mightypork.rogue.world; |
|
||||||
|
|
||||||
|
|
||||||
import mightypork.rogue.world.map.Level; |
|
||||||
import mightypork.rogue.world.map.TileRenderContext; |
|
||||||
import mightypork.util.constraints.rect.Rect; |
|
||||||
import mightypork.util.constraints.rect.RectConst; |
|
||||||
import mightypork.util.constraints.rect.proxy.RectBound; |
|
||||||
import mightypork.util.constraints.vect.VectConst; |
|
||||||
|
|
||||||
|
|
||||||
public class LevelRenderer { |
|
||||||
|
|
||||||
/** |
|
||||||
* 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 static void render(Level level, PlayerEntity player, RectBound viewport, final int yTiles, final int xTiles, final int minSize) |
|
||||||
{ |
|
||||||
final Rect r = viewport.getRect(); |
|
||||||
final double vpH = r.height().value(); |
|
||||||
final double vpW = r.width().value(); |
|
||||||
|
|
||||||
// adjust tile size to fit desired amount of tiles
|
|
||||||
|
|
||||||
final double allowedSizeW = vpW / xTiles; |
|
||||||
final double allowedSizeH = vpH / yTiles; |
|
||||||
int tileSize = (int) Math.round(Math.max(Math.min(allowedSizeH, allowedSizeW), minSize)); |
|
||||||
|
|
||||||
tileSize -= tileSize % 16; |
|
||||||
|
|
||||||
final VectConst vpCenter = r.center().sub(tileSize * 0.5, tileSize).freeze(); // 0.5 to center, 1 to move up (down is teh navbar)
|
|
||||||
|
|
||||||
final double playerX = player.getPosition().getVisualX(); |
|
||||||
final double playerY = player.getPosition().getVisualY(); |
|
||||||
|
|
||||||
// total map area
|
|
||||||
//@formatter:off
|
|
||||||
final RectConst mapRect = vpCenter.startRect().grow( |
|
||||||
playerX*tileSize, |
|
||||||
(level.getWidth() - playerX) * tileSize, |
|
||||||
playerY*tileSize, |
|
||||||
(level.getHeight() - playerY) * tileSize |
|
||||||
).freeze(); |
|
||||||
//@formatter:on
|
|
||||||
|
|
||||||
// tiles to render
|
|
||||||
final int x1 = (int) Math.floor(playerX - (vpW / tileSize)); |
|
||||||
final int y1 = (int) Math.floor(playerY - (vpH / tileSize)); |
|
||||||
final int x2 = (int) Math.ceil(playerX + (vpW / tileSize)); |
|
||||||
final int y2 = (int) Math.ceil(playerY + (vpH / tileSize)); |
|
||||||
|
|
||||||
final TileRenderContext trc = new TileRenderContext(level, mapRect); //-tileSize*0.5
|
|
||||||
for (trc.y = y1; trc.y <= y2; trc.y++) { |
|
||||||
for (trc.x = x1; trc.x <= x2; trc.x++) { |
|
||||||
trc.render(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,83 +0,0 @@ |
|||||||
package mightypork.rogue.world; |
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
|
|
||||||
import mightypork.rogue.world.map.MapObserver; |
|
||||||
import mightypork.util.ion.IonBundle; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Player info |
|
||||||
* |
|
||||||
* @author MightyPork |
|
||||||
*/ |
|
||||||
public class PlayerEntity extends WorldEntity implements MapObserver { |
|
||||||
|
|
||||||
public static final double PLAYER_STEP_TIME = 0.3; |
|
||||||
|
|
||||||
public boolean connected = false; |
|
||||||
|
|
||||||
|
|
||||||
public PlayerEntity() { |
|
||||||
super(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public PlayerEntity(ServerWorld world, int x, int y, int floor) { |
|
||||||
super(world, new WorldPos(x, y, floor)); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void load(IonBundle bundle) throws IOException |
|
||||||
{ |
|
||||||
super.load(bundle); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void save(IonBundle bundle) throws IOException |
|
||||||
{ |
|
||||||
super.save(bundle); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public int getViewRange() |
|
||||||
{ |
|
||||||
return 15; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
protected double getStepTime() |
|
||||||
{ |
|
||||||
return PLAYER_STEP_TIME; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public boolean isConnected() |
|
||||||
{ |
|
||||||
return connected; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void setConnected(boolean connected) |
|
||||||
{ |
|
||||||
this.connected = connected; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public WorldPos getViewPosition() |
|
||||||
{ |
|
||||||
return getPosition(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean isPhysical() |
|
||||||
{ |
|
||||||
return isConnected(); |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,62 @@ |
|||||||
|
package mightypork.rogue.world; |
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
import mightypork.util.ion.IonBundle; |
||||||
|
import mightypork.util.ion.IonBundled; |
||||||
|
|
||||||
|
|
||||||
|
public class PlayerInfo implements IonBundled { |
||||||
|
|
||||||
|
private int eid = -1; // marks not initialized
|
||||||
|
private int level; |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void load(IonBundle bundle) throws IOException |
||||||
|
{ |
||||||
|
eid = bundle.get("attached_eid", 0); |
||||||
|
level = bundle.get("current_level", 0); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void save(IonBundle bundle) throws IOException |
||||||
|
{ |
||||||
|
bundle.put("attached_eid", eid); |
||||||
|
bundle.put("current_level", level); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void setEID(int eid) |
||||||
|
{ |
||||||
|
if (isInitialized()) throw new RuntimeException("Cannot change player EID."); |
||||||
|
this.eid = eid; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void setLevel(int level) |
||||||
|
{ |
||||||
|
this.level = level; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public int getEID() |
||||||
|
{ |
||||||
|
return eid; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public int getLevel() |
||||||
|
{ |
||||||
|
return level; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public boolean isInitialized() |
||||||
|
{ |
||||||
|
return eid != -1; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,107 +0,0 @@ |
|||||||
package mightypork.rogue.world; |
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.util.*; |
|
||||||
|
|
||||||
import mightypork.rogue.world.map.Level; |
|
||||||
import mightypork.util.control.timing.Updateable; |
|
||||||
import mightypork.util.ion.IonBundle; |
|
||||||
import mightypork.util.ion.IonBundled; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* World on a server. To a server, all players and levels are equal. |
|
||||||
* |
|
||||||
* @author MightyPork |
|
||||||
*/ |
|
||||||
public class ServerWorld implements IonBundled, Updateable, WorldAccess { |
|
||||||
|
|
||||||
private final ArrayList<Level> levels = new ArrayList<>(); |
|
||||||
|
|
||||||
private final Map<String, PlayerEntity> players = new HashMap<>(); |
|
||||||
|
|
||||||
/** This seed can be used to re-create identical world. */ |
|
||||||
private long seed; |
|
||||||
|
|
||||||
/** Next spawned entity ID */ |
|
||||||
private long eid; |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void load(IonBundle in) throws IOException |
|
||||||
{ |
|
||||||
seed = in.get("seed", 0L); |
|
||||||
eid = in.get("eid", 0L); |
|
||||||
in.loadSequence("levels", levels); |
|
||||||
in.loadMap("players", players); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void save(IonBundle out) throws IOException |
|
||||||
{ |
|
||||||
out.put("seed", seed); |
|
||||||
out.put("eid", eid); |
|
||||||
out.putSequence("levels", levels); |
|
||||||
out.putMap("players", players); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void addLevel(Level level) |
|
||||||
{ |
|
||||||
levels.add(level); |
|
||||||
} |
|
||||||
|
|
||||||
public void addPlayer(String name, PlayerEntity player) |
|
||||||
{ |
|
||||||
players.put(name, player); |
|
||||||
} |
|
||||||
|
|
||||||
public void removePlayer(String name) |
|
||||||
{ |
|
||||||
players.remove(name); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void update(double delta) |
|
||||||
{ |
|
||||||
Set<Integer> occupiedLevels = new HashSet<>(); |
|
||||||
|
|
||||||
// food meters and such
|
|
||||||
for (final PlayerEntity pl : players.values()) { |
|
||||||
if(pl.isConnected()) { |
|
||||||
pl.updateLogic(this, delta); |
|
||||||
occupiedLevels.add(pl.getPosition().floor); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
for(int i : occupiedLevels) { |
|
||||||
levels.get(i).updateLogic(this, delta); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void setSeed(long seed) |
|
||||||
{ |
|
||||||
this.seed = seed; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public long getSeed() |
|
||||||
{ |
|
||||||
return seed; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public long generateEntityId() |
|
||||||
{ |
|
||||||
return eid++; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean isServer() |
|
||||||
{ |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,121 @@ |
|||||||
|
package mightypork.rogue.world; |
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.util.ArrayList; |
||||||
|
|
||||||
|
import mightypork.rogue.world.entity.Entities; |
||||||
|
import mightypork.rogue.world.entity.Entity; |
||||||
|
import mightypork.rogue.world.level.Level; |
||||||
|
import mightypork.util.constraints.rect.proxy.RectBound; |
||||||
|
import mightypork.util.control.timing.Updateable; |
||||||
|
import mightypork.util.ion.IonBundle; |
||||||
|
import mightypork.util.ion.IonBundled; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* World on a server. To a server, all players and levels are equal. |
||||||
|
* |
||||||
|
* @author MightyPork |
||||||
|
*/ |
||||||
|
public class World implements IonBundled, Updateable { |
||||||
|
|
||||||
|
private final ArrayList<Level> levels = new ArrayList<>(); |
||||||
|
|
||||||
|
private final PlayerInfo player = new PlayerInfo(); |
||||||
|
|
||||||
|
private long seed; // world seed
|
||||||
|
private int eid; // next entity ID
|
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void load(IonBundle in) throws IOException |
||||||
|
{ |
||||||
|
seed = in.get("seed", 0L); |
||||||
|
eid = in.get("next_eid", 0); |
||||||
|
in.loadSequence("levels", levels); |
||||||
|
in.loadBundled("player", player); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void save(IonBundle out) throws IOException |
||||||
|
{ |
||||||
|
out.put("seed", seed); |
||||||
|
out.put("next_eid", eid); |
||||||
|
out.putSequence("levels", levels); |
||||||
|
out.putBundled("player", player); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void addLevel(Level level) |
||||||
|
{ |
||||||
|
levels.add(level); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void update(double delta) |
||||||
|
{ |
||||||
|
getCurrentLevel().update(delta); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void setSeed(long seed) |
||||||
|
{ |
||||||
|
this.seed = seed; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public long getSeed() |
||||||
|
{ |
||||||
|
return seed; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* @return new entity ID |
||||||
|
*/ |
||||||
|
public int getNewEID() |
||||||
|
{ |
||||||
|
return eid++; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void createPlayer(int x, int y, int level) |
||||||
|
{ |
||||||
|
if (player.isInitialized()) { |
||||||
|
throw new RuntimeException("Player already created."); |
||||||
|
} |
||||||
|
|
||||||
|
// make entity
|
||||||
|
int playerEid = getNewEID(); |
||||||
|
|
||||||
|
final Entity entity = Entities.PLAYER.createEntity(playerEid, new WorldPos(x, y)); |
||||||
|
|
||||||
|
player.setLevel(level); |
||||||
|
player.setEID(playerEid); |
||||||
|
|
||||||
|
levels.get(level).addEntity(entity); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 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(RectBound viewport, final int yTiles, final int xTiles, final int minSize) |
||||||
|
{ |
||||||
|
getCurrentLevel().render(player, viewport, yTiles, xTiles, minSize); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public Level getCurrentLevel() |
||||||
|
{ |
||||||
|
return levels.get(player.getLevel()); |
||||||
|
} |
||||||
|
} |
@ -1,8 +0,0 @@ |
|||||||
package mightypork.rogue.world; |
|
||||||
|
|
||||||
|
|
||||||
public interface WorldAccess { |
|
||||||
|
|
||||||
public boolean isServer(); |
|
||||||
|
|
||||||
} |
|
@ -1,143 +0,0 @@ |
|||||||
package mightypork.rogue.world; |
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.util.LinkedList; |
|
||||||
import java.util.Queue; |
|
||||||
|
|
||||||
import mightypork.util.ion.IonBundle; |
|
||||||
import mightypork.util.ion.IonBundled; |
|
||||||
|
|
||||||
|
|
||||||
public abstract class WorldEntity implements IonBundled { |
|
||||||
|
|
||||||
private final WorldPos position = new WorldPos(); |
|
||||||
private Runnable moveEndListener, pathEndListener; |
|
||||||
|
|
||||||
private long serial_id = 0L; |
|
||||||
|
|
||||||
private final Queue<PathStep> path = new LinkedList<>(); |
|
||||||
|
|
||||||
|
|
||||||
public WorldEntity(ServerWorld world, WorldPos pos) { |
|
||||||
this.serial_id = world.generateEntityId(); |
|
||||||
this.position.setTo(pos); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public WorldEntity() { |
|
||||||
// for ion
|
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void save(IonBundle bundle) throws IOException |
|
||||||
{ |
|
||||||
bundle.putBundled("pos", position); |
|
||||||
bundle.putSequence("steps", path); |
|
||||||
bundle.put("eid", serial_id); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void load(IonBundle bundle) throws IOException |
|
||||||
{ |
|
||||||
bundle.loadBundled("pos", position); |
|
||||||
bundle.loadSequence("path", path); |
|
||||||
serial_id = bundle.get("eid", 0L); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void setMoveEndListener(Runnable moveEndListener) |
|
||||||
{ |
|
||||||
this.moveEndListener = moveEndListener; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void setPathEndListener(Runnable pathEndListener) |
|
||||||
{ |
|
||||||
this.pathEndListener = pathEndListener; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public WorldPos getPosition() |
|
||||||
{ |
|
||||||
return position; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void setPosition(WorldPos pos) |
|
||||||
{ |
|
||||||
position.setTo(pos); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void setPosition(int x, int y, int floor) |
|
||||||
{ |
|
||||||
position.setTo(x, y, floor); |
|
||||||
cancelPath(); // discard remaining steps
|
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* @param world the world |
|
||||||
* @param delta delta time |
|
||||||
*/ |
|
||||||
public void updateLogic(WorldAccess world, double delta) |
|
||||||
{ |
|
||||||
if(!isPhysical()) return; |
|
||||||
|
|
||||||
if (!position.isFinished()) { |
|
||||||
position.update(delta); |
|
||||||
} |
|
||||||
|
|
||||||
if (position.isFinished()) { |
|
||||||
|
|
||||||
if (moveEndListener != null) moveEndListener.run(); |
|
||||||
|
|
||||||
if (!path.isEmpty()) { |
|
||||||
// get next step to walk
|
|
||||||
PathStep step = path.poll(); |
|
||||||
position.walk(step.x, step.y, getStepTime()); |
|
||||||
} else { |
|
||||||
// notify AI or whatever
|
|
||||||
if (pathEndListener != null) pathEndListener.run(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* @param world the world |
|
||||||
* @param delta delta time |
|
||||||
*/ |
|
||||||
public void updateVisual(WorldAccess world, double delta) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public boolean isPathFinished() |
|
||||||
{ |
|
||||||
return position.isFinished() && path.isEmpty(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void addStep(PathStep step) |
|
||||||
{ |
|
||||||
path.add(step); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void cancelPath() |
|
||||||
{ |
|
||||||
path.clear(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
protected abstract double getStepTime(); |
|
||||||
|
|
||||||
public boolean isPhysical() { |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,44 @@ |
|||||||
|
package mightypork.rogue.world.entity; |
||||||
|
|
||||||
|
|
||||||
|
import mightypork.rogue.world.entity.models.EntityModel; |
||||||
|
import mightypork.rogue.world.entity.models.PlayerModel; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Tile registry |
||||||
|
* |
||||||
|
* @author MightyPork |
||||||
|
*/ |
||||||
|
public final class Entities { |
||||||
|
|
||||||
|
private static final EntityModel[] entities = new EntityModel[256]; |
||||||
|
|
||||||
|
public static final EntityModel PLAYER = new PlayerModel(0); |
||||||
|
|
||||||
|
|
||||||
|
public static void register(int id, EntityModel model) |
||||||
|
{ |
||||||
|
if (id < 0 || id >= entities.length) { |
||||||
|
throw new IllegalArgumentException("Entity model ID " + id + " is out of range."); |
||||||
|
} |
||||||
|
|
||||||
|
if (entities[id] != null) { |
||||||
|
throw new IllegalArgumentException("Entity model ID " + id + " already in use."); |
||||||
|
} |
||||||
|
|
||||||
|
entities[id] = model; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public static EntityModel get(int id) |
||||||
|
{ |
||||||
|
final EntityModel e = entities[id]; |
||||||
|
|
||||||
|
if (e == null) { |
||||||
|
throw new IllegalArgumentException("No entity model with ID " + id + "."); |
||||||
|
} |
||||||
|
|
||||||
|
return e; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,192 @@ |
|||||||
|
package mightypork.rogue.world.entity; |
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.util.LinkedList; |
||||||
|
import java.util.Queue; |
||||||
|
|
||||||
|
import mightypork.rogue.world.PathStep; |
||||||
|
import mightypork.rogue.world.World; |
||||||
|
import mightypork.rogue.world.WorldPos; |
||||||
|
import mightypork.rogue.world.entity.models.EntityModel; |
||||||
|
import mightypork.rogue.world.level.Level; |
||||||
|
import mightypork.util.ion.IonBinary; |
||||||
|
import mightypork.util.ion.IonBundle; |
||||||
|
import mightypork.util.ion.IonBundled; |
||||||
|
import mightypork.util.ion.IonInput; |
||||||
|
import mightypork.util.ion.IonOutput; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* World entity (mob or player) |
||||||
|
* |
||||||
|
* @author MightyPork |
||||||
|
*/ |
||||||
|
public final class Entity implements IonBinary, IonBundled { |
||||||
|
|
||||||
|
// binary & bundled - binary stores via a bundle
|
||||||
|
|
||||||
|
public static final int ION_MARK = 52; |
||||||
|
|
||||||
|
private final WorldPos position = new WorldPos(); |
||||||
|
|
||||||
|
/** Entity ID */ |
||||||
|
private int eid = 0; |
||||||
|
|
||||||
|
/** Model ID */ |
||||||
|
private int id; |
||||||
|
|
||||||
|
private final Queue<PathStep> path = new LinkedList<>(); |
||||||
|
private EntityModel model; |
||||||
|
private final IonBundle metadata = new IonBundle(); |
||||||
|
|
||||||
|
|
||||||
|
public Entity(int eid, WorldPos pos, EntityModel entityModel) |
||||||
|
{ |
||||||
|
this.eid = eid; |
||||||
|
this.position.setTo(pos); |
||||||
|
|
||||||
|
setModel(entityModel); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private void setModel(EntityModel entityModel) |
||||||
|
{ |
||||||
|
this.id = entityModel.id; |
||||||
|
this.model = entityModel; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public Entity() |
||||||
|
{ |
||||||
|
// for ion
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public short getIonMark() |
||||||
|
{ |
||||||
|
return ION_MARK; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void save(IonOutput out) throws IOException |
||||||
|
{ |
||||||
|
final IonBundle ib = new IonBundle(); |
||||||
|
save(ib); |
||||||
|
out.writeBundle(ib); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void load(IonInput in) throws IOException |
||||||
|
{ |
||||||
|
load(in.readBundle()); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void save(IonBundle bundle) throws IOException |
||||||
|
{ |
||||||
|
bundle.put("id", id); |
||||||
|
bundle.putBundled("pos", position); |
||||||
|
bundle.putSequence("steps", path); |
||||||
|
bundle.put("eid", eid); |
||||||
|
bundle.put("metadata", metadata); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void load(IonBundle bundle) throws IOException |
||||||
|
{ |
||||||
|
id = bundle.get("id", 0); |
||||||
|
|
||||||
|
if (model == null || id != model.id) { |
||||||
|
setModel(Entities.get(id)); |
||||||
|
} |
||||||
|
|
||||||
|
bundle.loadBundled("pos", position); |
||||||
|
bundle.loadSequence("path", path); |
||||||
|
eid = bundle.get("eid", eid); |
||||||
|
|
||||||
|
metadata.clear(); |
||||||
|
bundle.loadBundle("metadata", metadata); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public int getEID() |
||||||
|
{ |
||||||
|
return eid; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public WorldPos getPosition() |
||||||
|
{ |
||||||
|
return position; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void setPosition(WorldPos pos) |
||||||
|
{ |
||||||
|
position.setTo(pos); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void setPosition(int x, int y) |
||||||
|
{ |
||||||
|
position.setTo(x, y); |
||||||
|
cancelPath(); // discard remaining steps
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* @param world the world |
||||||
|
* @param delta delta time |
||||||
|
*/ |
||||||
|
public void update(World world, Level level, double delta) |
||||||
|
{ |
||||||
|
if (!position.isFinished()) { |
||||||
|
position.update(delta); |
||||||
|
} |
||||||
|
|
||||||
|
if (position.isFinished()) { |
||||||
|
|
||||||
|
model.onStepFinished(this, world, level); |
||||||
|
|
||||||
|
if (!path.isEmpty()) { |
||||||
|
// get next step to walk
|
||||||
|
final PathStep step = path.poll(); |
||||||
|
position.walk(step.x, step.y, getStepTime()); |
||||||
|
} else { |
||||||
|
// notify AI or whatever
|
||||||
|
model.onPathFinished(this, world, level); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public boolean isPathFinished() |
||||||
|
{ |
||||||
|
return position.isFinished() && path.isEmpty(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void addStep(PathStep step) |
||||||
|
{ |
||||||
|
path.add(step); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void cancelPath() |
||||||
|
{ |
||||||
|
path.clear(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
protected double getStepTime() |
||||||
|
{ |
||||||
|
return model.getStepTime(this); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,71 @@ |
|||||||
|
package mightypork.rogue.world.entity.models; |
||||||
|
|
||||||
|
|
||||||
|
import mightypork.rogue.world.World; |
||||||
|
import mightypork.rogue.world.WorldPos; |
||||||
|
import mightypork.rogue.world.entity.Entities; |
||||||
|
import mightypork.rogue.world.entity.Entity; |
||||||
|
import mightypork.rogue.world.entity.renderers.EntityRenderer; |
||||||
|
import mightypork.rogue.world.level.Level; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Entity model |
||||||
|
* |
||||||
|
* @author MightyPork |
||||||
|
*/ |
||||||
|
public abstract class EntityModel { |
||||||
|
|
||||||
|
/** Model ID */ |
||||||
|
public final int id; |
||||||
|
public EntityRenderer renderer = EntityRenderer.NONE; |
||||||
|
|
||||||
|
|
||||||
|
public EntityModel(int id) |
||||||
|
{ |
||||||
|
Entities.register(id, this); |
||||||
|
this.id = id; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public EntityModel setRenderer(EntityRenderer renderer) |
||||||
|
{ |
||||||
|
this.renderer = renderer; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* @return new tile of this type; if 100% invariant, can return cached one. |
||||||
|
*/ |
||||||
|
public Entity createEntity(int eid, WorldPos pos) |
||||||
|
{ |
||||||
|
return new Entity(eid, pos, this); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Update entity |
||||||
|
*/ |
||||||
|
public abstract void update(Entity entity, Level level, double delta); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* @return true if this entity type has metadata worth saving |
||||||
|
*/ |
||||||
|
public abstract boolean hasMetadata(); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* @param entity the value is valid for |
||||||
|
* @return step time (seconds) |
||||||
|
*/ |
||||||
|
public abstract double getStepTime(Entity entity); |
||||||
|
|
||||||
|
|
||||||
|
public abstract void onStepFinished(Entity entity, World world, Level level); |
||||||
|
|
||||||
|
|
||||||
|
public abstract void onPathFinished(Entity entity, World world, Level level); |
||||||
|
|
||||||
|
} |
@ -0,0 +1,67 @@ |
|||||||
|
package mightypork.rogue.world.entity.models; |
||||||
|
|
||||||
|
|
||||||
|
import mightypork.rogue.world.World; |
||||||
|
import mightypork.rogue.world.WorldPos; |
||||||
|
import mightypork.rogue.world.entity.Entity; |
||||||
|
import mightypork.rogue.world.level.Level; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Player info |
||||||
|
* |
||||||
|
* @author MightyPork |
||||||
|
*/ |
||||||
|
public class PlayerModel extends EntityModel { |
||||||
|
|
||||||
|
private static final double STEP_TIME = 0.3; |
||||||
|
|
||||||
|
|
||||||
|
public PlayerModel(int id) |
||||||
|
{ |
||||||
|
super(id); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public Entity createEntity(int eid, WorldPos pos) |
||||||
|
{ |
||||||
|
final Entity e = super.createEntity(eid, pos); |
||||||
|
|
||||||
|
// set metadata
|
||||||
|
|
||||||
|
return e; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void update(Entity entity, Level level, double delta) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasMetadata() |
||||||
|
{ |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public double getStepTime(Entity entity) |
||||||
|
{ |
||||||
|
return STEP_TIME; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void onStepFinished(Entity entity, World world, Level level) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void onPathFinished(Entity entity, World world, Level level) |
||||||
|
{ |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,8 @@ |
|||||||
|
package mightypork.rogue.world.entity.renderers; |
||||||
|
|
||||||
|
|
||||||
|
public class EntityRenderer { |
||||||
|
|
||||||
|
public static final EntityRenderer NONE = new NullEntityRenderer(); |
||||||
|
|
||||||
|
} |
@ -0,0 +1,6 @@ |
|||||||
|
package mightypork.rogue.world.entity.renderers; |
||||||
|
|
||||||
|
|
||||||
|
public class NullEntityRenderer extends EntityRenderer { |
||||||
|
|
||||||
|
} |
@ -0,0 +1,330 @@ |
|||||||
|
package mightypork.rogue.world.level; |
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.HashSet; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL11; |
||||||
|
|
||||||
|
import mightypork.gamecore.render.Render; |
||||||
|
import mightypork.rogue.Res; |
||||||
|
import mightypork.rogue.world.PlayerInfo; |
||||||
|
import mightypork.rogue.world.WorldPos; |
||||||
|
import mightypork.rogue.world.entity.Entity; |
||||||
|
import mightypork.rogue.world.level.render.TileRenderContext; |
||||||
|
import mightypork.rogue.world.tile.Tile; |
||||||
|
import mightypork.rogue.world.tile.Tiles; |
||||||
|
import mightypork.rogue.world.tile.models.TileModel; |
||||||
|
import mightypork.util.constraints.rect.Rect; |
||||||
|
import mightypork.util.constraints.rect.RectConst; |
||||||
|
import mightypork.util.constraints.rect.proxy.RectBound; |
||||||
|
import mightypork.util.constraints.vect.VectConst; |
||||||
|
import mightypork.util.ion.IonBinary; |
||||||
|
import mightypork.util.ion.IonBundle; |
||||||
|
import mightypork.util.ion.IonInput; |
||||||
|
import mightypork.util.ion.IonOutput; |
||||||
|
import mightypork.util.math.noise.NoiseGen; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* One level of the dungeon |
||||||
|
* |
||||||
|
* @author MightyPork |
||||||
|
*/ |
||||||
|
public class Level implements MapAccess, IonBinary { |
||||||
|
|
||||||
|
public static final int ION_MARK = 53; |
||||||
|
|
||||||
|
private static final boolean USE_BATCH_RENDERING = true; |
||||||
|
|
||||||
|
private int width, height; |
||||||
|
|
||||||
|
/** Array of tiles [y][x] */ |
||||||
|
private Tile[][] tiles; |
||||||
|
|
||||||
|
private final Map<Integer, Entity> entity_map = new HashMap<>(); |
||||||
|
private final Set<Entity> entity_set = new HashSet<>(); |
||||||
|
|
||||||
|
/** Level seed (used for generation and tile variation) */ |
||||||
|
public long seed; |
||||||
|
|
||||||
|
private transient NoiseGen noiseGen; |
||||||
|
|
||||||
|
|
||||||
|
public Level() |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public Level(int width, int height) |
||||||
|
{ |
||||||
|
this.width = width; |
||||||
|
this.height = height; |
||||||
|
buildArray(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private void buildArray() |
||||||
|
{ |
||||||
|
this.tiles = new Tile[height][width]; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void fill(short 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] = model.createTile(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@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); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
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; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public final int getWidth() |
||||||
|
{ |
||||||
|
return width; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public final int getHeight() |
||||||
|
{ |
||||||
|
return height; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void setSeed(long seed) |
||||||
|
{ |
||||||
|
this.seed = seed; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public long getSeed() |
||||||
|
{ |
||||||
|
return seed; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void load(IonInput in) throws IOException |
||||||
|
{ |
||||||
|
// metadata
|
||||||
|
final IonBundle ib = in.readBundle(); |
||||||
|
seed = ib.get("seed", 0L); |
||||||
|
width = ib.get("w", 0); |
||||||
|
height = ib.get("h", 0); |
||||||
|
|
||||||
|
ib.loadSequence("entities", entity_set); |
||||||
|
for (final Entity ent : entity_set) { |
||||||
|
entity_map.put(ent.getEID(), ent); |
||||||
|
} |
||||||
|
|
||||||
|
// init array of size
|
||||||
|
buildArray(); |
||||||
|
|
||||||
|
// load tiles
|
||||||
|
for (int y = 0; y < height; y++) { |
||||||
|
for (int x = 0; x < width; x++) { |
||||||
|
// no mark
|
||||||
|
tiles[y][x] = new Tile(); |
||||||
|
tiles[y][x].load(in); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void save(IonOutput out) throws IOException |
||||||
|
{ |
||||||
|
// metadata
|
||||||
|
final IonBundle ib = new IonBundle(); |
||||||
|
ib.put("seed", seed); |
||||||
|
ib.put("w", width); |
||||||
|
ib.put("h", height); |
||||||
|
ib.putSequence("entities", entity_set); |
||||||
|
out.writeBundle(ib); |
||||||
|
|
||||||
|
// tiles (writing this way to save space)
|
||||||
|
for (int y = 0; y < height; y++) { |
||||||
|
for (int x = 0; x < width; x++) { |
||||||
|
// no mark to save space
|
||||||
|
tiles[y][x].save(out); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public short getIonMark() |
||||||
|
{ |
||||||
|
return ION_MARK; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void update(double delta) |
||||||
|
{ |
||||||
|
// just update them all
|
||||||
|
for (int y = 0; y < height; y++) { |
||||||
|
for (int x = 0; x < width; x++) { |
||||||
|
getTile(x, y).update(this, delta); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public NoiseGen getNoiseGen() |
||||||
|
{ |
||||||
|
if (noiseGen == null) { |
||||||
|
noiseGen = new NoiseGen(0.2, 0, 0.5, 1, seed); |
||||||
|
} |
||||||
|
|
||||||
|
return noiseGen; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Draw on screen |
||||||
|
* |
||||||
|
* @param playerInfo layer |
||||||
|
* @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(PlayerInfo playerInfo, RectBound viewport, final int yTiles, final int xTiles, final int minSize) |
||||||
|
{ |
||||||
|
final WorldPos pos; |
||||||
|
|
||||||
|
try { |
||||||
|
pos = getEntity(playerInfo.getEID()).getPosition(); |
||||||
|
} catch (NullPointerException e) { |
||||||
|
throw new RuntimeException("Player entity not found in level.", e); |
||||||
|
} |
||||||
|
|
||||||
|
final Rect r = viewport.getRect(); |
||||||
|
final double vpH = r.height().value(); |
||||||
|
final double vpW = r.width().value(); |
||||||
|
|
||||||
|
// adjust tile size to fit desired amount of tiles
|
||||||
|
|
||||||
|
final double allowedSizeW = vpW / xTiles; |
||||||
|
final double allowedSizeH = vpH / yTiles; |
||||||
|
int tileSize = (int) Math.round(Math.max(Math.min(allowedSizeH, allowedSizeW), minSize)); |
||||||
|
|
||||||
|
tileSize -= tileSize % 16; |
||||||
|
|
||||||
|
final VectConst vpCenter = r.center().sub(tileSize * 0.5, tileSize).freeze(); // 0.5 to center, 1 to move up (down is teh navbar)
|
||||||
|
|
||||||
|
final double playerX = pos.getVisualX(); |
||||||
|
final double playerY = pos.getVisualY(); |
||||||
|
|
||||||
|
// total map area
|
||||||
|
//@formatter:off
|
||||||
|
final RectConst mapRect = vpCenter.startRect().grow( |
||||||
|
playerX*tileSize, |
||||||
|
(getWidth() - playerX) * tileSize, |
||||||
|
playerY*tileSize, |
||||||
|
(getHeight() - playerY) * tileSize |
||||||
|
).freeze(); |
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
// tiles to render
|
||||||
|
final int x1 = (int) Math.floor(playerX - (vpW / tileSize / 2)); |
||||||
|
|
||||||
|
final int y1 = (int) Math.floor(playerY - (vpH / tileSize / 2)); |
||||||
|
final int x2 = (int) Math.ceil(playerX + (vpW / tileSize / 2)); |
||||||
|
final int y2 = (int) Math.ceil(playerY + (vpH / tileSize / 2)); |
||||||
|
|
||||||
|
final TileRenderContext trc = new TileRenderContext(this, mapRect); //-tileSize*0.5
|
||||||
|
|
||||||
|
// batch rendering of the tiles
|
||||||
|
if (USE_BATCH_RENDERING) { |
||||||
|
Render.enterBatchTexturedQuadMode(Res.getTexture("tiles")); |
||||||
|
} |
||||||
|
|
||||||
|
for (trc.y = y1; trc.y <= y2; trc.y++) { |
||||||
|
for (trc.x = x1; trc.x <= x2; trc.x++) { |
||||||
|
trc.renderTile(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (USE_BATCH_RENDERING) { |
||||||
|
Render.leaveBatchTexturedQuadMode(); |
||||||
|
} |
||||||
|
|
||||||
|
// render extras
|
||||||
|
for (trc.y = y1; trc.y <= y2; trc.y++) { |
||||||
|
for (trc.x = x1; trc.x <= x2; trc.x++) { |
||||||
|
trc.renderItems(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public Entity getEntity(int eid) |
||||||
|
{ |
||||||
|
return entity_map.get(eid); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void addEntity(Entity entity) |
||||||
|
{ |
||||||
|
entity_map.put(entity.getEID(), entity); |
||||||
|
entity_set.add(entity); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void removeEntity(Entity entity) |
||||||
|
{ |
||||||
|
entity_map.remove(entity.getEID()); |
||||||
|
entity_set.remove(entity); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void removeEntity(int eid) |
||||||
|
{ |
||||||
|
final Entity removed = entity_map.remove(eid); |
||||||
|
entity_set.remove(removed); |
||||||
|
} |
||||||
|
} |
@ -1,4 +1,4 @@ |
|||||||
package mightypork.rogue.world.map; |
package mightypork.rogue.world.level; |
||||||
|
|
||||||
|
|
||||||
import mightypork.rogue.world.tile.Tile; |
import mightypork.rogue.world.tile.Tile; |
@ -1,6 +1,7 @@ |
|||||||
package mightypork.rogue.world.map; |
package mightypork.rogue.world.level.render; |
||||||
|
|
||||||
|
|
||||||
|
import mightypork.rogue.world.level.MapAccess; |
||||||
import mightypork.util.constraints.rect.Rect; |
import mightypork.util.constraints.rect.Rect; |
||||||
|
|
||||||
|
|
@ -1,6 +1,7 @@ |
|||||||
package mightypork.rogue.world.map; |
package mightypork.rogue.world.level.render; |
||||||
|
|
||||||
|
|
||||||
|
import mightypork.rogue.world.level.MapAccess; |
||||||
import mightypork.util.constraints.rect.Rect; |
import mightypork.util.constraints.rect.Rect; |
||||||
import mightypork.util.constraints.rect.builders.TiledRect; |
import mightypork.util.constraints.rect.builders.TiledRect; |
||||||
|
|
@ -1,248 +0,0 @@ |
|||||||
package mightypork.rogue.world.map; |
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import mightypork.rogue.world.PlayerEntity; |
|
||||||
import mightypork.rogue.world.WorldAccess; |
|
||||||
import mightypork.rogue.world.WorldEntity; |
|
||||||
import mightypork.rogue.world.WorldPos; |
|
||||||
import mightypork.rogue.world.tile.Tile; |
|
||||||
import mightypork.rogue.world.tile.TileModel; |
|
||||||
import mightypork.rogue.world.tile.Tiles; |
|
||||||
import mightypork.util.ion.IonBinary; |
|
||||||
import mightypork.util.ion.IonBundle; |
|
||||||
import mightypork.util.ion.IonInput; |
|
||||||
import mightypork.util.ion.IonOutput; |
|
||||||
import mightypork.util.math.noise.NoiseGen; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* One level of the dungeon |
|
||||||
* |
|
||||||
* @author MightyPork |
|
||||||
*/ |
|
||||||
public class Level implements MapAccess, IonBinary { |
|
||||||
|
|
||||||
public static final int ION_MARK = 53; |
|
||||||
|
|
||||||
private int width, height; |
|
||||||
|
|
||||||
/** Array of tiles [y][x] */ |
|
||||||
private Tile[][] tiles; |
|
||||||
|
|
||||||
private final List<WorldEntity> entities = new ArrayList<>(); |
|
||||||
|
|
||||||
/** Level seed (used for generation and tile variation) */ |
|
||||||
public long seed; |
|
||||||
|
|
||||||
private transient NoiseGen noiseGen; |
|
||||||
|
|
||||||
|
|
||||||
public Level() |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public Level(int width, int height) |
|
||||||
{ |
|
||||||
this.width = width; |
|
||||||
this.height = height; |
|
||||||
buildArray(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
private void buildArray() |
|
||||||
{ |
|
||||||
this.tiles = new Tile[height][width]; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void fill(short 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] = model.createTile(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@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); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
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; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public final int getWidth() |
|
||||||
{ |
|
||||||
return width; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public final int getHeight() |
|
||||||
{ |
|
||||||
return height; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void setSeed(long seed) |
|
||||||
{ |
|
||||||
this.seed = seed; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public long getSeed() |
|
||||||
{ |
|
||||||
return seed; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void load(IonInput in) throws IOException |
|
||||||
{ |
|
||||||
// metadata
|
|
||||||
final IonBundle ib = in.readBundle(); |
|
||||||
seed = ib.get("seed", 0L); |
|
||||||
width = ib.get("w", 0); |
|
||||||
height = ib.get("h", 0); |
|
||||||
|
|
||||||
ib.loadSequence("entities", entities); |
|
||||||
|
|
||||||
// init array of size
|
|
||||||
buildArray(); |
|
||||||
|
|
||||||
// load tiles
|
|
||||||
for (int y = 0; y < height; y++) { |
|
||||||
for (int x = 0; x < width; x++) { |
|
||||||
// no mark
|
|
||||||
tiles[y][x] = new Tile(); |
|
||||||
tiles[y][x].load(in); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void save(IonOutput out) throws IOException |
|
||||||
{ |
|
||||||
// metadata
|
|
||||||
final IonBundle ib = new IonBundle(); |
|
||||||
ib.put("seed", seed); |
|
||||||
ib.put("w", width); |
|
||||||
ib.put("h", height); |
|
||||||
ib.putSequence("entities", entities); |
|
||||||
out.writeBundle(ib); |
|
||||||
|
|
||||||
// tiles (writing this way to save space)
|
|
||||||
for (int y = 0; y < height; y++) { |
|
||||||
for (int x = 0; x < width; x++) { |
|
||||||
// no mark to save space
|
|
||||||
tiles[y][x].save(out); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public short getIonMark() |
|
||||||
{ |
|
||||||
return ION_MARK; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public void updateLogic(WorldAccess world, double delta) |
|
||||||
{ |
|
||||||
if (!world.isServer()) { |
|
||||||
throw new RuntimeException("Not allowed for client."); |
|
||||||
} |
|
||||||
|
|
||||||
// just update them all
|
|
||||||
for (int y = 0; y < height; y++) { |
|
||||||
for (int x = 0; x < width; x++) { |
|
||||||
getTile(x, y).updateLogic(world, this, delta); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Update visuals for player (particle effects etc) |
|
||||||
* |
|
||||||
* @param world |
|
||||||
* @param player |
|
||||||
* @param delta |
|
||||||
*/ |
|
||||||
public void updateVisual(WorldAccess world, PlayerEntity player, double delta) |
|
||||||
{ |
|
||||||
if (world.isServer()) { |
|
||||||
throw new RuntimeException("Not allowed for server."); |
|
||||||
} |
|
||||||
|
|
||||||
final int viewRange = player.getViewRange(); |
|
||||||
final WorldPos eyepos = player.getViewPosition(); |
|
||||||
|
|
||||||
int x1 = eyepos.x - viewRange; |
|
||||||
int y1 = eyepos.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).updateVisual(world, this, delta); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public NoiseGen getNoiseGen() |
|
||||||
{ |
|
||||||
if (noiseGen == null) { |
|
||||||
noiseGen = new NoiseGen(0.2, 0, 0.5, 1, seed); |
|
||||||
} |
|
||||||
|
|
||||||
return noiseGen; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,13 +0,0 @@ |
|||||||
package mightypork.rogue.world.map; |
|
||||||
|
|
||||||
|
|
||||||
import mightypork.rogue.world.WorldPos; |
|
||||||
|
|
||||||
|
|
||||||
public interface MapObserver { |
|
||||||
|
|
||||||
int getViewRange(); |
|
||||||
|
|
||||||
|
|
||||||
WorldPos getViewPosition(); |
|
||||||
} |
|
@ -1,9 +1,9 @@ |
|||||||
package mightypork.rogue.world.tile; |
package mightypork.rogue.world.tile.renderers; |
||||||
|
|
||||||
|
|
||||||
import mightypork.rogue.world.item.Item; |
import mightypork.rogue.world.item.Item; |
||||||
import mightypork.rogue.world.map.TileRenderContext; |
import mightypork.rogue.world.level.render.TileRenderContext; |
||||||
import mightypork.rogue.world.tile.renderers.NullTileRenderer; |
import mightypork.rogue.world.tile.DroppedItemRenderer; |
||||||
|
|
||||||
|
|
||||||
/** |
/** |
Loading…
Reference in new issue