I spent the past day or so improving my LoS code I posted earlier. It had some issues with how the LoS worked at the ends of hallways, but I think I've got them worked out. I don't think the way I worked around it is especially pretty (from the standpoint of how the code looks), but it should be alright as to practical concerns.
Here's a link to the jar file so anyone who wants to take a look at the LoS code in action can do so. I'd appreciate any comments and/or suggestions.
http://rapidshare.com/files/259173760/Guardian.zip.htmlEverything is very much so a WIP. There's no gameplay in there, the inventory and equipment screens are as bland as can be, and there's only one NPC who just follows ou around, but none of those things are the reason why I'm posting this.
Also, here is the updated code if anyone is interested:
public void calculateFieldOfView() {
initializeTileVisibility();
for (int tileCounterY = 0; tileCounterY < Map.getStageSizeY(); tileCounterY++) {
for (int tileCounterX = 0; tileCounterX < Map.getStageSizeX(); tileCounterX++) {
// This will cut out unnecessary tiles to save processing time.
if (tileCounterX < xLocation - lineOfSightRange) {
tileCounterX = xLocation - lineOfSightRange;
}
if (tileCounterY < yLocation - lineOfSightRange) {
tileCounterY = yLocation - lineOfSightRange;
}
if (tileCounterX > xLocation + lineOfSightRange) {
tileCounterX = Map.getStageSizeX();
}
if (tileCounterY > yLocation + lineOfSightRange) {
tileCounterY = Map.getStageSizeY();
}
if (Calculate.calculateLineOfSightDistance(xLocation, yLocation, tileCounterX, tileCounterY) <= lineOfSightRange) {
if (tileVisibility[tileCounterX][tileCounterY] == false) {
checkLineOfSightConnection(tileCounterX, tileCounterY);
}
}
}
}
}
// This will check whether the character in question can see the location in question
private void checkLineOfSightConnection(int xCoordinate, int yCoordinate) {
Map currentLevel = Main.getCurrentLevel();
// This will follow a path from the character's location to the destination point to see if there's something in the way.
int scanX = xLocation;
int scanY = yLocation;
// This is marked as true if something is blocking the character's view
boolean blocked = false;
// This is the slope of the scanner's location measured against the destination.
float currentSlope;
// These are for dealing with the hallway issues.
boolean firstMove = true;
boolean limitHorizontal = true;
tileVisibility[scanX][scanY] = true;
if (this == Main.getPlayer()) {
int tileType = currentLevel.getMapData(scanX, scanY);
currentLevel.setMapMemoryData(scanX, scanY, tileType);
tileLighting[scanX][scanY] = true;
}
// This will loop until the ray has reached its target, or is blocked by something;
while (scanX != xCoordinate || scanY != yCoordinate) {
// This is to ensure we don't get any divide by zero errors. The slope is high enough that it'll work no matter what.
if (scanX == xCoordinate) {
currentSlope = 10000;
} else {
// We figure out what our current slope is, so we know how to reach our target.
currentSlope = Math.abs(Calculate.getSlope(scanX, scanY, xCoordinate, yCoordinate));
}
// Now we use the slope to figure out how the scan coordinates should move.
if (currentSlope <= 0.50) {
if (scanX < xCoordinate) {
scanX += 1;
}
if (scanX > xCoordinate) {
scanX -= 1;
}
limitHorizontal = false;
} else if (currentSlope >= 2.00) {
if (scanY < yCoordinate) {
scanY += 1;
}
if (scanY > yCoordinate) {
scanY -= 1;
}
limitHorizontal = true;
} else {
if (scanX < xCoordinate) {
scanX += 1;
}
if (scanX > xCoordinate) {
scanX -= 1;
}
if (scanY < yCoordinate) {
scanY += 1;
}
if (scanY > yCoordinate) {
scanY -= 1;
}
firstMove = false;
}
// This is for resolving the problems I've been having at the ends of hallways.
if (firstMove == true) {
// We only need to do this if the target is more than one space away in both directions
if ((Math.abs(xLocation - xCoordinate)) > 1 && Math.abs(yLocation - yCoordinate) > 1) {
int xTargetDirection;
int yTargetDirection;
int limitScanX;
int limitScanY;
boolean limitPov = false;
int targetDistance;
targetDistance = 0;
if (limitHorizontal == true) {
targetDistance = Math.abs(xLocation - xCoordinate);
} else {
targetDistance = Math.abs(yLocation - yCoordinate);
}
if (xLocation > xCoordinate) {
xTargetDirection = -1;
} else {
xTargetDirection = 1;
}
if (yLocation > yCoordinate) {
yTargetDirection = -1;
} else {
yTargetDirection = 1;
}
// This part checks to see if there are obstructions in the way.
// It moves diagonally starting at the player's location moving towards the target.
for (int obstructionDistance = 1; obstructionDistance <= targetDistance; obstructionDistance++) {
limitScanX = xLocation + (xTargetDirection * (obstructionDistance));
limitScanY = yLocation + (yTargetDirection * (obstructionDistance));
if (limitScanX >= Map.getStageSizeX()) {
limitScanX = Map.getStageSizeX() - 1;
}
if (limitScanX < 0) {
limitScanX = 0;
}
if (limitScanY >= Map.getStageSizeY()) {
limitScanY = Map.getStageSizeY() - 1;
}
if (limitScanY < 0) {
limitScanY = 0;
}
if (currentLevel.checkOpacity(limitScanX, limitScanY) == true) {
limitPov = true;
}
// These check either straight horizontal or vertical rows to see if the view is blocked.
if (limitHorizontal == true) {
if (limitScanY > yCoordinate) {
while (limitScanY > yCoordinate + obstructionDistance) {
limitScanY += yTargetDirection;
if (currentLevel.checkOpacity(limitScanX, limitScanY) == true) {
limitPov = true;
//xCoordinate = xLocation + xTargetDirection;
limitScanY = yCoordinate;
}
}
} else {
while (limitScanY < yCoordinate - obstructionDistance) {
limitScanY += yTargetDirection;
if (currentLevel.checkOpacity(limitScanX, limitScanY) == true) {
limitPov = true;
//xCoordinate = xLocation + xTargetDirection;
limitScanY = yCoordinate;
}
}
}
} else {
if (limitScanX > xCoordinate) {
while (limitScanX > xCoordinate + obstructionDistance) {
limitScanX += xTargetDirection;
if (currentLevel.checkOpacity(limitScanX, limitScanY) == true) {
limitPov = true;
//xCoordinate = xLocation + xTargetDirection;
limitScanX = xCoordinate;
}
}
} else {
while (limitScanX < xCoordinate - obstructionDistance) {
limitScanX += xTargetDirection;
if (currentLevel.checkOpacity(limitScanX, limitScanY) == true) {
limitPov = true;
//xCoordinate = xLocation + xTargetDirection;
limitScanX = xCoordinate;
}
}
}
}
// Now if we do find something blocking the way, we move the target coordinates in to better simulate real LoS.
if (limitPov == true) {
// First we do this so the loop ends. There's no reason to keep it going.
obstructionDistance = targetDistance;
// Now we move the target coordinates appropriately.
if (limitHorizontal == true) {
xCoordinate = limitScanX;
} else {
yCoordinate = limitScanY;
}
}
}
}
firstMove = false;
}
// If the ray hits something opaque, we set blocked to true so the ray stops.
if (blocked == false) {
tileVisibility[scanX][scanY] = true;
if (this == Main.getPlayer()) {
int tileType = currentLevel.getMapData(scanX, scanY);
currentLevel.setMapMemoryData(scanX, scanY, tileType);
tileLighting[scanX][scanY] = true;
}
}
if (currentLevel.checkOpacity(scanX, scanY) == true) {
blocked = true;
}
}
}
// This sets every tile to unseen to start the turn out.
private void initializeTileVisibility() {
for (int yCounter = 0; yCounter <
Map.getStageSizeY(); yCounter++) {
for (int xCounter = 0; xCounter <
Map.getStageSizeX(); xCounter++) {
tileVisibility[xCounter][yCounter] = false;
if (this == Main.getPlayer()) {
tileLighting[xCounter][yCounter] = false;
}
}
}
}