Hey, I'm back for some more advice.
I replaced my old method of comparing the current slope with the end slope to one that only uses the current slope of where the "scanner" is to where the destination tile is. It's much simpler, and is working mostly better, but with one problem - it's being too permissive with what it shows, but only to targets that are mostly horizontal. I'll add some screens to show what I mean:
http://img6.imageshack.us/img6/8611/badscreen.pngSee, in this one it's expanding at a 45 degree angle at the end of the hallway. That's just too much.
http://img6.imageshack.us/img6/1197/goodscreen.pngHere is how I want it. It expands, but much more conservatively.
Here's the code I'm using for this, anyone who wants to use or modify this is free to do so.
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();
int scanX = xLocation;
int scanY = yLocation;
boolean blocked = false;
double currentSlope;
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;
}
} else if (currentSlope >= 2.00) {
if (scanY < yCoordinate) {
scanY += 1;
}
if (scanY > yCoordinate) {
scanY -= 1;
}
} else {
if (scanX < xCoordinate) {
scanX += 1;
}
if (scanX > xCoordinate) {
scanX -= 1;
}
if (scanY < yCoordinate) {
scanY += 1;
}
if (scanY > yCoordinate) {
scanY -= 1;
}
}
// 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;
}
}
}
Can any of you spot what the cause of the problem I'm having is? I can't figure it out.
Edit: And a few explanations to help make this more clear maybe:
Calculate.getSlope returns the slope of the two coordinate pairs it's given.
Calculate.calculateLineOfSightDistance returns the distance between the two tiles.
xLocation and yLocation are the current character's coordinates.
tileLighting is a boolean array for whether the player character can currently see the tile's location. It currently does nothing, but that'll change in the near future when I make it so tiles that are remembered but not seen are darkened/don't have characters drawn on them.
currentLevel.setMapMemoryData sets what the current tile on the current level is remembered as. This is exclusively what is currently used for determining what to draw.
tileVisibility is whether the current character can see the current tile, regardless of whether they're a player character or not. This is what will be used for ai characters' sight.
scanX and scanY are the locations of the scanner that moves from the character's location to the destination tile.
Does that explain everything well enough?