DEADSOFTWARE

Fix greedy fluids updater
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / world / GameFluidsThread.java
1 package ru.deadsoftware.cavedroid.game.world;
3 import com.badlogic.gdx.utils.TimeUtils;
4 import ru.deadsoftware.cavedroid.game.mobs.MobsController;
6 import java.util.Arrays;
7 import java.util.TimerTask;
9 import static ru.deadsoftware.cavedroid.game.GameItems.*;
11 class GameFluidsThread extends TimerTask {
13 public static final int FLUID_UPDATE_INTERVAL_MS = 100;
14 private static final int FLUID_STATES = 5;
16 private static final int[] WATER_IDS = {8, 60, 61, 62, 63};
17 private static final int[] LAVA_IDS = {9, 64, 65, 66, 67};
19 private long mFluidLastUpdateTimestamp = 0;
21 private final GameWorld mGameWorld;
22 private final MobsController mMobsController;
24 private final Thread mMainThread;
26 GameFluidsThread(GameWorld gameWorld,
27 MobsController mobsController,
28 Thread mainThread) {
29 mGameWorld = gameWorld;
30 mMobsController = mobsController;
31 mMainThread = mainThread;
32 }
34 private int getBlockState(int id) {
35 return isWater(id) ? Arrays.binarySearch(WATER_IDS, id) : Arrays.binarySearch(LAVA_IDS, id);
36 }
38 private int getNextBlockState(int id) {
39 if (!isFluid(id)) {
40 return -1;
41 }
42 int state = getBlockState(id);
43 if (state < FLUID_STATES - 1) {
44 return state + 1;
45 }
46 return -1;
47 }
49 private int getNextBlockStateId(int id) {
50 int nextState = getNextBlockState(id);
51 if (nextState == -1) {
52 return 0;
53 }
54 if (isWater(id)) {
55 return WATER_IDS[nextState];
56 }
57 return LAVA_IDS[nextState];
58 }
60 private int id(int x, int y) {
61 return mGameWorld.getForeMap(x, y);
62 }
64 private boolean sameFluid(int thisId, int thatId) {
65 return isFluid(thatId) && isWater(thatId) == isWater(thisId);
66 }
68 private boolean noFluidNearby(int x, int y) {
69 return !isFluid(id(x, y - 1)) &&
70 (!isFluid(id(x - 1, y)) || id(x - 1, y) >= id(x, y)) &&
71 (!isFluid(id(x + 1, y)) || id(x + 1, y) >= id(x, y));
72 }
74 private boolean drainFluid(int x, int y) {
75 if (getBlockState(id(x, y)) > 0) {
76 if (noFluidNearby(x, y)) {
77 mGameWorld.setForeMap(x, y, getNextBlockStateId(id(x, y)));
78 }
79 if (!isFluid(id(x, y))) {
80 mGameWorld.setForeMap(x, y, 0);
81 return true;
82 }
83 }
84 return false;
85 }
87 private void flowFluidTo(int thisId, int x, int y, int nextStateId) {
88 int thatId = id(x, y);
89 if (fluidCanFlowThere(thisId, thatId)) {
90 mGameWorld.setForeMap(x, y, nextStateId);
91 } else if (isWater(thisId) && isLava(thatId)) {
92 if (getBlockState(thatId) > 0) {
93 mGameWorld.setForeMap(x, y, 4); //cobblestone
94 } else {
95 mGameWorld.setForeMap(x, y, 68); //obsidian
96 }
97 } else if (isLava(thisId) && isWater(thatId)) {
98 mGameWorld.setForeMap(x, y, 1); //stone
99 }
102 private void flowFluid(int x, int y) {
103 int id = id(x, y);
104 if (getBlockState(id) < FLUID_STATES - 1 && getBlock(id(x, y + 1)).hasCollision()) {
105 int nextState = getNextBlockState(id);
106 int nextStateId = getNextBlockStateId(id);
107 if (nextState == 1) {
108 nextStateId++;
110 flowFluidTo(id, x - 1, y, nextStateId);
111 flowFluidTo(id, x + 1, y, nextStateId);
112 } else {
113 flowFluidTo(id, x, y + 1, isWater(id) ? WATER_IDS[1] : LAVA_IDS[1]);
118 private void updateFluids(int x, int y) {
119 if (!isFluid(id(x, y))) {
120 return;
122 if (drainFluid(x, y)) {
123 return;
125 flowFluid(x, y);
128 private void fluidUpdater() {
129 int midScreen = (int) mMobsController.getPlayer().x / 16;
130 for (int y = mGameWorld.getHeight() - 1; y >= 0; y--) {
131 for (int x = 0; x <= mGameWorld.getWidth() / 2; x++) {
132 updateFluids(midScreen + x, y);
133 updateFluids(midScreen - x, y);
138 private boolean timeToUpdate() {
139 if (TimeUtils.timeSinceMillis(mFluidLastUpdateTimestamp) >= FLUID_UPDATE_INTERVAL_MS) {
140 mFluidLastUpdateTimestamp = TimeUtils.millis();
141 return true;
143 return false;
146 @Override
147 public void run() {
148 fluidUpdater();