Add support for 2x2 autotiles | create connect auto tile option #3
This commit is contained in:
@@ -6,6 +6,7 @@ import com.bartlomiejpluta.base.engine.gui.asset.WidgetDefinitionAsset;
|
||||
import com.bartlomiejpluta.base.engine.project.model.Project;
|
||||
import com.bartlomiejpluta.base.engine.world.animation.asset.AnimationAsset;
|
||||
import com.bartlomiejpluta.base.engine.world.autotile.asset.AutoTileSetAsset;
|
||||
import com.bartlomiejpluta.base.engine.world.autotile.model.AutoTileLayout;
|
||||
import com.bartlomiejpluta.base.engine.world.character.asset.CharacterSetAsset;
|
||||
import com.bartlomiejpluta.base.engine.world.icon.asset.IconSetAsset;
|
||||
import com.bartlomiejpluta.base.engine.world.image.asset.ImageAsset;
|
||||
@@ -42,7 +43,7 @@ public class ProtobufProjectDeserializer extends ProjectDeserializer {
|
||||
}
|
||||
|
||||
private AutoTileSetAsset parseAutoTileSetAsset(ProjectProto.AutoTileSetAsset proto) {
|
||||
return new AutoTileSetAsset(proto.getUid(), proto.getSource(), proto.getRows(), proto.getColumns());
|
||||
return new AutoTileSetAsset(proto.getUid(), proto.getSource(), proto.getRows(), proto.getColumns(), AutoTileLayout.valueOf(proto.getLayout().name()));
|
||||
}
|
||||
|
||||
private TileSetAsset parseTileSetAsset(ProjectProto.TileSetAsset proto) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.bartlomiejpluta.base.engine.world.autotile.asset;
|
||||
|
||||
import com.bartlomiejpluta.base.engine.common.asset.Asset;
|
||||
import com.bartlomiejpluta.base.engine.world.autotile.model.AutoTileLayout;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
|
||||
@@ -8,10 +9,13 @@ import lombok.NonNull;
|
||||
public class AutoTileSetAsset extends Asset {
|
||||
private final int rows;
|
||||
private final int columns;
|
||||
private final AutoTileLayout layout;
|
||||
|
||||
public AutoTileSetAsset(@NonNull String uid, @NonNull String source, int rows, int columns) {
|
||||
|
||||
public AutoTileSetAsset(@NonNull String uid, @NonNull String source, int rows, int columns, @NonNull AutoTileLayout layout) {
|
||||
super(uid, source);
|
||||
this.rows = rows;
|
||||
this.columns = columns;
|
||||
this.layout = layout;
|
||||
}
|
||||
}
|
||||
@@ -54,8 +54,8 @@ public class DefaultAutoTileSetManager implements AutoTileManager {
|
||||
}
|
||||
|
||||
var source = configuration.projectFile("autotiles", asset.getSource());
|
||||
var texture = textureManager.loadTexture(source, asset.getRows() * AutoTileSet.ROWS, asset.getColumns() * AutoTileSet.COLUMNS);
|
||||
autoTile = new AutoTileSet(texture, mesh, asset.getRows(), asset.getColumns());
|
||||
var texture = textureManager.loadTexture(source, asset.getRows() * asset.getLayout().getRows() * 2, asset.getColumns() * asset.getLayout().getColumns() * 2);
|
||||
autoTile = new AutoTileSet(texture, mesh, asset.getRows(), asset.getColumns(), asset.getLayout());
|
||||
log.info("Loading auto tile set from assets to cache under the key: [{}]", uid);
|
||||
autoTiles.put(uid, autoTile);
|
||||
}
|
||||
|
||||
@@ -1,2 +1,14 @@
|
||||
package com.bartlomiejpluta.base.engine.world.autotile.model;public enum AutoTileLayout {
|
||||
package com.bartlomiejpluta.base.engine.world.autotile.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum AutoTileLayout {
|
||||
LAYOUT_2X2(2, 2),
|
||||
LAYOUT_2X3(2, 3);
|
||||
|
||||
private final int columns;
|
||||
private final int rows;
|
||||
}
|
||||
|
||||
@@ -12,30 +12,36 @@ import java.util.LinkedList;
|
||||
|
||||
// Algorithm source: https://love2d.org/forums/viewtopic.php?t=7826
|
||||
public class AutoTileSet {
|
||||
public static final int ROWS = 6;
|
||||
public static final int COLUMNS = 4;
|
||||
private static final Vector2ic ISLAND_TILE_2x3 = new Vector2i(0, 0);
|
||||
private static final Vector2ic CROSS_TILE_2x3 = new Vector2i(1, 0);
|
||||
private static final Vector2ic TOP_LEFT_TILE_2x3 = new Vector2i(0, 1);
|
||||
private static final Vector2ic TOP_RIGHT_TILE_2x3 = new Vector2i(1, 1);
|
||||
private static final Vector2ic BOTTOM_LEFT_TILE_2x3 = new Vector2i(0, 2);
|
||||
private static final Vector2ic BOTTOM_RIGHT_TILE_2x3 = new Vector2i(1, 2);
|
||||
|
||||
private static final Vector2ic TOP_LEFT_TILE_2x2 = new Vector2i(0, 0);
|
||||
private static final Vector2ic TOP_RIGHT_TILE_2x2 = new Vector2i(1, 0);
|
||||
private static final Vector2ic BOTTOM_LEFT_TILE_2x2 = new Vector2i(0, 1);
|
||||
private static final Vector2ic BOTTOM_RIGHT_TILE_2x2 = new Vector2i(1, 1);
|
||||
|
||||
private final int textureSubTilesRows;
|
||||
private final int textureSubTilesColumns;
|
||||
|
||||
private static final Vector2ic ISLAND_TILE = new Vector2i(0, 0);
|
||||
private static final Vector2ic CROSS_TILE = new Vector2i(1, 0);
|
||||
private static final Vector2ic TOP_LEFT_TILE = new Vector2i(0, 1);
|
||||
private static final Vector2ic TOP_RIGHT_TILE = new Vector2i(1, 1);
|
||||
private static final Vector2ic BOTTOM_LEFT_TILE = new Vector2i(0, 2);
|
||||
private static final Vector2ic BOTTOM_RIGHT_TILE = new Vector2i(1, 2);
|
||||
|
||||
@Getter
|
||||
private final Vector2ic[][] islandSubTiles;
|
||||
private Vector2ic[][] islandSubTiles;
|
||||
|
||||
@Getter
|
||||
private final Vector2ic[][] topLeftSubTiles;
|
||||
private Vector2ic[][] topLeftSubTiles;
|
||||
|
||||
@Getter
|
||||
private final Vector2ic[][] topRightSubTiles;
|
||||
private Vector2ic[][] topRightSubTiles;
|
||||
|
||||
@Getter
|
||||
private final Vector2ic[][] bottomLeftSubTiles;
|
||||
private Vector2ic[][] bottomLeftSubTiles;
|
||||
|
||||
@Getter
|
||||
private final Vector2ic[][] bottomRightSubTiles;
|
||||
private Vector2ic[][] bottomRightSubTiles;
|
||||
|
||||
@Getter
|
||||
private final Texture texture;
|
||||
@@ -43,20 +49,33 @@ public class AutoTileSet {
|
||||
|
||||
@Getter
|
||||
private final Vector2fc tileSize;
|
||||
|
||||
@Getter
|
||||
private final AutoTileLayout layout;
|
||||
private final int rows;
|
||||
private final int columns;
|
||||
|
||||
@Getter
|
||||
private final int setsCount;
|
||||
|
||||
public AutoTileSet(@NonNull Texture texture, @NonNull Mesh mesh, int rows, int columns) {
|
||||
public AutoTileSet(@NonNull Texture texture, @NonNull Mesh mesh, int rows, int columns, @NonNull AutoTileLayout layout) {
|
||||
this.texture = texture;
|
||||
this.mesh = mesh;
|
||||
this.rows = rows;
|
||||
this.columns = columns;
|
||||
this.tileSize = texture.getSpriteSize();
|
||||
this.layout = layout;
|
||||
this.setsCount = rows * columns;
|
||||
this.textureSubTilesRows = layout.getRows() * 2;
|
||||
this.textureSubTilesColumns = layout.getColumns() * 2;
|
||||
|
||||
switch (layout) {
|
||||
case LAYOUT_2X2 -> init2x2();
|
||||
case LAYOUT_2X3 -> init2x3();
|
||||
}
|
||||
}
|
||||
|
||||
private void init2x3() {
|
||||
var islandSubTiles = new LinkedList<Vector2ic[]>();
|
||||
var topLeftSubTiles = new LinkedList<Vector2ic[]>();
|
||||
var topRightSubTiles = new LinkedList<Vector2ic[]>();
|
||||
@@ -64,11 +83,11 @@ public class AutoTileSet {
|
||||
var bottomRightSubTiles = new LinkedList<Vector2ic[]>();
|
||||
|
||||
for (int setId = 0; setId < setsCount; ++setId) {
|
||||
var crossSubTiles = cutSubTiles(setId, CROSS_TILE);
|
||||
var topLeftTileSubTiles = cutSubTiles(setId, TOP_LEFT_TILE);
|
||||
var topRightTileSubTiles = cutSubTiles(setId, TOP_RIGHT_TILE);
|
||||
var bottomLeftTileSubTiles = cutSubTiles(setId, BOTTOM_LEFT_TILE);
|
||||
var bottomRightTileSubTiles = cutSubTiles(setId, BOTTOM_RIGHT_TILE);
|
||||
var crossSubTiles = cutSubTiles(setId, CROSS_TILE_2x3);
|
||||
var topLeftTileSubTiles = cutSubTiles(setId, TOP_LEFT_TILE_2x3);
|
||||
var topRightTileSubTiles = cutSubTiles(setId, TOP_RIGHT_TILE_2x3);
|
||||
var bottomLeftTileSubTiles = cutSubTiles(setId, BOTTOM_LEFT_TILE_2x3);
|
||||
var bottomRightTileSubTiles = cutSubTiles(setId, BOTTOM_RIGHT_TILE_2x3);
|
||||
|
||||
/*
|
||||
* Indexes:
|
||||
@@ -103,7 +122,7 @@ public class AutoTileSet {
|
||||
var bl2 = bottomRightTileSubTiles[2];
|
||||
var br0 = bottomRightTileSubTiles[3];
|
||||
|
||||
islandSubTiles.add(cutSubTiles(setId, ISLAND_TILE));
|
||||
islandSubTiles.add(cutSubTiles(setId, ISLAND_TILE_2x3));
|
||||
topLeftSubTiles.add(new Vector2ic[]{tl0, tl1, tl2, tl3, tl4});
|
||||
topRightSubTiles.add(new Vector2ic[]{tr0, tr1, tr2, tr3, tr4});
|
||||
bottomLeftSubTiles.add(new Vector2ic[]{bl0, bl1, bl2, bl3, bl4});
|
||||
@@ -117,6 +136,58 @@ public class AutoTileSet {
|
||||
this.bottomRightSubTiles = bottomRightSubTiles.toArray(new Vector2ic[bottomRightSubTiles.size()][]);
|
||||
}
|
||||
|
||||
private void init2x2() {
|
||||
var topLeftSubTiles = new LinkedList<Vector2ic[]>();
|
||||
var topRightSubTiles = new LinkedList<Vector2ic[]>();
|
||||
var bottomLeftSubTiles = new LinkedList<Vector2ic[]>();
|
||||
var bottomRightSubTiles = new LinkedList<Vector2ic[]>();
|
||||
|
||||
for (int setId = 0; setId < setsCount; ++setId) {
|
||||
var topLeftTileSubTiles = cutSubTiles(setId, TOP_LEFT_TILE_2x2);
|
||||
var topRightTileSubTiles = cutSubTiles(setId, TOP_RIGHT_TILE_2x2);
|
||||
var bottomLeftTileSubTiles = cutSubTiles(setId, BOTTOM_LEFT_TILE_2x2);
|
||||
var bottomRightTileSubTiles = cutSubTiles(setId, BOTTOM_RIGHT_TILE_2x2);
|
||||
|
||||
/*
|
||||
* Indexes:
|
||||
* 0 - No connected tiles
|
||||
* 1 - Left tile is connected
|
||||
* 2 - Right tile is connected
|
||||
* 3 - Left, Right, and Center tiles are connected.
|
||||
*/
|
||||
|
||||
var tl0 = topLeftTileSubTiles[0];
|
||||
var tr2 = topLeftTileSubTiles[1];
|
||||
var bl1 = topLeftTileSubTiles[2];
|
||||
var br3 = topLeftTileSubTiles[3];
|
||||
|
||||
var tl1 = topRightTileSubTiles[0];
|
||||
var tr0 = topRightTileSubTiles[1];
|
||||
var bl3 = topRightTileSubTiles[2];
|
||||
var br2 = topRightTileSubTiles[3];
|
||||
|
||||
var tl2 = bottomLeftTileSubTiles[0];
|
||||
var tr3 = bottomLeftTileSubTiles[1];
|
||||
var bl0 = bottomLeftTileSubTiles[2];
|
||||
var br1 = bottomLeftTileSubTiles[3];
|
||||
|
||||
var tl3 = bottomRightTileSubTiles[0];
|
||||
var tr1 = bottomRightTileSubTiles[1];
|
||||
var bl2 = bottomRightTileSubTiles[2];
|
||||
var br0 = bottomRightTileSubTiles[3];
|
||||
|
||||
topLeftSubTiles.add(new Vector2ic[]{tl0, tl1, tl2, tl3});
|
||||
topRightSubTiles.add(new Vector2ic[]{tr0, tr1, tr2, tr3});
|
||||
bottomLeftSubTiles.add(new Vector2ic[]{bl0, bl1, bl2, bl3});
|
||||
bottomRightSubTiles.add(new Vector2ic[]{br0, br1, br2, br3});
|
||||
}
|
||||
|
||||
this.topLeftSubTiles = topLeftSubTiles.toArray(new Vector2ic[topLeftSubTiles.size()][]);
|
||||
this.topRightSubTiles = topRightSubTiles.toArray(new Vector2ic[topRightSubTiles.size()][]);
|
||||
this.bottomLeftSubTiles = bottomLeftSubTiles.toArray(new Vector2ic[bottomLeftSubTiles.size()][]);
|
||||
this.bottomRightSubTiles = bottomRightSubTiles.toArray(new Vector2ic[bottomRightSubTiles.size()][]);
|
||||
}
|
||||
|
||||
private Vector2ic[] cutSubTiles(int setId, Vector2ic tile) {
|
||||
var topLeft = getTile(setId, tile.y() * 2, tile.x() * 2);
|
||||
var topRight = getTile(setId, tile.y() * 2, tile.x() * 2 + 1);
|
||||
@@ -127,7 +198,7 @@ public class AutoTileSet {
|
||||
}
|
||||
|
||||
private Vector2ic getTile(int setId, int row, int column) {
|
||||
return new Vector2i(((setId / columns) * ROWS) + row, ((setId % columns) * COLUMNS) + column);
|
||||
return new Vector2i(((setId / columns) * textureSubTilesRows) + row, ((setId % columns) * textureSubTilesColumns) + column);
|
||||
}
|
||||
|
||||
public AutoTile createTile(int setId) {
|
||||
|
||||
@@ -16,15 +16,17 @@ import java.util.Arrays;
|
||||
public class DefaultAutoTileLayer extends BaseLayer implements AutoTileLayer {
|
||||
private final AutoTileSet autoTileSet;
|
||||
private final AutoTile[][] layer;
|
||||
private boolean animated;
|
||||
private double animationDuration;
|
||||
private final boolean animated;
|
||||
private final double animationDuration;
|
||||
private final boolean connect;
|
||||
private double accumulator;
|
||||
|
||||
public DefaultAutoTileLayer(@NonNull GameMap map, @NonNull AutoTileSet autoTileSet, int rows, int columns, boolean animated, double animationDuration) {
|
||||
public DefaultAutoTileLayer(@NonNull GameMap map, @NonNull AutoTileSet autoTileSet, int rows, int columns, boolean animated, double animationDuration, boolean connect) {
|
||||
super(map);
|
||||
this.autoTileSet = autoTileSet;
|
||||
this.animated = animated;
|
||||
this.animationDuration = animationDuration;
|
||||
this.connect = connect;
|
||||
layer = new AutoTile[rows][columns];
|
||||
Arrays.stream(layer).forEach(tiles -> Arrays.fill(tiles, null));
|
||||
}
|
||||
@@ -48,6 +50,13 @@ public class DefaultAutoTileLayer extends BaseLayer implements AutoTileLayer {
|
||||
}
|
||||
|
||||
private void recalculateTile(Integer setId, int row, int column) {
|
||||
switch(autoTileSet.getLayout()) {
|
||||
case LAYOUT_2X2 -> recalculateTile2x2(setId, row, column);
|
||||
case LAYOUT_2X3 -> recalculateTile2x3(setId, row, column);
|
||||
}
|
||||
}
|
||||
|
||||
private void recalculateTile2x2(Integer setId, int row, int column) {
|
||||
if (layer[row][column] == null) {
|
||||
return;
|
||||
}
|
||||
@@ -58,52 +67,97 @@ public class DefaultAutoTileLayer extends BaseLayer implements AutoTileLayer {
|
||||
var bottomRight = 0;
|
||||
|
||||
var tile = layer[row][column];
|
||||
var centerSetId = tile.getSetId();
|
||||
|
||||
if (animated) {
|
||||
tile.shiftTileSet();
|
||||
}
|
||||
|
||||
// Top
|
||||
if (row > 0 && layer[row - 1][column] != null) {
|
||||
if (row > 0 && (layer[row - 1][column] != null && (connect || layer[row - 1][column].getSetId() == centerSetId))) {
|
||||
topLeft += 2;
|
||||
topRight += 1;
|
||||
}
|
||||
|
||||
// Bottom
|
||||
if (row < map.getRows() - 1 && layer[row + 1][column] != null) {
|
||||
if (row < map.getRows() - 1 && (layer[row + 1][column] != null && (connect || layer[row + 1][column].getSetId() == centerSetId))) {
|
||||
bottomLeft += 1;
|
||||
bottomRight += 2;
|
||||
}
|
||||
|
||||
// Left
|
||||
if (column > 0 && layer[row][column - 1] != null) {
|
||||
if (column > 0 && (layer[row][column - 1] != null && (connect || layer[row][column - 1].getSetId() == centerSetId))) {
|
||||
topLeft += 1;
|
||||
bottomLeft += 2;
|
||||
}
|
||||
|
||||
// Right
|
||||
if (column < map.getColumns() - 1 && layer[row][column + 1] != null) {
|
||||
if (column < map.getColumns() - 1 && (layer[row][column + 1] != null && (connect || layer[row][column + 1].getSetId() == centerSetId))) {
|
||||
topRight += 2;
|
||||
bottomRight += 1;
|
||||
}
|
||||
|
||||
tile.regularTile(setId, topLeft, topRight, bottomLeft, bottomRight);
|
||||
}
|
||||
|
||||
private void recalculateTile2x3(Integer setId, int row, int column) {
|
||||
if (layer[row][column] == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var topLeft = 0;
|
||||
var topRight = 0;
|
||||
var bottomLeft = 0;
|
||||
var bottomRight = 0;
|
||||
|
||||
var tile = layer[row][column];
|
||||
var centerSetId = tile.getSetId();
|
||||
|
||||
if (animated) {
|
||||
tile.shiftTileSet();
|
||||
}
|
||||
|
||||
// Top
|
||||
if (row > 0 && (layer[row - 1][column] != null && (connect || layer[row - 1][column].getSetId() == centerSetId))) {
|
||||
topLeft += 2;
|
||||
topRight += 1;
|
||||
}
|
||||
|
||||
// Bottom
|
||||
if (row < map.getRows() - 1 && (layer[row + 1][column] != null && (connect || layer[row + 1][column].getSetId() == centerSetId))) {
|
||||
bottomLeft += 1;
|
||||
bottomRight += 2;
|
||||
}
|
||||
|
||||
// Left
|
||||
if (column > 0 && (layer[row][column - 1] != null && (connect || layer[row][column - 1].getSetId() == centerSetId))) {
|
||||
topLeft += 1;
|
||||
bottomLeft += 2;
|
||||
}
|
||||
|
||||
// Right
|
||||
if (column < map.getColumns() - 1 && (layer[row][column + 1] != null && (connect || layer[row][column + 1].getSetId() == centerSetId))) {
|
||||
topRight += 2;
|
||||
bottomRight += 1;
|
||||
}
|
||||
|
||||
// Top left
|
||||
if (row > 0 && column > 0 && layer[row - 1][column - 1] != null && topLeft == 3) {
|
||||
if (row > 0 && column > 0 && (layer[row - 1][column - 1] != null && (connect || layer[row - 1][column - 1].getSetId() == centerSetId)) && topLeft == 3) {
|
||||
topLeft = 4;
|
||||
}
|
||||
|
||||
// Top right
|
||||
if (row > 0 && column < map.getColumns() - 1 && layer[row - 1][column + 1] != null && topRight == 3) {
|
||||
if (row > 0 && column < map.getColumns() - 1 && (layer[row - 1][column + 1] != null && (connect || layer[row - 1][column + 1].getSetId() == centerSetId)) && topRight == 3) {
|
||||
topRight = 4;
|
||||
}
|
||||
|
||||
// Bottom left
|
||||
if (row < map.getRows() - 1 && column > 0 && layer[row + 1][column - 1] != null && bottomLeft == 3) {
|
||||
if (row < map.getRows() - 1 && column > 0 && (layer[row + 1][column - 1] != null && (connect || layer[row + 1][column - 1].getSetId() == centerSetId)) && bottomLeft == 3) {
|
||||
bottomLeft = 4;
|
||||
}
|
||||
|
||||
// Bottom right
|
||||
if (row < map.getRows() - 1 && column < map.getColumns() - 1 && layer[row + 1][column + 1] != null && bottomRight == 3) {
|
||||
if (row < map.getRows() - 1 && column < map.getColumns() - 1 && (layer[row + 1][column + 1] != null && (connect || layer[row + 1][column + 1].getSetId() == centerSetId)) && bottomRight == 3) {
|
||||
bottomRight = 4;
|
||||
}
|
||||
|
||||
|
||||
@@ -120,8 +120,8 @@ public class DefaultGameMap implements Renderable, Updatable, GameMap {
|
||||
return layer;
|
||||
}
|
||||
|
||||
public DefaultAutoTileLayer createAutoTileLayer(@NonNull AutoTileSet autoTileSet, boolean animated, double animationDuration) {
|
||||
var layer = new DefaultAutoTileLayer(this, autoTileSet, rows, columns, animated, animationDuration);
|
||||
public DefaultAutoTileLayer createAutoTileLayer(@NonNull AutoTileSet autoTileSet, boolean animated, double animationDuration, boolean connect) {
|
||||
var layer = new DefaultAutoTileLayer(this, autoTileSet, rows, columns, animated, animationDuration, connect);
|
||||
layers.add(layer);
|
||||
|
||||
return layer;
|
||||
|
||||
@@ -71,8 +71,9 @@ public class ProtobufMapDeserializer extends MapDeserializer {
|
||||
var autoTileSet = autoTileManager.loadObject(proto.getAutoTileLayer().getAutotileUID());
|
||||
var animated = proto.getAutoTileLayer().getAnimated();
|
||||
var animationDuration = proto.getAutoTileLayer().getAnimationDuration();
|
||||
var connect = proto.getAutoTileLayer().getConnect();
|
||||
|
||||
var layer = map.createAutoTileLayer(autoTileSet, animated, animationDuration);
|
||||
var layer = map.createAutoTileLayer(autoTileSet, animated, animationDuration, connect);
|
||||
var columns = map.getColumns();
|
||||
var tiles = proto.getAutoTileLayer().getTilesList();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user