mirror of
https://github.com/collinsmith/riiablo.git
synced 2025-02-21 20:18:14 +07:00
Rewrote MapRenderer, added interpolated movement, and added path finding with collision detection
Removed gdx-ai dependency and replaced GraphPath with my own implementation Refactored Entity.updatePath to Entity.setPath Removed src position from path (first element is now first target) MapPather works in real-time -- improvements to be made Disabled updateTask in client to use update(float) entity method instead Added floating point position support to MapRenderer camera Rewrote MapRenderer with optimizations for 60%+ FPS improvement! Fixed numerous performance hogs and made optimizations (more to come) Fixed issue where render bounds was calculated before zoom applied Frame time on Android (GN5) down from 25ms to 10ms Frame time on PC seeing similar results (now 0.17ms from about 0.45) Implemented gdx-ai path finder for testing Repo cleanup Added support for path finding metrics for debugging purposes Disabled some Entity debug messages Implemented path smoothing on generated paths Created MapGraph.MapGraphPath MapRenderer will now render path as lines between points Entity will clear path once final target reached Added angle and animation support to Entity pathing Entities will now change to run animation and set direction to target angle Implemented basic touchpad support with new movement system Replaced MapRenderer and MapViewer and removed any existing dependencies Removed code comments from older revisions MapRenderer.drawDebug changes projection matrix automatically Added debug support for path smoothing Added back networking to player movements Removed old MapPather and references Deleted Entity.move() as it's now irrelevant
This commit is contained in:
parent
46423e10f7
commit
679984b9b5
@ -3,8 +3,6 @@ package gdx.diablo.entity;
|
||||
import android.support.annotation.CallSuper;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.ai.pfa.DefaultGraphPath;
|
||||
import com.badlogic.gdx.ai.pfa.GraphPath;
|
||||
import com.badlogic.gdx.assets.AssetDescriptor;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||
@ -12,11 +10,14 @@ import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||
import com.badlogic.gdx.math.MathUtils;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
|
||||
import gdx.diablo.Diablo;
|
||||
import gdx.diablo.codec.Animation;
|
||||
@ -29,7 +30,7 @@ import gdx.diablo.graphics.PaletteIndexedColorDrawable;
|
||||
import gdx.diablo.map.DS1;
|
||||
import gdx.diablo.map.DT1.Tile;
|
||||
import gdx.diablo.map.Map;
|
||||
import gdx.diablo.map.Point2;
|
||||
import gdx.diablo.map.MapGraph;
|
||||
import gdx.diablo.widget.Label;
|
||||
|
||||
public class Entity {
|
||||
@ -40,6 +41,8 @@ public class Entity {
|
||||
private static final boolean DEBUG_DIRTY = DEBUG && true;
|
||||
private static final boolean DEBUG_ASSETS = DEBUG && true;
|
||||
private static final boolean DEBUG_STATE = DEBUG && true;
|
||||
private static final boolean DEBUG_PATH = DEBUG && !true;
|
||||
private static final boolean DEBUG_TARGET = DEBUG && true;
|
||||
|
||||
protected enum EntType {
|
||||
OBJECT("OBJECTS"),
|
||||
@ -130,7 +133,8 @@ public class Entity {
|
||||
Label label;
|
||||
String name;
|
||||
Vector3 target = new Vector3();
|
||||
GraphPath<Point2> path = new DefaultGraphPath<>();
|
||||
MapGraph.MapGraphPath path = new MapGraph.MapGraphPath();
|
||||
Iterator<MapGraph.Point2> targets = Collections.emptyIterator();
|
||||
|
||||
public static Entity create(DS1 ds1, DS1.Object obj) {
|
||||
final int type = obj.type;
|
||||
@ -224,12 +228,57 @@ public class Entity {
|
||||
return target;
|
||||
}
|
||||
|
||||
public GraphPath<Point2> path() {
|
||||
public MapGraph.MapGraphPath path() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void updatePath(Map map, Vector3 target) {
|
||||
map.path(position, target, path);
|
||||
public void setPath(Map map, Vector3 dst) {
|
||||
boolean success = map.findPath(position, dst, path);
|
||||
if (!success) return;
|
||||
if (DEBUG_PATH) Gdx.app.debug(TAG, "path=" + path);
|
||||
map.smoothPath(path);
|
||||
targets = new Array.ArrayIterator<>(path.nodes);
|
||||
targets.next(); // consume src position
|
||||
if (targets.hasNext()) {
|
||||
MapGraph.Point2 firstDst = targets.next();
|
||||
target.set(firstDst.x, firstDst.y, 0);
|
||||
} else {
|
||||
target.set(position);
|
||||
}
|
||||
|
||||
//if (DEBUG_TARGET) Gdx.app.debug(TAG, "target=" + target);
|
||||
}
|
||||
|
||||
public void update(float delta) {
|
||||
if (target.equals(Vector3.Zero)) return;
|
||||
if (position.epsilonEquals(target)) {
|
||||
if (!targets.hasNext()) {
|
||||
path.clear();
|
||||
setMode("NU");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setMode("RN");
|
||||
//float targetLen = target.len();
|
||||
float speed = 9f * 2f;
|
||||
float distance = speed * delta;
|
||||
float traveled = 0;
|
||||
while (traveled < distance) {
|
||||
float targetLen = position.dst(target);
|
||||
float part = Math.min(distance - traveled, targetLen);
|
||||
if (part == 0) break;
|
||||
position.lerp(target, part / targetLen);
|
||||
traveled += part;
|
||||
if (part == targetLen) {
|
||||
if (targets.hasNext()) {
|
||||
MapGraph.Point2 next = targets.next();
|
||||
target.set(next.x, next.y, 0);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float getAngle() {
|
||||
@ -406,24 +455,6 @@ public class Entity {
|
||||
label.draw(batch, 1);
|
||||
}
|
||||
|
||||
public boolean move() {
|
||||
int x = Direction.getOffX(angle);
|
||||
int y = Direction.getOffY(angle);
|
||||
position.add(x, y, 0);
|
||||
//if (position.epsilonEquals(target) || target.equals(Vector3.Zero)) {
|
||||
// if (path.getCount() > 0) {
|
||||
// Point2 point = path.get(0);
|
||||
// target.set(point.x, point.y, 0);
|
||||
// } else {
|
||||
// setMode("NU");
|
||||
// }
|
||||
//}
|
||||
|
||||
//position.lerp(target, 1f);
|
||||
//position.set(target);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean contains(Vector3 coords) {
|
||||
if (animation == null) return false;
|
||||
BBox box = animation.getBox();
|
||||
|
@ -296,6 +296,7 @@ public class Player extends Entity {
|
||||
setArmType(Component.SH, SH != null ? SH.base.alternateGfx : "");
|
||||
}
|
||||
|
||||
/*
|
||||
@Override
|
||||
public boolean move() {
|
||||
if (!mode.equalsIgnoreCase("WL")
|
||||
@ -306,6 +307,7 @@ public class Player extends Entity {
|
||||
|
||||
return super.move();
|
||||
}
|
||||
*/
|
||||
|
||||
private void notifySlotChanged(BodyLoc bodyLoc, Item oldItem, Item item) {
|
||||
for (SlotListener l : SLOT_LISTENERS) l.onChanged(this, bodyLoc, oldItem, item);
|
||||
|
@ -4,11 +4,14 @@ import com.google.common.base.Preconditions;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.ai.pfa.GraphPath;
|
||||
import com.badlogic.gdx.ai.pfa.SmoothableGraphPath;
|
||||
import com.badlogic.gdx.ai.pfa.indexed.IndexedAStarPathFinder;
|
||||
import com.badlogic.gdx.assets.AssetDescriptor;
|
||||
import com.badlogic.gdx.assets.AssetManager;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.math.GridPoint2;
|
||||
import com.badlogic.gdx.math.MathUtils;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.Bits;
|
||||
@ -545,13 +548,15 @@ public class Map implements Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean path(Vector3 src, Vector3 dst, GraphPath<Point2> path) {
|
||||
//return new MapGraph(this).path(src, dst);
|
||||
//return MapUtils.path(this, src, dst, new DefaultGraphPath<MapUtils.Point2>());
|
||||
//long start = System.currentTimeMillis();
|
||||
//...
|
||||
//System.out.println("time = " + (System.currentTimeMillis() - start) + "ms");
|
||||
return new MapPather(this).path(src, dst, path);
|
||||
private MapGraph mapGraph = new MapGraph(this);
|
||||
private IndexedAStarPathFinder<MapGraph.Point2> pathFinder = new IndexedAStarPathFinder<>(mapGraph, true);
|
||||
|
||||
public boolean findPath(Vector3 src, Vector3 dst, GraphPath<MapGraph.Point2> path) {
|
||||
return mapGraph.searchNodePath(pathFinder, src, dst, path);
|
||||
}
|
||||
|
||||
public void smoothPath(SmoothableGraphPath<MapGraph.Point2, Vector2> path) {
|
||||
mapGraph.smoothPath(path);
|
||||
}
|
||||
|
||||
static class Zone {
|
||||
|
301
core/src/gdx/diablo/map/MapGraph.java
Normal file
301
core/src/gdx/diablo/map/MapGraph.java
Normal file
@ -0,0 +1,301 @@
|
||||
package gdx.diablo.map;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.ai.pfa.Connection;
|
||||
import com.badlogic.gdx.ai.pfa.DefaultConnection;
|
||||
import com.badlogic.gdx.ai.pfa.DefaultGraphPath;
|
||||
import com.badlogic.gdx.ai.pfa.GraphPath;
|
||||
import com.badlogic.gdx.ai.pfa.Heuristic;
|
||||
import com.badlogic.gdx.ai.pfa.PathFinder;
|
||||
import com.badlogic.gdx.ai.pfa.PathSmoother;
|
||||
import com.badlogic.gdx.ai.pfa.SmoothableGraphPath;
|
||||
import com.badlogic.gdx.ai.pfa.indexed.IndexedAStarPathFinder;
|
||||
import com.badlogic.gdx.ai.pfa.indexed.IndexedGraph;
|
||||
import com.badlogic.gdx.ai.utils.Collision;
|
||||
import com.badlogic.gdx.ai.utils.Ray;
|
||||
import com.badlogic.gdx.ai.utils.RaycastCollisionDetector;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.IntMap;
|
||||
|
||||
public class MapGraph implements IndexedGraph<MapGraph.Point2> {
|
||||
private static final String TAG = "MapGraph";
|
||||
private static final boolean DEBUG = true;
|
||||
private static final boolean DEBUG_METRICS = DEBUG && !true;
|
||||
|
||||
Heuristic<Point2> heuristic = new EuclideanDistanceHeuristic();
|
||||
|
||||
Map map;
|
||||
IntMap<Point2> points = new IntMap<>();
|
||||
PathSmoother<Point2, Vector2> pathSmoother;
|
||||
|
||||
public MapGraph(Map map) {
|
||||
this.map = map;
|
||||
pathSmoother = new PathSmoother<>(new MapRaycastCollisionDetector(this));
|
||||
}
|
||||
|
||||
public GraphPath<Point2> path(Vector3 src, Vector3 dst, GraphPath<Point2> path) {
|
||||
Map.Zone zone = map.getZone((int) dst.x, (int) dst.y);
|
||||
if (zone != null && zone.flags((int) dst.x, (int) dst.y) != 0) {
|
||||
return path;
|
||||
}
|
||||
|
||||
int hash = Point2.hash(src);
|
||||
Point2 srcP = points.get(hash);
|
||||
if (srcP == null) {
|
||||
srcP = new Point2(src);
|
||||
points.put(hash, srcP);
|
||||
}
|
||||
hash = Point2.hash(dst);
|
||||
Point2 dstP = points.get(hash);
|
||||
if (dstP == null) {
|
||||
dstP = new Point2(dst);
|
||||
points.put(hash, dstP);
|
||||
}
|
||||
return path(srcP, dstP, path);
|
||||
}
|
||||
|
||||
public GraphPath<Point2> path(Point2 src, Point2 dst, GraphPath<Point2> path) {
|
||||
path.clear();
|
||||
new IndexedAStarPathFinder<>(this).searchNodePath(src, dst, heuristic, path);
|
||||
return path;
|
||||
}
|
||||
|
||||
public boolean searchNodePath(PathFinder<Point2> pathFinder, Vector3 src, Vector3 dst, GraphPath<Point2> path) {
|
||||
path.clear();
|
||||
if (dst == null) return false;
|
||||
Map.Zone zone = map.getZone((int) dst.x, (int) dst.y);
|
||||
if (zone != null && zone.flags((int) dst.x, (int) dst.y) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int hash = Point2.hash(src);
|
||||
Point2 srcP = points.get(hash);
|
||||
if (srcP == null) {
|
||||
srcP = new Point2(src);
|
||||
points.put(hash, srcP);
|
||||
}
|
||||
hash = Point2.hash(dst);
|
||||
Point2 dstP = points.get(hash);
|
||||
if (dstP == null) {
|
||||
dstP = new Point2(dst);
|
||||
points.put(hash, dstP);
|
||||
}
|
||||
return searchNodePath(pathFinder, srcP, dstP, path);
|
||||
}
|
||||
|
||||
public boolean searchNodePath(PathFinder<Point2> pathFinder, Point2 src, Point2 dst, GraphPath<Point2> path) {
|
||||
boolean success = pathFinder.searchNodePath(src, dst, heuristic, path);
|
||||
if (DEBUG_METRICS && pathFinder instanceof IndexedAStarPathFinder) {
|
||||
IndexedAStarPathFinder.Metrics metrics = ((IndexedAStarPathFinder) pathFinder).metrics;
|
||||
Gdx.app.debug(TAG, String.format("visitedNodes=%d, openListAdditions=%d, openListPeak=%d",
|
||||
metrics.visitedNodes, metrics.openListAdditions, metrics.openListPeak));
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
public void smoothPath(SmoothableGraphPath<Point2, Vector2> path) {
|
||||
pathSmoother.smoothPath(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndex(Point2 node) {
|
||||
return node.index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNodeCount() {
|
||||
return 2 << 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Array<Connection<Point2>> getConnections(Point2 src) {
|
||||
Array<Connection<Point2>> connections = src.connections;
|
||||
if (connections == null) {
|
||||
connections = src.connections = new Array<>(8);
|
||||
tryConnect(src, src.x - 1, src.y - 1);
|
||||
tryConnect(src, src.x - 1, src.y );
|
||||
tryConnect(src, src.x - 1, src.y + 1);
|
||||
tryConnect(src, src.x , src.y - 1);
|
||||
tryConnect(src, src.x , src.y + 1);
|
||||
tryConnect(src, src.x + 1, src.y - 1);
|
||||
tryConnect(src, src.x + 1, src.y );
|
||||
tryConnect(src, src.x + 1, src.y + 1);
|
||||
}
|
||||
|
||||
return connections;
|
||||
}
|
||||
|
||||
private void tryConnect(Point2 src, int x, int y) {
|
||||
Map.Zone zone = map.getZone(x, y);
|
||||
if (zone != null && zone.flags(x, y) == 0) {
|
||||
final int hash = Point2.hash(x, y);
|
||||
Point2 dst = points.get(hash);
|
||||
if (dst == null) {
|
||||
dst = new Point2(x, y);
|
||||
points.put(hash, dst);
|
||||
}
|
||||
src.connections.add(new Path(src, dst));
|
||||
}
|
||||
}
|
||||
|
||||
public static class Point2 {
|
||||
public int x;
|
||||
public int y;
|
||||
int index;
|
||||
Array<Connection<Point2>> connections;
|
||||
|
||||
static int indexes = 0;
|
||||
|
||||
Point2(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
index = indexes++;
|
||||
}
|
||||
|
||||
Point2(Vector3 src) {
|
||||
this((int) src.x, (int) src.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hash(x, y);
|
||||
}
|
||||
|
||||
static int hash(Vector3 src) {
|
||||
return hash((int) src.x, (int) src.y);
|
||||
}
|
||||
|
||||
static int hash(int x, int y) {
|
||||
return (x * 73856093) ^ (y * 83492791);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + x + "," + y + ")";
|
||||
}
|
||||
}
|
||||
|
||||
static class Path extends DefaultConnection<Point2> {
|
||||
static final float DIAGONAL_COST = (float)Math.sqrt(2);
|
||||
|
||||
Path(Point2 src, Point2 dst) {
|
||||
super(src, dst);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCost() {
|
||||
return fromNode.x != toNode.x && fromNode.y != toNode.y ? DIAGONAL_COST : 1;
|
||||
}
|
||||
}
|
||||
|
||||
static class ManhattanDistanceHeuristic implements Heuristic<Point2> {
|
||||
@Override
|
||||
public float estimate(Point2 src, Point2 dst) {
|
||||
return Math.abs(dst.x - src.x) + Math.abs(dst.y - src.y);
|
||||
}
|
||||
}
|
||||
|
||||
static class EuclideanDistanceHeuristic implements Heuristic<Point2> {
|
||||
@Override
|
||||
public float estimate(Point2 src, Point2 dst) {
|
||||
return Vector2.dst(src.x, src.y, dst.x, dst.y);
|
||||
}
|
||||
}
|
||||
|
||||
public static class MapGraphPath extends DefaultGraphPath<Point2> implements SmoothableGraphPath<Point2, Vector2> {
|
||||
private Vector2 tmp = new Vector2();
|
||||
|
||||
@Override
|
||||
public Vector2 getNodePosition(int index) {
|
||||
Point2 src = nodes.get(index);
|
||||
return tmp.set(src.x, src.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swapNodes(int index1, int index2) {
|
||||
nodes.set(index1, nodes.get(index2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void truncatePath(int newLength) {
|
||||
nodes.truncate(newLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return nodes.toString();
|
||||
}
|
||||
}
|
||||
|
||||
static class MapRaycastCollisionDetector implements RaycastCollisionDetector<Vector2> {
|
||||
Map map;
|
||||
MapGraph mapGraph;
|
||||
|
||||
public MapRaycastCollisionDetector(MapGraph mapGraph) {
|
||||
this.mapGraph = mapGraph;
|
||||
this.map = mapGraph.map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collides(Ray<Vector2> ray) {
|
||||
int x0 = (int) ray.start.x;
|
||||
int y0 = (int) ray.start.y;
|
||||
int x1 = (int) ray.end.x;
|
||||
int y1 = (int) ray.end.y;
|
||||
|
||||
int tmp;
|
||||
boolean steep = Math.abs(y1 - y0) > Math.abs(x1 - x0);
|
||||
if (steep) {
|
||||
// Swap x0 and y0
|
||||
tmp = x0;
|
||||
x0 = y0;
|
||||
y0 = tmp;
|
||||
// Swap x1 and y1
|
||||
tmp = x1;
|
||||
x1 = y1;
|
||||
y1 = tmp;
|
||||
}
|
||||
if (x0 > x1) {
|
||||
// Swap x0 and x1
|
||||
tmp = x0;
|
||||
x0 = x1;
|
||||
x1 = tmp;
|
||||
// Swap y0 and y1
|
||||
tmp = y0;
|
||||
y0 = y1;
|
||||
y1 = tmp;
|
||||
}
|
||||
|
||||
int deltax = x1 - x0;
|
||||
int deltay = Math.abs(y1 - y0);
|
||||
int error = 0;
|
||||
int y = y0;
|
||||
int ystep = (y0 < y1 ? 1 : -1);
|
||||
for (int x = x0; x <= x1; x++) {
|
||||
// TODO: Why is this distinction needed?
|
||||
if (steep) {
|
||||
Map.Zone zone = map.getZone(y, x);
|
||||
if (zone == null || zone.flags(y, x) != 0) return true; // We've hit a wall
|
||||
} else {
|
||||
Map.Zone zone = map.getZone(x, y);
|
||||
if (zone == null || zone.flags(x, y) != 0) return true; // We've hit a wall
|
||||
}
|
||||
error += deltay;
|
||||
if (error + error >= deltax) {
|
||||
y += ystep;
|
||||
error -= deltax;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean findCollision(Collision<Vector2> outputCollision, Ray<Vector2> inputRay) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
package gdx.diablo.map;
|
||||
|
||||
import com.badlogic.gdx.ai.pfa.GraphPath;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.ObjectFloatMap;
|
||||
import com.badlogic.gdx.utils.ObjectMap;
|
||||
|
||||
public class MapPather {
|
||||
Map map;
|
||||
Heuristic heuristic = new DiagonalHeuristic();
|
||||
|
||||
public MapPather(Map map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public boolean path(Vector3 src, Vector3 dst, GraphPath<Point2> path) {
|
||||
if (src.dst(dst) > 25f) return false;
|
||||
return path(new Point2(src), new Point2(dst), path);
|
||||
}
|
||||
|
||||
public boolean path(Point2 src, Point2 dst, GraphPath<Point2> path) {
|
||||
path.clear();
|
||||
Map.Zone zone = map.getZone(dst.x, dst.y);
|
||||
if (zone == null || zone.flags(dst.x, dst.y) != 0) return false;
|
||||
|
||||
BinaryHeap<Point2> closedSet = new BinaryHeap<>();
|
||||
BinaryHeap<Point2> openSet = new BinaryHeap<>();
|
||||
openSet.add(src);
|
||||
|
||||
closedSet.contains(dst, false);
|
||||
|
||||
ObjectMap<Point2, Point2> cameFrom = new ObjectMap<>();
|
||||
|
||||
ObjectFloatMap<Point2> gScore = new ObjectFloatMap<>();
|
||||
gScore.put(src, 0);
|
||||
|
||||
ObjectFloatMap<Point2> fScore = new ObjectFloatMap<>();
|
||||
fScore.put(src, heuristic.estimate(src, dst));
|
||||
|
||||
Array<Point2> neighbors = new Array<>(8);
|
||||
|
||||
while (openSet.size > 0) {
|
||||
Point2 current = openSet.pop();
|
||||
closedSet.add(current);
|
||||
if (current.equals(dst)) {
|
||||
buildPath(current, cameFrom, path);
|
||||
return true;
|
||||
}
|
||||
|
||||
getNeighbors(current, neighbors);
|
||||
for (Point2 neighbor : neighbors) {
|
||||
if (closedSet.contains(neighbor, false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float tent_gScore = gScore.get(current, Float.POSITIVE_INFINITY) + Point2.dst(current, neighbor);
|
||||
if (!openSet.contains(neighbor, false)) {
|
||||
openSet.add(neighbor);
|
||||
} else if (tent_gScore >= gScore.get(neighbor, Float.POSITIVE_INFINITY)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cameFrom.put(neighbor, current);
|
||||
gScore.put(neighbor, tent_gScore);
|
||||
fScore.put(neighbor, gScore.get(neighbor, Float.POSITIVE_INFINITY) + heuristic.estimate(neighbor, dst));
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void buildPath(Point2 src, ObjectMap<Point2, Point2> cameFrom, GraphPath<Point2> path) {
|
||||
path.add(src);
|
||||
while (cameFrom.containsKey(src)) {
|
||||
src = cameFrom.get(src);
|
||||
path.add(src);
|
||||
}
|
||||
}
|
||||
|
||||
private void getNeighbors(Point2 src, Array<Point2> dst) {
|
||||
dst.size = 0;
|
||||
addNeighbor(src, src.x - 1, src.y - 1, dst);
|
||||
addNeighbor(src, src.x - 1, src.y , dst);
|
||||
addNeighbor(src, src.x - 1, src.y + 1, dst);
|
||||
addNeighbor(src, src.x , src.y - 1, dst);
|
||||
addNeighbor(src, src.x , src.y + 1, dst);
|
||||
addNeighbor(src, src.x + 1, src.y - 1, dst);
|
||||
addNeighbor(src, src.x + 1, src.y , dst);
|
||||
addNeighbor(src, src.x + 1, src.y + 1, dst);
|
||||
}
|
||||
|
||||
private void addNeighbor(Point2 src, int x, int y, Array<Point2> dst) {
|
||||
Map.Zone zone = map.getZone(x, y);
|
||||
if (zone == null) return;
|
||||
if (zone.flags(x, y) == 0) {
|
||||
float cost = src.getValue() + ((x != src.x && y != src.y) ? 1.414213562373095f : 1f);
|
||||
Point2 point = new Point2(x, y, cost);
|
||||
dst.add(point);
|
||||
}
|
||||
}
|
||||
|
||||
interface Heuristic {
|
||||
float estimate(Point2 src, Point2 dst);
|
||||
}
|
||||
|
||||
static class DiagonalHeuristic implements Heuristic {
|
||||
@Override
|
||||
public float estimate(Point2 src, Point2 dst) {
|
||||
int dx = Math.abs(src.x - dst.x);
|
||||
int dy = Math.abs(src.y - dst.y);
|
||||
return 1f * Math.max(dx, dy) + (1.414213562373095f-1f) * Math.min(dx, dy);
|
||||
}
|
||||
}
|
||||
|
||||
static class EuclideanHeuristic implements Heuristic {
|
||||
@Override
|
||||
public float estimate(Point2 src, Point2 dst) {
|
||||
return Point2.dst(src, dst);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
package gdx.diablo.map;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.ai.pfa.GraphPath;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
@ -9,12 +8,16 @@ import com.badlogic.gdx.graphics.g2d.GlyphLayout;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||
import com.badlogic.gdx.math.GridPoint2;
|
||||
import com.badlogic.gdx.math.MathUtils;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.Bits;
|
||||
import com.badlogic.gdx.utils.IntMap;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
|
||||
import gdx.diablo.Diablo;
|
||||
import gdx.diablo.entity.Entity;
|
||||
@ -35,7 +38,7 @@ public class MapRenderer {
|
||||
private static final boolean DEBUG_SPECIAL = DEBUG && true;
|
||||
private static final boolean DEBUG_MOUSE = DEBUG && true;
|
||||
private static final boolean DEBUG_PATHS = DEBUG && true;
|
||||
private static final boolean DEBUG_POPPADS = DEBUG && true;
|
||||
private static final boolean DEBUG_POPPADS = DEBUG && !true;
|
||||
|
||||
public static boolean RENDER_DEBUG_SUBTILE = DEBUG_SUBTILE;
|
||||
public static boolean RENDER_DEBUG_TILE = DEBUG_TILE;
|
||||
@ -51,10 +54,24 @@ public class MapRenderer {
|
||||
private static final Color RENDER_DEBUG_GRID_COLOR_3 = new Color(0x0000ff3f);
|
||||
public static int DEBUG_GRID_MODES = 3;
|
||||
|
||||
// Extra padding to ensure proper overscan, should be odd value
|
||||
private static final int TILES_PADDING_X = 3;
|
||||
private static final int TILES_PADDING_Y = 3;
|
||||
|
||||
private final Vector3 tmpVec3 = new Vector3();
|
||||
private final Vector2 tmpVec2a = new Vector2();
|
||||
private final Vector2 tmpVec2b = new Vector2();
|
||||
private final GridPoint2 tmpVec2i = new GridPoint2();
|
||||
|
||||
PaletteIndexedBatch batch;
|
||||
OrthographicCamera camera;
|
||||
Map map;
|
||||
int[] viewBuffer;
|
||||
OrthographicCamera camera;
|
||||
Map map;
|
||||
int viewBuffer[];
|
||||
//int viewBuffer2[]; // lower walls
|
||||
//int viewBuffer3[]; // upper walls
|
||||
|
||||
Entity src;
|
||||
Vector3 currentPos = new Vector3();
|
||||
|
||||
// sub-tile index in world-space
|
||||
int x, y;
|
||||
@ -84,74 +101,31 @@ public class MapRenderer {
|
||||
// tpx and tpy of startX, startY tile in world-space
|
||||
int startPx, startPy;
|
||||
|
||||
// camera bounds
|
||||
int renderMinX, renderMinY;
|
||||
int renderMaxX, renderMaxY;
|
||||
|
||||
// DT1 mainIndexes to not draw
|
||||
final Bits popped = new Bits();
|
||||
|
||||
IntMap<? extends Entity> entities;
|
||||
|
||||
public MapRenderer(PaletteIndexedBatch batch, OrthographicCamera camera) {
|
||||
this.batch = batch;
|
||||
this.camera = camera;
|
||||
public MapRenderer(PaletteIndexedBatch batch) {
|
||||
this.batch = batch;
|
||||
this.camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
|
||||
camera.setToOrtho(false, 480f * 16 / 9, 480);
|
||||
setClipPlane(-1000, 1000);
|
||||
}
|
||||
|
||||
// This adjusts clip plane
|
||||
camera.near = -1000;
|
||||
camera.far = 1000;
|
||||
// This adjusts clip plane for debugging purposes (some elements rotated to map grid)
|
||||
private void setClipPlane(float near, float far) {
|
||||
camera.near = near;
|
||||
camera.far = far;
|
||||
camera.update();
|
||||
}
|
||||
|
||||
public void setEntities(IntMap<? extends Entity> entities) {
|
||||
this.entities = entities;
|
||||
}
|
||||
|
||||
public Entity hit() {
|
||||
Vector3 coords = new Vector3();
|
||||
coords.set(Gdx.input.getX(), Gdx.input.getY(), 0);
|
||||
camera.unproject(coords);
|
||||
float adjustX = (int) coords.x;
|
||||
float adjustY = (int) coords.y - Tile.SUBTILE_HEIGHT50;
|
||||
|
||||
float selectX = ( adjustX / Tile.SUBTILE_WIDTH50 - adjustY / Tile.SUBTILE_HEIGHT50) / 2;
|
||||
float selectY = (-adjustX / Tile.SUBTILE_WIDTH50 - adjustY / Tile.SUBTILE_HEIGHT50) / 2;
|
||||
if (selectX < 0) selectX--;
|
||||
if (selectY < 0) selectY--;
|
||||
|
||||
int mx = -Tile.SUBTILE_WIDTH50 + ((int)selectX * Tile.SUBTILE_WIDTH50) - ((int)selectY * Tile.SUBTILE_WIDTH50);
|
||||
int my = -Tile.SUBTILE_HEIGHT50 - ((int)selectX * Tile.SUBTILE_HEIGHT50) - ((int)selectY * Tile.SUBTILE_HEIGHT50);
|
||||
|
||||
Map.Zone zone = map.getZone((int) selectX, (int) selectY);
|
||||
if (zone != null) {
|
||||
for (Entity entity : zone.entities) {
|
||||
entity.over = entity.contains(coords);
|
||||
/*Vector3 position = entity.position();
|
||||
float x = +(position.x * Tile.SUBTILE_WIDTH50) - (position.y * Tile.SUBTILE_WIDTH50);
|
||||
float y = -(position.x * Tile.SUBTILE_HEIGHT50) - (position.y * Tile.SUBTILE_HEIGHT50);
|
||||
if (x < coords.x && coords.x < x + 50
|
||||
&& y < coords.y && coords.y < y + 50) {
|
||||
entity.over = true;
|
||||
return entity;
|
||||
} else {
|
||||
entity.over = false;
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Vector3 getCursor() {
|
||||
Vector3 coords = new Vector3();
|
||||
coords.set(Gdx.input.getX(), Gdx.input.getY(), 0);
|
||||
camera.unproject(coords);
|
||||
float adjustX = (int) coords.x;
|
||||
float adjustY = (int) coords.y - Tile.SUBTILE_HEIGHT50;
|
||||
|
||||
float selectX = ( adjustX / Tile.SUBTILE_WIDTH50 - adjustY / Tile.SUBTILE_HEIGHT50) / 2;
|
||||
float selectY = (-adjustX / Tile.SUBTILE_WIDTH50 - adjustY / Tile.SUBTILE_HEIGHT50) / 2;
|
||||
if (selectX < 0) selectX--;
|
||||
if (selectY < 0) selectY--;
|
||||
coords.x = (int) selectX;
|
||||
coords.y = (int) selectY;
|
||||
return coords;
|
||||
public Map getMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
public void setMap(Map map) {
|
||||
@ -160,24 +134,95 @@ public class MapRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
public Map getMap() {
|
||||
return map;
|
||||
public Entity getSrc() {
|
||||
return src;
|
||||
}
|
||||
|
||||
public GridPoint2 toWorldSpace(int x, int y) {// So final actual commands are:
|
||||
x -= (camera.viewportWidth / 2);
|
||||
y -= (camera.viewportHeight / 2);
|
||||
x += stx;
|
||||
y += sty;
|
||||
return new GridPoint2(
|
||||
(x / Tile.SUBTILE_WIDTH50 + y / Tile.SUBTILE_HEIGHT50) / 2,
|
||||
(y / Tile.SUBTILE_HEIGHT50 - x / Tile.SUBTILE_WIDTH50 ) / 2);
|
||||
public void setSrc(Entity src) {
|
||||
if (this.src != src) {
|
||||
this.src = src;
|
||||
}
|
||||
}
|
||||
|
||||
public void setEntities(IntMap<? extends Entity> entities) {
|
||||
this.entities = entities;
|
||||
}
|
||||
|
||||
public float zoom() {
|
||||
return camera.zoom;
|
||||
}
|
||||
|
||||
public void zoom(float zoom) {
|
||||
zoom(zoom, false);
|
||||
}
|
||||
|
||||
public void zoom(float zoom, boolean resize) {
|
||||
if (camera.zoom != zoom) {
|
||||
camera.zoom = zoom;
|
||||
update(true);
|
||||
if (resize) resize();
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 project(Vector2 dst) {
|
||||
return project(dst.x, dst.y, dst);
|
||||
}
|
||||
|
||||
public Vector2 project(float x, float y, Vector2 dst) {
|
||||
dst.x = +(x * Tile.SUBTILE_WIDTH50) - (y * Tile.SUBTILE_WIDTH50);
|
||||
dst.y = -(x * Tile.SUBTILE_HEIGHT50) - (y * Tile.SUBTILE_HEIGHT50);
|
||||
return dst;
|
||||
}
|
||||
|
||||
public Vector2 unproject(Vector2 dst) {
|
||||
return unproject(dst.x, dst.y, dst);
|
||||
}
|
||||
|
||||
public Vector2 unproject(float x, float y) {
|
||||
return unproject(x, y, new Vector2());
|
||||
}
|
||||
|
||||
public Vector2 unproject(float x, float y, Vector2 dst) {
|
||||
tmpVec3.set(x, y, 0);
|
||||
camera.unproject(tmpVec3);
|
||||
return dst.set(tmpVec3.x, tmpVec3.y);
|
||||
}
|
||||
|
||||
public GridPoint2 coords() {
|
||||
return coords(new GridPoint2());
|
||||
}
|
||||
|
||||
public GridPoint2 coords(GridPoint2 dst) {
|
||||
tmpVec2a.set(Gdx.input.getX(), Gdx.input.getY());
|
||||
unproject(tmpVec2a);
|
||||
return coords(tmpVec2a.x, tmpVec2a.y, dst);
|
||||
}
|
||||
|
||||
public GridPoint2 coords(float x, float y) {
|
||||
return coords(x, y, new GridPoint2());
|
||||
}
|
||||
|
||||
public GridPoint2 coords(float x, float y, GridPoint2 dst) {
|
||||
float adjustX = (int) x;
|
||||
float adjustY = (int) y - Tile.SUBTILE_HEIGHT50;
|
||||
float selectX = ( adjustX / Tile.SUBTILE_WIDTH50 - adjustY / Tile.SUBTILE_HEIGHT50) / 2;
|
||||
float selectY = (-adjustX / Tile.SUBTILE_WIDTH50 - adjustY / Tile.SUBTILE_HEIGHT50) / 2;
|
||||
if (selectX < 0) selectX--;
|
||||
if (selectY < 0) selectY--;
|
||||
return dst.set((int) selectX, (int) selectY);
|
||||
}
|
||||
|
||||
public float angle(Vector3 src, Vector3 dst) {
|
||||
project(tmpVec2a.set(src.x, src.y));
|
||||
project(tmpVec2b.set(dst.x, dst.y));
|
||||
tmpVec2b.sub(tmpVec2a);
|
||||
return MathUtils.atan2(tmpVec2b.y, tmpVec2b.x);
|
||||
}
|
||||
|
||||
public void resize() {
|
||||
updateBounds();
|
||||
final int viewBufferLen = tilesX + tilesY - 1;
|
||||
final int viewBufferMax = tilesX * 2 - 1;
|
||||
final int viewBufferMax = tilesY * 2 - 1; // was tilesX, but seems better if bound to height
|
||||
viewBuffer = new int[viewBufferLen];
|
||||
int x, y;
|
||||
for (x = 0, y = 1; y < viewBufferMax; x++, y += 2)
|
||||
@ -188,80 +233,91 @@ public class MapRenderer {
|
||||
}
|
||||
|
||||
private void updateBounds() {
|
||||
width = (int) camera.viewportWidth;
|
||||
height = (int) camera.viewportHeight;
|
||||
width = (int) (camera.viewportWidth * camera.zoom);
|
||||
height = (int) (camera.viewportHeight * camera.zoom);
|
||||
|
||||
renderMinX = (int) camera.position.x - (width >>> 1);
|
||||
renderMinY = (int) camera.position.y - (height >>> 1);
|
||||
renderMaxX = renderMinX + width;
|
||||
renderMaxY = renderMinY + height;
|
||||
|
||||
int minTilesX = ((width + Tile.WIDTH - 1) / Tile.WIDTH);
|
||||
int minTilesY = ((height + Tile.HEIGHT - 1) / Tile.HEIGHT);
|
||||
if ((minTilesX & 1) == 1) minTilesX++;
|
||||
if ((minTilesY & 1) == 1) minTilesY++;
|
||||
tilesX = minTilesX + 3; // pad width comfortably
|
||||
tilesY = minTilesY + 7; // pad height for lower walls / upper walls
|
||||
tilesX = minTilesX + TILES_PADDING_X;
|
||||
tilesY = minTilesY + TILES_PADDING_Y;
|
||||
renderWidth = tilesX * Tile.WIDTH;
|
||||
renderHeight = tilesY * Tile.HEIGHT;
|
||||
assert (tilesX & 1) == 1 && (tilesY & 1) == 1;
|
||||
}
|
||||
|
||||
public void setPosition(GridPoint2 origin) {
|
||||
setPosition(origin.x, origin.y);
|
||||
public void update() {
|
||||
update(false);
|
||||
}
|
||||
|
||||
public void setPosition(int x, int y) {
|
||||
setPosition(x, y, false);
|
||||
}
|
||||
public void update(boolean force) {
|
||||
hitAll();
|
||||
if (src == null) return;
|
||||
Vector3 pos = src.position();
|
||||
if (pos.epsilonEquals(currentPos) && !force) return;
|
||||
currentPos.set(pos);
|
||||
this.x = (int) pos.x;
|
||||
this.y = (int) pos.y;
|
||||
spx = (x * Tile.SUBTILE_WIDTH50) - (y * Tile.SUBTILE_WIDTH50);
|
||||
spy = -(x * Tile.SUBTILE_HEIGHT50) - (y * Tile.SUBTILE_HEIGHT50);
|
||||
float spxf = (pos.x * Tile.SUBTILE_WIDTH50) - (pos.y * Tile.SUBTILE_WIDTH50);
|
||||
float spyf = -(pos.x * Tile.SUBTILE_HEIGHT50) - (pos.y * Tile.SUBTILE_HEIGHT50);
|
||||
camera.position.set(spxf, spyf, 0);
|
||||
camera.update();
|
||||
|
||||
public void setPosition(int x, int y, boolean force) {
|
||||
if (this.x != x || this.y != y || force) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
spx = (x * Tile.SUBTILE_WIDTH50) - (y * Tile.SUBTILE_WIDTH50);
|
||||
spy = -(x * Tile.SUBTILE_HEIGHT50) - (y * Tile.SUBTILE_HEIGHT50);
|
||||
camera.position.set(spx, spy, 0);
|
||||
camera.update();
|
||||
// subtile index in tile-space
|
||||
stx = x < 0
|
||||
? (x + 1) % Tile.SUBTILE_SIZE + (Tile.SUBTILE_SIZE - 1)
|
||||
: x % Tile.SUBTILE_SIZE;
|
||||
sty = y < 0
|
||||
? (y + 1) % Tile.SUBTILE_SIZE + (Tile.SUBTILE_SIZE - 1)
|
||||
: y % Tile.SUBTILE_SIZE;
|
||||
t = Tile.SUBTILE_INDEX[stx][sty];
|
||||
// subtile index in tile-space
|
||||
stx = x < 0
|
||||
? (x + 1) % Tile.SUBTILE_SIZE + (Tile.SUBTILE_SIZE - 1)
|
||||
: x % Tile.SUBTILE_SIZE;
|
||||
sty = y < 0
|
||||
? (y + 1) % Tile.SUBTILE_SIZE + (Tile.SUBTILE_SIZE - 1)
|
||||
: y % Tile.SUBTILE_SIZE;
|
||||
t = Tile.SUBTILE_INDEX[stx][sty];
|
||||
|
||||
// pixel offset of subtile in world-space
|
||||
spx = -Tile.SUBTILE_WIDTH50 + (x * Tile.SUBTILE_WIDTH50) - (y * Tile.SUBTILE_WIDTH50);
|
||||
spy = -Tile.SUBTILE_HEIGHT50 - (x * Tile.SUBTILE_HEIGHT50) - (y * Tile.SUBTILE_HEIGHT50);
|
||||
// pixel offset of subtile in world-space
|
||||
spx = -Tile.SUBTILE_WIDTH50 + (x * Tile.SUBTILE_WIDTH50) - (y * Tile.SUBTILE_WIDTH50);
|
||||
spy = -Tile.SUBTILE_HEIGHT50 - (x * Tile.SUBTILE_HEIGHT50) - (y * Tile.SUBTILE_HEIGHT50);
|
||||
|
||||
// tile index in world-space
|
||||
tx = x < 0
|
||||
? ((x + 1) / Tile.SUBTILE_SIZE) - 1
|
||||
: (x / Tile.SUBTILE_SIZE);
|
||||
ty = y < 0
|
||||
? ((y + 1) / Tile.SUBTILE_SIZE) - 1
|
||||
: (y / Tile.SUBTILE_SIZE);
|
||||
// tile index in world-space
|
||||
tx = x < 0
|
||||
? ((x + 1) / Tile.SUBTILE_SIZE) - 1
|
||||
: (x / Tile.SUBTILE_SIZE);
|
||||
ty = y < 0
|
||||
? ((y + 1) / Tile.SUBTILE_SIZE) - 1
|
||||
: (y / Tile.SUBTILE_SIZE);
|
||||
|
||||
tpx = spx - Tile.SUBTILE_OFFSET[t][0];
|
||||
tpy = spy - Tile.SUBTILE_OFFSET[t][1];
|
||||
tpx = spx - Tile.SUBTILE_OFFSET[t][0];
|
||||
tpy = spy - Tile.SUBTILE_OFFSET[t][1];
|
||||
|
||||
updateBounds();
|
||||
//updateBounds();
|
||||
renderMinX = (int) camera.position.x - (width >>> 1);
|
||||
renderMinY = (int) camera.position.y - (height >>> 1);
|
||||
renderMaxX = renderMinX + width;
|
||||
renderMaxY = renderMinY + height;
|
||||
|
||||
final int offX = tilesX >>> 1;
|
||||
final int offY = tilesY >>> 1;
|
||||
startX = tx + offX - offY;
|
||||
startY = ty - offX - offY;
|
||||
startPx = tpx + renderWidth / 2 - Tile.WIDTH50;
|
||||
startPy = tpy + renderHeight / 2 - Tile.HEIGHT50;
|
||||
final int offX = tilesX >>> 1;
|
||||
final int offY = tilesY >>> 1;
|
||||
startX = tx + offX - offY;
|
||||
startY = ty - offX - offY;
|
||||
startPx = tpx + renderWidth / 2 - Tile.WIDTH50;
|
||||
startPy = tpy + renderHeight / 2 - Tile.HEIGHT50;
|
||||
|
||||
if (DEBUG_MATH) {
|
||||
Gdx.app.debug(TAG,
|
||||
String.format("(%2d,%2d){%d,%d}[%2d,%2d](%dx%d)[%dx%d] %d,%d",
|
||||
x, y, stx, sty, tx, ty, width, height, tilesX, tilesY, spx, spy));
|
||||
}
|
||||
if (DEBUG_MATH) {
|
||||
Gdx.app.debug(TAG,
|
||||
String.format("(%2d,%2d){%d,%d}[%2d,%2d](%dx%d)[%dx%d] %d,%d",
|
||||
x, y, stx, sty, tx, ty, width, height, tilesX, tilesY, spx, spy));
|
||||
}
|
||||
|
||||
map.updatePopPads(popped, x, y, tx, ty, stx, sty);
|
||||
if (DEBUG_POPPADS) {
|
||||
String popPads = getPopPads();
|
||||
if (!popPads.isEmpty()) Gdx.app.debug(TAG, "PopPad IDs: " + popPads);
|
||||
}
|
||||
map.updatePopPads(popped, x, y, tx, ty, stx, sty);
|
||||
if (DEBUG_POPPADS) {
|
||||
String popPads = getPopPads();
|
||||
if (!popPads.isEmpty()) Gdx.app.debug(TAG, "PopPad IDs: " + popPads);
|
||||
}
|
||||
}
|
||||
|
||||
@ -278,8 +334,18 @@ public class MapRenderer {
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
// TODO: render will overscan image in y-axis to accommodate walls, should change to wall only instead of entire frame
|
||||
public void render() {
|
||||
private void hitAll() {
|
||||
coords(tmpVec2i); // also sets tmpVec3 to unprojected coords -- TODO: tmpVec3 should be passed in explicitly
|
||||
Map.Zone zone = map.getZone(tmpVec2i.x, tmpVec2i.y);
|
||||
if (zone != null) {
|
||||
for (Entity entity : zone.entities) {
|
||||
entity.over = entity.contains(tmpVec3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void draw(float delta) {
|
||||
batch.setProjectionMatrix(camera.combined);
|
||||
for (int i = 0, x, y; i < Map.MAX_LAYERS; i++) {
|
||||
int startX2 = startX;
|
||||
int startY2 = startY;
|
||||
@ -301,6 +367,9 @@ public class MapRenderer {
|
||||
Map.Tile tile = zone.get(i, tx, ty);
|
||||
switch (i) {
|
||||
case Map.FLOOR_OFFSET: case Map.FLOOR_OFFSET + 1:
|
||||
// TODO: Expand upon this idea... Good idea to limit upper/lower walls too!
|
||||
if (px > renderMaxX || py > renderMaxY) break;
|
||||
if (px + Tile.WIDTH < renderMinX || py + Tile.HEIGHT < renderMinY) break;
|
||||
//drawWalls(batch, tile, px, py, false);
|
||||
drawFloor(batch, tile, px, py);
|
||||
break;
|
||||
@ -312,6 +381,7 @@ public class MapRenderer {
|
||||
case Map.WALL_OFFSET:
|
||||
drawEntities(batch, stx, sty);
|
||||
drawObjects(batch, zone, stx, sty);
|
||||
// fall-through
|
||||
case Map.WALL_OFFSET + 1: case Map.WALL_OFFSET + 2: case Map.WALL_OFFSET + 3:
|
||||
drawWall(batch, tile, px, py);
|
||||
break;
|
||||
@ -397,16 +467,18 @@ public class MapRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
public void renderDebug(ShapeRenderer shapes) {
|
||||
public void drawDebug(ShapeRenderer shapes) {
|
||||
batch.setProjectionMatrix(camera.combined);
|
||||
shapes.setProjectionMatrix(camera.combined);
|
||||
if (RENDER_DEBUG_GRID > 0)
|
||||
renderDebugGrid(shapes);
|
||||
drawDebugGrid(shapes);
|
||||
|
||||
if (RENDER_DEBUG_WALKABLE > 0)
|
||||
renderDebugWalkable(shapes);
|
||||
drawDebugWalkable(shapes);
|
||||
|
||||
if (RENDER_DEBUG_SPECIAL) {
|
||||
renderDebugSpecial(shapes);
|
||||
}
|
||||
|
||||
if (RENDER_DEBUG_SPECIAL)
|
||||
drawDebugSpecial(shapes);
|
||||
|
||||
if (RENDER_DEBUG_TILE) {
|
||||
shapes.setColor(Color.OLIVE);
|
||||
@ -418,200 +490,48 @@ public class MapRenderer {
|
||||
drawDiamond(shapes, spx, spy, Tile.SUBTILE_WIDTH, Tile.SUBTILE_HEIGHT);
|
||||
}
|
||||
|
||||
if (RENDER_DEBUG_PATHS) {
|
||||
renderDebugPaths(shapes);
|
||||
}
|
||||
if (RENDER_DEBUG_PATHS)
|
||||
drawDebugPaths(shapes);
|
||||
|
||||
if (RENDER_DEBUG_CAMERA) {
|
||||
float viewportWidth = width;
|
||||
float viewportHeight = height;
|
||||
shapes.setColor(Color.GREEN);
|
||||
shapes.rect(
|
||||
camera.position.x - camera.viewportWidth / 2,
|
||||
camera.position.y - camera.viewportHeight / 2,
|
||||
camera.viewportWidth + 1, camera.viewportHeight + 1);
|
||||
camera.position.x - MathUtils.ceil(viewportWidth / 2),
|
||||
camera.position.y - MathUtils.ceil(viewportHeight / 2),
|
||||
viewportWidth + 2, viewportHeight + 2);
|
||||
}
|
||||
|
||||
if (RENDER_DEBUG_OVERSCAN) {
|
||||
shapes.setColor(Color.GRAY);
|
||||
/*shapes.setColor(Color.LIGHT_GRAY);
|
||||
shapes.rect(
|
||||
tpx - renderWidth / 2 + Tile.WIDTH50,
|
||||
tpy - renderHeight / 2 + Tile.HEIGHT50 + renderHeight,
|
||||
renderWidth, 96);
|
||||
shapes.setColor(Color.GRAY);*/
|
||||
shapes.rect(
|
||||
tpx - renderWidth / 2 + Tile.WIDTH50,
|
||||
tpy - renderHeight / 2 + Tile.HEIGHT50,
|
||||
renderWidth, renderHeight);
|
||||
/*shapes.setColor(Color.DARK_GRAY);
|
||||
shapes.rect(
|
||||
tpx - renderWidth / 2 + Tile.WIDTH50,
|
||||
tpy - renderHeight / 2 + Tile.HEIGHT50 - 96,
|
||||
renderWidth, 96);*/
|
||||
}
|
||||
|
||||
if (DEBUG_MOUSE) {
|
||||
//int screenX = (int) camera.position.x - (int) camera.viewportWidth / 2 + Gdx.input.getX();
|
||||
//int screenY = (int) camera.position.y + (int) camera.viewportHeight / 2 - Gdx.input.getY();
|
||||
//int screenX = (int) (((int) camera.position.x - (int) camera.viewportWidth / 2 + Gdx.input.getX()) * camera.zoom);
|
||||
//int screenY = (int) (((int) camera.position.y + (int) camera.viewportHeight / 2 - Gdx.input.getY()) * camera.zoom);
|
||||
//int adjustX = screenX;
|
||||
//int adjustY = screenY - Tile.SUBTILE_HEIGHT50;
|
||||
Vector3 coords = new Vector3();
|
||||
coords.set(Gdx.input.getX(), Gdx.input.getY(), 0);
|
||||
camera.unproject(coords);
|
||||
float adjustX = (int) coords.x;
|
||||
float adjustY = (int) coords.y - Tile.SUBTILE_HEIGHT50;
|
||||
coords(tmpVec2i);
|
||||
int mx = -Tile.SUBTILE_WIDTH50 + (tmpVec2i.x * Tile.SUBTILE_WIDTH50) - (tmpVec2i.y * Tile.SUBTILE_WIDTH50);
|
||||
int my = -Tile.SUBTILE_HEIGHT50 - (tmpVec2i.x * Tile.SUBTILE_HEIGHT50) - (tmpVec2i.y * Tile.SUBTILE_HEIGHT50);
|
||||
|
||||
//shapes.setColor(Color.VIOLET);
|
||||
//shapes.line(screenX - 10, screenY, screenX + 10, screenY);
|
||||
//shapes.line(screenX, screenY - 10, screenX, screenY + 10);
|
||||
|
||||
float selectX = ( adjustX / Tile.SUBTILE_WIDTH50 - adjustY / Tile.SUBTILE_HEIGHT50) / 2;
|
||||
float selectY = (-adjustX / Tile.SUBTILE_WIDTH50 - adjustY / Tile.SUBTILE_HEIGHT50) / 2;
|
||||
if (selectX < 0) selectX--;
|
||||
if (selectY < 0) selectY--;
|
||||
|
||||
int mx = -Tile.SUBTILE_WIDTH50 + ((int)selectX * Tile.SUBTILE_WIDTH50) - ((int)selectY * Tile.SUBTILE_WIDTH50);
|
||||
int my = -Tile.SUBTILE_HEIGHT50 - ((int)selectX * Tile.SUBTILE_HEIGHT50) - ((int)selectY * Tile.SUBTILE_HEIGHT50);
|
||||
|
||||
//shapes.end();
|
||||
//batch.begin();
|
||||
//batch.setShader(null);
|
||||
//batch.setProjectionMatrix(camera.combined);
|
||||
//Diablo.fonts.consolas16.draw(batch,
|
||||
// String.format("%3.0f,%3.0f%n%3.0f,%3.0f%n%3.0f,%3.0f%n%3d,%3d",
|
||||
// coords.x, coords.y, adjustX, adjustY, selectX, selectY, mx + Tile.SUBTILE_WIDTH50, my + Tile.SUBTILE_HEIGHT50),
|
||||
// coords.x + 10, coords.y - 10);
|
||||
//batch.end();
|
||||
//batch.getProjectionMatrix().idt();
|
||||
//shapes.begin();
|
||||
shapes.setColor(Color.VIOLET);
|
||||
drawDiamond(shapes, mx, my, Tile.SUBTILE_WIDTH, Tile.SUBTILE_HEIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderDebugWalkable(ShapeRenderer shapes) {
|
||||
final int[] WALKABLE_ID = {
|
||||
20, 21, 22, 23, 24,
|
||||
15, 16, 17, 18, 19,
|
||||
10, 11, 12, 13, 14,
|
||||
5, 6, 7, 8, 9,
|
||||
0, 1, 2, 3, 4
|
||||
};
|
||||
|
||||
ShapeRenderer.ShapeType shapeType = shapes.getCurrentType();
|
||||
shapes.set(ShapeRenderer.ShapeType.Filled);
|
||||
|
||||
int startX2 = startX;
|
||||
int startY2 = startY;
|
||||
int startPx2 = startPx;
|
||||
int startPy2 = startPy;
|
||||
int x, y;
|
||||
for (y = 0; y < viewBuffer.length; y++) {
|
||||
int tx = startX2;
|
||||
int ty = startY2;
|
||||
int px = startPx2;
|
||||
int py = startPy2;
|
||||
int size = viewBuffer[y];
|
||||
for (x = 0; x < size; x++) {
|
||||
Map.Zone zone = map.getZone(tx * Tile.SUBTILE_SIZE, ty * Tile.SUBTILE_SIZE);
|
||||
if (zone != null) {
|
||||
if (RENDER_DEBUG_WALKABLE == 1) {
|
||||
for (int sty = 0, t = 0; sty < Tile.SUBTILE_SIZE; sty++) {
|
||||
for (int stx = 0; stx < Tile.SUBTILE_SIZE; stx++, t++) {
|
||||
int flags = zone.flags[zone.getLocalTX(tx) * Tile.SUBTILE_SIZE + stx][zone.getLocalTY(ty) * Tile.SUBTILE_SIZE + sty] & 0xFF;
|
||||
if (flags == 0) continue;
|
||||
renderDebugWalkableTiles(shapes, px, py, t, flags);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//Map.Tile[][] tiles = zone.tiles[RENDER_DEBUG_WALKABLE - 1];
|
||||
//if (tiles != null) {
|
||||
Map.Tile tile = zone.get(RENDER_DEBUG_WALKABLE - 2, tx, ty);
|
||||
for (int t = 0; tile != null && tile.tile != null && t < Tile.NUM_SUBTILES; t++) {
|
||||
int flags = tile.tile.flags[WALKABLE_ID[t]] & 0xFF;
|
||||
if (flags == 0) continue;
|
||||
renderDebugWalkableTiles(shapes, px, py, t, flags);
|
||||
}
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
tx++;
|
||||
px += Tile.WIDTH50;
|
||||
py -= Tile.HEIGHT50;
|
||||
}
|
||||
|
||||
startY2++;
|
||||
if (y >= tilesX - 1) {
|
||||
startX2++;
|
||||
startPy2 -= Tile.HEIGHT;
|
||||
} else {
|
||||
startX2--;
|
||||
startPx2 -= Tile.WIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
shapes.set(shapeType);
|
||||
}
|
||||
|
||||
private void renderDebugWalkableTiles(ShapeRenderer shapes, int px, int py, int t, int flags) {
|
||||
int offX = px + Tile.SUBTILE_OFFSET[t][0];
|
||||
int offY = py + Tile.SUBTILE_OFFSET[t][1];
|
||||
|
||||
shapes.setColor(Color.CORAL);
|
||||
drawDiamond(shapes, offX, offY, Tile.SUBTILE_WIDTH, Tile.SUBTILE_HEIGHT);
|
||||
|
||||
offY += Tile.SUBTILE_HEIGHT50;
|
||||
|
||||
if ((flags & Tile.FLAG_BLOCK_WALK) != 0) {
|
||||
shapes.setColor(Color.FIREBRICK);
|
||||
shapes.triangle(
|
||||
offX + 16, offY,
|
||||
offX + 16, offY + 8,
|
||||
offX + 24, offY + 4);
|
||||
}
|
||||
if ((flags & Tile.FLAG_BLOCK_LIGHT_LOS) != 0) {
|
||||
shapes.setColor(Color.FOREST);
|
||||
shapes.triangle(
|
||||
offX + 16, offY,
|
||||
offX + 32, offY,
|
||||
offX + 24, offY + 4);
|
||||
}
|
||||
if ((flags & Tile.FLAG_BLOCK_JUMP) != 0) {
|
||||
shapes.setColor(Color.ROYAL);
|
||||
shapes.triangle(
|
||||
offX + 16, offY,
|
||||
offX + 32, offY,
|
||||
offX + 24, offY - 4);
|
||||
}
|
||||
if ((flags & Tile.FLAG_BLOCK_PLAYER_WALK) != 0) {
|
||||
shapes.setColor(Color.VIOLET);
|
||||
shapes.triangle(
|
||||
offX + 16, offY,
|
||||
offX + 16, offY - 8,
|
||||
offX + 24, offY - 4);
|
||||
}
|
||||
if ((flags & Tile.FLAG_BLOCK_UNKNOWN1) != 0) {
|
||||
shapes.setColor(Color.GOLD);
|
||||
shapes.triangle(
|
||||
offX + 16, offY,
|
||||
offX + 16, offY - 8,
|
||||
offX + 8, offY - 4);
|
||||
}
|
||||
if ((flags & Tile.FLAG_BLOCK_LIGHT) != 0) {
|
||||
shapes.setColor(Color.SKY);
|
||||
shapes.triangle(
|
||||
offX, offY,
|
||||
offX + 16, offY,
|
||||
offX + 8, offY - 4);
|
||||
}
|
||||
if ((flags & Tile.FLAG_BLOCK_UNKNOWN2) != 0) {
|
||||
shapes.setColor(Color.WHITE);
|
||||
shapes.triangle(
|
||||
offX, offY,
|
||||
offX + 16, offY,
|
||||
offX + 8, offY + 4);
|
||||
}
|
||||
if ((flags & Tile.FLAG_BLOCK_UNKNOWN3) != 0) {
|
||||
shapes.setColor(Color.SLATE);
|
||||
shapes.triangle(
|
||||
offX + 16, offY,
|
||||
offX + 16, offY + 8,
|
||||
offX + 8, offY + 4);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderDebugGrid(ShapeRenderer shapes) {
|
||||
private void drawDebugGrid(ShapeRenderer shapes) {
|
||||
int x, y;
|
||||
switch (RENDER_DEBUG_GRID) {
|
||||
case 1:
|
||||
@ -747,7 +667,139 @@ public class MapRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
private void renderDebugSpecial(ShapeRenderer shapes) {
|
||||
private void drawDebugWalkable(ShapeRenderer shapes) {
|
||||
final int[] WALKABLE_ID = {
|
||||
20, 21, 22, 23, 24,
|
||||
15, 16, 17, 18, 19,
|
||||
10, 11, 12, 13, 14,
|
||||
5, 6, 7, 8, 9,
|
||||
0, 1, 2, 3, 4
|
||||
};
|
||||
|
||||
ShapeRenderer.ShapeType shapeType = shapes.getCurrentType();
|
||||
shapes.set(ShapeRenderer.ShapeType.Filled);
|
||||
|
||||
int startX2 = startX;
|
||||
int startY2 = startY;
|
||||
int startPx2 = startPx;
|
||||
int startPy2 = startPy;
|
||||
int x, y;
|
||||
for (y = 0; y < viewBuffer.length; y++) {
|
||||
int tx = startX2;
|
||||
int ty = startY2;
|
||||
int px = startPx2;
|
||||
int py = startPy2;
|
||||
int size = viewBuffer[y];
|
||||
for (x = 0; x < size; x++) {
|
||||
Map.Zone zone = map.getZone(tx * Tile.SUBTILE_SIZE, ty * Tile.SUBTILE_SIZE);
|
||||
if (zone != null) {
|
||||
if (RENDER_DEBUG_WALKABLE == 1) {
|
||||
for (int sty = 0, t = 0; sty < Tile.SUBTILE_SIZE; sty++) {
|
||||
for (int stx = 0; stx < Tile.SUBTILE_SIZE; stx++, t++) {
|
||||
int flags = zone.flags[zone.getLocalTX(tx) * Tile.SUBTILE_SIZE + stx][zone.getLocalTY(ty) * Tile.SUBTILE_SIZE + sty] & 0xFF;
|
||||
if (flags == 0) continue;
|
||||
drawDebugWalkableTiles(shapes, px, py, t, flags);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//Map.Tile[][] tiles = zone.tiles[RENDER_DEBUG_WALKABLE - 1];
|
||||
//if (tiles != null) {
|
||||
Map.Tile tile = zone.get(RENDER_DEBUG_WALKABLE - 2, tx, ty);
|
||||
for (int t = 0; tile != null && tile.tile != null && t < Tile.NUM_SUBTILES; t++) {
|
||||
int flags = tile.tile.flags[WALKABLE_ID[t]] & 0xFF;
|
||||
if (flags == 0) continue;
|
||||
drawDebugWalkableTiles(shapes, px, py, t, flags);
|
||||
}
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
tx++;
|
||||
px += Tile.WIDTH50;
|
||||
py -= Tile.HEIGHT50;
|
||||
}
|
||||
|
||||
startY2++;
|
||||
if (y >= tilesX - 1) {
|
||||
startX2++;
|
||||
startPy2 -= Tile.HEIGHT;
|
||||
} else {
|
||||
startX2--;
|
||||
startPx2 -= Tile.WIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
shapes.set(shapeType);
|
||||
}
|
||||
|
||||
private void drawDebugWalkableTiles(ShapeRenderer shapes, int px, int py, int t, int flags) {
|
||||
int offX = px + Tile.SUBTILE_OFFSET[t][0];
|
||||
int offY = py + Tile.SUBTILE_OFFSET[t][1];
|
||||
|
||||
shapes.setColor(Color.CORAL);
|
||||
drawDiamond(shapes, offX, offY, Tile.SUBTILE_WIDTH, Tile.SUBTILE_HEIGHT);
|
||||
|
||||
offY += Tile.SUBTILE_HEIGHT50;
|
||||
|
||||
if ((flags & Tile.FLAG_BLOCK_WALK) != 0) {
|
||||
shapes.setColor(Color.FIREBRICK);
|
||||
shapes.triangle(
|
||||
offX + 16, offY,
|
||||
offX + 16, offY + 8,
|
||||
offX + 24, offY + 4);
|
||||
}
|
||||
if ((flags & Tile.FLAG_BLOCK_LIGHT_LOS) != 0) {
|
||||
shapes.setColor(Color.FOREST);
|
||||
shapes.triangle(
|
||||
offX + 16, offY,
|
||||
offX + 32, offY,
|
||||
offX + 24, offY + 4);
|
||||
}
|
||||
if ((flags & Tile.FLAG_BLOCK_JUMP) != 0) {
|
||||
shapes.setColor(Color.ROYAL);
|
||||
shapes.triangle(
|
||||
offX + 16, offY,
|
||||
offX + 32, offY,
|
||||
offX + 24, offY - 4);
|
||||
}
|
||||
if ((flags & Tile.FLAG_BLOCK_PLAYER_WALK) != 0) {
|
||||
shapes.setColor(Color.VIOLET);
|
||||
shapes.triangle(
|
||||
offX + 16, offY,
|
||||
offX + 16, offY - 8,
|
||||
offX + 24, offY - 4);
|
||||
}
|
||||
if ((flags & Tile.FLAG_BLOCK_UNKNOWN1) != 0) {
|
||||
shapes.setColor(Color.GOLD);
|
||||
shapes.triangle(
|
||||
offX + 16, offY,
|
||||
offX + 16, offY - 8,
|
||||
offX + 8, offY - 4);
|
||||
}
|
||||
if ((flags & Tile.FLAG_BLOCK_LIGHT) != 0) {
|
||||
shapes.setColor(Color.SKY);
|
||||
shapes.triangle(
|
||||
offX, offY,
|
||||
offX + 16, offY,
|
||||
offX + 8, offY - 4);
|
||||
}
|
||||
if ((flags & Tile.FLAG_BLOCK_UNKNOWN2) != 0) {
|
||||
shapes.setColor(Color.WHITE);
|
||||
shapes.triangle(
|
||||
offX, offY,
|
||||
offX + 16, offY,
|
||||
offX + 8, offY + 4);
|
||||
}
|
||||
if ((flags & Tile.FLAG_BLOCK_UNKNOWN3) != 0) {
|
||||
shapes.setColor(Color.SLATE);
|
||||
shapes.triangle(
|
||||
offX + 16, offY,
|
||||
offX + 16, offY + 8,
|
||||
offX + 8, offY + 4);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawDebugSpecial(ShapeRenderer shapes) {
|
||||
for (int i = Map.WALL_OFFSET, x, y; i < Map.WALL_OFFSET + Map.MAX_WALLS; i++) {
|
||||
int startX2 = startX;
|
||||
int startY2 = startY;
|
||||
@ -831,7 +883,7 @@ public class MapRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
private void renderDebugPaths(ShapeRenderer shapes) {
|
||||
private void drawDebugPaths(ShapeRenderer shapes) {
|
||||
shapes.set(ShapeRenderer.ShapeType.Filled);
|
||||
int startX2 = startX;
|
||||
int startY2 = startY;
|
||||
@ -869,89 +921,6 @@ public class MapRenderer {
|
||||
shapes.set(ShapeRenderer.ShapeType.Line);
|
||||
}
|
||||
|
||||
public void renderDebugPath(ShapeRenderer shapes, Vector3 src, Vector3 dst) {
|
||||
shapes.setColor(Color.TAN);
|
||||
shapes.set(ShapeRenderer.ShapeType.Filled);
|
||||
if (Math.abs(dst.y - src.y) < Math.abs(dst.x - src.x)) {
|
||||
if (src.x > dst.x) {
|
||||
plotLineLow(shapes, dst, src);
|
||||
} else {
|
||||
plotLineLow(shapes, src, dst);
|
||||
}
|
||||
} else {
|
||||
if (src.y > dst.y) {
|
||||
plotLineHigh(shapes, dst, src);
|
||||
} else {
|
||||
plotLineHigh(shapes, src, dst);
|
||||
}
|
||||
}
|
||||
|
||||
shapes.set(ShapeRenderer.ShapeType.Line);
|
||||
}
|
||||
|
||||
private void plotLineLow(ShapeRenderer shapes, Vector3 src, Vector3 dst) {
|
||||
float dx = dst.x - src.x;
|
||||
float dy = dst.y - src.y;
|
||||
int yi = 1;
|
||||
if (dy < 0) {
|
||||
yi = -1;
|
||||
dy = -dy;
|
||||
}
|
||||
|
||||
float D = 2*dy - dx;
|
||||
float y = src.y;
|
||||
for (float x = src.x; x <= dst.x; x++) {
|
||||
float px = +((int) x * Tile.SUBTILE_WIDTH50) - ((int) y * Tile.SUBTILE_WIDTH50) - Tile.SUBTILE_WIDTH50;
|
||||
float py = -((int) x * Tile.SUBTILE_HEIGHT50) - ((int) y * Tile.SUBTILE_HEIGHT50) - Tile.SUBTILE_HEIGHT50;
|
||||
drawDiamondSolid(shapes, px, py, Tile.SUBTILE_WIDTH, Tile.SUBTILE_HEIGHT);
|
||||
if (D > 0) {
|
||||
y = y + yi;
|
||||
D = D - 2*dx;
|
||||
}
|
||||
|
||||
D = D + 2*dy;
|
||||
}
|
||||
}
|
||||
|
||||
private void plotLineHigh(ShapeRenderer shapes, Vector3 src, Vector3 dst) {
|
||||
float dx = dst.x - src.x;
|
||||
float dy = dst.y - src.y;
|
||||
int xi = 1;
|
||||
if (dx < 0) {
|
||||
xi = -1;
|
||||
dx = -dx;
|
||||
}
|
||||
|
||||
float D = 2*dx - dy;
|
||||
float x = src.x;
|
||||
for (float y = src.y; y <= dst.y; y++) {
|
||||
float px = +((int) x * Tile.SUBTILE_WIDTH50) - ((int) y * Tile.SUBTILE_WIDTH50) - Tile.SUBTILE_WIDTH50;
|
||||
float py = -((int) x * Tile.SUBTILE_HEIGHT50) - ((int) y * Tile.SUBTILE_HEIGHT50) - Tile.SUBTILE_HEIGHT50;
|
||||
drawDiamondSolid(shapes, px, py, Tile.SUBTILE_WIDTH, Tile.SUBTILE_HEIGHT);
|
||||
if (D > 0) {
|
||||
x = x + xi;
|
||||
D = D - 2*dy;
|
||||
}
|
||||
|
||||
D = D + 2*dx;
|
||||
}
|
||||
}
|
||||
|
||||
public void renderDebugPath2(ShapeRenderer shapes, GraphPath<Point2> path) {
|
||||
if (path == null) return;
|
||||
shapes.setColor(Color.TAN);
|
||||
shapes.set(ShapeRenderer.ShapeType.Filled);
|
||||
final int size = path.getCount();
|
||||
for (int i = 0; i < size; i++) {
|
||||
Point2 point = path.get(i);
|
||||
float px = +(point.x * Tile.SUBTILE_WIDTH50) - (point.y * Tile.SUBTILE_WIDTH50) - Tile.SUBTILE_WIDTH50;
|
||||
float py = -(point.x * Tile.SUBTILE_HEIGHT50) - (point.y * Tile.SUBTILE_HEIGHT50) - Tile.SUBTILE_HEIGHT50;
|
||||
drawDiamondSolid(shapes, px, py, Tile.SUBTILE_WIDTH, Tile.SUBTILE_HEIGHT);
|
||||
}
|
||||
|
||||
shapes.set(ShapeRenderer.ShapeType.Line);
|
||||
}
|
||||
|
||||
private static void drawDiamond(ShapeRenderer shapes, float x, float y, int width, int height) {
|
||||
int hw = width >>> 1;
|
||||
int hh = height >>> 1;
|
||||
@ -961,6 +930,27 @@ public class MapRenderer {
|
||||
shapes.line(x + hw , y , x , y + hh );
|
||||
}
|
||||
|
||||
public void drawDebugPath(ShapeRenderer shapes, MapGraph.MapGraphPath path) {
|
||||
drawDebugPath(shapes, path, Color.RED);
|
||||
}
|
||||
|
||||
public void drawDebugPath(ShapeRenderer shapes, MapGraph.MapGraphPath path, Color color) {
|
||||
if (path == null || path.getCount() < 2) return;
|
||||
shapes.setProjectionMatrix(camera.combined);
|
||||
shapes.setColor(color);
|
||||
shapes.set(ShapeRenderer.ShapeType.Line);
|
||||
Iterator<MapGraph.Point2> it = new Array.ArrayIterator<>(path.nodes);
|
||||
MapGraph.Point2 src = it.next();
|
||||
for (MapGraph.Point2 dst; it.hasNext(); src = dst) {
|
||||
dst = it.next();
|
||||
float px1 = +(src.x * Tile.SUBTILE_WIDTH50) - (src.y * Tile.SUBTILE_WIDTH50);
|
||||
float py1 = -(src.x * Tile.SUBTILE_HEIGHT50) - (src.y * Tile.SUBTILE_HEIGHT50);
|
||||
float px2 = +(dst.x * Tile.SUBTILE_WIDTH50) - (dst.y * Tile.SUBTILE_WIDTH50);
|
||||
float py2 = -(dst.x * Tile.SUBTILE_HEIGHT50) - (dst.y * Tile.SUBTILE_HEIGHT50);
|
||||
shapes.line(px1, py1, px2, py2);
|
||||
}
|
||||
}
|
||||
|
||||
private static void drawDiamondSolid(ShapeRenderer shapes, float x, float y, int width, int height) {
|
||||
int hw = width >>> 1;
|
||||
int hh = height >>> 1;
|
||||
|
@ -1,193 +0,0 @@
|
||||
package gdx.diablo.map;
|
||||
|
||||
import com.badlogic.gdx.ai.pfa.GraphPath;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
public class MapUtils {
|
||||
|
||||
private MapUtils() {}
|
||||
|
||||
public static GraphPath<Point2> path(Map map, Vector3 src, Vector3 dst, GraphPath<Point2> path) {
|
||||
Point2 srcP = new Point2(src);
|
||||
Point2 dstP = new Point2(dst);
|
||||
Array<Point2> coords = new Array<>();
|
||||
Array<Point2> children = new Array<>(8);
|
||||
coords.add(dstP);
|
||||
boolean found = false;
|
||||
do {
|
||||
for (Point2 point : coords) {
|
||||
found = expand(map, srcP, point, coords, children);
|
||||
coords.addAll(children);
|
||||
if (found) break;
|
||||
}
|
||||
} while (!found);
|
||||
|
||||
if (!found) {
|
||||
return path;
|
||||
}
|
||||
|
||||
Point2 next = null;
|
||||
Point2 last = coords.removeIndex(coords.size - 1);
|
||||
path.add(last);
|
||||
while (true) {
|
||||
for (Point2 coord : coords) {
|
||||
if (last.adjacent(coord)) {
|
||||
if (next == null || coord.cost < next.cost) {
|
||||
next = coord;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
path.add(next);
|
||||
last = next;
|
||||
next = null;
|
||||
if (dstP.x == last.x && dstP.y == last.y) break;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
private static boolean expand(Map map, Point2 dst, Point2 src, Array<Point2> coords, Array<Point2> children) {
|
||||
children.clear();
|
||||
if (check(map, dst, src, src.x - 1, src.y - 1, coords, children)) return true;
|
||||
if (check(map, dst, src, src.x - 1, src.y , coords, children)) return true;
|
||||
if (check(map, dst, src, src.x - 1, src.y + 1, coords, children)) return true;
|
||||
if (check(map, dst, src, src.x , src.y - 1, coords, children)) return true;
|
||||
if (check(map, dst, src, src.x , src.y , coords, children)) return true;
|
||||
if (check(map, dst, src, src.x , src.y + 1, coords, children)) return true;
|
||||
if (check(map, dst, src, src.x + 1, src.y - 1, coords, children)) return true;
|
||||
if (check(map, dst, src, src.x + 1, src.y , coords, children)) return true;
|
||||
if (check(map, dst, src, src.x + 1, src.y + 1, coords, children)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean check(Map map, Point2 dst, Point2 src, int x, int y, Array<Point2> coords, Array<Point2> children) {
|
||||
Map.Zone zone = map.getZone(x, y);
|
||||
if (zone != null) {
|
||||
if (zone.flags(x, y) == 0) {
|
||||
float cost = src.cost;
|
||||
cost += (x != src.x && y != src.y) ? 1.414213562373095f : 1;
|
||||
if (!contains(coords, x, y, cost)) {
|
||||
Point2 point = new Point2(x, y, cost);
|
||||
children.add(point);
|
||||
if (dst.x == x && dst.y == y) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean contains(Array<Point2> coords, int x, int y, float cost) {
|
||||
for (Point2 point : new Array.ArrayIterator<>(coords)) {
|
||||
if (point.x == x && point.y == y && point.cost <= cost) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static class Point2 {
|
||||
int x;
|
||||
int y;
|
||||
float cost;
|
||||
|
||||
Point2(int x, int y, float cost) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.cost = cost;
|
||||
}
|
||||
|
||||
Point2(Vector3 src) {
|
||||
x = (int) src.x;
|
||||
y = (int) src.y;
|
||||
}
|
||||
|
||||
boolean adjacent(Point2 other) {
|
||||
return Vector2.dst2(x, y, other.x, other.y) < 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public static Array<Vector3> path(Map map, Vector3 src, Vector3 dst) {
|
||||
ObjectSet<Vector3> open = new ObjectSet<>();
|
||||
ObjectSet<Vector3> closed = new ObjectSet<>();
|
||||
open.add(src);
|
||||
|
||||
int x, y;
|
||||
while (!open.isEmpty()) {
|
||||
Node cur = null;
|
||||
if (cur.data.equals(dst)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
x = (int) cur.data.x;
|
||||
y = (int) cur.data.y;
|
||||
|
||||
Array<Node> neighbors = getNeighbors(map, cur, x, y);
|
||||
for (Node neighbor : neighbors) {
|
||||
float score = cur.cost + neighbor.cost;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Array<Node> getNeighbors(Map map, Node n, int x, int y) {
|
||||
Array<Node> neighbors = new Array<>(8);
|
||||
addIfValid(neighbors, map, n, x - 1, y - 1);
|
||||
addIfValid(neighbors, map, n, x - 1, y );
|
||||
addIfValid(neighbors, map, n, x - 1, y + 1);
|
||||
addIfValid(neighbors, map, n, x , y - 1);
|
||||
addIfValid(neighbors, map, n, x , y );
|
||||
addIfValid(neighbors, map, n, x , y + 1);
|
||||
addIfValid(neighbors, map, n, x + 1, y - 1);
|
||||
addIfValid(neighbors, map, n, x + 1, y );
|
||||
addIfValid(neighbors, map, n, x + 1, y + 1);
|
||||
return neighbors;
|
||||
}
|
||||
|
||||
private static boolean addIfValid(Array<Node> arr, Map map, Node n, int x, int y) {
|
||||
Map.Zone zone = map.getZone(x, y);
|
||||
if (zone != null) {
|
||||
if (zone.flags(x, y) == 0) {
|
||||
Node node = new Node();
|
||||
node.prev = n;
|
||||
node.data = new Vector3(x, y, 0);
|
||||
if (x != node.data.x && y != node.data.y) {
|
||||
node.cost = 1.414213562373095f;
|
||||
} else {
|
||||
node.cost = 1;
|
||||
}
|
||||
|
||||
arr.add(node);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static class Node {
|
||||
Node prev;
|
||||
Vector3 data;
|
||||
float cost;
|
||||
float score;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) return false;
|
||||
if (obj == this) return true;
|
||||
if (!(obj instanceof Node)) return false;
|
||||
return data.equals(((Node) obj).data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return data.hashCode();
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
package gdx.diablo.map;
|
||||
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
|
||||
public class Point2 extends BinaryHeap.Node {
|
||||
public final int x;
|
||||
public final int y;
|
||||
final int hash;
|
||||
|
||||
Point2(int x, int y, float cost) {
|
||||
super(cost);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.hash = hash();
|
||||
}
|
||||
|
||||
Point2(Vector3 src) {
|
||||
this((int) src.x, (int) src.y, 0);
|
||||
}
|
||||
|
||||
private int hash() {
|
||||
return 31 * x + y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) return false;
|
||||
if (obj == this) return true;
|
||||
if (!(obj instanceof Point2)) return false;
|
||||
Point2 other = (Point2) obj;
|
||||
return x == other.x && y == other.y;
|
||||
}
|
||||
|
||||
public boolean equals(int x, int y) {
|
||||
return this.x == x && this.y == y;
|
||||
}
|
||||
|
||||
public static float dst(Point2 src, Point2 dst) {
|
||||
final float dx = dst.x - src.x;
|
||||
final float dy = dst.y - src.y;
|
||||
return (float) Math.sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
}
|
@ -8,7 +8,6 @@ import com.badlogic.gdx.InputProcessor;
|
||||
import com.badlogic.gdx.ScreenAdapter;
|
||||
import com.badlogic.gdx.assets.AssetDescriptor;
|
||||
import com.badlogic.gdx.audio.Sound;
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||
import com.badlogic.gdx.math.GridPoint2;
|
||||
@ -19,7 +18,6 @@ import com.badlogic.gdx.scenes.scene2d.Actor;
|
||||
import com.badlogic.gdx.scenes.scene2d.Stage;
|
||||
import com.badlogic.gdx.scenes.scene2d.Touchable;
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Touchpad;
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.UIUtils;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
@ -36,6 +34,8 @@ import java.io.PrintWriter;
|
||||
|
||||
import gdx.diablo.Diablo;
|
||||
import gdx.diablo.Keys;
|
||||
import gdx.diablo.entity.Direction;
|
||||
import gdx.diablo.entity.Entity;
|
||||
import gdx.diablo.entity.Player;
|
||||
import gdx.diablo.graphics.PaletteIndexedBatch;
|
||||
import gdx.diablo.graphics.PaletteIndexedColorDrawable;
|
||||
@ -62,7 +62,7 @@ import gdx.diablo.widget.TextArea;
|
||||
|
||||
public class GameScreen extends ScreenAdapter implements LoadingScreen.Loadable {
|
||||
private static final String TAG = "GameScreen";
|
||||
private static final boolean DEBUG_TOUCHPAD = true;
|
||||
private static final boolean DEBUG_TOUCHPAD = !true;
|
||||
private static final boolean DEBUG_MOBILE = true;
|
||||
|
||||
final AssetDescriptor<Sound> windowopenDescriptor = new AssetDescriptor<>("data\\global\\sfx\\cursor\\windowopen.wav", Sound.class);
|
||||
@ -87,7 +87,6 @@ public class GameScreen extends ScreenAdapter implements LoadingScreen.Loadable
|
||||
final AssetDescriptor<Map> mapDescriptor = new AssetDescriptor<>("Act 1", Map.class, MapLoader.MapParameters.of(0, 0, 0));
|
||||
Map map;
|
||||
MapRenderer mapRenderer;
|
||||
OrthographicCamera camera;
|
||||
InputProcessor inputProcessorTest;
|
||||
|
||||
public TextArea input;
|
||||
@ -216,25 +215,6 @@ public class GameScreen extends ScreenAdapter implements LoadingScreen.Loadable
|
||||
}});
|
||||
touchpad.setSize(164, 164);
|
||||
touchpad.setPosition(0, 0);
|
||||
touchpad.addListener(new ChangeListener() {
|
||||
@Override
|
||||
public void changed(ChangeEvent event, Actor actor) {
|
||||
float x = touchpad.getKnobPercentX();
|
||||
float y = touchpad.getKnobPercentY();
|
||||
if (x == 0 && y == 0) {
|
||||
player.setMode("TN");
|
||||
return;
|
||||
//} else if (-0.5f < x && x < 0.5f
|
||||
// && -0.5f < y && y < 0.5f) {
|
||||
// character.setMode("tw");
|
||||
} else {
|
||||
player.setMode("RN");
|
||||
}
|
||||
|
||||
float rad = MathUtils.atan2(y, x);
|
||||
player.setAngle(rad);
|
||||
}
|
||||
});
|
||||
stage.addActor(touchpad);
|
||||
}
|
||||
|
||||
@ -295,20 +275,19 @@ public class GameScreen extends ScreenAdapter implements LoadingScreen.Loadable
|
||||
switch (amount) {
|
||||
case -1:
|
||||
if (UIUtils.ctrl()) {
|
||||
camera.zoom = Math.max(0.50f, camera.zoom - ZOOM_AMOUNT);
|
||||
mapRenderer.zoom(Math.max(0.25f, mapRenderer.zoom() - ZOOM_AMOUNT));
|
||||
}
|
||||
|
||||
break;
|
||||
case 1:
|
||||
if (UIUtils.ctrl()) {
|
||||
camera.zoom = Math.min(5.0f, camera.zoom + ZOOM_AMOUNT);
|
||||
mapRenderer.zoom(Math.min(2.50f, mapRenderer.zoom() + ZOOM_AMOUNT));
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
camera.update();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -364,9 +343,10 @@ public class GameScreen extends ScreenAdapter implements LoadingScreen.Loadable
|
||||
case Packets.MOVETO:
|
||||
MoveTo moveTo = packet.readValue(MoveTo.class);
|
||||
Player p = entities.get(moveTo.id);
|
||||
//if (p == player) break; // Disable forced update positions for now
|
||||
if (p != null) {
|
||||
p.position().set(moveTo.x, moveTo.y, 0);
|
||||
p.setAngle(moveTo.angle);
|
||||
p.setPath(map, new Vector3(moveTo.x, moveTo.y, 0));
|
||||
//p.setAngle(moveTo.angle);
|
||||
}
|
||||
break;
|
||||
case Packets.CONNECT_RESPONSE:
|
||||
@ -382,64 +362,47 @@ public class GameScreen extends ScreenAdapter implements LoadingScreen.Loadable
|
||||
PaletteIndexedBatch b = Diablo.batch;
|
||||
b.setPalette(Diablo.palettes.act1);
|
||||
|
||||
mapRenderer.hit();
|
||||
if (Gdx.input.isButtonPressed(Input.Buttons.LEFT)) {
|
||||
// FIXME: should block click events on UI panels, bugged right now
|
||||
//Actor hit = stage.hit(Gdx.input.getX(), Gdx.input.getY(), true);
|
||||
//if (hit != null) {
|
||||
Vector3 coords = mapRenderer.getCursor();
|
||||
//player.target().set(coords);
|
||||
//player.updatePath(map, coords);
|
||||
//if (player.path().getCount() > 0) {
|
||||
// player.setMode("RN");
|
||||
//}
|
||||
//} else {
|
||||
// System.out.println(hit);
|
||||
//}
|
||||
if (DEBUG_TOUCHPAD || Gdx.app.getType() == Application.ApplicationType.Android) {
|
||||
float x = touchpad.getKnobPercentX();
|
||||
float y = touchpad.getKnobPercentY();
|
||||
if (x == 0 && y == 0) {
|
||||
player.setPath(map, null);
|
||||
} else {
|
||||
float rad = MathUtils.atan2(y, x);
|
||||
x = Direction.getOffX(rad);
|
||||
y = Direction.getOffY(rad);
|
||||
player.setPath(map, new Vector3(x, y, 0).add(player.position()));
|
||||
}
|
||||
} else {
|
||||
if (Gdx.input.isButtonPressed(Input.Buttons.LEFT)) {
|
||||
GridPoint2 coords = mapRenderer.coords();
|
||||
player.setPath(map, new Vector3(coords.x, coords.y, 0));
|
||||
}
|
||||
}
|
||||
|
||||
b.setProjectionMatrix(camera.combined);
|
||||
for (Entity entity : entities.values()) {
|
||||
entity.update(delta);
|
||||
if (!entity.position().epsilonEquals(entity.target())) {
|
||||
float angle = mapRenderer.angle(entity.position(), entity.target());
|
||||
entity.setAngle(angle);
|
||||
}
|
||||
}
|
||||
|
||||
mapRenderer.update();
|
||||
|
||||
b.begin();
|
||||
//map.draw(b, 0, 0, 30, 13, Diablo.VIRTUAL_WIDTH, Diablo.VIRTUAL_HEIGHT, 1.5f);
|
||||
mapRenderer.render();
|
||||
mapRenderer.draw(delta);
|
||||
b.end();
|
||||
|
||||
// pixel offset of subtile in world-space
|
||||
//int spx = + (character.x * Tile.SUBTILE_WIDTH50) - (character.y * Tile.SUBTILE_WIDTH50);
|
||||
//int spy = - (character.x * Tile.SUBTILE_HEIGHT50) - (character.y * Tile.SUBTILE_HEIGHT50);
|
||||
//character.draw(b, spx, spy);
|
||||
//int spx = + (player.getOrigin().x * Tile.SUBTILE_WIDTH50) - (player.getOrigin().y * Tile.SUBTILE_WIDTH50);
|
||||
//int spy = - (player.getOrigin().x * Tile.SUBTILE_HEIGHT50) - (player.getOrigin().y * Tile.SUBTILE_HEIGHT50);
|
||||
//player.draw(b, spx, spy);
|
||||
//player.draw(b);
|
||||
|
||||
Diablo.shapes.setAutoShapeType(true);
|
||||
Diablo.shapes.setProjectionMatrix(camera.combined);
|
||||
Diablo.shapes.begin(ShapeRenderer.ShapeType.Line);
|
||||
mapRenderer.renderDebug(Diablo.shapes);
|
||||
//player.drawDebug(Diablo.shapes, spx, spy);
|
||||
mapRenderer.renderDebugPath2(Diablo.shapes, player.path());
|
||||
mapRenderer.drawDebug(Diablo.shapes);
|
||||
mapRenderer.drawDebugPath(Diablo.shapes, player.path());
|
||||
player.drawDebug(Diablo.shapes);
|
||||
Diablo.shapes.end();
|
||||
|
||||
//b.setProjectionMatrix(camera.combined);
|
||||
//b.begin();
|
||||
|
||||
//for (Player p : entities.values()) {
|
||||
// p.draw(b);
|
||||
//}
|
||||
|
||||
//b.end();
|
||||
b.setProjectionMatrix(Diablo.viewport.getCamera().combined);
|
||||
|
||||
//Diablo.shapes.setAutoShapeType(true);
|
||||
//Diablo.shapes.setProjectionMatrix(camera.combined);
|
||||
//Diablo.shapes.begin(ShapeRenderer.ShapeType.Line);
|
||||
//mapRenderer.renderDebug(Diablo.shapes);
|
||||
////player.drawDebug(Diablo.shapes, spx, spy);
|
||||
//player.drawDebug(Diablo.shapes);
|
||||
//Diablo.shapes.end();
|
||||
|
||||
stage.act();
|
||||
stage.draw();
|
||||
}
|
||||
@ -450,23 +413,16 @@ public class GameScreen extends ScreenAdapter implements LoadingScreen.Loadable
|
||||
Diablo.assets.get(windowopenDescriptor).play();
|
||||
|
||||
map = Diablo.assets.get(mapDescriptor);
|
||||
// FIXME: Below causes bug with debug text in MapRenderer, setting camera to screen dims fixes, but renders far too much on mobile
|
||||
camera = new OrthographicCamera(Diablo.VIRTUAL_WIDTH, Diablo.VIRTUAL_HEIGHT);
|
||||
//camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
|
||||
mapRenderer = new MapRenderer(Diablo.batch, camera);
|
||||
mapRenderer = new MapRenderer(Diablo.batch);
|
||||
mapRenderer.setMap(map);
|
||||
mapRenderer.setSrc(player);
|
||||
mapRenderer.setEntities(entities);
|
||||
if (Gdx.app.getType() == Application.ApplicationType.Android) {
|
||||
mapRenderer.zoom(0.80f);
|
||||
}
|
||||
mapRenderer.resize();
|
||||
|
||||
GridPoint2 origin = map.find(Map.ID.TOWN_ENTRY_1);
|
||||
mapRenderer.setPosition(origin);
|
||||
if (Gdx.app.getType() == Application.ApplicationType.Android) {
|
||||
camera.zoom = 0.80f;
|
||||
camera.update();
|
||||
}
|
||||
|
||||
//character.x = origin.x;
|
||||
//character.y = origin.y;
|
||||
player.position().set(origin.x, origin.y, 0);
|
||||
|
||||
Keys.Esc.addStateListener(mappedKeyStateListener);
|
||||
@ -496,11 +452,8 @@ public class GameScreen extends ScreenAdapter implements LoadingScreen.Loadable
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (UIUtils.shift()) return;
|
||||
boolean moved = player.move();
|
||||
position.set((int) player.position().x, (int) player.position().y);
|
||||
mapRenderer.setPosition(position);
|
||||
if (!moved) return;
|
||||
Vector3 pos = player.target();
|
||||
position.set((int) pos.x, (int) pos.y);
|
||||
String moveTo = Packets.build(new MoveTo(position, player.getAngle()));
|
||||
out.println(moveTo);
|
||||
}
|
||||
|
@ -6,14 +6,11 @@ import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Input;
|
||||
import com.badlogic.gdx.InputAdapter;
|
||||
import com.badlogic.gdx.InputMultiplexer;
|
||||
import com.badlogic.gdx.ai.pfa.DefaultGraphPath;
|
||||
import com.badlogic.gdx.ai.pfa.GraphPath;
|
||||
import com.badlogic.gdx.assets.AssetManager;
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
|
||||
@ -24,6 +21,7 @@ import com.badlogic.gdx.scenes.scene2d.utils.UIUtils;
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException;
|
||||
|
||||
import gdx.diablo.COFs;
|
||||
import gdx.diablo.CharClass;
|
||||
import gdx.diablo.Colors;
|
||||
import gdx.diablo.Diablo;
|
||||
import gdx.diablo.Files;
|
||||
@ -37,6 +35,8 @@ import gdx.diablo.codec.FontTBL;
|
||||
import gdx.diablo.codec.Palette;
|
||||
import gdx.diablo.codec.TXT;
|
||||
import gdx.diablo.codec.excel.Excel;
|
||||
import gdx.diablo.entity.Entity;
|
||||
import gdx.diablo.entity.Player;
|
||||
import gdx.diablo.graphics.PaletteIndexedBatch;
|
||||
import gdx.diablo.loader.BitmapFontLoader;
|
||||
import gdx.diablo.loader.COFLoader;
|
||||
@ -54,7 +54,7 @@ public class MapViewer extends ApplicationAdapter {
|
||||
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
|
||||
config.title = "Map Builder";
|
||||
config.resizable = true;
|
||||
config.width = 1280;
|
||||
config.width = 1280; // 1280
|
||||
config.height = 720;
|
||||
config.foregroundFPS = config.backgroundFPS = 144;
|
||||
MapViewer client = new MapViewer();
|
||||
@ -68,8 +68,8 @@ public class MapViewer extends ApplicationAdapter {
|
||||
Map map;
|
||||
DS1Types DS1Types;
|
||||
|
||||
Entity ent;
|
||||
MapRenderer mapRenderer;
|
||||
OrthographicCamera camera;
|
||||
|
||||
BitmapFont font;
|
||||
|
||||
@ -77,7 +77,8 @@ public class MapViewer extends ApplicationAdapter {
|
||||
|
||||
Vector3 src;
|
||||
Vector3 dst;
|
||||
GraphPath<Point2> path = new DefaultGraphPath<>();
|
||||
MapGraph.MapGraphPath path = new MapGraph.MapGraphPath();
|
||||
MapGraph.MapGraphPath smoothedPath = new MapGraph.MapGraphPath();
|
||||
|
||||
boolean drawCrosshair;
|
||||
boolean drawGrid;
|
||||
@ -128,10 +129,7 @@ public class MapViewer extends ApplicationAdapter {
|
||||
shapes = new ShapeRenderer();
|
||||
Gdx.gl.glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
|
||||
|
||||
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
|
||||
camera.update();
|
||||
|
||||
mapRenderer = new MapRenderer(batch, camera);
|
||||
mapRenderer = new MapRenderer(batch);
|
||||
mapRenderer.resize();
|
||||
|
||||
InputMultiplexer multiplexer = new InputMultiplexer();
|
||||
@ -140,7 +138,8 @@ public class MapViewer extends ApplicationAdapter {
|
||||
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
|
||||
switch (button) {
|
||||
case Input.Buttons.LEFT:
|
||||
src = mapRenderer.getCursor();
|
||||
GridPoint2 srcCoords = mapRenderer.coords();
|
||||
src = new Vector3(srcCoords.x, srcCoords.y, 0);
|
||||
dst = null;
|
||||
break;
|
||||
case Input.Buttons.RIGHT:
|
||||
@ -153,7 +152,8 @@ public class MapViewer extends ApplicationAdapter {
|
||||
@Override
|
||||
public boolean touchDragged(int screenX, int screenY, int button) {
|
||||
if (src != null) {
|
||||
dst = mapRenderer.getCursor();
|
||||
GridPoint2 dstCoords = mapRenderer.coords();
|
||||
dst = new Vector3(dstCoords.x, dstCoords.y, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -162,18 +162,13 @@ public class MapViewer extends ApplicationAdapter {
|
||||
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
|
||||
switch (button) {
|
||||
case Input.Buttons.LEFT:
|
||||
dst = mapRenderer.getCursor();
|
||||
System.out.println("src = " + src);
|
||||
System.out.println("dst = " + dst);
|
||||
|
||||
//float srcX = +(src.x * Tile.SUBTILE_WIDTH50) - (src.y * Tile.SUBTILE_WIDTH50);
|
||||
//float srcY = -(src.x * Tile.SUBTILE_HEIGHT50) - (src.y * Tile.SUBTILE_HEIGHT50);
|
||||
//float dstX = +(dst.x * Tile.SUBTILE_WIDTH50) - (dst.y * Tile.SUBTILE_WIDTH50);
|
||||
//float dstY = -(dst.x * Tile.SUBTILE_HEIGHT50) - (dst.y * Tile.SUBTILE_HEIGHT50);
|
||||
//System.out.println(new Vector2(dstX, dstY).dst(srcX, srcY));
|
||||
System.out.println(src.dst(dst));
|
||||
|
||||
map.path(src, dst, path);
|
||||
GridPoint2 dstCoords = mapRenderer.coords();
|
||||
dst = new Vector3(dstCoords.x, dstCoords.y, 0);
|
||||
map.findPath(src, dst, path);
|
||||
smoothedPath.nodes.clear();
|
||||
smoothedPath.nodes.addAll(path.nodes);
|
||||
map.smoothPath(smoothedPath);
|
||||
System.out.println(path + "->" + smoothedPath);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
@ -186,15 +181,14 @@ public class MapViewer extends ApplicationAdapter {
|
||||
public boolean scrolled(int amount) {
|
||||
switch (amount) {
|
||||
case -1:
|
||||
camera.zoom = Math.max(0.50f, camera.zoom - ZOOM_AMOUNT);
|
||||
mapRenderer.zoom(Math.max(0.25f, mapRenderer.zoom() - ZOOM_AMOUNT));
|
||||
break;
|
||||
case 1:
|
||||
camera.zoom = Math.min(5.0f, camera.zoom + ZOOM_AMOUNT);
|
||||
mapRenderer.zoom(Math.min(2.50f, mapRenderer.zoom() + ZOOM_AMOUNT));
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
camera.update();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -213,6 +207,9 @@ public class MapViewer extends ApplicationAdapter {
|
||||
MapRenderer.RENDER_DEBUG_WALKABLE = 0;
|
||||
}
|
||||
return true;
|
||||
case Input.Keys.ALT_LEFT:
|
||||
mapRenderer.resize();
|
||||
return true;
|
||||
case Input.Keys.F1:
|
||||
drawCrosshair = !drawCrosshair;
|
||||
return true;
|
||||
@ -236,35 +233,31 @@ public class MapViewer extends ApplicationAdapter {
|
||||
return true;
|
||||
case Input.Keys.W:
|
||||
//case Input.Keys.UP:
|
||||
int amount = UIUtils.ctrl() ? 1 : DT1.Tile.SUBTILE_SIZE;
|
||||
int amount = UIUtils.ctrl() ? 1 : Tile.SUBTILE_SIZE;
|
||||
if (UIUtils.shift()) amount *= 8;
|
||||
y -= amount;
|
||||
mapRenderer.setPosition(x, y);
|
||||
//mapRenderer.runMath(x, y);
|
||||
ent.position().set(x, y, 0);
|
||||
return true;
|
||||
case Input.Keys.S:
|
||||
//case Input.Keys.DOWN:
|
||||
amount = UIUtils.ctrl() ? 1 : DT1.Tile.SUBTILE_SIZE;
|
||||
amount = UIUtils.ctrl() ? 1 : Tile.SUBTILE_SIZE;
|
||||
if (UIUtils.shift()) amount *= 8;
|
||||
y += amount;
|
||||
mapRenderer.setPosition(x, y);
|
||||
//mapRenderer.runMath(x, y);
|
||||
ent.position().set(x, y, 0);
|
||||
return true;
|
||||
case Input.Keys.A:
|
||||
//case Input.Keys.LEFT:
|
||||
amount = UIUtils.ctrl() ? 1 : DT1.Tile.SUBTILE_SIZE;
|
||||
amount = UIUtils.ctrl() ? 1 : Tile.SUBTILE_SIZE;
|
||||
if (UIUtils.shift()) amount *= 8;
|
||||
x -= amount;
|
||||
mapRenderer.setPosition(x, y);
|
||||
//mapRenderer.runMath(x, y);
|
||||
ent.position().set(x, y, 0);
|
||||
return true;
|
||||
case Input.Keys.D:
|
||||
//case Input.Keys.RIGHT:
|
||||
amount = UIUtils.ctrl() ? 1 : DT1.Tile.SUBTILE_SIZE;
|
||||
amount = UIUtils.ctrl() ? 1 : Tile.SUBTILE_SIZE;
|
||||
if (UIUtils.shift()) amount *= 8;
|
||||
x += amount;
|
||||
mapRenderer.setPosition(x, y);
|
||||
//mapRenderer.runMath(x, y);
|
||||
ent.position().set(x, y, 0);
|
||||
return true;
|
||||
case Input.Keys.UP:
|
||||
Gdx.input.setCursorPosition(Gdx.input.getX(), Gdx.input.getY() - 1);
|
||||
@ -285,7 +278,7 @@ public class MapViewer extends ApplicationAdapter {
|
||||
|
||||
@Override
|
||||
public boolean mouseMoved(int screenX, int screenY) {
|
||||
GridPoint2 pt = mapRenderer.toWorldSpace(screenX, screenY);
|
||||
//GridPoint2 pt = mapRenderer.toWorldSpace(screenX, screenY);
|
||||
//System.out.println(pt);
|
||||
return true;
|
||||
}
|
||||
@ -336,19 +329,13 @@ public class MapViewer extends ApplicationAdapter {
|
||||
|
||||
GridPoint2 origin = map.find(Map.ID.TOWN_ENTRY_1);
|
||||
if (origin != null) {
|
||||
//x = origin.x;
|
||||
//y = origin.y;
|
||||
//mapRenderer.setPosition(x, y);
|
||||
} else {
|
||||
//x += DT1.Tile.SUBTILE_CENTER.x;
|
||||
//y += DT1.Tile.SUBTILE_CENTER.y;
|
||||
//mapRenderer.setPosition(x, y);
|
||||
x = origin.x;
|
||||
y = origin.y;
|
||||
}
|
||||
|
||||
x = 0;
|
||||
y = 0;
|
||||
mapRenderer.setPosition(x, y, true);
|
||||
|
||||
ent = new Player("null", CharClass.BARBARIAN);
|
||||
ent.position().set(x, y, 0);
|
||||
mapRenderer.setSrc(ent);
|
||||
|
||||
for (String asset : Diablo.assets.getAssetNames()) {
|
||||
Gdx.app.debug(TAG, Diablo.assets.getReferenceCount(asset) + " : " + asset);
|
||||
@ -362,21 +349,19 @@ public class MapViewer extends ApplicationAdapter {
|
||||
public void render() {
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
mapRenderer.hit();
|
||||
mapRenderer.update();
|
||||
|
||||
PaletteIndexedBatch batch = Diablo.batch;
|
||||
batch.setProjectionMatrix(camera.combined);
|
||||
batch.begin(palette);
|
||||
mapRenderer.render();
|
||||
mapRenderer.draw(Gdx.graphics.getDeltaTime());
|
||||
batch.end();
|
||||
|
||||
shapes.setProjectionMatrix(camera.combined);
|
||||
shapes.setAutoShapeType(true);
|
||||
shapes.begin(ShapeRenderer.ShapeType.Line);
|
||||
mapRenderer.renderDebug(shapes);
|
||||
mapRenderer.drawDebug(shapes);
|
||||
if (src != null && dst != null) {
|
||||
//mapRenderer.renderDebugPath(shapes, src, dst);
|
||||
mapRenderer.renderDebugPath2(shapes, path);
|
||||
mapRenderer.drawDebugPath(shapes, path);
|
||||
mapRenderer.drawDebugPath(shapes, smoothedPath, Color.GREEN);
|
||||
float srcX = +(src.x * Tile.SUBTILE_WIDTH50) - (src.y * Tile.SUBTILE_WIDTH50);
|
||||
float srcY = -(src.x * Tile.SUBTILE_HEIGHT50) - (src.y * Tile.SUBTILE_HEIGHT50);
|
||||
float dstX = +(dst.x * Tile.SUBTILE_WIDTH50) - (dst.y * Tile.SUBTILE_WIDTH50);
|
||||
@ -391,6 +376,17 @@ public class MapViewer extends ApplicationAdapter {
|
||||
|
||||
final int width = Gdx.graphics.getWidth();
|
||||
final int height = Gdx.graphics.getHeight();
|
||||
|
||||
if (drawCrosshair) {
|
||||
shapes.getProjectionMatrix().setToOrtho2D(0, 0, width, height);
|
||||
shapes.updateMatrices();
|
||||
shapes.begin(ShapeRenderer.ShapeType.Line);
|
||||
shapes.setColor(Color.GREEN);
|
||||
shapes.line(0, height / 2, width, height / 2);
|
||||
shapes.line(width / 2, 0, width / 2, height);
|
||||
shapes.end();
|
||||
}
|
||||
|
||||
batch.getProjectionMatrix().setToOrtho2D(0, 0, width, height);
|
||||
batch.begin();
|
||||
batch.setShader(null);
|
||||
@ -407,16 +403,6 @@ public class MapViewer extends ApplicationAdapter {
|
||||
|
||||
batch.end();
|
||||
batch.setShader(Diablo.shader);
|
||||
|
||||
/*final int width = Gdx.graphics.getWidth();
|
||||
final int height = Gdx.graphics.getHeight();
|
||||
shapes.getProjectionMatrix().setToOrtho2D(0, 0, width, height);
|
||||
shapes.updateMatrices();
|
||||
shapes.begin(ShapeRenderer.ShapeType.Line);
|
||||
shapes.setColor(Color.GREEN);
|
||||
shapes.line(width >>> 1, 0, width >>> 1, height);
|
||||
shapes.line(0, height >>> 1, width, height >>> 1);
|
||||
shapes.end();*/
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user