DEADSOFTWARE

Fix blocks at x=0 not selectable by mouse
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / world / GameWorld.java
1 package ru.deadsoftware.cavedroid.game.world;
3 import com.badlogic.gdx.utils.Disposable;
4 import com.badlogic.gdx.utils.TimeUtils;
5 import kotlin.Pair;
6 import ru.deadsoftware.cavedroid.game.GameItems;
7 import ru.deadsoftware.cavedroid.game.GameScope;
8 import ru.deadsoftware.cavedroid.game.mobs.FallingGravel;
9 import ru.deadsoftware.cavedroid.game.mobs.FallingSand;
10 import ru.deadsoftware.cavedroid.game.mobs.MobsController;
11 import ru.deadsoftware.cavedroid.game.objects.Block;
12 import ru.deadsoftware.cavedroid.game.objects.DropController;
14 import javax.annotation.CheckForNull;
15 import javax.inject.Inject;
17 @GameScope
18 public class GameWorld implements Disposable {
20 private static final int DEFAULT_WIDTH = 1024;
21 private static final int DEFAULT_HEIGHT = 256;
22 private static final int UPDATE_RANGE = 16;
24 private final DropController mDropController;
25 private final MobsController mMobsController;
26 private final GameFluidsThread mGameFluidsThread;
28 private final int mWidth;
29 private final int mHeight;
30 private final int[][] mForeMap;
31 private final int[][] mBackMap;
33 private boolean mShouldUpdate;
34 private int mUpdateX;
35 private int mUpdateY;
37 @Inject
38 public GameWorld(DropController dropController,
39 MobsController mobsController,
40 @CheckForNull int[][] foreMap,
41 @CheckForNull int[][] backMap) {
42 mDropController = dropController;
43 mMobsController = mobsController;
45 boolean isNewGame = foreMap == null || backMap == null;
47 if (isNewGame) {
48 mWidth = DEFAULT_WIDTH;
49 mHeight = DEFAULT_HEIGHT;
50 Pair<int[][], int[][]> maps = GameWorldGenerator.INSTANCE.generate(mWidth, mHeight, TimeUtils.millis());
51 mForeMap = maps.getFirst();
52 mBackMap = maps.getSecond();
53 mMobsController.getPlayer().respawn(this);
54 } else {
55 mForeMap = foreMap;
56 mBackMap = backMap;
57 mWidth = mForeMap.length;
58 mHeight = mForeMap[0].length;
59 }
61 mGameFluidsThread = new GameFluidsThread(this, mMobsController, Thread.currentThread());
62 }
64 public int getWidth() {
65 return mWidth;
66 }
68 public int getHeight() {
69 return mHeight;
70 }
72 public float getWidthPx() {
73 return mWidth * 16f;
74 }
76 public float getHeightPx() {
77 return mHeight * 16f;
78 }
80 public int[][] getFullForeMap() {
81 return mForeMap;
82 }
84 public int[][] getFullBackMap() {
85 return mBackMap;
86 }
88 private int transformX(int x) {
89 x = x % getWidth();
90 if (x < 0) {
91 x = getWidth() - Math.abs(x);
92 }
93 return x;
94 }
96 private int getMap(int x, int y, int layer) {
97 int map = 0;
98 try {
99 x = transformX(x);
100 map = (layer == 0) ? mForeMap[x][y] : mBackMap[x][y];
101 } catch (ArrayIndexOutOfBoundsException ignored) {
103 return map;
106 private void setMap(int x, int y, int layer, int value) {
107 try {
108 x = transformX(x);
109 if (layer == 0) {
110 mForeMap[x][y] = value;
111 } else {
112 mBackMap[x][y] = value;
114 } catch (ArrayIndexOutOfBoundsException ignored) {
118 public boolean hasForeAt(int x, int y) {
119 return getMap(x, y, 0) != 0;
122 public boolean hasBackAt(int x, int y) {
123 return getMap(x, y, 1) != 0;
126 public int getForeMap(int x, int y) {
127 return getMap(x, y, 0);
130 public Block getForeMapBlock(int x, int y) {
131 return GameItems.getBlock(getMap(x, y, 0));
134 public void setForeMap(int x, int y, int id) {
135 setMap(x, y, 0, id);
138 public int getBackMap(int x, int y) {
139 return getMap(x, y, 1);
142 public Block getBackMapBlock(int x, int y) {
143 return GameItems.getBlock(getMap(x, y, 1));
146 public void setBackMap(int x, int y, int id) {
147 setMap(x, y, 1, id);
150 private void placeSlab(int x, int y, int value) {
151 switch (value) {
152 case 51:
153 setForeMap(x, y, 52);
154 break;
155 case 53:
156 setForeMap(x, y, 21);
157 break;
158 case 54:
159 setForeMap(x, y, 5);
160 break;
161 case 55:
162 setForeMap(x, y, 4);
163 break;
164 case 56:
165 setForeMap(x, y, 28);
166 break;
167 case 58:
168 setForeMap(x, y, 57);
169 break;
173 public void placeToForeground(int x, int y, int value) {
174 if (!hasForeAt(x, y) || value == 0 || !GameItems.getBlock(getForeMap(x, y)).hasCollision()) {
175 setForeMap(x, y, value);
176 } else if (GameItems.isSlab(value) && getForeMap(x, y) == value) {
177 placeSlab(x, y, value);
179 mUpdateX = x - 8;
180 mUpdateY = y - 8;
181 mShouldUpdate = true;
184 public void placeToBackground(int x, int y, int value) {
185 if (value == 0 || (getBackMap(x, y) == 0 && GameItems.getBlock(value).hasCollision()) &&
186 (!GameItems.getBlock(value).isTransparent() || value == 18)) {
187 setBackMap(x, y, value);
191 public void destroyForeMap(int x, int y) {
192 Block block = GameItems.getBlock(getForeMap(x, y));
193 if (block.hasDrop()) {
194 mDropController.addDrop(transformX(x) * 16 + 4, y * 16 + 4, GameItems.getItemId(block.getDrop()));
196 placeToForeground(x, y, 0);
199 public void destroyBackMap(int x, int y) {
200 Block block = GameItems.getBlock(getBackMap(x, y));
201 if (block.hasDrop()) {
202 mDropController.addDrop(transformX(x) * 16 + 4, y * 16 + 4, GameItems.getItemId(block.getDrop()));
204 placeToBackground(x, y, 0);
207 private void updateBlock(int x, int y) {
208 if (getForeMap(x, y) == 10) {
209 if (!hasForeAt(x, y + 1) || !getForeMapBlock(x, y + 1).hasCollision()) {
210 setForeMap(x, y, 0);
211 mMobsController.addMob(FallingSand.class, x * 16, y * 16);
212 updateBlock(x, y - 1);
213 }
216 if (getForeMap(x, y) == 11) {
217 if (!hasForeAt(x, y + 1) || !getForeMapBlock(x, y + 1).hasCollision()) {
218 setForeMap(x, y, 0);
219 mMobsController.addMob(FallingGravel.class, x * 16, y * 16);
220 updateBlock(x, y - 1);
224 if (hasForeAt(x, y) && getForeMapBlock(x, y).requiresBlock()) {
225 if (!hasForeAt(x, y + 1) || !getForeMapBlock(x, y + 1).hasCollision()) {
226 destroyForeMap(x, y);
227 updateBlock(x, y - 1);
231 if (getForeMap(x, y) == 2) {
232 if (hasForeAt(x, y - 1) && (getForeMapBlock(x, y - 1).hasCollision() ||
233 GameItems.isFluid(getForeMap(x, y - 1)))) {
234 setForeMap(x, y, 3);
239 public void update() {
240 if (mShouldUpdate) {
241 for (int y = mUpdateY; y < mUpdateY + UPDATE_RANGE; y++) {
242 for (int x = mUpdateX; x < mUpdateX + UPDATE_RANGE; x++) {
243 updateBlock(x, y);
246 mShouldUpdate = false;
249 if (!mGameFluidsThread.isAlive()) {
250 mGameFluidsThread.start();
254 public void startFluidsThread() {
255 mGameFluidsThread.start();
258 @Override
259 public void dispose() {
260 mGameFluidsThread.interrupt();