X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=core%2Fsrc%2Fru%2Fdeadsoftware%2Fcavedroid%2Fgame%2Fworld%2FGameWorldFluidsLogicControllerTask.java;h=416721f7c25b6c946b6e9768ef41afad42c12da7;hb=387ad284ceb79b07cba3726fa7350b7e83916815;hp=d996cf42989c41a1025b54fb1c1fd2b77e053cf0;hpb=894d9f1babeff18c9cbb5f83206ff2c549de0bdb;p=cavedroid.git diff --git a/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldFluidsLogicControllerTask.java b/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldFluidsLogicControllerTask.java index d996cf4..416721f 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldFluidsLogicControllerTask.java +++ b/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldFluidsLogicControllerTask.java @@ -1,119 +1,193 @@ package ru.deadsoftware.cavedroid.game.world; import com.badlogic.gdx.utils.Timer; +import ru.deadsoftware.cavedroid.game.GameItemsHolder; import ru.deadsoftware.cavedroid.game.GameScope; import ru.deadsoftware.cavedroid.game.mobs.MobsController; +import ru.deadsoftware.cavedroid.game.model.block.Block; +import javax.annotation.CheckForNull; import javax.inject.Inject; -import java.util.Arrays; - -import static ru.deadsoftware.cavedroid.game.GameItems.*; +import java.util.*; @GameScope public class GameWorldFluidsLogicControllerTask extends Timer.Task { - public static final float FLUID_UPDATE_INTERVAL_SEC = 0.1f; - private static final int FLUID_STATES = 5; + public static final float FLUID_UPDATE_INTERVAL_SEC = 0.25f; - private static final int[] WATER_IDS = {8, 60, 61, 62, 63}; - private static final int[] LAVA_IDS = {9, 64, 65, 66, 67}; + private short mUpdateTick = 0; private final GameWorld mGameWorld; private final MobsController mMobsController; + private final GameItemsHolder mGameItemsHolder; + + private final Map, List> mFluidStatesMap; + + private final class UpdateCommand { + final Runnable command; + final int priority; + + private UpdateCommand(int priority, Runnable command) { + this.priority = priority; + this.command = command; + } + + private UpdateCommand(Block block, int x, int y, int priority) { + this(priority, () -> mGameWorld.setForeMap(x, y, block)); + } + + private UpdateCommand(Block.Fluid fluid, int x, int y) { + this(fluid, x, y, ((5 -fluid.getState() )+ 1) * (fluid.isLava() ? 2 : 1)); + } + + private int getPriority() { + return priority; + } + + private void exec() { + command.run(); + } + } + + private final PriorityQueue mUpdateQueue + = new PriorityQueue<>(Comparator.comparingInt(UpdateCommand::getPriority)); @Inject GameWorldFluidsLogicControllerTask(GameWorld gameWorld, - MobsController mobsController) { + MobsController mobsController, + GameItemsHolder gameItemsHolder) { mGameWorld = gameWorld; mMobsController = mobsController; + mGameItemsHolder = gameItemsHolder; + + final List waters = mGameItemsHolder.getBlocksByType(Block.Water.class); + waters.sort(Comparator.comparingInt(Block.Water::getState)); + + final List lavas = mGameItemsHolder.getBlocksByType(Block.Lava.class); + lavas.sort(Comparator.comparingInt(Block.Lava::getState)); + + mFluidStatesMap = new HashMap<>(); + mFluidStatesMap.put(Block.Water.class, waters); + mFluidStatesMap.put(Block.Lava.class, lavas); } - private int getBlockState(int id) { - return isWater(id) ? Arrays.binarySearch(WATER_IDS, id) : Arrays.binarySearch(LAVA_IDS, id); + @CheckForNull + private List getFluidStateList(Block.Fluid fluid) { + return mFluidStatesMap.get(fluid.getClass()); } - private int getNextBlockState(int id) { - if (!isFluid(id)) { + private int getCurrentStateIndex(Block.Fluid fluid) { + @CheckForNull final List stateList = getFluidStateList(fluid); + + if (stateList == null) { return -1; } - int state = getBlockState(id); - if (state < FLUID_STATES - 1) { - return state + 1; - } - return -1; + + return stateList.indexOf(fluid); } - private int getNextBlockStateId(int id) { - int nextState = getNextBlockState(id); - if (nextState == -1) { - return 0; + @CheckForNull + private Block.Fluid getNextStateBlock(Block.Fluid fluid) { + @CheckForNull final List stateList = getFluidStateList(fluid); + + if (stateList == null) { + return null; + } + + int currentState = stateList.indexOf(fluid); + + if (currentState < 0) { + return null; } - if (isWater(id)) { - return WATER_IDS[nextState]; + + int nextState = currentState + 1; + + if (nextState == 1) { + nextState++; } - return LAVA_IDS[nextState]; - } - private int id(int x, int y) { - return mGameWorld.getForeMap(x, y); - } + if (nextState < stateList.size()) { + return stateList.get(nextState); + } - private boolean sameFluid(int thisId, int thatId) { - return isFluid(thatId) && isWater(thatId) == isWater(thisId); + return null; } private boolean noFluidNearby(int x, int y) { - return !isFluid(id(x, y - 1)) && - (!isFluid(id(x - 1, y)) || id(x - 1, y) >= id(x, y)) && - (!isFluid(id(x + 1, y)) || id(x + 1, y) >= id(x, y)); + return !mGameWorld.getForeMap(x, y - 1).isFluid() && + (!mGameWorld.getForeMap(x - 1, y).isFluid() || ((Block.Fluid)mGameWorld.getForeMap(x - 1, y)).getState() >= ((Block.Fluid)mGameWorld.getForeMap(x, y)).getState()) && + (!mGameWorld.getForeMap(x + 1, y).isFluid() || ((Block.Fluid)mGameWorld.getForeMap(x + 1, y)).getState() >= ((Block.Fluid)mGameWorld.getForeMap(x, y)).getState()); } private boolean drainFluid(int x, int y) { - if (getBlockState(id(x, y)) > 0) { + final Block block = mGameWorld.getForeMap(x, y); + + if (!(block instanceof Block.Fluid fluid)) { + return true; + } + + if (fluid.getState() > 0) { if (noFluidNearby(x, y)) { - mGameWorld.setForeMap(x, y, getNextBlockStateId(id(x, y))); - } - if (!isFluid(id(x, y))) { - mGameWorld.setForeMap(x, y, 0); - return true; + @CheckForNull final Block.Fluid nextState = getNextStateBlock(fluid); + if (nextState == null) { + mUpdateQueue.offer(new UpdateCommand(-1, () -> mGameWorld.resetForeMap(x, y))); + return true; + } + + mUpdateQueue.offer(new UpdateCommand(nextState, x, y)); } } return false; } - private void flowFluidTo(int thisId, int x, int y, int nextStateId) { - int thatId = id(x, y); - if (fluidCanFlowThere(thisId, thatId)) { - mGameWorld.setForeMap(x, y, nextStateId); - } else if (isWater(thisId) && isLava(thatId)) { - if (getBlockState(thatId) > 0) { - mGameWorld.setForeMap(x, y, 4); //cobblestone + private boolean fluidCanFlowThere(Block.Fluid fluid, Block targetBlock) { + return targetBlock == mGameItemsHolder.getFallbackBlock() || + (!targetBlock.getParams().getHasCollision() && !targetBlock.isFluid()) || + (fluid.getClass() == targetBlock.getClass() && fluid.getState() < ((Block.Fluid)targetBlock).getState()); + } + + private void flowFluidTo(Block.Fluid currentFluid, int x, int y, Block.Fluid nextStateFluid) { + final Block targetBlock = mGameWorld.getForeMap(x, y); + + if (fluidCanFlowThere(currentFluid, targetBlock)) { + mUpdateQueue.offer(new UpdateCommand(nextStateFluid, x, y)); + } else if (currentFluid.isWater() && targetBlock.isLava()) { + if (((Block.Lava)targetBlock).getState() > 0) { + mUpdateQueue.offer(new UpdateCommand(100, () -> mGameWorld.setForeMap(x, y, mGameItemsHolder.getBlock("cobblestone")))); } else { - mGameWorld.setForeMap(x, y, 68); //obsidian + mUpdateQueue.offer(new UpdateCommand(300, () -> mGameWorld.setForeMap(x, y, mGameItemsHolder.getBlock("obsidian")))); } - } else if (isLava(thisId) && isWater(thatId)) { - mGameWorld.setForeMap(x, y, 1); //stone + } else if (currentFluid.isLava() && targetBlock.isWater()) { + mUpdateQueue.offer(new UpdateCommand(200, () -> mGameWorld.setForeMap(x, y, mGameItemsHolder.getBlock("stone")))); } } private void flowFluid(int x, int y) { - int id = id(x, y); - if (getBlockState(id) < FLUID_STATES - 1 && getBlock(id(x, y + 1)).hasCollision()) { - int nextState = getNextBlockState(id); - int nextStateId = getNextBlockStateId(id); - if (nextState == 1) { - nextStateId++; + Block.Fluid fluid = (Block.Fluid) mGameWorld.getForeMap(x, y); + @CheckForNull final List stateList = getFluidStateList(fluid); + + if (stateList == null) { + return; + } + + if (fluid.getState() < stateList.size() - 1 && mGameWorld.getForeMap(x, y + 1).hasCollision()) { + @CheckForNull Block.Fluid nextState = getNextStateBlock(fluid); + + if (nextState == null) { + return; } - flowFluidTo(id, x - 1, y, nextStateId); - flowFluidTo(id, x + 1, y, nextStateId); + + flowFluidTo(fluid, x - 1, y, nextState); + flowFluidTo(fluid, x + 1, y, nextState); } else { - flowFluidTo(id, x, y + 1, isWater(id) ? WATER_IDS[1] : LAVA_IDS[1]); + flowFluidTo(fluid, x, y + 1, stateList.get(1)); } } private void updateFluids(int x, int y) { - if (!isFluid(id(x, y))) { + final Block block = mGameWorld.getForeMap(x, y); + if (!block.isFluid() || (block.isLava() && mUpdateTick % 2 == 0)) { return; } if (drainFluid(x, y)) { @@ -125,15 +199,25 @@ public class GameWorldFluidsLogicControllerTask extends Timer.Task { private void fluidUpdater() { int midScreen = (int) mMobsController.getPlayer().x / 16; for (int y = mGameWorld.getHeight() - 1; y >= 0; y--) { - for (int x = 0; x <= mGameWorld.getWidth() / 2; x++) { + for (int x = 0; x <= Math.min(mGameWorld.getWidth() / 2, 32); x++) { updateFluids(midScreen + x, y); updateFluids(midScreen - x, y); } } + + while (!mUpdateQueue.isEmpty()) { + final UpdateCommand command = mUpdateQueue.poll(); + command.exec(); + } } @Override public void run() { + if (mUpdateTick < 0xFF) { + mUpdateTick ++; + } else { + mUpdateTick = 0; + } fluidUpdater(); } }