v0.5.0: more refactoring and improvements to the dungeon tilemaps

This commit is contained in:
Evan Debenham 2016-12-11 01:17:03 -05:00
parent 47fafadade
commit 9472cd2953
7 changed files with 166 additions and 209 deletions

View File

@ -25,6 +25,7 @@ import android.opengl.GLES20;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Badges;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.tiles.DungeonTerrainTilemap;
import com.shatteredpixel.shatteredpixeldungeon.tiles.DungeonTilemap;
import com.shatteredpixel.shatteredpixeldungeon.FogOfWar;
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
@ -110,7 +111,7 @@ public class GameScene extends PixelScene {
static GameScene scene;
private SkinnedBlock water;
private DungeonTilemap tiles;
private DungeonTerrainTilemap tiles;
private TerrainFeaturesTilemap terrainFeatures;
private DungeonWallsTilemap walls;
private FogOfWar fog;
@ -185,7 +186,7 @@ public class GameScene extends PixelScene {
DungeonTileSheet.setupVariance(Dungeon.level.map.length, Dungeon.seedCurDepth());
tiles = new DungeonTilemap();
tiles = new DungeonTerrainTilemap();
terrain.add( tiles );
ripples = new Group();

View File

@ -0,0 +1,71 @@
package com.shatteredpixel.shatteredpixeldungeon.tiles;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.watabou.noosa.Image;
import com.watabou.utils.PathFinder;
public class DungeonTerrainTilemap extends DungeonTilemap {
static DungeonTerrainTilemap instance;
public DungeonTerrainTilemap(){
super(Dungeon.level.tilesTex());
map( Dungeon.level.map, Dungeon.level.width() );
instance = this;
}
@Override
protected int getTileVisual(int pos, int tile, boolean flat) {
int visual = DungeonTileSheet.directVisuals.get(tile, -1);
if (visual != -1) return DungeonTileSheet.getVisualWithAlts(visual, pos);
if (tile == Terrain.WATER) {
return DungeonTileSheet.stitchWaterTile(
map[pos + PathFinder.CIRCLE4[0]],
map[pos + PathFinder.CIRCLE4[1]],
map[pos + PathFinder.CIRCLE4[2]],
map[pos + PathFinder.CIRCLE4[3]]
);
} else if (tile == Terrain.CHASM) {
return DungeonTileSheet.stitchChasmTile( pos > mapWidth ? map[pos - mapWidth] : -1);
}
if (!flat) {
if ((DungeonTileSheet.doorTiles.contains(tile))) {
return DungeonTileSheet.getRaisedDoorTile(tile, map[pos - mapWidth]);
} else if (tile == Terrain.WALL || tile == Terrain.WALL_DECO){
return DungeonTileSheet.getRaisedWallTile(
tile,
pos,
(pos+1) % mapWidth != 0 ? map[pos + 1] : -1,
pos + mapWidth < size ? map[pos + mapWidth] : -1,
pos % mapWidth != 0 ? map[pos - 1] : -1
);
} else {
return -1;
}
} else {
return DungeonTileSheet.getVisualWithAlts(
DungeonTileSheet.directFlatVisuals.get(tile),
pos);
}
}
public static Image tile(int pos, int tile ) {
Image img = new Image( instance.texture );
img.frame( instance.tileset.get( instance.getTileVisual( pos, tile, true ) ) );
return img;
}
@Override
protected boolean needsRender(int pos) {
return (Level.discoverable[pos] || data[pos] == DungeonTileSheet.CHASM)
&& data[pos] != DungeonTileSheet.WATER;
}
}

View File

@ -37,11 +37,14 @@ public class DungeonTileSheet {
return x + WIDTH*y;
}
//used in cases like map-edge decision making.
public static final int NULL_TILE = -1;
/**********************************************************************
* Floor Tiles
************************/
**********************************************************************/
private static final int GROUND = xy(1, 1); //32 slots
public static final int FLOOR = GROUND +0;
@ -94,7 +97,7 @@ public class DungeonTileSheet {
);
//+1 for ground above, +2 for ground right, +4 for ground below, +8 for ground left.
public static int getWaterTile(int top, int right, int bottom, int left){
public static int stitchWaterTile(int top, int right, int bottom, int left){
int result = WATER;
if (waterStitcheable.contains(top)) result += 1;
if (waterStitcheable.contains(right)) result += 2;
@ -144,7 +147,9 @@ public class DungeonTileSheet {
chasmStitcheable.put( Terrain.WATER, CHASM_WATER );
}
public static int stitchChasmTile(int above){
return chasmStitcheable.get(above, CHASM);
}
/**********************************************************************
Flat Wall Tiles
@ -165,9 +170,6 @@ public class DungeonTileSheet {
public static final int LOCKED_EXIT = FLAT_DOORS+4;
public static SparseIntArray defaultFlatVisuals = new SparseIntArray(32);
/**********************************************************************
* Raised Wall Tiles, Lower Layer
@ -183,6 +185,26 @@ public class DungeonTileSheet {
public static final int RAISED_WALL_ALT = RAISED_WALLS+16;
public static final int RAISED_WALL_DECO_ALT = RAISED_WALLS+20;
//These tiles count as wall for the purposes of wall stitching
public static List wallStitcheable = Arrays.asList(
Terrain.WALL, Terrain.WALL_DECO, Terrain.SECRET_DOOR,
Terrain.LOCKED_EXIT, Terrain.UNLOCKED_EXIT, NULL_TILE
);
public static int getRaisedWallTile(int tile, int pos, int right, int below, int left){
int result;
if (doorTiles.contains(below)) result = RAISED_WALL_DOOR;
else if (tile == Terrain.WALL) result = RAISED_WALL;
else if (tile == Terrain.WALL_DECO) result = RAISED_WALL_DECO;
else return -1;
result = getVisualWithAlts(result, pos);
if (wallStitcheable.contains(right)) result += 1;
if (wallStitcheable.contains(left)) result += 2;
return result;
}
private static final int RAISED_DOORS = xy(1, 10); //16 slots
public static final int RAISED_DOOR = RAISED_DOORS+0;
public static final int RAISED_DOOR_OPEN = RAISED_DOORS+1;
@ -191,10 +213,16 @@ public class DungeonTileSheet {
public static final int RAISED_DOOR_SIDEWAYS = RAISED_DOORS+3;
//These tiles count as wall for the purposes of wall stitching
public static List wallStitcheable = Arrays.asList(
Terrain.WALL, Terrain.WALL_DECO, Terrain.SECRET_DOOR,
Terrain.LOCKED_EXIT, Terrain.UNLOCKED_EXIT
public static int getRaisedDoorTile(int tile, int below){
if (wallStitcheable.contains(below)) return RAISED_DOOR_SIDEWAYS;
else if (tile == Terrain.DOOR) return DungeonTileSheet.RAISED_DOOR;
else if (tile == Terrain.OPEN_DOOR) return DungeonTileSheet.RAISED_DOOR_OPEN;
else if (tile == Terrain.LOCKED_DOOR) return DungeonTileSheet.RAISED_DOOR_LOCKED;
else return -1;
}
public static List doorTiles = Arrays.asList(
Terrain.DOOR, Terrain.LOCKED_DOOR, Terrain.OPEN_DOOR
);
@ -203,21 +231,42 @@ public class DungeonTileSheet {
* Raised Wall Tiles, Upper Layer
**********************************************************************/
//+1 for wall right, +2 for wall right-below, +4 for wall left-below, +8 for wall left.
//+1 for open right, +2 for open right-below, +4 for open left-below, +8 for open left.
public static final int WALLS_INTERNAL = xy(1, 12); //16 slots
//+1 for walls to the down-right, +2 for walls to the down-left
public static int stitchInternalWallTile(int right, int rightBelow, int leftBelow, int left){
int result = WALLS_INTERNAL;
if (!wallStitcheable.contains(right)) result += 1;
if (!wallStitcheable.contains(rightBelow)) result += 2;
if (!wallStitcheable.contains(leftBelow)) result += 4;
if (!wallStitcheable.contains(left)) result += 8;
return result;
}
//+1 for open to the down-right, +2 for open to the down-left
private static final int WALLS_OVERHANG = xy(1, 13); //16 slots
public static final int WALL_OVERHANG = WALLS_OVERHANG+0;
public static final int DOOR_SIDEWAYS_OVERHANG = WALL_OVERHANG+4;
public static final int DOOR_SIDEWAYS_OVERHANG_OPEN = WALL_OVERHANG+8;
public static int stitchWallOverhangTile(int tile, int rightBelow, int leftBelow){
int visual;
if (tile == Terrain.DOOR || tile == Terrain.LOCKED_DOOR) visual = DOOR_SIDEWAYS_OVERHANG;
else if (tile == Terrain.OPEN_DOOR) visual = DOOR_SIDEWAYS_OVERHANG_OPEN;
else visual = WALL_OVERHANG;
if (!wallStitcheable.contains(rightBelow)) visual += 1;
if (!wallStitcheable.contains(leftBelow)) visual += 2;
return visual;
}
//no attachment to adjacent walls
public static final int DOOR_OVERHANG = WALL_OVERHANG+12;
public static final int DOOR_OVERHANG_OPEN = WALL_OVERHANG+13;
public static final int DOOR_SIDEWAYS = WALL_OVERHANG+14;
public static final int DOOR_SIDEWAYS_LOCKED = WALL_OVERHANG+15;
/**********************************************************************
* Logic for the selection of tile visuals
**********************************************************************/

View File

@ -21,8 +21,6 @@
package com.shatteredpixel.shatteredpixeldungeon.tiles;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.watabou.noosa.Image;
import com.watabou.noosa.TextureFilm;
import com.watabou.noosa.Tilemap;
@ -31,22 +29,14 @@ import com.watabou.utils.PathFinder;
import com.watabou.utils.Point;
import com.watabou.utils.PointF;
public class DungeonTilemap extends Tilemap {
public abstract class DungeonTilemap extends Tilemap {
public static final int SIZE = 16;
private static DungeonTilemap instance;
protected int[] map;
private int[] map;
public DungeonTilemap() {
super(
Dungeon.level.tilesTex(),
new TextureFilm( Dungeon.level.tilesTex(), SIZE, SIZE ) );
map( Dungeon.level.map, Dungeon.level.width() );
instance = this;
public DungeonTilemap(String tex) {
super(tex, new TextureFilm( tex, SIZE, SIZE ) );
}
@Override
@ -80,56 +70,7 @@ public class DungeonTilemap extends Tilemap {
}
}
private int getTileVisual(int pos, int tile, boolean flat) {
int visual = DungeonTileSheet.directVisuals.get(tile, -1);
if (tile == Terrain.WATER) {
return DungeonTileSheet.getWaterTile(
map[pos + PathFinder.CIRCLE4[0]],
map[pos + PathFinder.CIRCLE4[1]],
map[pos + PathFinder.CIRCLE4[2]],
map[pos + PathFinder.CIRCLE4[3]]
);
} else if (tile == Terrain.CHASM && pos >= mapWidth) {
return DungeonTileSheet.chasmStitcheable.get(map[pos - mapWidth], DungeonTileSheet.CHASM);
}
if (!flat) {
if ((tile == Terrain.DOOR || tile == Terrain.LOCKED_DOOR || tile == Terrain.OPEN_DOOR) && map[pos - mapWidth] == Terrain.WALL) {
return DungeonTileSheet.RAISED_DOOR_SIDEWAYS;
} else if (tile == Terrain.DOOR) {
return DungeonTileSheet.RAISED_DOOR;
} else if (tile == Terrain.OPEN_DOOR) {
return DungeonTileSheet.RAISED_DOOR_OPEN;
} else if (tile == Terrain.LOCKED_DOOR) {
return DungeonTileSheet.RAISED_DOOR_LOCKED;
} else if (tile == Terrain.WALL || tile == Terrain.WALL_DECO){
if (tile == Terrain.WALL) {
if (pos + mapWidth < size && (map[pos + mapWidth] == Terrain.DOOR || map[pos + mapWidth] == Terrain.LOCKED_DOOR || map[pos + mapWidth] == Terrain.OPEN_DOOR)){
visual = DungeonTileSheet.RAISED_WALL_DOOR;
} else {
visual = DungeonTileSheet.RAISED_WALL;
}
} else
visual = DungeonTileSheet.RAISED_WALL_DECO;
visual = DungeonTileSheet.getVisualWithAlts(visual, pos);
if (pos % mapWidth != 0 && !DungeonTileSheet.wallStitcheable.contains(map[pos - 1]))
visual += 2;
if (pos % mapWidth != mapWidth-1 && !DungeonTileSheet.wallStitcheable.contains(map[pos + 1]))
visual += 1;
return visual;
}
} else {
if (visual == -1)
visual = DungeonTileSheet.directFlatVisuals.get(tile);
}
return DungeonTileSheet.getVisualWithAlts(visual, pos);
}
protected abstract int getTileVisual(int pos, int tile, boolean flat);
public int screenToTile(int x, int y ) {
Point p = camera().screenToCamera( x, y ).
@ -151,7 +92,8 @@ public class DungeonTilemap extends Tilemap {
public void discover( int pos, int oldValue ) {
final Image tile = tile( pos, oldValue );
final Image tile = new Image( texture );
tile.frame( tileset.get( getTileVisual( pos, oldValue, false)));
tile.point( tileToWorld( pos ) );
parent.add( tile );
@ -174,20 +116,9 @@ public class DungeonTilemap extends Tilemap {
(pos / Dungeon.level.width() + 0.5f) * SIZE );
}
public static Image tile( int pos, int tile ) {
Image img = new Image( instance.texture );
img.frame( instance.tileset.get( instance.getTileVisual( pos, tile, true ) ) );
return img;
}
@Override
public boolean overlapsScreenPoint( int x, int y ) {
return true;
}
@Override
protected boolean needsRender(int pos) {
return (Level.discoverable[pos] || data[pos] == DungeonTileSheet.CHASM)
&& data[pos] != DungeonTileSheet.WATER;
}
}

View File

@ -31,56 +31,17 @@ import com.watabou.utils.Random;
import java.util.Arrays;
import java.util.List;
public class DungeonWallsTilemap extends Tilemap {
public static final int SIZE = 16;
private static DungeonWallsTilemap instance;
private int[] map;
public class DungeonWallsTilemap extends DungeonTilemap {
public DungeonWallsTilemap(){
super(
Dungeon.level.tilesTex(),
new TextureFilm( Dungeon.level.tilesTex(), SIZE, SIZE ) );
super(Dungeon.level.tilesTex());
map( Dungeon.level.map, Dungeon.level.width() );
instance = this;
}
@Override
//we need to retain two arrays, map is the dungeon tilemap which we can reference.
// Data is our own internal image representation of the tiles, which may differ.
public void map(int[] data, int cols) {
map = data;
super.map(new int[data.length], cols);
}
protected int getTileVisual(int pos, int tile, boolean flat){
@Override
public synchronized void updateMap() {
super.updateMap();
for (int i = 0; i < data.length; i++)
data[i] = getTileVisual(i ,map[i]);
}
@Override
public synchronized void updateMapCell(int cell) {
//update in a 3x3 grid to account for neighbours which might also be affected
if (Dungeon.level.insideMap(cell)) {
super.updateMapCell(cell - mapWidth - 1);
super.updateMapCell(cell + mapWidth + 1);
for (int i : PathFinder.NEIGHBOURS9)
data[cell + i] = getTileVisual(cell + i, map[cell + i]);
//unless we're at the level's edge, then just do the one tile.
} else {
super.updateMapCell(cell);
data[cell] = getTileVisual(cell, map[cell]);
}
}
private int getTileVisual(int pos, int tile){
if (flat) return -1;
if (DungeonTileSheet.wallStitcheable.contains(tile)) {
if (pos + mapWidth < size && !DungeonTileSheet.wallStitcheable.contains(map[pos + mapWidth])){
@ -89,38 +50,26 @@ public class DungeonWallsTilemap extends Tilemap {
return DungeonTileSheet.DOOR_SIDEWAYS;
} else if (map[pos + mapWidth] == Terrain.LOCKED_DOOR){
return DungeonTileSheet.DOOR_SIDEWAYS_LOCKED;
} else {
return -1;
}
} else {
//otherwise, need to stitch with right, bottom-right, bottom-left, and left.
int visual = DungeonTileSheet.WALLS_INTERNAL;
if (pos % mapWidth != 0 && !DungeonTileSheet.wallStitcheable.contains(map[pos - 1]))
visual += 8;
if (pos % mapWidth != 0 && pos + mapWidth < size && !DungeonTileSheet.wallStitcheable.contains(map[pos - 1 + mapWidth]))
visual += 4;
if ((pos+1) % mapWidth != 0 && pos + mapWidth < size && !DungeonTileSheet.wallStitcheable.contains(map[pos + 1 + mapWidth]))
visual += 2;
if ((pos+1) % mapWidth != 0 && !DungeonTileSheet.wallStitcheable.contains(map[pos + 1]))
visual += 1;
return visual;
return DungeonTileSheet.stitchInternalWallTile(
(pos+1) % mapWidth != 0 ? map[pos + 1] : -1,
(pos+1) % mapWidth != 0 && pos + mapWidth < size ? map[pos + 1 + mapWidth] : -1,
pos % mapWidth != 0 && pos + mapWidth < size ? map[pos - 1 + mapWidth] : -1,
pos % mapWidth != 0 ? map[pos - 1] : -1
);
}
} else if (Dungeon.level.insideMap(pos) && DungeonTileSheet.wallStitcheable.contains(map[pos+mapWidth])) {
int visual;
if (map[pos] == Terrain.DOOR || map[pos] == Terrain.LOCKED_DOOR)
visual = DungeonTileSheet.DOOR_SIDEWAYS_OVERHANG;
else if (map[pos] == Terrain.OPEN_DOOR)
visual = DungeonTileSheet.DOOR_SIDEWAYS_OVERHANG_OPEN;
else
visual = DungeonTileSheet.WALL_OVERHANG;
if (!DungeonTileSheet.wallStitcheable.contains(map[pos - 1 + mapWidth]))
visual += 2;
if (!DungeonTileSheet.wallStitcheable.contains(map[pos + 1 + mapWidth]))
visual += 1;
return visual;
return DungeonTileSheet.stitchWallOverhangTile(
tile,
map[pos + 1 + mapWidth],
map[pos - 1 + mapWidth]
);
} else if (Dungeon.level.insideMap(pos) && (map[pos+mapWidth] == Terrain.DOOR || map[pos+mapWidth] == Terrain.LOCKED_DOOR) ) {
return DungeonTileSheet.DOOR_OVERHANG;

View File

@ -34,19 +34,15 @@ import com.watabou.utils.PointF;
import com.watabou.utils.SparseArray;
//TODO add in a proper set of vfx for plants growing/withering, grass burning, discovering traps
public class TerrainFeaturesTilemap extends Tilemap {
public static final int SIZE = 16;
public class TerrainFeaturesTilemap extends DungeonTilemap {
private static TerrainFeaturesTilemap instance;
private int[] map;
private SparseArray<Plant> plants;
private SparseArray<Trap> traps;
public TerrainFeaturesTilemap(SparseArray<Plant> plants, SparseArray<Trap> traps) {
super(Assets.TERRAIN_FEATURES, new TextureFilm( Assets.TERRAIN_FEATURES, SIZE, SIZE ));
super(Assets.TERRAIN_FEATURES);
this.plants = plants;
this.traps = traps;
@ -56,38 +52,7 @@ public class TerrainFeaturesTilemap extends Tilemap {
instance = this;
}
@Override
//we need to retain two arrays, map is the dungeon tilemap which we can reference.
// Data is our own internal image representation of the tiles, which may differ.
public void map(int[] data, int cols) {
map = data;
super.map(new int[data.length], cols);
}
@Override
public synchronized void updateMap() {
super.updateMap();
for (int i = 0; i < data.length; i++)
data[i] = getTileVisual(i ,map[i]);
}
@Override
public synchronized void updateMapCell(int cell) {
//update in a 3x3 grid to account for neighbours which might also be affected
if (Dungeon.level.insideMap(cell)) {
super.updateMapCell(cell - mapWidth - 1);
super.updateMapCell(cell + mapWidth + 1);
for (int i : PathFinder.NEIGHBOURS9)
data[cell + i] = getTileVisual(cell + i, map[cell + i]);
//unless we're at the level's edge, then just do the one tile.
} else {
super.updateMapCell(cell);
data[cell] = getTileVisual(cell, map[cell]);
}
}
private int getTileVisual(int pos, int tile){
protected int getTileVisual(int pos, int tile, boolean flat){
if (traps.get(pos) != null){
Trap trap = traps.get(pos);
if (!trap.visible)
@ -113,7 +78,7 @@ public class TerrainFeaturesTilemap extends Tilemap {
public static Image tile(int pos, int tile ) {
Image img = new Image( instance.texture );
img.frame( instance.tileset.get( instance.getTileVisual( pos, tile ) ) );
img.frame( instance.tileset.get( instance.getTileVisual( pos, tile, true ) ) );
return img;
}
@ -134,16 +99,6 @@ public class TerrainFeaturesTilemap extends Tilemap {
} );
}
@Override
public boolean overlapsPoint( float x, float y ) {
return true;
}
@Override
public boolean overlapsScreenPoint( int x, int y ) {
return true;
}
@Override
protected boolean needsRender(int pos) {
return data[pos] != -1;

View File

@ -21,6 +21,7 @@
package com.shatteredpixel.shatteredpixeldungeon.windows;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.tiles.DungeonTerrainTilemap;
import com.shatteredpixel.shatteredpixeldungeon.tiles.DungeonTilemap;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
@ -76,7 +77,7 @@ public class WndInfoCell extends Window {
water.frame(0, 0, DungeonTilemap.SIZE, DungeonTilemap.SIZE);
titlebar.icon(water);
} else {
titlebar.icon(DungeonTilemap.tile( cell, tile ));
titlebar.icon(DungeonTerrainTilemap.tile( cell, tile ));
}
titlebar.label(Dungeon.level.tileName(tile));
desc += Dungeon.level.tileDesc(tile);