v0.6.3: significant refactoring and performance improvements to fog of war
This commit is contained in:
parent
acc9fd33d2
commit
c290e5fe47
|
@ -99,6 +99,15 @@ public class Rect {
|
|||
return result;
|
||||
}
|
||||
|
||||
public Rect union( Rect other ){
|
||||
Rect result = new Rect();
|
||||
result.left = Math.min( left, other.left );
|
||||
result.right = Math.max( right, other.right );
|
||||
result.top = Math.min( top, other.top );
|
||||
result.bottom = Math.max( bottom, other.bottom );
|
||||
return result;
|
||||
}
|
||||
|
||||
public Rect union( int x, int y ) {
|
||||
if (isEmpty()) {
|
||||
return set( x, y, x + 1, y + 1 );
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 152 B After Width: | Height: | Size: 162 B |
|
@ -29,12 +29,14 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Light;
|
|||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MindVision;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Blacksmith;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Ghost;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Imp;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Wandmaker;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Ankh;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.DriedRose;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.potions.Potion;
|
||||
|
@ -744,30 +746,45 @@ public class Dungeon {
|
|||
|
||||
level.updateFieldOfView(hero, level.heroFOV);
|
||||
|
||||
if (hero.buff(MindVision.class) != null || hero.buff(Awareness.class) != null) {
|
||||
BArray.or( level.visited, level.heroFOV, 0, level.heroFOV.length, level.visited );
|
||||
|
||||
GameScene.updateFog();
|
||||
} else {
|
||||
|
||||
int cx = hero.pos % level.width();
|
||||
int cy = hero.pos / level.width();
|
||||
|
||||
int ax = Math.max( 0, cx - dist );
|
||||
int bx = Math.min( cx + dist, level.width() - 1 );
|
||||
int ay = Math.max( 0, cy - dist );
|
||||
int by = Math.min( cy + dist, level.height() - 1 );
|
||||
|
||||
int len = bx - ax + 1;
|
||||
int pos = ax + ay * level.width();
|
||||
|
||||
for (int y = ay; y <= by; y++, pos+=level.width()) {
|
||||
BArray.or( level.visited, level.heroFOV, pos, len, level.visited );
|
||||
}
|
||||
|
||||
GameScene.updateFog(ax, ay, len, by-ay);
|
||||
int x = hero.pos % level.width();
|
||||
int y = hero.pos / level.width();
|
||||
|
||||
//left, right, top, bottom
|
||||
int l = Math.max( 0, x - dist );
|
||||
int r = Math.min( x + dist, level.width() - 1 );
|
||||
int t = Math.max( 0, y - dist );
|
||||
int b = Math.min( y + dist, level.height() - 1 );
|
||||
|
||||
int length = r - l + 1;
|
||||
int width = t - b + 1;
|
||||
|
||||
int pos = l + t * level.width();
|
||||
|
||||
for (int i = t; i <= b; i++) {
|
||||
BArray.or( level.visited, level.heroFOV, pos, length, level.visited );
|
||||
pos+=level.width();
|
||||
}
|
||||
|
||||
GameScene.updateFog(l, t, length, width);
|
||||
|
||||
if (hero.buff(MindVision.class) != null){
|
||||
for (Mob m : level.mobs.toArray(new Mob[0])){
|
||||
BArray.or( level.visited, level.heroFOV, m.pos - 1 - level.width(), 3, level.visited );
|
||||
BArray.or( level.visited, level.heroFOV, m.pos, 3, level.visited );
|
||||
BArray.or( level.visited, level.heroFOV, m.pos - 1 + level.width(), 3, level.visited );
|
||||
//updates adjacent cells too
|
||||
GameScene.updateFog(m.pos, 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (hero.buff(Awareness.class) != null){
|
||||
for (Heap h : level.heaps.values()){
|
||||
BArray.or( level.visited, level.heroFOV, h.pos - 1 - level.width(), 3, level.visited );
|
||||
BArray.or( level.visited, level.heroFOV, h.pos - 1, 3, level.visited );
|
||||
BArray.or( level.visited, level.heroFOV, h.pos - 1 + level.width(), 3, level.visited );
|
||||
GameScene.updateFog(h.pos, 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GameScene.afterObserve();
|
||||
}
|
||||
|
|
|
@ -105,7 +105,6 @@ import com.watabou.noosa.audio.Music;
|
|||
import com.watabou.noosa.audio.Sample;
|
||||
import com.watabou.noosa.particles.Emitter;
|
||||
import com.watabou.utils.GameMath;
|
||||
import com.watabou.utils.PathFinder;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -777,7 +776,8 @@ public class GameScene extends PixelScene {
|
|||
scene.visualGrid.updateMapCell( cell );
|
||||
scene.terrainFeatures.updateMapCell( cell );
|
||||
scene.walls.updateMapCell( cell );
|
||||
updateFog( cell );
|
||||
//update adjacent cells too
|
||||
updateFog( cell, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -813,21 +813,11 @@ public class GameScene extends PixelScene {
|
|||
scene.wallBlocking.updateArea(x, y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateFog( int cell ){
|
||||
|
||||
public static void updateFog( int cell, int radius ){
|
||||
if (scene != null) {
|
||||
//update in a 3x3 grid to account for neighbours which might also be affected
|
||||
if (Dungeon.level.insideMap(cell)) {
|
||||
for (int i : PathFinder.NEIGHBOURS9) {
|
||||
scene.fog.updateFogCell( cell + i );
|
||||
scene.wallBlocking.updateMapCell( cell + i );
|
||||
}
|
||||
|
||||
//unless we're at the level's edge, then just do the one tile.
|
||||
} else {
|
||||
scene.fog.updateFogCell( cell );
|
||||
scene.wallBlocking.updateMapCell( cell );
|
||||
}
|
||||
scene.fog.updateFog( cell, radius );
|
||||
scene.wallBlocking.updateArea( cell, radius );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ import com.watabou.utils.Rect;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class FogOfWar extends Image {
|
||||
|
||||
|
@ -77,11 +78,19 @@ public class FogOfWar extends Image {
|
|||
private int width2;
|
||||
private int height2;
|
||||
|
||||
private volatile Rect updated;
|
||||
private Rect updating;
|
||||
private volatile ArrayList<Rect> toUpdate;
|
||||
private volatile ArrayList<Rect> updating;
|
||||
|
||||
//should be divisible by 2
|
||||
private static final int PIX_PER_TILE = 2;
|
||||
|
||||
/*
|
||||
TODO currently the center of each fox pixel is aligned with the inside of a cell
|
||||
might be possible to create a better fog effect by aligning them with edges of a cell,
|
||||
similar to the existing fog effect in vanilla (although probably with more precision)
|
||||
the advantage here is that it may be possible to totally eliminate the tile blocking map
|
||||
*/
|
||||
|
||||
public FogOfWar( int mapWidth, int mapHeight ) {
|
||||
|
||||
super();
|
||||
|
@ -113,26 +122,47 @@ public class FogOfWar extends Image {
|
|||
DungeonTilemap.SIZE / PIX_PER_TILE,
|
||||
DungeonTilemap.SIZE / PIX_PER_TILE);
|
||||
|
||||
updated = new Rect(0, 0, mapWidth, mapHeight);
|
||||
toUpdate = new ArrayList<>();
|
||||
toUpdate.add(new Rect(0, 0, mapWidth, mapHeight));
|
||||
}
|
||||
|
||||
public synchronized void updateFog(){
|
||||
updated.set( 0, 0, mapWidth, mapHeight );
|
||||
toUpdate.clear();
|
||||
toUpdate.add(new Rect(0, 0, mapWidth, mapHeight));
|
||||
}
|
||||
|
||||
public synchronized void updateFog(Rect update){
|
||||
for (Rect r : toUpdate.toArray(new Rect[0])){
|
||||
if (!r.intersect(update).isEmpty()){
|
||||
toUpdate.remove(r);
|
||||
toUpdate.add(r.union(update));
|
||||
return;
|
||||
}
|
||||
}
|
||||
toUpdate.add(update);
|
||||
}
|
||||
|
||||
public synchronized void updateFogCell( int cell ){
|
||||
updateFogArea( cell % mapWidth , cell / mapWidth, 1, 1 );
|
||||
public synchronized void updateFog( int cell, int radius ){
|
||||
Rect update = new Rect(
|
||||
(cell % mapWidth) - radius,
|
||||
(cell / mapWidth) - radius,
|
||||
(cell % mapWidth) - radius + 1 + 2*radius,
|
||||
(cell / mapWidth) - radius + 1 + 2*radius);
|
||||
update.left = Math.max(0, update.left);
|
||||
update.top = Math.max(0, update.top);
|
||||
update.right = Math.min(mapWidth, update.right);
|
||||
update.bottom = Math.min(mapHeight, update.bottom);
|
||||
if (update.isEmpty()) return;
|
||||
updateFog( update );
|
||||
}
|
||||
|
||||
public synchronized void updateFogArea(int x, int y, int w, int h){
|
||||
updated.union(x, y);
|
||||
updated.union(x + w, y + h);
|
||||
updated = updated.intersect( new Rect(0, 0, mapWidth, mapHeight) );
|
||||
updateFog(new Rect(x, y, x + w, y + h));
|
||||
}
|
||||
|
||||
public synchronized void moveToUpdating(){
|
||||
updating = new Rect(updated);
|
||||
updated.setEmpty();
|
||||
private synchronized void moveToUpdating(){
|
||||
updating = toUpdate;
|
||||
toUpdate = new ArrayList<>();
|
||||
}
|
||||
|
||||
private boolean[] visible;
|
||||
|
@ -147,101 +177,116 @@ public class FogOfWar extends Image {
|
|||
this.brightness = ShatteredPixelDungeon.brightness() + 2;
|
||||
|
||||
moveToUpdating();
|
||||
|
||||
boolean fullUpdate = updating.height() == mapHeight && updating.width() == mapWidth;
|
||||
|
||||
boolean fullUpdate = false;
|
||||
if (updating.size() == 1){
|
||||
Rect update = updating.get(0);
|
||||
if (update.height() == mapHeight && update.width() == mapWidth){
|
||||
fullUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
FogTexture fog = (FogTexture)texture;
|
||||
|
||||
int cell;
|
||||
int[] colorArray = new int[PIX_PER_TILE*PIX_PER_TILE];
|
||||
for (int i=updating.top; i < updating.bottom; i++) {
|
||||
cell = mapWidth * i + updating.left;
|
||||
for (int j=updating.left; j < updating.right; j++) {
|
||||
|
||||
if (cell >= Dungeon.level.length()) continue; //do nothing
|
||||
|
||||
if (!Dungeon.level.discoverable[cell]
|
||||
|| (!visible[cell] && !visited[cell] && !mapped[cell])){
|
||||
//we skip filling cells here if it isn't a full update
|
||||
// because they must already be dark
|
||||
if (fullUpdate)
|
||||
fillCell(j, i, FOG_COLORS[INVISIBLE][brightness]);
|
||||
cell++;
|
||||
continue;
|
||||
}
|
||||
|
||||
//wall tiles
|
||||
if (DungeonTileSheet.wallStitcheable(Dungeon.level.map[cell])){
|
||||
|
||||
//internal wall tiles
|
||||
if (cell + mapWidth >= mapLength){
|
||||
fillCell(j, i, FOG_COLORS[INVISIBLE][brightness]);
|
||||
|
||||
} else if (DungeonTileSheet.wallStitcheable(Dungeon.level.map[cell + mapWidth])){
|
||||
|
||||
//these tiles need to check both the left and right side, to account for only one half of them being seen
|
||||
if (cell % mapWidth != 0){
|
||||
|
||||
//picks the darkest fog between current tile, left, and below-left(if left is a wall).
|
||||
if (cell + mapWidth < mapLength && DungeonTileSheet.wallStitcheable(Dungeon.level.map[cell - 1])){
|
||||
|
||||
//if below-left is also a wall, then we should be dark no matter what.
|
||||
if (DungeonTileSheet.wallStitcheable(Dungeon.level.map[cell + mapWidth - 1])){
|
||||
colorArray[0] = colorArray[2] = FOG_COLORS[INVISIBLE][brightness];
|
||||
} else {
|
||||
colorArray[0] = colorArray[2] = FOG_COLORS[Math.max(getCellFog(cell), Math.max(getCellFog(cell + mapWidth - 1), getCellFog(cell - 1)))][brightness];
|
||||
}
|
||||
|
||||
} else {
|
||||
colorArray[0] = colorArray[2] = FOG_COLORS[Math.max(getCellFog(cell), getCellFog(cell - 1))][brightness];
|
||||
}
|
||||
|
||||
} else {
|
||||
colorArray[0] = colorArray [2] = FOG_COLORS[INVISIBLE][brightness];
|
||||
}
|
||||
|
||||
if ((cell+1) % mapWidth != 0){
|
||||
|
||||
//picks the darkest fog between current tile, right, and below-right(if right is a wall).
|
||||
if (cell + mapWidth < mapLength && DungeonTileSheet.wallStitcheable(Dungeon.level.map[cell + 1])){
|
||||
|
||||
//if below-right is also a wall, then we should be dark no matter what.
|
||||
if (DungeonTileSheet.wallStitcheable(Dungeon.level.map[cell + mapWidth + 1])){
|
||||
colorArray[1] = colorArray[3] = FOG_COLORS[INVISIBLE][brightness];
|
||||
} else {
|
||||
colorArray[1] = colorArray[3] = FOG_COLORS[Math.max(getCellFog(cell), Math.max(getCellFog(cell + mapWidth + 1), getCellFog(cell + 1)))][brightness];
|
||||
}
|
||||
|
||||
} else {
|
||||
colorArray[1] = colorArray[3] =
|
||||
FOG_COLORS[Math.max(getCellFog(cell), getCellFog(cell + 1))][brightness];
|
||||
}
|
||||
|
||||
} else {
|
||||
colorArray[1] = colorArray [3] = FOG_COLORS[INVISIBLE][brightness];
|
||||
}
|
||||
|
||||
fillCell(j, i, colorArray);
|
||||
|
||||
//camera-facing wall tiles
|
||||
} else {
|
||||
fillCell(j, i, FOG_COLORS[Math.max(getCellFog(cell), getCellFog(cell + mapWidth))][brightness]);
|
||||
|
||||
for (Rect update : updating) {
|
||||
for (int i = update.top; i <= update.bottom; i++) {
|
||||
cell = mapWidth * i + update.left;
|
||||
for (int j = update.left; j <= update.right; j++) {
|
||||
|
||||
if (cell >= Dungeon.level.length()) continue; //do nothing
|
||||
|
||||
if (!Dungeon.level.discoverable[cell]
|
||||
|| (!visible[cell] && !visited[cell] && !mapped[cell])) {
|
||||
//we skip filling cells here if it isn't a full update
|
||||
// because they must already be dark
|
||||
if (fullUpdate)
|
||||
fillCell(j, i, FOG_COLORS[INVISIBLE][brightness]);
|
||||
cell++;
|
||||
continue;
|
||||
}
|
||||
|
||||
//other tiles
|
||||
} else {
|
||||
fillCell(j, i, FOG_COLORS[getCellFog(cell)][brightness]);
|
||||
|
||||
//wall tiles
|
||||
if (wall(cell)) {
|
||||
|
||||
//always dark if nothing is beneath them
|
||||
if (cell + mapWidth >= mapLength) {
|
||||
fillCell(j, i, FOG_COLORS[INVISIBLE][brightness]);
|
||||
|
||||
//internal wall tiles, need to check both the left and right side,
|
||||
// to account for only one half of them being seen
|
||||
} else if (wall(cell + mapWidth)) {
|
||||
|
||||
//left side
|
||||
if (cell % mapWidth != 0) {
|
||||
|
||||
//picks the darkest fog between current tile, left, and below-left(if left is a wall).
|
||||
if (wall(cell - 1)) {
|
||||
|
||||
//if below-left is also a wall, then we should be dark no matter what.
|
||||
if (wall(cell + mapWidth - 1)) {
|
||||
fillLeft(j, i, FOG_COLORS[INVISIBLE][brightness]);
|
||||
} else {
|
||||
fillLeft(j, i, FOG_COLORS[Math.max(getCellFog(cell), Math.max(getCellFog(cell + mapWidth - 1), getCellFog(cell - 1)))][brightness]);
|
||||
}
|
||||
|
||||
} else {
|
||||
fillLeft(j, i, FOG_COLORS[Math.max(getCellFog(cell), getCellFog(cell - 1))][brightness]);
|
||||
}
|
||||
|
||||
} else {
|
||||
fillLeft(j, i, FOG_COLORS[INVISIBLE][brightness]);
|
||||
}
|
||||
|
||||
//right side
|
||||
if ((cell + 1) % mapWidth != 0) {
|
||||
|
||||
//picks the darkest fog between current tile, right, and below-right(if right is a wall).
|
||||
if (wall(cell + 1)) {
|
||||
|
||||
//if below-right is also a wall, then we should be dark no matter what.
|
||||
if (wall(cell + mapWidth + 1)) {
|
||||
fillRight(j, i, FOG_COLORS[INVISIBLE][brightness]);
|
||||
} else {
|
||||
fillRight(j, i, FOG_COLORS[Math.max(getCellFog(cell), Math.max(getCellFog(cell + mapWidth + 1), getCellFog(cell + 1)))][brightness]);
|
||||
}
|
||||
|
||||
} else {
|
||||
fillRight(j, i, FOG_COLORS[Math.max(getCellFog(cell), getCellFog(cell + 1))][brightness]);
|
||||
}
|
||||
|
||||
} else {
|
||||
fillRight(j, i, FOG_COLORS[INVISIBLE][brightness]);
|
||||
}
|
||||
|
||||
//camera-facing wall tiles
|
||||
//darkest between themselves and the tile below them
|
||||
} else {
|
||||
fillCell(j, i, FOG_COLORS[Math.max(getCellFog(cell), getCellFog(cell + mapWidth))][brightness]);
|
||||
}
|
||||
|
||||
//other tiles, just their direct value
|
||||
} else {
|
||||
fillCell(j, i, FOG_COLORS[getCellFog(cell)][brightness]);
|
||||
}
|
||||
|
||||
cell++;
|
||||
}
|
||||
|
||||
cell++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (updating.size() == 1 && !fullUpdate){
|
||||
fog.update(updating.get(0).top * PIX_PER_TILE, updating.get(0).bottom * PIX_PER_TILE);
|
||||
} else {
|
||||
fog.update();
|
||||
}
|
||||
|
||||
if (updating.width() == mapWidth && updating.height() == mapHeight)
|
||||
fog.update();
|
||||
else
|
||||
fog.update(updating.top * PIX_PER_TILE, updating.bottom * PIX_PER_TILE);
|
||||
|
||||
}
|
||||
|
||||
private boolean wall(int cell) {
|
||||
return DungeonTileSheet.wallStitcheable(Dungeon.level.map[cell]);
|
||||
}
|
||||
|
||||
private int getCellFog( int cell ){
|
||||
|
@ -256,13 +301,23 @@ public class FogOfWar extends Image {
|
|||
return INVISIBLE;
|
||||
}
|
||||
}
|
||||
|
||||
private void fillCell( int x, int y, int[] colors){
|
||||
|
||||
private void fillLeft( int x, int y, int color){
|
||||
FogTexture fog = (FogTexture)texture;
|
||||
for (int i = 0; i < PIX_PER_TILE; i++){
|
||||
fog.pixels.position(((y * PIX_PER_TILE)+i)*width2 + x * PIX_PER_TILE);
|
||||
for (int j = 0; j < PIX_PER_TILE; j++) {
|
||||
fog.pixels.put(colors[i*PIX_PER_TILE + j]);
|
||||
for (int j = 0; j < PIX_PER_TILE/2; j++) {
|
||||
fog.pixels.put(color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fillRight( int x, int y, int color){
|
||||
FogTexture fog = (FogTexture)texture;
|
||||
for (int i = 0; i < PIX_PER_TILE; i++){
|
||||
fog.pixels.position(((y * PIX_PER_TILE)+i)*width2 + x * PIX_PER_TILE + PIX_PER_TILE/2);
|
||||
for (int j = PIX_PER_TILE/2; j < PIX_PER_TILE; j++) {
|
||||
fog.pixels.put(color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -356,9 +411,8 @@ public class FogOfWar extends Image {
|
|||
@Override
|
||||
public void draw() {
|
||||
|
||||
if (!updated.isEmpty()){
|
||||
if (!toUpdate.isEmpty()){
|
||||
updateTexture(Dungeon.level.heroFOV, Dungeon.level.visited, Dungeon.level.mapped);
|
||||
updating.setEmpty();
|
||||
}
|
||||
|
||||
super.draw();
|
||||
|
|
|
@ -30,11 +30,12 @@ public class WallBlockingTilemap extends Tilemap {
|
|||
|
||||
public static final int SIZE = 16;
|
||||
|
||||
private static final int CLEARED = -1;
|
||||
private static final int BLOCK_NONE = 0;
|
||||
private static final int BLOCK_RIGHT = 1;
|
||||
private static final int BLOCK_LEFT = 2;
|
||||
private static final int BLOCK_ALL = 3;
|
||||
private static final int CLEARED = -2;
|
||||
private static final int BLOCK_NONE = -1;
|
||||
private static final int BLOCK_RIGHT = 0;
|
||||
private static final int BLOCK_LEFT = 1;
|
||||
private static final int BLOCK_ALL = 2;
|
||||
private static final int BLOCK_BELOW = 3;
|
||||
|
||||
public WallBlockingTilemap() {
|
||||
super("wall_blocking.png", new TextureFilm( "wall_blocking.png", SIZE, SIZE ) );
|
||||
|
@ -45,109 +46,158 @@ public class WallBlockingTilemap extends Tilemap {
|
|||
public synchronized void updateMap() {
|
||||
super.updateMap();
|
||||
data = new int[size]; //clears all values, including cleared tiles
|
||||
for (int i = 0; i < data.length; i++)
|
||||
updateMapCell(i);
|
||||
|
||||
for (int cell = 0; cell < data.length; cell++) {
|
||||
//force all none-discoverable and border cells to cleared
|
||||
if (!Dungeon.level.discoverable[cell] ||
|
||||
!Dungeon.level.insideMap(cell)){
|
||||
data[cell] = CLEARED;
|
||||
} else {
|
||||
updateMapCell(cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int curr;
|
||||
|
||||
@Override
|
||||
public synchronized void updateMapCell(int cell) {
|
||||
int prev = data[cell];
|
||||
int curr;
|
||||
|
||||
//TODO should doors be considered? currently the blocking is a bit permissive around doors
|
||||
|
||||
if (prev == CLEARED){
|
||||
return;
|
||||
//non-wall tiles
|
||||
if (!wall(cell)) {
|
||||
|
||||
} else if (!Dungeon.level.discoverable[cell]) {
|
||||
curr = CLEARED;
|
||||
|
||||
//handles blocking wall overhang (which is technically on a none wall tile)
|
||||
} else if (!wall(cell)) {
|
||||
|
||||
if (!fogHidden(cell)) {
|
||||
//clear empty floor tiles and cells which are visible
|
||||
if (!fogHidden(cell) || !wall(cell + mapWidth)) {
|
||||
curr = CLEARED;
|
||||
|
||||
} else if ( wall(cell + mapWidth) && !fogHidden(cell + mapWidth)
|
||||
&& fogHidden(cell - 1) && fogHidden(cell + 1)) {
|
||||
curr = BLOCK_ALL;
|
||||
//block wall overhang if:
|
||||
//- The cell below is a wall and visible
|
||||
//- All of left, below-left, right, below-right is either a wall or hidden
|
||||
} else if ( !fogHidden(cell + mapWidth)
|
||||
&& (fogHidden(cell - 1) || wall(cell - 1))
|
||||
&& (fogHidden(cell + 1) || wall(cell + 1))
|
||||
&& (fogHidden(cell - 1 + mapWidth) || wall(cell - 1 + mapWidth))
|
||||
&& (fogHidden(cell + 1 + mapWidth) || wall(cell + 1 + mapWidth))) {
|
||||
curr = BLOCK_BELOW;
|
||||
|
||||
} else {
|
||||
curr = BLOCK_NONE;
|
||||
}
|
||||
|
||||
//wall tiles
|
||||
} else {
|
||||
|
||||
if (fogHidden(cell - mapWidth) && fogHidden(cell) && fogHidden(cell + mapWidth)) {
|
||||
curr = BLOCK_NONE;
|
||||
//camera-facing wall tiles
|
||||
if (!wall(cell + mapWidth)) {
|
||||
|
||||
//camera-facing wall tiles
|
||||
} else if (!wall(cell + mapWidth)) {
|
||||
|
||||
if (!fogHidden(cell + mapWidth)){
|
||||
//Block a camera-facing wall if:
|
||||
//- the cell above, above-left, or above-right is not a wall, visible, and has a wall below
|
||||
//- none of the remaining 5 neighbour cells are both not a wall and visible
|
||||
|
||||
//if all 3 above are wall we can shortcut and just clear the cell
|
||||
if (wall(cell - 1 - mapWidth) && wall(cell - mapWidth) && wall(cell + 1 - mapWidth)){
|
||||
curr = CLEARED;
|
||||
|
||||
} else if ((cell + 1) % mapWidth != 0 && !fogHidden(cell + 1)
|
||||
&& !door(cell + 1) && !(wall(cell + 1) && wall(cell + 1 + mapWidth))){
|
||||
curr = CLEARED;
|
||||
|
||||
} else if (cell % mapWidth != 0 && !fogHidden(cell - 1)
|
||||
&& !door(cell - 1) && !(wall(cell - 1) && wall(cell - 1 + mapWidth))){
|
||||
curr = CLEARED;
|
||||
|
||||
|
||||
} else if ((!wall(cell - 1 - mapWidth) && !fogHidden(cell - 1 - mapWidth) && wall(cell - 1)) ||
|
||||
(!wall(cell - mapWidth) && !fogHidden(cell - mapWidth)) ||
|
||||
(!wall(cell + 1 - mapWidth) && !fogHidden(cell + 1 - mapWidth) && wall(cell+1))){
|
||||
|
||||
if ( !fogHidden( cell + mapWidth) ||
|
||||
(!wall(cell - 1) && !fogHidden(cell - 1)) ||
|
||||
(!wall(cell - 1 + mapWidth) && !fogHidden(cell - 1 + mapWidth)) ||
|
||||
(!wall(cell + 1) && !fogHidden(cell + 1)) ||
|
||||
(!wall(cell + 1 + mapWidth) && !fogHidden(cell + 1 + mapWidth))){
|
||||
curr = CLEARED;
|
||||
} else {
|
||||
curr = BLOCK_ALL;
|
||||
}
|
||||
|
||||
} else {
|
||||
curr = BLOCK_ALL;
|
||||
curr = BLOCK_NONE;
|
||||
}
|
||||
|
||||
//internal wall tiles
|
||||
//internal wall tiles
|
||||
} else {
|
||||
|
||||
//Block the side of an internal wall if:
|
||||
//- the cell above, below, or the cell itself is visible
|
||||
//and all of the following are NOT true:
|
||||
//- the top-side neighbour is visible and the side neighbour isn't a wall.
|
||||
//- the side neighbour is both not a wall and visible
|
||||
//- the bottom-side neighbour is both not a wall and visible
|
||||
|
||||
curr = BLOCK_NONE;
|
||||
|
||||
if ((cell + 1) % mapWidth != 0) {
|
||||
if ((wall(cell + 1) || fogHidden(cell + 1 - mapWidth))
|
||||
&& fogHidden(cell + 1)
|
||||
&& (wall(cell + 1 + mapWidth) || fogHidden(cell + 1 + mapWidth))){
|
||||
|
||||
if (!fogHidden(cell - mapWidth)
|
||||
|| !fogHidden(cell)
|
||||
|| !fogHidden(cell + mapWidth)) {
|
||||
|
||||
//right side
|
||||
if ((!wall(cell + 1) && !fogHidden(cell + 1 - mapWidth)) ||
|
||||
(!wall(cell + 1) && !fogHidden(cell + 1)) ||
|
||||
(!wall(cell + 1 + mapWidth) && !fogHidden(cell + 1 + mapWidth))
|
||||
){
|
||||
//do nothing
|
||||
} else {
|
||||
curr += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (cell % mapWidth != 0) {
|
||||
if ((wall(cell - 1) || fogHidden(cell - 1 - mapWidth))
|
||||
&& fogHidden(cell - 1)
|
||||
&& (wall(cell - 1 + mapWidth) || fogHidden(cell - 1 + mapWidth))){
|
||||
|
||||
//left side
|
||||
if ((!wall(cell - 1) && !fogHidden(cell - 1 - mapWidth)) ||
|
||||
(!wall(cell - 1) && !fogHidden(cell - 1)) ||
|
||||
(!wall(cell - 1 + mapWidth) && !fogHidden(cell - 1 + mapWidth))
|
||||
){
|
||||
//do nothing
|
||||
} else {
|
||||
curr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (curr == BLOCK_NONE) {
|
||||
curr = CLEARED;
|
||||
|
||||
if (curr == BLOCK_NONE) {
|
||||
curr = CLEARED;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (prev != curr){
|
||||
if (data[cell] != curr){
|
||||
data[cell] = curr;
|
||||
super.updateMapCell(cell);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean fogHidden(int cell){
|
||||
if (cell < 0 || cell >= Dungeon.level.length()) return false;
|
||||
if (!Dungeon.level.visited[cell] && !Dungeon.level.mapped[cell]) return true;
|
||||
if (wall(cell) && cell + mapWidth < Dungeon.level.length() && !wall(cell + mapWidth) &&
|
||||
!Dungeon.level.visited[cell + mapWidth] && !Dungeon.level.mapped[cell + mapWidth])
|
||||
if (!Dungeon.level.visited[cell] && !Dungeon.level.mapped[cell]) {
|
||||
return true;
|
||||
} else if (wall(cell) && !wall(cell + mapWidth) &&
|
||||
!Dungeon.level.visited[cell + mapWidth] && !Dungeon.level.mapped[cell + mapWidth]) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//for the purposes of wall stitching, tiles below the map count as walls
|
||||
private boolean wall(int cell) {
|
||||
return cell >= 0 && (cell >= size || DungeonTileSheet.wallStitcheable(Dungeon.level.map[cell]));
|
||||
return DungeonTileSheet.wallStitcheable(Dungeon.level.map[cell]);
|
||||
}
|
||||
|
||||
private boolean door(int cell) {
|
||||
return cell >= 0 && cell < size && DungeonTileSheet.doorTile(Dungeon.level.map[cell]);
|
||||
return DungeonTileSheet.doorTile(Dungeon.level.map[cell]);
|
||||
}
|
||||
|
||||
public synchronized void updateArea(int cell, int radius){
|
||||
int l = cell%mapWidth - radius;
|
||||
int t = cell/mapWidth - radius;
|
||||
int r = cell%mapWidth + radius;
|
||||
int b = cell/mapWidth + radius;
|
||||
updateArea(
|
||||
Math.max(0, l),
|
||||
Math.max(0, t),
|
||||
Math.min(mapWidth-1, r - l),
|
||||
Math.min(mapHeight-1, b - t)
|
||||
);
|
||||
}
|
||||
|
||||
public synchronized void updateArea(int x, int y, int w, int h) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user