shape
This commit is contained in:
@@ -57,6 +57,7 @@ public class RegionCmd extends AbstractDevCmd {
|
|||||||
output += "Region Height: " + region.lerpY(((AbstractCharacter)target).loc) + newline;
|
output += "Region Height: " + region.lerpY(((AbstractCharacter)target).loc) + newline;
|
||||||
output += "is Stairs: " + region.isStairs() + newline;
|
output += "is Stairs: " + region.isStairs() + newline;
|
||||||
output += "is Outside: " + region.isOutside() + newline;
|
output += "is Outside: " + region.isOutside() + newline;
|
||||||
|
output += "is Entrance: " + region.isExit() + newline;
|
||||||
for(Vector3f point : region.regionPoints)
|
for(Vector3f point : region.regionPoints)
|
||||||
output += point + newline;
|
output += point + newline;
|
||||||
output += "NavMesh Data" + newline;
|
output += "NavMesh Data" + newline;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import engine.jobs.UpgradeBuildingJob;
|
|||||||
import engine.math.Bounds;
|
import engine.math.Bounds;
|
||||||
import engine.math.Vector2f;
|
import engine.math.Vector2f;
|
||||||
import engine.math.Vector3fImmutable;
|
import engine.math.Vector3fImmutable;
|
||||||
|
import engine.mobileAI.utilities.PathingUtilities;
|
||||||
import engine.net.client.ClientConnection;
|
import engine.net.client.ClientConnection;
|
||||||
import engine.net.client.msg.ErrorPopupMsg;
|
import engine.net.client.msg.ErrorPopupMsg;
|
||||||
import engine.net.client.msg.ManageCityAssetsMsg;
|
import engine.net.client.msg.ManageCityAssetsMsg;
|
||||||
@@ -998,6 +999,29 @@ public enum BuildingManager {
|
|||||||
meshBound.lineTo(rotatedStart.x,rotatedStart.z);
|
meshBound.lineTo(rotatedStart.x,rotatedStart.z);
|
||||||
meshBound.closePath();
|
meshBound.closePath();
|
||||||
building.meshes.add(meshBound);
|
building.meshes.add(meshBound);
|
||||||
|
building.parentZone.navObstacles.add(meshBound);
|
||||||
|
}
|
||||||
|
//add navNodes to parent zone list
|
||||||
|
float X = building.getBounds().getHalfExtents().x;
|
||||||
|
float Y = building.getBounds().getHalfExtents().y;
|
||||||
|
ArrayList<Vector2f> cornersAndFaces = new ArrayList<>();
|
||||||
|
cornersAndFaces.add(new Vector2f(building.loc.x - X,building.loc.z - Y));
|
||||||
|
cornersAndFaces.add(new Vector2f(building.loc.x + X,building.loc.z + Y));
|
||||||
|
cornersAndFaces.add(new Vector2f(building.loc.x + X,building.loc.z - Y));
|
||||||
|
cornersAndFaces.add(new Vector2f(building.loc.x - X,building.loc.z + Y));
|
||||||
|
cornersAndFaces.add(new Vector2f(building.loc.x - X,building.loc.z));
|
||||||
|
cornersAndFaces.add(new Vector2f(building.loc.x + X,building.loc.z));
|
||||||
|
cornersAndFaces.add(new Vector2f(building.loc.x,building.loc.z - Y));
|
||||||
|
cornersAndFaces.add(new Vector2f(building.loc.x,building.loc.z + Y));
|
||||||
|
for(Vector2f point : cornersAndFaces){
|
||||||
|
if(!NavigationManager.pointIsBlocked(new Vector3fImmutable(point.x,building.loc.y,point.y))){
|
||||||
|
building.parentZone.navNodes.add(new PathingUtilities.Node(point,null,building));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//add region centers to the zones navNodes list
|
||||||
|
for(Regions region : building.getBounds().getRegions()){
|
||||||
|
building.parentZone.navNodes.add(new PathingUtilities.Node(new Vector2f(region.center.x,region.center.z),region,building));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package engine.gameManager;
|
|||||||
|
|
||||||
import engine.Enum;
|
import engine.Enum;
|
||||||
import engine.math.Vector3fImmutable;
|
import engine.math.Vector3fImmutable;
|
||||||
|
import engine.mobileAI.MobAI;
|
||||||
import engine.net.client.msg.MoveToPointMsg;
|
import engine.net.client.msg.MoveToPointMsg;
|
||||||
import engine.objects.*;
|
import engine.objects.*;
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
@@ -14,31 +15,16 @@ public class NavigationManager {
|
|||||||
private static final int stepHeight = 2;
|
private static final int stepHeight = 2;
|
||||||
|
|
||||||
public static void pathfind(AbstractCharacter character, Vector3fImmutable goal) {
|
public static void pathfind(AbstractCharacter character, Vector3fImmutable goal) {
|
||||||
|
if(!pathBlocked(character.loc,goal)){
|
||||||
|
character.destination = goal;
|
||||||
|
MobAI.directMove((Mob)character,character.combatTarget != null);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
ArrayList<Vector3fImmutable> path = getPath(character.loc, goal);//getOptimizedPath(getPath(character.loc, goal), getPath(goal, character.loc));
|
ArrayList<Vector3fImmutable> path = getPath(character.loc, goal);//getOptimizedPath(getPath(character.loc, goal), getPath(goal, character.loc));
|
||||||
if (path.isEmpty()) {
|
if (path.isEmpty()) {
|
||||||
MoveToPointMsg msg = new MoveToPointMsg();
|
MobAI.directMove((Mob)character,character.combatTarget != null);
|
||||||
|
|
||||||
msg.setSourceType(Enum.GameObjectType.Mob.ordinal());
|
|
||||||
msg.setSourceID(character.getObjectUUID());
|
|
||||||
msg.setStartCoord(character.loc);
|
|
||||||
msg.setEndCoord(goal);
|
|
||||||
Regions region = Regions.getRegionAtLocation(goal);
|
|
||||||
if (region != null) {
|
|
||||||
msg.setInBuildingFloor(region.room);
|
|
||||||
msg.setInBuilding(region.level);
|
|
||||||
msg.setStartLocType(0);
|
|
||||||
msg.setInBuildingUUID(region.parentBuildingID);
|
|
||||||
} else {
|
|
||||||
msg.setInBuildingFloor(-1);
|
|
||||||
msg.setInBuilding(-1);
|
|
||||||
msg.setStartLocType(0);
|
|
||||||
msg.setInBuildingUUID(0);
|
|
||||||
}
|
|
||||||
return; //no points to walk to
|
return; //no points to walk to
|
||||||
}
|
}
|
||||||
|
|
||||||
//character.destination = path.get(1);
|
|
||||||
character.navPath = path;
|
character.navPath = path;
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -109,30 +95,43 @@ public class NavigationManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static float getCost(Vector3fImmutable point, Vector3fImmutable start, Vector3fImmutable goal) {
|
public static float getCost(Vector3fImmutable point, Vector3fImmutable start, Vector3fImmutable goal) {
|
||||||
float gCost = start.distanceSquared(point);
|
float gCost = start.distanceSquared(point);
|
||||||
float hCost = goal.distanceSquared(point);
|
float hCost = goal.distanceSquared(point);
|
||||||
return gCost + hCost;
|
return gCost + hCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean pointIsBlocked(Vector3fImmutable point) {
|
public static boolean pathBlocked(Vector3fImmutable start, Vector3fImmutable end){
|
||||||
|
Zone zone = ZoneManager.findSmallestZone(start);
|
||||||
Building building = BuildingManager.getBuildingAtLocation(point);
|
if(zone != null) {
|
||||||
if(building != null) {
|
for (Path2D.Float obstacle : zone.navObstacles)
|
||||||
for (Path2D.Float mesh : building.meshes) {
|
if(obstacle.intersects(start.x,start.z,end.x,end.z))
|
||||||
if (mesh.contains(point.x,point.z)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
|
||||||
for (Regions region : building.getBounds().getRegions()) {
|
|
||||||
if (region.isPointInPolygon(point))
|
|
||||||
if (Math.abs(region.lerpY(point) - point.y) > stepHeight) // get the height distance between current height and target location height
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
public static boolean pointIsBlocked(Vector3fImmutable point) {
|
||||||
|
Zone zone = ZoneManager.findSmallestZone(point);
|
||||||
|
if(zone != null){
|
||||||
|
for(Path2D.Float obstacle : zone.navObstacles)
|
||||||
|
if (obstacle.contains(point.x,point.z)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Building building = BuildingManager.getBuildingAtLocation(point);
|
||||||
|
//if(building != null) {
|
||||||
|
//for (Path2D.Float mesh : building.meshes) {
|
||||||
|
//if (mesh.contains(point.x,point.z)) {
|
||||||
|
//return true;
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
//for (Regions region : building.getBounds().getRegions()) {
|
||||||
|
//if (region.isPointInPolygon(point))
|
||||||
|
//if (Math.abs(region.lerpY(point) - point.y) > stepHeight) // get the height distance between current height and target location height
|
||||||
|
//return true;
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1345,14 +1345,14 @@ public class MobAI {
|
|||||||
|
|
||||||
public static void aiMove(Mob mob, boolean isWalking, float offset) {
|
public static void aiMove(Mob mob, boolean isWalking, float offset) {
|
||||||
|
|
||||||
if(mob.navPath.isEmpty() || mob.navPath.size() == 1){
|
|
||||||
NavigationManager.pathfind(mob,mob.destination);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(mob.isMoving()) {
|
if(mob.isMoving()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(mob.navPath.isEmpty()){
|
||||||
|
NavigationManager.pathfind(mob,mob.destination);
|
||||||
|
return;
|
||||||
|
}
|
||||||
Vector3fImmutable PathPoint = mob.navPath.get(0);
|
Vector3fImmutable PathPoint = mob.navPath.get(0);
|
||||||
if(mob.loc.distanceSquared(mob.destination) > mob.loc.distanceSquared2D(mob.destination)) {
|
if(mob.loc.distanceSquared(mob.destination) > mob.loc.distanceSquared2D(mob.destination)) {
|
||||||
mob.navPath.remove(0);
|
mob.navPath.remove(0);
|
||||||
@@ -1393,6 +1393,46 @@ public class MobAI {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
MovementManager.movement(msg, mob);
|
||||||
|
} catch (MsgSendException e) {
|
||||||
|
// TODO Figure out how we want to handle the msg send exception
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void directMove(Mob mob,boolean isWalking){
|
||||||
|
//update our walk/run state.
|
||||||
|
if (isWalking && !mob.isWalk()) {
|
||||||
|
mob.setWalkMode(true);
|
||||||
|
MovementManager.sendRWSSMsg(mob);
|
||||||
|
} else if (!isWalking && mob.isWalk()) {
|
||||||
|
mob.setWalkMode(false);
|
||||||
|
MovementManager.sendRWSSMsg(mob);
|
||||||
|
}
|
||||||
|
mob.endLoc = mob.destination;
|
||||||
|
|
||||||
|
MoveToPointMsg msg = new MoveToPointMsg();
|
||||||
|
|
||||||
|
msg.setSourceType(Enum.GameObjectType.Mob.ordinal());
|
||||||
|
msg.setSourceID(mob.getObjectUUID());
|
||||||
|
msg.setStartCoord(mob.loc);
|
||||||
|
msg.setEndCoord(mob.destination);
|
||||||
|
Regions region = Regions.getRegionAtLocation(mob.destination);
|
||||||
|
if(region != null){
|
||||||
|
msg.setInBuildingFloor(region.room);
|
||||||
|
msg.setInBuilding(region.level);
|
||||||
|
msg.setStartLocType(0);
|
||||||
|
msg.setInBuildingUUID(region.parentBuildingID);
|
||||||
|
} else{
|
||||||
|
msg.setInBuildingFloor(-1);
|
||||||
|
msg.setInBuilding(-1);
|
||||||
|
msg.setStartLocType(0);
|
||||||
|
msg.setInBuildingUUID(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
MovementManager.movement(msg, mob);
|
MovementManager.movement(msg, mob);
|
||||||
} catch (MsgSendException e) {
|
} catch (MsgSendException e) {
|
||||||
|
|||||||
@@ -1,80 +1,22 @@
|
|||||||
package engine.mobileAI.utilities;
|
package engine.mobileAI.utilities;
|
||||||
|
import engine.math.Vector2f;
|
||||||
|
import engine.objects.Building;
|
||||||
import engine.objects.Regions;
|
import engine.objects.Regions;
|
||||||
import java.awt.geom.Area;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class PathingUtilities {
|
public class PathingUtilities {
|
||||||
public static class Point {
|
public static class Node {
|
||||||
public int x;
|
public Vector2f location;
|
||||||
public int y;
|
public ArrayList<Node> neighbors;
|
||||||
public Point previous;
|
public Regions region;
|
||||||
|
public Building parentBuilding;
|
||||||
|
|
||||||
public Point(int x, int y, Point previous) {
|
public Node(Vector2f loc, Regions reg, Building parent){
|
||||||
this.x = x;
|
this.location = loc;
|
||||||
this.y = y;
|
this.region = reg;
|
||||||
this.previous = previous;
|
this.parentBuilding = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Point offset(int ox, int oy) { return new Point(x + ox, y + oy, this); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean IsWalkable(Area navMesh, Point point) {
|
|
||||||
if (navMesh.contains(point.x, point.y))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
Regions region = Regions.getRegionAtPoint(point);
|
|
||||||
if (region != null) {
|
|
||||||
return !(region.getHeightAtPoint(point) - point.y > 2);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ArrayList<Point> FindNeighbors(Area navMesh, Point point) {
|
|
||||||
ArrayList<Point> neighbors = new ArrayList<>();
|
|
||||||
Point up = point.offset(0, 1);
|
|
||||||
Point down = point.offset(0, -1);
|
|
||||||
Point left = point.offset(-1, 0);
|
|
||||||
Point right = point.offset(1, 0);
|
|
||||||
if (IsWalkable(navMesh, up)) neighbors.add(up);
|
|
||||||
if (IsWalkable(navMesh, down)) neighbors.add(down);
|
|
||||||
if (IsWalkable(navMesh, left)) neighbors.add(left);
|
|
||||||
if (IsWalkable(navMesh, right)) neighbors.add(right);
|
|
||||||
return neighbors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ArrayList<Point> FindPath(Area navMesh, Point start, Point end) {
|
|
||||||
boolean finished = false;
|
|
||||||
ArrayList<Point> used = new ArrayList<>();
|
|
||||||
used.add(start);
|
|
||||||
while (!finished) {
|
|
||||||
ArrayList<Point> newOpen = new ArrayList<>();
|
|
||||||
for(int i = 0; i < used.size(); ++i){
|
|
||||||
Point point = used.get(i);
|
|
||||||
for (Point neighbor : FindNeighbors(navMesh, point)) {
|
|
||||||
if (!used.contains(neighbor) && !newOpen.contains(neighbor)) {
|
|
||||||
newOpen.add(neighbor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(Point point : newOpen) {
|
|
||||||
used.add(point);
|
|
||||||
if (end.equals(point)) {
|
|
||||||
finished = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!finished && newOpen.isEmpty())
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayList<Point> path = new ArrayList<>();
|
|
||||||
Point point = used.get(used.size() - 1);
|
|
||||||
while(point.previous != null) {
|
|
||||||
path.add(0, point);
|
|
||||||
point = point.previous;
|
|
||||||
}
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -289,22 +289,6 @@ public class Regions {
|
|||||||
}
|
}
|
||||||
return region;
|
return region;
|
||||||
}
|
}
|
||||||
public static Regions getRegionAtPoint(PathingUtilities.Point point) {
|
|
||||||
Vector3fImmutable baseLoc = new Vector3fImmutable(point.x,0,point.y);
|
|
||||||
baseLoc.setY(Terrain.getWorldHeight(baseLoc));
|
|
||||||
Building building = BuildingManager.getBuildingAtLocation(baseLoc);
|
|
||||||
if(building == null)
|
|
||||||
return null;
|
|
||||||
for(Regions region : building.getBounds().getRegions())
|
|
||||||
if(region.isPointInPolygon(baseLoc))
|
|
||||||
return region;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getHeightAtPoint(PathingUtilities.Point point){
|
|
||||||
Vector3fImmutable baseLoc = new Vector3fImmutable(point.x,0,point.y);
|
|
||||||
return this.lerpY(baseLoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRoom() {
|
public int getRoom() {
|
||||||
return room;
|
return room;
|
||||||
|
|||||||
@@ -17,10 +17,12 @@ import engine.gameManager.ZoneManager;
|
|||||||
import engine.math.Bounds;
|
import engine.math.Bounds;
|
||||||
import engine.math.Vector2f;
|
import engine.math.Vector2f;
|
||||||
import engine.math.Vector3fImmutable;
|
import engine.math.Vector3fImmutable;
|
||||||
|
import engine.mobileAI.utilities.PathingUtilities;
|
||||||
import engine.net.ByteBufferWriter;
|
import engine.net.ByteBufferWriter;
|
||||||
import engine.server.MBServerStatics;
|
import engine.server.MBServerStatics;
|
||||||
import org.pmw.tinylog.Logger;
|
import org.pmw.tinylog.Logger;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.awt.geom.Path2D;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -65,8 +67,8 @@ public class Zone extends AbstractWorldObject {
|
|||||||
public float sea_level;
|
public float sea_level;
|
||||||
|
|
||||||
public Terrain terrain = null;
|
public Terrain terrain = null;
|
||||||
|
public ArrayList<Path2D.Float> navObstacles = new ArrayList<>();
|
||||||
public Area navMesh;
|
public ArrayList<PathingUtilities.Node> navNodes = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ResultSet Constructor
|
* ResultSet Constructor
|
||||||
@@ -183,18 +185,6 @@ public class Zone extends AbstractWorldObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ZoneManager.populateZoneCollections(this);
|
ZoneManager.populateZoneCollections(this);
|
||||||
|
|
||||||
//this.createNavMesh();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createNavMesh(){
|
|
||||||
int xPoint = (int)(this.absX - this.bounds.getHalfExtents().x);
|
|
||||||
int zPoint = (int) (this.absZ - this.bounds.getHalfExtents().y);
|
|
||||||
int extentsX = (int) (this.bounds.getHalfExtents().x * 2);
|
|
||||||
int extentsZ = (int) (this.bounds.getHalfExtents().y * 2);
|
|
||||||
|
|
||||||
this.navMesh = new Area(new Rectangle(xPoint, zPoint, extentsX, extentsZ));
|
|
||||||
}
|
}
|
||||||
/* Method sets a default value for player cities
|
/* Method sets a default value for player cities
|
||||||
* otherwise using values derived from the loadnum
|
* otherwise using values derived from the loadnum
|
||||||
|
|||||||
Reference in New Issue
Block a user