DEADSOFTWARE

Closes #5: Reimplement world generator in kotlin
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / GameWorld.java
1 package ru.deadsoftware.cavedroid.game;
3 import com.badlogic.gdx.utils.Disposable;
4 import com.badlogic.gdx.utils.TimeUtils;
5 import kotlin.Pair;
6 import ru.deadsoftware.cavedroid.game.mobs.FallingGravel;
7 import ru.deadsoftware.cavedroid.game.mobs.FallingSand;
8 import ru.deadsoftware.cavedroid.game.mobs.MobsController;
9 import ru.deadsoftware.cavedroid.game.objects.Block;
10 import ru.deadsoftware.cavedroid.game.objects.DropController;
12 import javax.annotation.CheckForNull;
13 import javax.inject.Inject;
15 @GameScope
16 public class GameWorld implements Disposable {
18 private static final int DEFAULT_WIDTH = 1024;
19 private static final int DEFAULT_HEIGHT = 256;
20 private static final int UPDATE_RANGE = 16;
22 private final DropController mDropController;
23 private final MobsController mMobsController;
24 private final GameFluidsThread mGameFluidsThread;
26 private final int mWidth;
27 private final int mHeight;
28 private final int[][] mForeMap;
29 private final int[][] mBackMap;
31 private boolean mShouldUpdate;
32 private int mUpdateX;
33 private int mUpdateY;
35 @Inject
36 public GameWorld(DropController dropController,
37 MobsController mobsController,
38 @CheckForNull int[][] foreMap,
39 @CheckForNull int[][] backMap) {
40 mDropController = dropController;
41 mMobsController = mobsController;
43 boolean isNewGame = foreMap == null || backMap == null;
45 if (isNewGame) {
46 mWidth = DEFAULT_WIDTH;
47 mHeight = DEFAULT_HEIGHT;
48 Pair<int[][], int[][]> maps = GameWorldGeneratorKt.generate(mWidth, mHeight, TimeUtils.millis());
49 mForeMap = maps.getFirst();
50 mBackMap = maps.getSecond();
51 mMobsController.getPlayer().respawn(this);
52 } else {
53 mForeMap = foreMap;
54 mBackMap = backMap;
55 mWidth = mForeMap.length;
56 mHeight = mForeMap[0].length;
57 }
59 mGameFluidsThread = new GameFluidsThread(this, mMobsController, Thread.currentThread());
60 }
62 public int getWidth() {
63 return mWidth;
64 }
66 public int getHeight() {
67 return mHeight;
68 }
70 public float getWidthPx() {
71 return mWidth * 16f;
72 }
74 public float getHeightPx() {
75 return mHeight * 16f;
76 }
78 int[][] getFullForeMap() {
79 return mForeMap;
80 }
82 int[][] getFullBackMap() {
83 return mBackMap;
84 }
86 private int transformX(int x) {
87 x = x % getWidth();
88 if (x < 0) {
89 x = getWidth() - Math.abs(x);
90 }
91 return x;
92 }
94 private int getMap(int x, int y, int layer) {
95 int map = 0;
96 try {
97 x = transformX(x);
98 map = (layer == 0) ? mForeMap[x][y] : mBackMap[x][y];
99 } catch (ArrayIndexOutOfBoundsException ignored) {
101 return map;
104 private void setMap(int x, int y, int layer, int value) {
105 try {
106 x = transformX(x);
107 if (layer == 0) {
108 mForeMap[x][y] = value;
109 } else {
110 mBackMap[x][y] = value;
112 } catch (ArrayIndexOutOfBoundsException ignored) {
116 public boolean hasForeAt(int x, int y) {
117 return getMap(x, y, 0) != 0;
120 public boolean hasBackAt(int x, int y) {
121 return getMap(x, y, 1) != 0;
124 public int getForeMap(int x, int y) {
125 return getMap(x, y, 0);
128 public Block getForeMapBlock(int x, int y) {
129 return GameItems.getBlock(getMap(x, y, 0));
132 public void setForeMap(int x, int y, int id) {
133 setMap(x, y, 0, id);
136 public int getBackMap(int x, int y) {
137 return getMap(x, y, 1);
140 public Block getBackMapBlock(int x, int y) {
141 return GameItems.getBlock(getMap(x, y, 1));
144 public void setBackMap(int x, int y, int id) {
145 setMap(x, y, 1, id);
148 private void placeSlab(int x, int y, int value) {
149 switch (value) {
150 case 51:
151 setForeMap(x, y, 52);
152 break;
153 case 53:
154 setForeMap(x, y, 21);
155 break;
156 case 54:
157 setForeMap(x, y, 5);
158 break;
159 case 55:
160 setForeMap(x, y, 4);
161 break;
162 case 56:
163 setForeMap(x, y, 28);
164 break;
165 case 58:
166 setForeMap(x, y, 57);
167 break;
171 public void placeToForeground(int x, int y, int value) {
172 if (!hasForeAt(x, y) || value == 0 || !GameItems.getBlock(getForeMap(x, y)).hasCollision()) {
173 setForeMap(x, y, value);
174 } else if (GameItems.isSlab(value) && getForeMap(x, y) == value) {
175 placeSlab(x, y, value);
177 mUpdateX = x - 8;
178 mUpdateY = y - 8;
179 mShouldUpdate = true;
182 public void placeToBackground(int x, int y, int value) {
183 if (value == 0 || (getBackMap(x, y) == 0 && GameItems.getBlock(value).hasCollision()) &&
184 (!GameItems.getBlock(value).isTransparent() || value == 18)) {
185 setBackMap(x, y, value);
189 public void destroyForeMap(int x, int y) {
190 Block block = GameItems.getBlock(getForeMap(x, y));
191 if (block.hasDrop()) {
192 mDropController.addDrop(transformX(x) * 16 + 4, y * 16 + 4, GameItems.getItemId(block.getDrop()));
194 placeToForeground(x, y, 0);
197 public void destroyBackMap(int x, int y) {
198 Block block = GameItems.getBlock(getBackMap(x, y));
199 if (block.hasDrop()) {
200 mDropController.addDrop(transformX(x) * 16 + 4, y * 16 + 4, GameItems.getItemId(block.getDrop()));
202 placeToBackground(x, y, 0);
205 private void updateBlock(int x, int y) {
206 if (getForeMap(x, y) == 10) {
207 if (!hasForeAt(x, y + 1) || !getForeMapBlock(x, y + 1).hasCollision()) {
208 setForeMap(x, y, 0);
209 mMobsController.addMob(FallingSand.class, x * 16, y * 16);
210 updateBlock(x, y - 1);
211 }
214 if (getForeMap(x, y) == 11) {
215 if (!hasForeAt(x, y + 1) || !getForeMapBlock(x, y + 1).hasCollision()) {
216 setForeMap(x, y, 0);
217 mMobsController.addMob(FallingGravel.class, x * 16, y * 16);
218 updateBlock(x, y - 1);
222 if (hasForeAt(x, y) && getForeMapBlock(x, y).requiresBlock()) {
223 if (!hasForeAt(x, y + 1) || !getForeMapBlock(x, y + 1).hasCollision()) {
224 destroyForeMap(x, y);
225 updateBlock(x, y - 1);
229 if (getForeMap(x, y) == 2) {
230 if (hasForeAt(x, y - 1) && (getForeMapBlock(x, y - 1).hasCollision() ||
231 GameItems.isFluid(getForeMap(x, y - 1)))) {
232 setForeMap(x, y, 3);
237 public void update() {
238 if (mShouldUpdate) {
239 for (int y = mUpdateY; y < mUpdateY + UPDATE_RANGE; y++) {
240 for (int x = mUpdateX; x < mUpdateX + UPDATE_RANGE; x++) {
241 updateBlock(x, y);
244 mShouldUpdate = false;
247 if (!mGameFluidsThread.isAlive()) {
248 mGameFluidsThread.start();
252 public void startFluidsThread() {
253 mGameFluidsThread.start();
256 @Override
257 public void dispose() {
258 mGameFluidsThread.interrupt();