v5stable
Ondřej Hruška 11 years ago
parent e14be3ec1b
commit 880bcfb553
  1. 4
      src/mightypork/rogue/App.java
  2. 21
      src/mightypork/rogue/world/ClientWorld.java
  3. 6
      src/mightypork/rogue/world/MapGenerator.java
  4. 16
      src/mightypork/rogue/world/MapObserver.java
  5. 49
      src/mightypork/rogue/world/PathStep.java
  6. 140
      src/mightypork/rogue/world/Player.java
  7. 83
      src/mightypork/rogue/world/PlayerEntity.java
  8. 33
      src/mightypork/rogue/world/ServerWorld.java
  9. 2
      src/mightypork/rogue/world/WorldAccess.java
  10. 139
      src/mightypork/rogue/world/WorldEntity.java
  11. 29
      src/mightypork/rogue/world/WorldPos.java
  12. 38
      src/mightypork/rogue/world/map/Level.java
  13. 13
      src/mightypork/rogue/world/map/MapObserver.java
  14. 10
      src/mightypork/rogue/world/tile/Tile.java
  15. 10
      src/mightypork/rogue/world/tile/TileModel.java

@ -22,7 +22,7 @@ import mightypork.rogue.screens.main_menu.ScreenMainMenu;
import mightypork.rogue.screens.test_bouncyboxes.ScreenTestBouncy; import mightypork.rogue.screens.test_bouncyboxes.ScreenTestBouncy;
import mightypork.rogue.screens.test_cat_sound.ScreenTestCat; import mightypork.rogue.screens.test_cat_sound.ScreenTestCat;
import mightypork.rogue.screens.test_render.ScreenTestRender; import mightypork.rogue.screens.test_render.ScreenTestRender;
import mightypork.rogue.world.Player; import mightypork.rogue.world.PlayerEntity;
import mightypork.rogue.world.item.Item; import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.map.Level; import mightypork.rogue.world.map.Level;
import mightypork.rogue.world.tile.Tile; import mightypork.rogue.world.tile.Tile;
@ -110,7 +110,7 @@ public final class App extends BaseApp {
Ion.registerBinary(Tile.ION_MARK, Tile.class); Ion.registerBinary(Tile.ION_MARK, Tile.class);
Ion.registerBinary(Item.ION_MARK, Item.class); Ion.registerBinary(Item.ION_MARK, Item.class);
Ion.registerBinary(Level.ION_MARK, Level.class); Ion.registerBinary(Level.ION_MARK, Level.class);
Ion.registerBinary(Level.ION_MARK, Player.class); Ion.registerBinary(Level.ION_MARK, PlayerEntity.class);
} }

@ -10,11 +10,11 @@ import mightypork.util.constraints.vect.VectConst;
import mightypork.util.control.timing.Updateable; import mightypork.util.control.timing.Updateable;
public class WorldClient implements Updateable { public class ClientWorld implements Updateable, WorldAccess {
private Level level = null; private Level level = null;
private final Player player = null; private final PlayerEntity player = null;
@Override @Override
@ -50,8 +50,8 @@ public class WorldClient implements Updateable {
final VectConst vpCenter = r.center().sub(tileSize * 0.5, tileSize).freeze(); // 0.5 to center, 1 to move up (down is teh navbar) 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().getXVisual(); final double playerX = player.getPosition().getVisualX();
final double playerY = player.getPosition().getYVisual(); final double playerY = player.getPosition().getVisualY();
// total map area // total map area
//@formatter:off //@formatter:off
@ -63,9 +63,6 @@ public class WorldClient implements Updateable {
).freeze(); ).freeze();
//@formatter:on //@formatter:on
System.out.println(playerX + "," + playerY + " : " + mapRect);
System.out.println(level.getWidth() + "," + level.getHeight());
// tiles to render // tiles to render
final int x1 = (int) Math.floor(playerX - (vpW / tileSize)); final int x1 = (int) Math.floor(playerX - (vpW / tileSize));
final int y1 = (int) Math.floor(playerY - (vpH / tileSize)); final int y1 = (int) Math.floor(playerY - (vpH / tileSize));
@ -81,9 +78,17 @@ public class WorldClient implements Updateable {
} }
public Player getPlayer() public PlayerEntity getPlayer()
{ {
return player; return player;
} }
@Override
public boolean isServer()
{
// TODO Auto-generated method stub
return false;
}
} }

@ -13,19 +13,19 @@ public class MapGenerator {
public static final Random rand = new Random(); public static final Random rand = new Random();
public static WorldServer createWorld(long seed) public static ServerWorld createWorld(long seed)
{ {
synchronized (rand) { synchronized (rand) {
rand.setSeed(seed); rand.setSeed(seed);
final WorldServer w = new WorldServer(); final ServerWorld w = new ServerWorld();
w.setSeed(seed); w.setSeed(seed);
w.addLevel(createLevel(rand.nextLong(), Tiles.CRYSTAL_FLOOR, Tiles.CRYSTAL_WALL)); w.addLevel(createLevel(rand.nextLong(), Tiles.CRYSTAL_FLOOR, Tiles.CRYSTAL_WALL));
w.addLevel(createLevel(rand.nextLong(), Tiles.BRCOBBLE_FLOOR, Tiles.BRCOBBLE_WALL)); w.addLevel(createLevel(rand.nextLong(), Tiles.BRCOBBLE_FLOOR, Tiles.BRCOBBLE_WALL));
// TODO place on start position // TODO place on start position
w.addPlayer("local", new Player(10, 10, 0)); w.addPlayer("local", new PlayerEntity(10, 10, 0));
return w; return w;
} }
} }

@ -1,16 +0,0 @@
package mightypork.rogue.world;
/**
* Player observing a map represented by an observer.
*
* @author MightyPork
*/
public interface MapObserver extends WorldEntity {
/**
* @return observed range (in tiles)
*/
public int getViewRange();
}

@ -0,0 +1,49 @@
package mightypork.rogue.world;
import java.io.IOException;
import mightypork.util.ion.IonBinary;
import mightypork.util.ion.IonInput;
import mightypork.util.ion.IonOutput;
public class PathStep implements IonBinary {
public static final int ION_MARK = 0;
public int x;
public int y;
public PathStep(int x, int y) {
this.x = x < 1 ? -1 : x > 0 ? 1 : 0;
this.y = y < 1 ? -1 : y > 0 ? 1 : 0;
y = (int) Math.signum(x);
}
@Override
public void load(IonInput in) throws IOException
{
x = in.readByte();
y = in.readByte();
}
@Override
public void save(IonOutput out) throws IOException
{
out.writeByte(x);
out.writeByte(y);
}
@Override
public short getIonMark()
{
return ION_MARK;
}
}

@ -1,140 +0,0 @@
package mightypork.rogue.world;
import java.io.IOException;
import mightypork.util.ion.IonBinary;
import mightypork.util.ion.IonBundle;
import mightypork.util.ion.IonInput;
import mightypork.util.ion.IonOutput;
/**
* Player info
*
* @author MightyPork
*/
public class Player implements IonBinary, MapObserver {
public static final short ION_MARK = 0;
private final double walktime = 0.3; // possibly make changeable for speed potion
private final WorldPos position = new WorldPos();
private final WorldPos target = new WorldPos();
private Runnable moveListenerCustom;
private Runnable moveListener = new Runnable() {
@Override
public void run()
{
if (moveListenerCustom != null) moveListenerCustom.run();
if (!target.equals(position)) {
int x = (target.x - position.x);
int y = (target.y - position.y);
if (Math.abs(x) >= Math.abs(y)) y = 0;
if (Math.abs(y) > Math.abs(x)) x = 0;
if (x > 0) x = 1;
if (x < 0) x = -1;
if (y > 0) y = 1;
if (y < 0) y = -1;
position.walk(x, y, walktime);
}
}
};
public Player()
{
position.setMoveListener(moveListener);
}
public Player(int x, int y, int floor)
{
position.setTo(x, y, floor);
target.setTo(position);
}
public Player(WorldPos pos)
{
this(pos.x, pos.y, pos.floor);
}
@Override
public void load(IonInput in) throws IOException
{
IonBundle ib = in.readBundle();
ib.loadBundled("pos", position);
}
@Override
public void save(IonOutput out) throws IOException
{
IonBundle ib = new IonBundle();
ib.putBundled("target", target);
out.writeBundle(ib);
}
@Override
public short getIonMark()
{
return ION_MARK;
}
@Override
public WorldPos getPosition()
{
return position;
}
@Override
public int getViewRange()
{
return 15;
}
public void teleport(WorldPos pos)
{
position.setTo(pos);
target.setTo(pos);
}
public void walk(int offsetX, int offsetY)
{
target.setTo(position.x + offsetX, position.y + offsetY, this.position.floor);
}
public void setMoveListener(Runnable r)
{
this.moveListenerCustom = r;
}
public void updateVisual(double delta)
{
position.update(delta);
}
public void updateLogic(double delta)
{
// server stuffs (sleep timer etc)
}
}

@ -0,0 +1,83 @@
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();
}
}

@ -12,24 +12,28 @@ import mightypork.util.ion.IonBundled;
/** /**
* World server. To a server, all players and levels are equal. * World on a server. To a server, all players and levels are equal.
* *
* @author MightyPork * @author MightyPork
*/ */
public class WorldServer implements IonBundled, Updateable { public class ServerWorld implements IonBundled, Updateable, WorldAccess {
private final ArrayList<Level> levels = new ArrayList<>(); private final ArrayList<Level> levels = new ArrayList<>();
private final Map<String, Player> players = new HashMap<>(); private final Map<String, PlayerEntity> players = new HashMap<>();
/** This seed can be used to re-create identical world. */ /** This seed can be used to re-create identical world. */
private long seed; private long seed;
/** Next spawned entity ID */
private long eid;
@Override @Override
public void load(IonBundle in) throws IOException public void load(IonBundle in) throws IOException
{ {
seed = in.get("seed", 0L); seed = in.get("seed", 0L);
eid = in.get("eid", 0L);
in.loadSequence("levels", levels); in.loadSequence("levels", levels);
in.loadMap("players", players); in.loadMap("players", players);
} }
@ -39,6 +43,7 @@ public class WorldServer implements IonBundled, Updateable {
public void save(IonBundle out) throws IOException public void save(IonBundle out) throws IOException
{ {
out.put("seed", seed); out.put("seed", seed);
out.put("eid", eid);
out.putSequence("levels", levels); out.putSequence("levels", levels);
out.putMap("players", players); out.putMap("players", players);
} }
@ -49,7 +54,7 @@ public class WorldServer implements IonBundled, Updateable {
levels.add(level); levels.add(level);
} }
public void addPlayer(String name, Player player) public void addPlayer(String name, PlayerEntity player)
{ {
players.put(name, player); players.put(name, player);
} }
@ -63,16 +68,16 @@ public class WorldServer implements IonBundled, Updateable {
public void update(double delta) public void update(double delta)
{ {
// food meters and such // food meters and such
for (final Player pl : players.values()) { for (final PlayerEntity pl : players.values()) {
pl.updateLogic(delta); if(pl.isConnected()) pl.updateLogic(this, delta);
} }
for (int level = 0; level < levels.size(); level++) { for (int level = 0; level < levels.size(); level++) {
// more than 1 player can be on floor, update for all of them // more than 1 player can be on floor, update for all of them
for (final Player pl : players.values()) { for (final PlayerEntity pl : players.values()) {
if (pl.getPosition().floor == level) { if (pl.getPosition().floor == level) {
levels.get(level).updateLogic(pl, delta); levels.get(level).updateLogic(this, pl, delta);
} }
} }
@ -90,4 +95,16 @@ public class WorldServer implements IonBundled, Updateable {
{ {
return seed; return seed;
} }
public long genEid()
{
return eid++;
}
@Override
public boolean isServer()
{
return true;
}
} }

@ -3,4 +3,6 @@ package mightypork.rogue.world;
public interface WorldAccess { public interface WorldAccess {
public boolean isServer();
} }

@ -1,10 +1,143 @@
package mightypork.rogue.world; package mightypork.rogue.world;
import mightypork.util.constraints.vect.Vect; import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;
import mightypork.util.ion.IonBundle;
import mightypork.util.ion.IonBundled;
public interface WorldEntity {
WorldPos getPosition(); 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.genEid();
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;
}
} }

@ -20,11 +20,9 @@ public class WorldPos implements IonBundled, Updateable {
public int x, y, floor; public int x, y, floor;
private final VectAnimated walkOffset = new VectAnimated(Vect.ZERO, Easing.LINEAR); private final VectAnimated walkOffset = new VectAnimated(Vect.ZERO, Easing.LINEAR);
private Runnable moveListener;
public WorldPos(int x, int y, int floor) public WorldPos(int x, int y, int floor) {
{
super(); super();
this.x = x; this.x = x;
this.y = y; this.y = y;
@ -32,8 +30,13 @@ public class WorldPos implements IonBundled, Updateable {
} }
public WorldPos() public WorldPos() {
}
public double getProgress()
{ {
return walkOffset.getProgress();
} }
@ -74,13 +77,13 @@ public class WorldPos implements IonBundled, Updateable {
} }
public double getXVisual() public double getVisualX()
{ {
return x + walkOffset.x(); return x + walkOffset.x();
} }
public double getYVisual() public double getVisualY()
{ {
return y + walkOffset.y(); return y + walkOffset.y();
} }
@ -135,12 +138,6 @@ public class WorldPos implements IonBundled, Updateable {
} }
public void add(int x, int y)
{
setTo(this.x + x, this.y + y);
}
public void walk(int x, int y, double secs) public void walk(int x, int y, double secs)
{ {
setTo(this.x + x, this.y + y); setTo(this.x + x, this.y + y);
@ -152,17 +149,13 @@ public class WorldPos implements IonBundled, Updateable {
@Override @Override
public void update(double delta) public void update(double delta)
{ {
if (!walkOffset.isFinished()) {
walkOffset.update(delta); walkOffset.update(delta);
} }
if (walkOffset.isFinished()) moveListener.run();
}
public void setMoveListener(Runnable listener) public boolean isFinished()
{ {
this.moveListener = listener; return walkOffset.isFinished();
} }
} }

@ -2,9 +2,12 @@ package mightypork.rogue.world.map;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import mightypork.rogue.world.MapObserver; import mightypork.rogue.world.PlayerEntity;
import mightypork.rogue.world.Player; import mightypork.rogue.world.WorldAccess;
import mightypork.rogue.world.WorldEntity;
import mightypork.rogue.world.WorldPos; import mightypork.rogue.world.WorldPos;
import mightypork.rogue.world.tile.Tile; import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.TileModel; import mightypork.rogue.world.tile.TileModel;
@ -30,19 +33,19 @@ public class Level implements MapAccess, IonBinary {
/** Array of tiles [y][x] */ /** Array of tiles [y][x] */
private Tile[][] tiles; private Tile[][] tiles;
private final List<WorldEntity> entities = new ArrayList<>();
/** Level seed (used for generation and tile variation) */ /** Level seed (used for generation and tile variation) */
public long seed; public long seed;
private transient NoiseGen noiseGen; private transient NoiseGen noiseGen;
public Level() public Level() {
{
} }
public Level(int width, int height) public Level(int width, int height) {
{
this.width = width; this.width = width;
this.height = height; this.height = height;
buildArray(); buildArray();
@ -136,6 +139,8 @@ public class Level implements MapAccess, IonBinary {
width = ib.get("w", 0); width = ib.get("w", 0);
height = ib.get("h", 0); height = ib.get("h", 0);
ib.loadSequence("entities", entities);
// init array of size // init array of size
buildArray(); buildArray();
@ -159,6 +164,7 @@ public class Level implements MapAccess, IonBinary {
ib.put("seed", seed); ib.put("seed", seed);
ib.put("w", width); ib.put("w", width);
ib.put("h", height); ib.put("h", height);
ib.putSequence("entities", entities);
out.writeBundle(ib); out.writeBundle(ib);
// tiles (writing this way to save space) // tiles (writing this way to save space)
@ -178,25 +184,25 @@ public class Level implements MapAccess, IonBinary {
} }
public void updateLogic(MapObserver observer, double delta) public void updateLogic(WorldAccess world, MapObserver observer, double delta)
{ {
updateForObserver(observer, delta, true, false); updateForObserver(world, observer, delta, true, false);
} }
public void updateVisual(Player player, double delta) public void updateVisual(WorldAccess world, PlayerEntity player, double delta)
{ {
updateForObserver(player, delta, false, true); updateForObserver(world, player, delta, false, true);
} }
private void updateForObserver(MapObserver observer, double delta, boolean logic, boolean visual) private void updateForObserver(WorldAccess world, MapObserver observer, double delta, boolean logic, boolean visual)
{ {
final int viewRange = observer.getViewRange(); final int viewRange = observer.getViewRange();
final WorldPos position = observer.getPosition(); final WorldPos eyepos = observer.getViewPosition();
int x1 = position.x - viewRange; int x1 = eyepos.x - viewRange;
int y1 = position.y - viewRange; int y1 = eyepos.y - viewRange;
int x2 = x1 + viewRange * 2; int x2 = x1 + viewRange * 2;
int y2 = y1 + viewRange * 2; int y2 = y1 + viewRange * 2;
@ -208,8 +214,8 @@ public class Level implements MapAccess, IonBinary {
for (int y = y1; y <= y2; y++) { for (int y = y1; y <= y2; y++) {
for (int x = x1; x <= x2; x++) { for (int x = x1; x <= x2; x++) {
if (logic) getTile(x, y).updateLogic(delta); if (logic) getTile(x, y).updateLogic(world, delta);
if (visual) getTile(x, y).updateVisual(delta); if (visual) getTile(x, y).updateVisual(world, delta);
} }
} }
} }

@ -0,0 +1,13 @@
package mightypork.rogue.world.map;
import mightypork.rogue.world.WorldPos;
public interface MapObserver {
int getViewRange();
WorldPos getViewPosition();
}

@ -4,10 +4,10 @@ package mightypork.rogue.world.tile;
import java.io.IOException; import java.io.IOException;
import java.util.Stack; import java.util.Stack;
import mightypork.rogue.world.WorldAccess;
import mightypork.rogue.world.item.Item; import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.map.TileRenderContext; import mightypork.rogue.world.map.TileRenderContext;
import mightypork.util.control.timing.Animator; import mightypork.util.control.timing.Animator;
import mightypork.util.control.timing.Updateable;
import mightypork.util.ion.IonBinary; import mightypork.util.ion.IonBinary;
import mightypork.util.ion.IonBundle; import mightypork.util.ion.IonBundle;
import mightypork.util.ion.IonInput; import mightypork.util.ion.IonInput;
@ -99,14 +99,14 @@ public final class Tile implements IonBinary {
} }
public void updateLogic(double delta) public void updateLogic(WorldAccess world, double delta)
{ {
model.updateLogic(this, delta); model.updateLogic(this, world, delta);
} }
public void updateVisual(double delta) public void updateVisual(WorldAccess world, double delta)
{ {
model.updateVisual(this, delta); model.updateVisual(this, world, delta);
if (hasItems()) { if (hasItems()) {
getItemRenderer().updateVisual(delta); getItemRenderer().updateVisual(delta);
} }

@ -1,6 +1,7 @@
package mightypork.rogue.world.tile; package mightypork.rogue.world.tile;
import mightypork.rogue.world.WorldAccess;
import mightypork.rogue.world.map.TileRenderContext; import mightypork.rogue.world.map.TileRenderContext;
import mightypork.util.annotations.DefaultImpl; import mightypork.util.annotations.DefaultImpl;
import mightypork.util.ion.IonBundle; import mightypork.util.ion.IonBundle;
@ -17,8 +18,7 @@ public abstract class TileModel {
public final int id; public final int id;
public TileModel(int id) public TileModel(int id) {
{
Tiles.register(id, this); Tiles.register(id, this);
this.id = id; this.id = id;
} }
@ -73,18 +73,20 @@ public abstract class TileModel {
* Update tile state etc * Update tile state etc
* *
* @param tile tile * @param tile tile
* @param world
* @param delta delta time * @param delta delta time
*/ */
public abstract void updateLogic(Tile tile, double delta); public abstract void updateLogic(Tile tile, WorldAccess world, double delta);
/** /**
* Update tile effects * Update tile effects
* *
* @param tile tile * @param tile tile
* @param world
* @param delta delta time * @param delta delta time
*/ */
public abstract void updateVisual(Tile tile, double delta); public abstract void updateVisual(Tile tile, WorldAccess world, double delta);
/** /**

Loading…
Cancel
Save