v0.4.2: FOV and shadowcaster optimizations

This commit is contained in:
Evan Debenham 2016-08-22 14:29:51 -04:00 committed by Evan Debenham
parent 9f8981db07
commit f1164af058
7 changed files with 57 additions and 53 deletions

View File

@ -663,8 +663,7 @@ public class Dungeon {
return;
}
level.updateFieldOfView( hero );
System.arraycopy( Level.fieldOfView, 0, visible, 0, visible.length );
level.updateFieldOfView(hero, visible);
BArray.or( level.visited, visible, level.visited );

View File

@ -79,7 +79,7 @@ public abstract class Char extends Actor {
@Override
protected boolean act() {
Dungeon.level.updateFieldOfView( this );
Dungeon.level.updateFieldOfView( this, Level.fieldOfView );
return false;
}

View File

@ -65,7 +65,7 @@ public class Guard extends Mob {
@Override
protected boolean act() {
Dungeon.level.updateFieldOfView( this );
Dungeon.level.updateFieldOfView( this, Level.fieldOfView );
if (state == HUNTING &&
paralysed <= 0 &&

View File

@ -62,7 +62,7 @@ public class Piranha extends Mob {
return true;
} else {
//this causes pirahna to move away when a door is closed on them.
Dungeon.level.updateFieldOfView( this );
Dungeon.level.updateFieldOfView( this, Level.fieldOfView );
enemy = chooseEnemy();
if (state == this.HUNTING &&
!(enemy != null && enemy.isAlive() && Level.fieldOfView[enemy.pos] && enemy.invisible <= 0)){

View File

@ -74,6 +74,7 @@ import com.shatteredpixel.shatteredpixeldungeon.plants.Plant;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite;
import com.shatteredpixel.shatteredpixeldungeon.ui.CustomTileVisual;
import com.shatteredpixel.shatteredpixeldungeon.utils.BArray;
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
import com.watabou.noosa.Game;
import com.watabou.noosa.Group;
@ -544,6 +545,8 @@ public abstract class Level implements Bundlable {
protected void buildFlagMaps() {
fieldOfView = new boolean[length()];
passable = new boolean[length()];
losBlocking = new boolean[length()];
flamable = new boolean[length()];
@ -896,10 +899,8 @@ public abstract class Level implements Bundlable {
}
}
public boolean[] updateFieldOfView( Char c ) {
public void updateFieldOfView( Char c, boolean[] fieldOfView ) {
fieldOfView = new boolean[length()];
int cx = c.pos % width();
int cy = c.pos / width();
@ -907,10 +908,13 @@ public abstract class Level implements Bundlable {
&& c.buff( TimekeepersHourglass.timeStasis.class ) == null && c.isAlive();
if (sighted) {
ShadowCaster.castShadow( cx, cy, fieldOfView, c.viewDistance );
} else {
BArray.setFalse(fieldOfView);
}
int sense = 1;
if (c.isAlive()) {
//Currently only the hero can get mind vision
if (c.isAlive() && c == Dungeon.hero) {
for (Buff b : c.buffs( MindVision.class )) {
sense = Math.max( ((MindVision)b).distance, sense );
}
@ -926,15 +930,12 @@ public abstract class Level implements Bundlable {
int len = bx - ax + 1;
int pos = ax + ay * width();
for (int y = ay; y <= by; y++, pos+=width()) {
Arrays.fill( fieldOfView, pos, pos + len, true );
}
for (int i=0; i < length(); i++) {
fieldOfView[i] &= discoverable[i];
System.arraycopy(discoverable, pos, fieldOfView, pos, len);
}
}
if (c.isAlive()) {
//Currently only the hero can get mind vision or awareness
if (c.isAlive() && c == Dungeon.hero) {
if (c.buff( MindVision.class ) != null) {
for (Mob mob : mobs) {
int p = mob.pos;
@ -948,7 +949,7 @@ public abstract class Level implements Bundlable {
fieldOfView[p + width()] = true;
fieldOfView[p - width()] = true;
}
} else if (c == Dungeon.hero && ((Hero)c).heroClass == HeroClass.HUNTRESS) {
} else if (((Hero)c).heroClass == HeroClass.HUNTRESS) {
for (Mob mob : mobs) {
int p = mob.pos;
if (distance( c.pos, p) == 2) {
@ -980,11 +981,12 @@ public abstract class Level implements Bundlable {
}
}
for (Heap heap : heaps.values())
if (!heap.seen && fieldOfView[heap.pos] && c == Dungeon.hero)
heap.seen = true;
return fieldOfView;
if (c == Dungeon.hero) {
for (Heap heap : heaps.values())
if (!heap.seen && fieldOfView[heap.pos])
heap.seen = true;
}
}
public int distance( int a, int b ) {

View File

@ -22,18 +22,13 @@ package com.shatteredpixel.shatteredpixeldungeon.mechanics;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import java.util.Arrays;
import com.shatteredpixel.shatteredpixeldungeon.utils.BArray;
public final class ShadowCaster {
private static final int MAX_DISTANCE = 8;
private static int distance;
private static int limits[];
private static boolean[] losBlocking;
private static boolean[] fieldOfView;
private static boolean[] falseArray;
private static int[][] rounding;
static {
@ -46,30 +41,28 @@ public final class ShadowCaster {
}
}
private static Obstacles obs = new Obstacles();
public static void castShadow( int x, int y, boolean[] fieldOfView, int distance ) {
losBlocking = Level.losBlocking;
ShadowCaster.distance = distance;
limits = rounding[distance];
ShadowCaster.fieldOfView = fieldOfView;
Arrays.fill( fieldOfView, false );
BArray.setFalse(fieldOfView);
fieldOfView[y * Dungeon.level.width() + x] = true;
scanSector( x, y, +1, +1, 0, 0 );
scanSector( x, y, -1, +1, 0, 0 );
scanSector( x, y, +1, -1, 0, 0 );
scanSector( x, y, -1, -1, 0, 0 );
scanSector( x, y, 0, 0, +1, +1 );
scanSector( x, y, 0, 0, -1, +1 );
scanSector( x, y, 0, 0, +1, -1 );
scanSector( x, y, 0, 0, -1, -1 );
boolean[] losBlocking = Level.losBlocking;
Obstacles obs = new Obstacles();
scanSector( distance, fieldOfView, losBlocking, obs, x, y, +1, +1, 0, 0 );
scanSector( distance, fieldOfView, losBlocking, obs, x, y, -1, +1, 0, 0 );
scanSector( distance, fieldOfView, losBlocking, obs, x, y, +1, -1, 0, 0 );
scanSector( distance, fieldOfView, losBlocking, obs, x, y, -1, -1, 0, 0 );
scanSector( distance, fieldOfView, losBlocking, obs, x, y, 0, 0, +1, +1 );
scanSector( distance, fieldOfView, losBlocking, obs, x, y, 0, 0, -1, +1 );
scanSector( distance, fieldOfView, losBlocking, obs, x, y, 0, 0, +1, -1 );
scanSector( distance, fieldOfView, losBlocking, obs, x, y, 0, 0, -1, -1 );
}
private static void scanSector( int cx, int cy, int m1, int m2, int m3, int m4 ) {
//TODO: This is still fairly expensive, look into further optimizing this
private static void scanSector( int distance, boolean[] fieldOfView, boolean[] losBlocking, Obstacles obs, int cx, int cy, int m1, int m2, int m3, int m4 ) {
obs.reset();
@ -77,7 +70,7 @@ public final class ShadowCaster {
float dq2 = 0.5f / p;
int pp = limits[p];
int pp = rounding[distance][p];
for (int q=0; q <= pp; q++) {
int x = cx + q * m1 + p * m3;
@ -112,8 +105,8 @@ public final class ShadowCaster {
private static final class Obstacles {
private static int SIZE = (MAX_DISTANCE+1) * (MAX_DISTANCE+1) / 2;
private static float[] a1 = new float[SIZE];
private static float[] a2 = new float[SIZE];
private float[] a1 = new float[SIZE];
private float[] a2 = new float[SIZE];
private int length;
private int limit;

View File

@ -22,6 +22,16 @@ package com.shatteredpixel.shatteredpixeldungeon.utils;
public class BArray {
private static boolean[] falseArray;
//This is MUCH faster than making a new boolean[] or using Arrays.fill;
public static void setFalse( boolean[] toBeFalse ){
if (falseArray == null || falseArray.length < toBeFalse.length)
falseArray = new boolean[toBeFalse.length];
System.arraycopy(falseArray, 0, toBeFalse, 0, toBeFalse.length);
}
public static boolean[] and( boolean[] a, boolean[] b, boolean[] result ) {
int length = a.length;