DEADSOFTWARE

Implement DI for menu and refactor #13
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / GameFluidsThread.java
1 package ru.deadsoftware.cavedroid.game;
3 import com.badlogic.gdx.utils.TimeUtils;
4 import ru.deadsoftware.cavedroid.game.mobs.MobsController;
6 import java.util.Arrays;
8 import static ru.deadsoftware.cavedroid.game.GameItems.*;
10 class GameFluidsThread extends Thread {
12 private static final int FLUID_UPDATE_INTERVAL_MS = 100;
13 private static final int FLUID_STATES = 5;
15 private static final int[] WATER_IDS = {8, 60, 61, 62, 63};
16 private static final int[] LAVA_IDS = {9, 64, 65, 66, 67};
18 private long mFluidLastUpdateTimestamp = 0;
20 private final GameWorld mGameWorld;
21 private final MobsController mMobsController;
23 private final Thread mMainThread;
25 GameFluidsThread(GameWorld gameWorld,
26 MobsController mobsController,
27 Thread mainThread) {
28 mGameWorld = gameWorld;
29 mMobsController = mobsController;
30 mMainThread = mainThread;
31 }
33 private int getBlockState(int id) {
34 return isWater(id) ? Arrays.binarySearch(WATER_IDS, id) : Arrays.binarySearch(LAVA_IDS, id);
35 }
37 private int getNextBlockState(int id) {
38 if (!isFluid(id)) {
39 return -1;
40 }
41 int state = getBlockState(id);
42 if (state < FLUID_STATES - 1) {
43 return state + 1;
44 }
45 return -1;
46 }
48 private int getNextBlockStateId(int id) {
49 int nextState = getNextBlockState(id);
50 if (nextState == -1) {
51 return 0;
52 }
53 if (isWater(id)) {
54 return WATER_IDS[nextState];
55 }
56 return LAVA_IDS[nextState];
57 }
59 private int id(int x, int y) {
60 return mGameWorld.getForeMap(x, y);
61 }
63 private boolean sameFluid(int thisId, int thatId) {
64 return isFluid(thatId) && isWater(thatId) == isWater(thisId);
65 }
67 private boolean noFluidNearby(int x, int y) {
68 return !isFluid(id(x, y - 1)) &&
69 (!isFluid(id(x - 1, y)) || id(x - 1, y) >= id(x, y)) &&
70 (!isFluid(id(x + 1, y)) || id(x + 1, y) >= id(x, y));
71 }
73 private boolean drainFluid(int x, int y) {
74 if (getBlockState(id(x, y)) > 0) {
75 if (noFluidNearby(x, y)) {
76 mGameWorld.setForeMap(x, y, getNextBlockStateId(id(x, y)));
77 }
78 if (!isFluid(id(x, y))) {
79 mGameWorld.setForeMap(x, y, 0);
80 return true;
81 }
82 }
83 return false;
84 }
86 private void flowFluidTo(int thisId, int x, int y, int nextStateId) {
87 int thatId = id(x, y);
88 if (fluidCanFlowThere(thisId, thatId)) {
89 mGameWorld.setForeMap(x, y, nextStateId);
90 } else if (isWater(thisId) && isLava(thatId)) {
91 if (getBlockState(thatId) > 0) {
92 mGameWorld.setForeMap(x, y, 4); //cobblestone
93 } else {
94 mGameWorld.setForeMap(x, y, 68); //obsidian
95 }
96 } else if (isLava(thisId) && isWater(thatId)) {
97 mGameWorld.setForeMap(x, y, 1); //stone
98 }
99 }
101 private void flowFluid(int x, int y) {
102 int id = id(x, y);
103 if (getBlockState(id) < FLUID_STATES - 1 && getBlock(id(x, y + 1)).hasCollision()) {
104 int nextState = getNextBlockState(id);
105 int nextStateId = getNextBlockStateId(id);
106 if (nextState == 1) {
107 nextStateId++;
109 flowFluidTo(id, x - 1, y, nextStateId);
110 flowFluidTo(id, x + 1, y, nextStateId);
111 } else {
112 flowFluidTo(id, x, y + 1, isWater(id) ? WATER_IDS[1] : LAVA_IDS[1]);
117 private void updateFluids(int x, int y) {
118 if (!isFluid(id(x, y))) {
119 return;
121 if (drainFluid(x, y)) {
122 return;
124 flowFluid(x, y);
127 private void fluidUpdater() {
128 int midScreen = (int) mMobsController.getPlayer().x / 16;
129 for (int y = mGameWorld.getHeight() - 1; y >= 0; y--) {
130 for (int x = 0; x <= mGameWorld.getWidth() / 2; x++) {
131 updateFluids(midScreen + x, y);
132 updateFluids(midScreen - x, y);
137 private boolean timeToUpdate() {
138 if (TimeUtils.timeSinceMillis(mFluidLastUpdateTimestamp) >= FLUID_UPDATE_INTERVAL_MS) {
139 mFluidLastUpdateTimestamp = TimeUtils.millis();
140 return true;
142 return false;
145 @Override
146 public void run() {
147 while (!this.isInterrupted() && mMainThread.isAlive()) {
148 if (timeToUpdate()) {
149 fluidUpdater();