DEADSOFTWARE

Closes #5: Reimplement world generator in kotlin
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / GameWorld.java
index 6aefd8945b760f3b25f8c92f56fa7904122712fc..3bf4981d76d5b5914679f3ed82d2f81adcf979b7 100644 (file)
@@ -1,40 +1,93 @@
 package ru.deadsoftware.cavedroid.game;
 
-import ru.deadsoftware.cavedroid.game.objects.Drop;
+import com.badlogic.gdx.utils.Disposable;
+import com.badlogic.gdx.utils.TimeUtils;
+import kotlin.Pair;
+import ru.deadsoftware.cavedroid.game.mobs.FallingGravel;
+import ru.deadsoftware.cavedroid.game.mobs.FallingSand;
+import ru.deadsoftware.cavedroid.game.mobs.MobsController;
+import ru.deadsoftware.cavedroid.game.objects.Block;
+import ru.deadsoftware.cavedroid.game.objects.DropController;
 
-public class GameWorld {
+import javax.annotation.CheckForNull;
+import javax.inject.Inject;
 
-    private int WIDTH, HEIGHT;
-    private int[][] foreMap;
-    private int[][] backMap;
+@GameScope
+public class GameWorld implements Disposable {
+
+    private static final int DEFAULT_WIDTH = 1024;
+    private static final int DEFAULT_HEIGHT = 256;
+    private static final int UPDATE_RANGE = 16;
+
+    private final DropController mDropController;
+    private final MobsController mMobsController;
+    private final GameFluidsThread mGameFluidsThread;
+
+    private final int mWidth;
+    private final int mHeight;
+    private final int[][] mForeMap;
+    private final int[][] mBackMap;
+
+    private boolean mShouldUpdate;
+    private int mUpdateX;
+    private int mUpdateY;
+
+    @Inject
+    public GameWorld(DropController dropController,
+                     MobsController mobsController,
+                     @CheckForNull int[][] foreMap,
+                     @CheckForNull int[][] backMap) {
+        mDropController = dropController;
+        mMobsController = mobsController;
+
+        boolean isNewGame = foreMap == null || backMap == null;
+
+        if (isNewGame) {
+            mWidth = DEFAULT_WIDTH;
+            mHeight = DEFAULT_HEIGHT;
+            Pair<int[][], int[][]> maps = GameWorldGeneratorKt.generate(mWidth, mHeight, TimeUtils.millis());
+            mForeMap = maps.getFirst();
+            mBackMap = maps.getSecond();
+            mMobsController.getPlayer().respawn(this);
+        } else {
+            mForeMap = foreMap;
+            mBackMap = backMap;
+            mWidth = mForeMap.length;
+            mHeight = mForeMap[0].length;
+        }
+
+        mGameFluidsThread = new GameFluidsThread(this, mMobsController, Thread.currentThread());
+    }
 
     public int getWidth() {
-        return WIDTH;
+        return mWidth;
     }
 
     public int getHeight() {
-        return HEIGHT;
+        return mHeight;
     }
 
     public float getWidthPx() {
-        return WIDTH * 16f;
+        return mWidth * 16f;
     }
 
     public float getHeightPx() {
-        return HEIGHT * 16f;
+        return mHeight * 16f;
     }
 
-    public int[][] getFullForeMap() {
-        return foreMap;
+    int[][] getFullForeMap() {
+        return mForeMap;
     }
 
-    public int[][] getFullBackMap() {
-        return backMap;
+    int[][] getFullBackMap() {
+        return mBackMap;
     }
 
     private int transformX(int x) {
         x = x % getWidth();
-        if (x < 0) x = getWidth() - Math.abs(x);
+        if (x < 0) {
+            x = getWidth() - Math.abs(x);
+        }
         return x;
     }
 
@@ -42,8 +95,8 @@ public class GameWorld {
         int map = 0;
         try {
             x = transformX(x);
-            map = (layer == 0) ? foreMap[x][y] : backMap[x][y];
-        } catch (ArrayIndexOutOfBoundsException e) {
+            map = (layer == 0) ? mForeMap[x][y] : mBackMap[x][y];
+        } catch (ArrayIndexOutOfBoundsException ignored) {
         }
         return map;
     }
@@ -51,26 +104,45 @@ public class GameWorld {
     private void setMap(int x, int y, int layer, int value) {
         try {
             x = transformX(x);
-            if (layer == 0) foreMap[x][y] = value;
-            else backMap[x][y] = value;
-        } catch (ArrayIndexOutOfBoundsException e) {
+            if (layer == 0) {
+                mForeMap[x][y] = value;
+            } else {
+                mBackMap[x][y] = value;
+            }
+        } catch (ArrayIndexOutOfBoundsException ignored) {
         }
     }
 
+    public boolean hasForeAt(int x, int y) {
+        return getMap(x, y, 0) != 0;
+    }
+
+    public boolean hasBackAt(int x, int y) {
+        return getMap(x, y, 1) != 0;
+    }
+
     public int getForeMap(int x, int y) {
         return getMap(x, y, 0);
     }
 
-    public void setForeMap(int x, int y, int value) {
-        setMap(x, y, 0, value);
+    public Block getForeMapBlock(int x, int y) {
+        return GameItems.getBlock(getMap(x, y, 0));
+    }
+
+    public void setForeMap(int x, int y, int id) {
+        setMap(x, y, 0, id);
     }
 
     public int getBackMap(int x, int y) {
         return getMap(x, y, 1);
     }
 
-    public void setBackMap(int x, int y, int value) {
-        setMap(x, y, 1, value);
+    public Block getBackMapBlock(int x, int y) {
+        return GameItems.getBlock(getMap(x, y, 1));
+    }
+
+    public void setBackMap(int x, int y, int id) {
+        setMap(x, y, 1, id);
     }
 
     private void placeSlab(int x, int y, int value) {
@@ -97,14 +169,14 @@ public class GameWorld {
     }
 
     public void placeToForeground(int x, int y, int value) {
-        if (getForeMap(x, y) == 0 || value == 0 || !GameItems.getBlock(getForeMap(x, y)).hasCollision()) {
+        if (!hasForeAt(x, y) || value == 0 || !GameItems.getBlock(getForeMap(x, y)).hasCollision()) {
             setForeMap(x, y, value);
         } else if (GameItems.isSlab(value) && getForeMap(x, y) == value) {
             placeSlab(x, y, value);
         }
-        GameProc.UPD_X = x - 8;
-        GameProc.UPD_Y = y - 8;
-        GameProc.DO_UPD = true;
+        mUpdateX = x - 8;
+        mUpdateY = y - 8;
+        mShouldUpdate = true;
     }
 
     public void placeToBackground(int x, int y, int value) {
@@ -114,32 +186,75 @@ public class GameWorld {
         }
     }
 
-    public void destroyForeMap(int x, int y, GameProc gp) {
-        if (GameItems.getBlock(getForeMap(x, y)).getDrop() > 0)
-            gp.drops.add(new Drop(transformX(x) * 16 + 4, y * 16 + 4, GameItems.getBlock(getForeMap(x, y)).getDrop()));
+    public void destroyForeMap(int x, int y) {
+        Block block = GameItems.getBlock(getForeMap(x, y));
+        if (block.hasDrop()) {
+            mDropController.addDrop(transformX(x) * 16 + 4, y * 16 + 4, GameItems.getItemId(block.getDrop()));
+        }
         placeToForeground(x, y, 0);
     }
 
-    public void destroyBackMap(int x, int y, GameProc gp) {
-        if (GameItems.getBlock(getBackMap(x, y)).getDrop() > 0)
-            gp.drops.add(new Drop(transformX(x) * 16 + 4, y * 16 + 4, GameItems.getBlock(getBackMap(x, y)).getDrop()));
+    public void destroyBackMap(int x, int y) {
+        Block block = GameItems.getBlock(getBackMap(x, y));
+        if (block.hasDrop()) {
+            mDropController.addDrop(transformX(x) * 16 + 4, y * 16 + 4, GameItems.getItemId(block.getDrop()));
+        }
         placeToBackground(x, y, 0);
     }
 
-    public void generate(int w, int h) {
-        WIDTH = w;
-        HEIGHT = h;
-        WorldGen.genWorld(WIDTH, HEIGHT);
-        foreMap = WorldGen.getForeMap();
-        backMap = WorldGen.getBackMap();
-        WorldGen.clear();
+    private void updateBlock(int x, int y) {
+        if (getForeMap(x, y) == 10) {
+            if (!hasForeAt(x, y + 1) || !getForeMapBlock(x, y + 1).hasCollision()) {
+                setForeMap(x, y, 0);
+                mMobsController.addMob(FallingSand.class, x * 16, y * 16);
+                updateBlock(x, y - 1);
+            }   
+        }
+
+        if (getForeMap(x, y) == 11) {
+            if (!hasForeAt(x, y + 1) || !getForeMapBlock(x, y + 1).hasCollision()) {
+                setForeMap(x, y, 0);
+                mMobsController.addMob(FallingGravel.class, x * 16, y * 16);
+                updateBlock(x, y - 1);
+            }
+        }
+
+        if (hasForeAt(x, y) && getForeMapBlock(x, y).requiresBlock()) {
+            if (!hasForeAt(x, y + 1) || !getForeMapBlock(x, y + 1).hasCollision()) {
+                destroyForeMap(x, y);
+                updateBlock(x, y - 1);
+            }
+        }
+
+        if (getForeMap(x, y) == 2) {
+            if (hasForeAt(x, y - 1) && (getForeMapBlock(x, y - 1).hasCollision() ||
+                    GameItems.isFluid(getForeMap(x, y - 1)))) {
+                setForeMap(x, y, 3);
+            }
+        }
+    }
+
+    public void update() {
+        if (mShouldUpdate) {
+            for (int y = mUpdateY; y < mUpdateY + UPDATE_RANGE; y++) {
+                for (int x = mUpdateX; x < mUpdateX + UPDATE_RANGE; x++) {
+                    updateBlock(x, y);
+                }
+            }
+            mShouldUpdate = false;
+        }
+
+        if (!mGameFluidsThread.isAlive()) {
+            mGameFluidsThread.start();
+        }
     }
 
-    public void setMaps(int[][] foreMap, int[][] backMap) {
-        this.foreMap = foreMap.clone();
-        this.backMap = backMap.clone();
-        WIDTH = foreMap.length;
-        HEIGHT = foreMap[0].length;
+    public void startFluidsThread() {
+        mGameFluidsThread.start();
     }
 
-}
+    @Override
+    public void dispose() {
+        mGameFluidsThread.interrupt();
+    }
+}
\ No newline at end of file