v0.4.2: performance optimizations for blobs

This commit is contained in:
Evan Debenham 2016-09-06 00:12:29 -04:00
parent b25ccd8bb3
commit 60c16201cf
14 changed files with 227 additions and 189 deletions

View File

@ -48,6 +48,7 @@ public class Alchemy extends Blob {
@Override @Override
protected void evolve() { protected void evolve() {
volume = off[pos] = cur[pos]; volume = off[pos] = cur[pos];
area.union(pos%Dungeon.level.width(), pos/Dungeon.level.width());
if (Dungeon.visible[pos]) { if (Dungeon.visible[pos]) {
Journal.add( Journal.Feature.ALCHEMY ); Journal.add( Journal.Feature.ALCHEMY );
@ -56,12 +57,14 @@ public class Alchemy extends Blob {
@Override @Override
public void seed( Level level, int cell, int amount ) { public void seed( Level level, int cell, int amount ) {
if (cur == null) cur = new int[level.length()]; super.seed(level, cell, amount);
if (off == null) off = new int[cur.length];
cur[pos] = 0; cur[pos] = 0;
pos = cell; pos = cell;
volume = cur[pos] = amount; volume = cur[pos] = amount;
area.setEmpty();
area.union(cell%level.width(), cell/level.width());
} }
public static void transmute( int cell ) { public static void transmute( int cell ) {

View File

@ -27,6 +27,7 @@ import com.shatteredpixel.shatteredpixeldungeon.effects.BlobEmitter;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level; import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.utils.BArray; import com.shatteredpixel.shatteredpixeldungeon.utils.BArray;
import com.watabou.utils.Bundle; import com.watabou.utils.Bundle;
import com.watabou.utils.Rect;
import java.util.Arrays; import java.util.Arrays;
@ -43,6 +44,8 @@ public class Blob extends Actor {
public BlobEmitter emitter; public BlobEmitter emitter;
public Rect area = new Rect();
private static final String CUR = "cur"; private static final String CUR = "cur";
private static final String START = "start"; private static final String START = "start";
private static final String LENGTH = "length"; private static final String LENGTH = "length";
@ -110,60 +113,81 @@ public class Blob extends Actor {
if (volume > 0) { if (volume > 0) {
volume = 0; if (area.isEmpty())
evolve(); setupArea();
volume = 0;
evolve();
int[] tmp = off; int[] tmp = off;
off = cur; off = cur;
cur = tmp; cur = tmp;
} else {
area.setEmpty();
} }
return true; return true;
} }
public void setupArea(){
for (int cell=0; cell < cur.length; cell++) {
if (cur[cell] != 0){
area.union(cell%Dungeon.level.width(), cell/Dungeon.level.width());
}
}
}
public void use( BlobEmitter emitter ) { public void use( BlobEmitter emitter ) {
this.emitter = emitter; this.emitter = emitter;
} }
protected void evolve() { protected void evolve() {
boolean[] notBlocking = BArray.not( Level.solid, null ); boolean[] blocking = Level.solid;
int cell;
for (int i=1; i < Dungeon.level.height()-1; i++) { for (int i=area.top-1; i <= area.bottom; i++) {
for (int j = area.left-1; j <= area.right; j++) {
int from = i * Dungeon.level.width() + 1; cell = j + i*Dungeon.level.width();
int to = from + Dungeon.level.width() - 2; if (!blocking[cell]) {
for (int pos=from; pos < to; pos++) {
if (notBlocking[pos]) {
int count = 1; int count = 1;
int sum = cur[pos]; int sum = cur[cell];
if (notBlocking[pos-1]) { if (!blocking[cell-1]) {
sum += cur[pos-1]; sum += cur[cell-1];
count++; count++;
} }
if (notBlocking[pos+1]) { if (!blocking[cell+1]) {
sum += cur[pos+1]; sum += cur[cell+1];
count++; count++;
} }
if (notBlocking[pos-Dungeon.level.width()]) { if (!blocking[cell-Dungeon.level.width()]) {
sum += cur[pos-Dungeon.level.width()]; sum += cur[cell-Dungeon.level.width()];
count++; count++;
} }
if (notBlocking[pos+Dungeon.level.width()]) { if (!blocking[cell+Dungeon.level.width()]) {
sum += cur[pos+Dungeon.level.width()]; sum += cur[cell+Dungeon.level.width()];
count++; count++;
} }
int value = sum >= count ? (sum / count) - 1 : 0; int value = sum >= count ? (sum / count) - 1 : 0;
off[pos] = value; off[cell] = value;
if (value > 0){
if (i < area.top)
area.top = i;
else if (i >= area.bottom)
area.bottom = i+1;
if (j < area.left)
area.left = j;
else if (j >= area.right)
area.right = j+1;
}
volume += value; volume += value;
} else { } else {
off[pos] = 0; off[cell] = 0;
} }
} }
} }
@ -175,6 +199,8 @@ public class Blob extends Actor {
cur[cell] += amount; cur[cell] += amount;
volume += amount; volume += amount;
area.union(cell%level.width(), cell/level.width());
} }
public void clear( int cell ) { public void clear( int cell ) {
@ -184,6 +210,7 @@ public class Blob extends Actor {
public void fullyClear(){ public void fullyClear(){
volume = 0; volume = 0;
area.setEmpty();
cur = new int[Dungeon.level.length()]; cur = new int[Dungeon.level.length()];
off = new int[Dungeon.level.length()]; off = new int[Dungeon.level.length()];
} }

View File

@ -36,10 +36,15 @@ public class ConfusionGas extends Blob {
super.evolve(); super.evolve();
Char ch; Char ch;
for (int i = 0; i < Dungeon.level.length(); i++) { int cell;
if (cur[i] > 0 && (ch = Actor.findChar( i )) != null) {
if (!ch.immunities().contains(this.getClass())) for (int i = area.left; i < area.right; i++){
Buff.prolong( ch, Vertigo.class, 2 ); for (int j = area.top; j < area.bottom; j++){
cell = i + j*Dungeon.level.width();
if (cur[cell] > 0 && (ch = Actor.findChar( cell )) != null) {
if (!ch.immunities().contains(this.getClass()))
Buff.prolong( ch, Vertigo.class, 2 );
}
} }
} }
} }

View File

@ -39,50 +39,49 @@ public class Fire extends Blob {
protected void evolve() { protected void evolve() {
boolean[] flamable = Level.flamable; boolean[] flamable = Level.flamable;
int cell;
int from = Dungeon.level.width() + 1; int fire;
int to = Dungeon.level.length() - Dungeon.level.width() - 1;
boolean observe = false; boolean observe = false;
for (int pos=from; pos < to; pos++) { for (int i = area.left-1; i <= area.right; i++) {
for (int j = area.top-1; j <= area.bottom; j++) {
cell = i + j*Dungeon.level.width();
if (cur[cell] > 0) {
int fire; burn( cell );
if (cur[pos] > 0) { fire = cur[cell] - 1;
if (fire <= 0 && flamable[cell]) {
burn( pos ); int oldTile = Dungeon.level.map[cell];
Dungeon.level.destroy( cell );
fire = cur[pos] - 1; observe = true;
if (fire <= 0 && flamable[pos]) { GameScene.updateMap( cell );
if (Dungeon.visible[cell]) {
int oldTile = Dungeon.level.map[pos]; GameScene.discoverTile( cell, oldTile );
Dungeon.level.destroy( pos ); }
observe = true;
GameScene.updateMap( pos );
if (Dungeon.visible[pos]) {
GameScene.discoverTile( pos, oldTile );
} }
}
} else {
if (flamable[pos]
&& (cur[pos-1] > 0
|| cur[pos+1] > 0
|| cur[pos-Dungeon.level.width()] > 0
|| cur[pos+Dungeon.level.width()] > 0)) {
fire = 4;
burn( pos );
} else { } else {
fire = 0;
if (flamable[cell]
&& (cur[cell-1] > 0
|| cur[cell+1] > 0
|| cur[cell-Dungeon.level.width()] > 0
|| cur[cell+Dungeon.level.width()] > 0)) {
fire = 4;
burn( cell );
area.union(i, j);
} else {
fire = 0;
}
} }
volume += (off[cell] = fire);
} }
volume += (off[pos] = fire);
} }
if (observe) { if (observe) {
@ -107,15 +106,6 @@ public class Fire extends Blob {
} }
} }
public void seed( Level level, int cell, int amount ) {
if (cur == null) cur = new int[level.length()];
if (off == null) off = new int[cur.length];
if (cur[cell] == 0) {
volume += amount;
cur[cell] = amount;
}
}
@Override @Override
public void use( BlobEmitter emitter ) { public void use( BlobEmitter emitter ) {
super.use( emitter ); super.use( emitter );

View File

@ -37,29 +37,29 @@ public class Foliage extends Blob {
@Override @Override
protected void evolve() { protected void evolve() {
int from = Dungeon.level.width() + 1;
int to = Dungeon.level.length() - Dungeon.level.width() - 1;
int[] map = Dungeon.level.map; int[] map = Dungeon.level.map;
boolean regrowth = false;
boolean visible = false; boolean visible = false;
for (int pos=from; pos < to; pos++) { int cell;
if (cur[pos] > 0) { for (int i = area.left; i < area.right; i++) {
for (int j = area.top; j < area.bottom; j++) {
cell = i + j*Dungeon.level.width();
if (cur[cell] > 0) {
off[pos] = cur[pos]; off[cell] = cur[cell];
volume += off[pos]; volume += off[cell];
if (map[pos] == Terrain.EMBERS) { if (map[cell] == Terrain.EMBERS) {
map[pos] = Terrain.GRASS; map[cell] = Terrain.GRASS;
regrowth = true; GameScene.updateMap(cell);
}
visible = visible || Dungeon.visible[cell];
} else {
off[cell] = 0;
} }
visible = visible || Dungeon.visible[pos];
} else {
off[pos] = 0;
} }
} }
@ -68,10 +68,6 @@ public class Foliage extends Blob {
Buff.affect( hero, Shadows.class ).prolong(); Buff.affect( hero, Shadows.class ).prolong();
} }
if (regrowth) {
GameScene.updateMap();
}
if (visible) { if (visible) {
Journal.add( Journal.Feature.GARDEN ); Journal.add( Journal.Feature.GARDEN );
} }

View File

@ -41,27 +41,20 @@ public class GooWarn extends Blob {
@Override @Override
protected void evolve() { protected void evolve() {
for (int i = 0; i < Dungeon.level.length(); i++) {
int offv = cur[i] > 0 ? cur[i] - 1 : 0; int cell;
off[i] = offv;
if (offv > 0) { for (int i = area.left; i < area.right; i++){
volume += offv; for (int j = area.top; j < area.bottom; j++){
cell = i + j*Dungeon.level.width();
off[cell] = cur[cell] > 0 ? cur[cell] - 1 : 0;
if (off[cell] > 0) {
volume += off[cell];
}
} }
} }
}
public void seed(Level level, int cell, int amount ) {
if (cur == null) cur = new int[level.length()];
if (off == null) off = new int[cur.length];
int diff = amount - cur[cell];
if (diff > 0) {
cur[cell] = amount;
volume += diff;
}
} }
@Override @Override

View File

@ -36,10 +36,15 @@ public class ParalyticGas extends Blob {
super.evolve(); super.evolve();
Char ch; Char ch;
for (int i = 0; i < Dungeon.level.length(); i++) { int cell;
if (cur[i] > 0 && (ch = Actor.findChar( i )) != null) {
if (!ch.immunities().contains(this.getClass())) for (int i = area.left; i < area.right; i++) {
Buff.prolong( ch, Paralysis.class, Paralysis.duration( ch ) ); for (int j = area.top; j < area.bottom; j++) {
cell = i + j * Dungeon.level.width();
if (cur[cell] > 0 && (ch = Actor.findChar(cell)) != null) {
if (!ch.immunities().contains(this.getClass()))
Buff.prolong(ch, Paralysis.class, Paralysis.duration(ch));
}
} }
} }
} }

View File

@ -38,33 +38,32 @@ public class Regrowth extends Blob {
super.evolve(); super.evolve();
if (volume > 0) { if (volume > 0) {
int cell;
for (int i=0; i < Dungeon.level.length(); i++) { for (int i = area.left; i < area.right; i++) {
if (off[i] > 0) { for (int j = area.top; j < area.bottom; j++) {
int c = Dungeon.level.map[i]; cell = i + j*Dungeon.level.width();
int c1 = c; if (off[cell] > 0) {
if (c == Terrain.EMPTY || c == Terrain.EMBERS || c == Terrain.EMPTY_DECO) { int c = Dungeon.level.map[cell];
c1 = cur[i] > 9 ? Terrain.HIGH_GRASS : Terrain.GRASS; int c1 = c;
} else if (c == Terrain.GRASS && cur[i] > 9 && Dungeon.level.plants.get(i) == null ) { if (c == Terrain.EMPTY || c == Terrain.EMBERS || c == Terrain.EMPTY_DECO) {
c1 = Terrain.HIGH_GRASS; c1 = cur[cell] > 9 ? Terrain.HIGH_GRASS : Terrain.GRASS;
} } else if (c == Terrain.GRASS && cur[cell] > 9 && Dungeon.level.plants.get(cell) == null ) {
c1 = Terrain.HIGH_GRASS;
if (c1 != c) {
Level.set( i, Terrain.HIGH_GRASS );
Dungeon.observe();
GameScene.updateMap( i );
if (Dungeon.visible[i]) {
GameScene.discoverTile( i, c );
} }
}
Char ch = Actor.findChar( i ); if (c1 != c) {
if (ch != null && cur[i] > 1) { Level.set( cell, c1 );
Buff.prolong( ch, Roots.class, TICK ); GameScene.updateMap( cell );
}
Char ch = Actor.findChar( cell );
if (ch != null && off[cell] > 1) {
Buff.prolong( ch, Roots.class, TICK );
}
} }
} }
} }
Dungeon.observe();
} }
} }

View File

@ -25,6 +25,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Paralysis; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Paralysis;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Vertigo;
import com.shatteredpixel.shatteredpixeldungeon.effects.BlobEmitter; import com.shatteredpixel.shatteredpixeldungeon.effects.BlobEmitter;
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
@ -36,10 +37,15 @@ public class StenchGas extends Blob {
super.evolve(); super.evolve();
Char ch; Char ch;
for (int i = 0; i < Dungeon.level.length(); i++) { int cell;
if (cur[i] > 0 && (ch = Actor.findChar(i)) != null) {
if (!ch.immunities().contains(this.getClass())) for (int i = area.left; i < area.right; i++){
Buff.prolong( ch, Paralysis.class, Paralysis.duration( ch )/5 ); for (int j = area.top; j < area.bottom; j++){
cell = i + j*Dungeon.level.width();
if (cur[cell] > 0 && (ch = Actor.findChar( cell )) != null) {
if (!ch.immunities().contains(this.getClass()))
Buff.prolong( ch, Paralysis.class, Paralysis.duration( ch )/5 );
}
} }
} }
} }

View File

@ -40,15 +40,19 @@ public class ToxicGas extends Blob implements Hero.Doom {
int levelDamage = 5 + Dungeon.depth * 5; int levelDamage = 5 + Dungeon.depth * 5;
Char ch; Char ch;
for (int i=0; i < Dungeon.level.length(); i++) { int cell;
if (cur[i] > 0 && (ch = Actor.findChar( i )) != null) {
int damage = (ch.HT + levelDamage) / 40; for (int i = area.left; i < area.right; i++){
if (Random.Int( 40 ) < (ch.HT + levelDamage) % 40) { for (int j = area.top; j < area.bottom; j++){
damage++; cell = i + j*Dungeon.level.width();
if (cur[cell] > 0 && (ch = Actor.findChar( cell )) != null) {
int damage = (ch.HT + levelDamage) / 40;
if (Random.Int( 40 ) < (ch.HT + levelDamage) % 40) {
damage++;
}
ch.damage( damage, this );
} }
ch.damage( damage, this );
} }
} }
} }

View File

@ -42,10 +42,15 @@ public class VenomGas extends Blob {
strength = 0; strength = 0;
} else { } else {
Char ch; Char ch;
for (int i = 0; i < Dungeon.level.length(); i++) { int cell;
if (cur[i] > 0 && (ch = Actor.findChar(i)) != null) {
if (!ch.immunities().contains(this.getClass())) for (int i = area.left; i < area.right; i++){
Buff.affect(ch, Venom.class).set(2f, strength); for (int j = area.top; j < area.bottom; j++){
cell = i + j*Dungeon.level.width();
if (cur[cell] > 0 && (ch = Actor.findChar( cell )) != null) {
if (!ch.immunities().contains(this.getClass()))
Buff.affect(ch, Venom.class).set(2f, strength);
}
} }
} }
} }

View File

@ -24,6 +24,7 @@ import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Paralysis;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Roots; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Roots;
import com.shatteredpixel.shatteredpixeldungeon.effects.BlobEmitter; import com.shatteredpixel.shatteredpixeldungeon.effects.BlobEmitter;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.WebParticle; import com.shatteredpixel.shatteredpixeldungeon.effects.particles.WebParticle;
@ -35,18 +36,21 @@ public class Web extends Blob {
@Override @Override
protected void evolve() { protected void evolve() {
for (int i = 0; i < Dungeon.level.length(); i++) { int cell;
int offv = cur[i] > 0 ? cur[i] - 1 : 0; for (int i = area.left; i < area.right; i++){
off[i] = offv; for (int j = area.top; j < area.bottom; j++){
cell = i + j*Dungeon.level.width();
off[cell] = cur[cell] > 0 ? cur[cell] - 1 : 0;
if (offv > 0) { if (off[cell] > 0) {
volume += offv; volume += off[cell];
Char ch = Actor.findChar( i ); Char ch = Actor.findChar( cell );
if (ch != null) { if (ch != null) {
Buff.prolong( ch, Roots.class, TICK ); Buff.prolong( ch, Roots.class, TICK );
}
} }
} }
} }
@ -59,16 +63,6 @@ public class Web extends Blob {
emitter.pour( WebParticle.FACTORY, 0.4f ); emitter.pour( WebParticle.FACTORY, 0.4f );
} }
public void seed(Level level, int cell, int amount ) {
if (cur == null) cur = new int[level.length()];
if (off == null) off = new int[cur.length];
int diff = amount - cur[cell];
if (diff > 0) {
cur[cell] = amount;
volume += diff;
}
}
@Override @Override
public String tileDesc() { public String tileDesc() {
return Messages.get(this, "desc"); return Messages.get(this, "desc");

View File

@ -52,6 +52,7 @@ public class WellWater extends Blob {
@Override @Override
protected void evolve() { protected void evolve() {
volume = off[pos] = cur[pos]; volume = off[pos] = cur[pos];
area.union(pos%Dungeon.level.width(), pos/Dungeon.level.width());
if (Dungeon.visible[pos]) { if (Dungeon.visible[pos]) {
if (this instanceof WaterOfAwareness) { if (this instanceof WaterOfAwareness) {
@ -125,11 +126,14 @@ public class WellWater extends Blob {
@Override @Override
public void seed( Level level, int cell, int amount ) { public void seed( Level level, int cell, int amount ) {
if (cur == null) cur = new int[level.length()]; super.seed(level, cell, amount);
if (off == null) off = new int[cur.length];
cur[pos] = 0; cur[pos] = 0;
pos = cell; pos = cell;
volume = cur[pos] = amount; volume = cur[pos] = amount;
area.setEmpty();
area.union(cell%level.width(), cell/level.width());
} }
public static void affectCell( int cell ) { public static void affectCell( int cell ) {

View File

@ -45,14 +45,21 @@ public class BlobEmitter extends Emitter {
return; return;
} }
if (blob.area.isEmpty())
blob.setupArea();
int[] map = blob.cur; int[] map = blob.cur;
float size = DungeonTilemap.SIZE; float size = DungeonTilemap.SIZE;
for (int i=0; i < Dungeon.level.length(); i++) { int cell;
if (map[i] > 0 && Dungeon.visible[i]) { for (int i = blob.area.left; i < blob.area.right; i++) {
float x = ((i % Dungeon.level.width()) + Random.Float()) * size; for (int j = blob.area.top; j < blob.area.bottom; j++) {
float y = ((i / Dungeon.level.width()) + Random.Float()) * size; cell = i + j*Dungeon.level.width();
factory.emit( this, index, x, y ); if (map[cell] > 0 && Dungeon.visible[cell]) {
float x = (i + Random.Float()) * size;
float y = (j + Random.Float()) * size;
factory.emit(this, index, x, y);
}
} }
} }
} }