DEADSOFTWARE

57c74700ee0d894c388f62b549a92ef96360cff2
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / GameFluidsThread.java
1 package ru.deadsoftware.cavedroid.game;
3 import com.badlogic.gdx.utils.TimeUtils;
5 import java.util.Arrays;
7 import static ru.deadsoftware.cavedroid.GameScreen.GP;
8 import static ru.deadsoftware.cavedroid.game.GameItems.*;
10 public 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 fluidLastUpdateTimestamp = 0;
20 private int getBlockState(int id) {
21 return isWater(id) ? Arrays.binarySearch(WATER_IDS, id) : Arrays.binarySearch(LAVA_IDS, id);
22 }
24 private int getNextBlockState(int id) {
25 if (!isFluid(id)) {
26 return -1;
27 }
28 int state = getBlockState(id);
29 if (state < FLUID_STATES - 1) {
30 return state + 1;
31 }
32 return -1;
33 }
35 private int getNextBlockStateId(int id) {
36 int nextState = getNextBlockState(id);
37 if (nextState == -1) return 0;
38 if (isWater(id)) {
39 return WATER_IDS[nextState];
40 }
41 return LAVA_IDS[nextState];
42 }
44 private int id(int x, int y) {
45 return GP.world.getForeMap(x, y);
46 }
48 private boolean sameFluid(int thisId, int thatId) {
49 return isFluid(thatId) && isWater(thatId) == isWater(thisId);
50 }
52 private boolean noFluidNearby(int x, int y) {
53 return !isFluid(id(x, y - 1)) &&
54 (!isFluid(id(x - 1, y)) || id(x - 1, y) >= id(x, y)) &&
55 (!isFluid(id(x + 1, y)) || id(x + 1, y) >= id(x, y));
56 }
58 private boolean drainFluid(int x, int y) {
59 if (getBlockState(id(x, y)) > 0) {
60 if (noFluidNearby(x, y)) {
61 GP.world.setForeMap(x, y, getNextBlockStateId(id(x, y)));
62 }
63 if (!isFluid(id(x, y))) {
64 GP.world.setForeMap(x, y, 0);
65 return true;
66 }
67 }
68 return false;
69 }
71 private void flowFluidTo(int thisId, int x, int y, int nextStateId) {
72 int thatId = id(x, y);
73 if (fluidCanFlowThere(thisId, thatId)) {
74 GP.world.setForeMap(x, y, nextStateId);
75 } else if (isWater(thisId) && isLava(thatId)) {
76 if (getBlockState(thatId) > 0) {
77 GP.world.setForeMap(x, y, 4); //cobblestone
78 } else {
79 GP.world.setForeMap(x, y, 68); //obsidian
80 }
81 } else if (isLava(thisId) && isWater(thatId)) {
82 GP.world.setForeMap(x, y, 1); //stone
83 }
84 }
86 private void flowFluid(int x, int y) {
87 int id = id(x, y);
88 if (getBlockState(id) < FLUID_STATES - 1 && getBlock(id(x, y + 1)).hasCollision()) {
89 int nextState = getNextBlockState(id);
90 int nextStateId = getNextBlockStateId(id);
91 if (nextState == 1) {
92 nextStateId++;
93 }
94 flowFluidTo(id, x - 1, y, nextStateId);
95 flowFluidTo(id, x + 1, y, nextStateId);
96 } else {
97 flowFluidTo(id, x, y + 1, isWater(id) ? WATER_IDS[1] : LAVA_IDS[1]);
98 }
102 private void updateFluids(int x, int y) {
103 if (!isFluid(id(x, y))) return;
104 if (drainFluid(x, y)) return;
105 flowFluid(x, y);
108 private void fluidUpdater() {
109 int midScreen = (int) (GP.renderer.getCamX() + GP.renderer.getWidth() / 2) / 16;
110 for (int y = GP.world.getHeight() - 1; y >= 0; y--) {
111 for (int x = 0; x <= GP.world.getWidth() / 2; x++) {
112 updateFluids(midScreen + x, y);
113 updateFluids(midScreen - x, y);
118 private boolean timeToUpdate() {
119 if (TimeUtils.timeSinceMillis(fluidLastUpdateTimestamp) >= FLUID_UPDATE_INTERVAL_MS) {
120 fluidLastUpdateTimestamp = TimeUtils.millis();
121 return true;
123 return false;
126 @Override
127 public void run() {
128 while (!this.isInterrupted()) {
129 if (timeToUpdate()) {
130 fluidUpdater();