Android Open Source - Gloomy-Dungeons-3D Portal Tracer






From Project

Back to project page Gloomy-Dungeons-3D.

License

The source code is released under:

MIT License

If you think the Android project Gloomy-Dungeons-3D listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package zame.game.engine;
// www  .  j  a  va 2  s . c  o  m
public class PortalTracer
{
  public class Wall
  {
    public int cellX;
    public int cellY;
    public int fromX;
    public int fromY;
    public int toX;
    public int toY;
    public int texture;
  }

  public class TouchedCell
  {
    public int x;
    public int y;
  }

  // +----> x
  // |
  // v
  // y

  // pts    sides
  //
  // 1 | 0  /-0-\
  // --+--  1   3
  // 2 | 3  \-2-/

  public static final float PI_M2F = (float)(Math.PI * 2.0);
  public static final float INFINITY = 0.000000001f;
  public static final int[] X_ADD = { 1, 0, 0, 1 };
  public static final int[] Y_ADD = { 0, 0, 1, 1 };

  // cell additions used by other classes
  public static final int[] X_CELL_ADD = {  0, -1,  0,  1 };
  public static final int[] Y_CELL_ADD = { -1,  0,  1,  0 };

  private static final int MAX_WALLS = 1024;
  private static final int MAX_TOUCHED_CELLS = 2048;

  private int levelWidth;
  private int levelHeight;
  private int[][] level;
  private float heroX;
  private float heroY;
  private int[][] drawedWalls = new int[Level.MAX_HEIGHT][Level.MAX_WIDTH];

  public Wall[] walls = new Wall[MAX_WALLS];
  public TouchedCell[] touchedCells = new TouchedCell[MAX_TOUCHED_CELLS];
  public boolean[][] touchedCellsMap = new boolean[Level.MAX_HEIGHT][Level.MAX_WIDTH];

  public int wallsCount = 0;
  public int touchedCellsCount = 0;

  public PortalTracer()
  {
    for (int i = 0; i < MAX_WALLS; i++) {
      walls[i] = new Wall();
    }

    for (int i = 0; i < MAX_TOUCHED_CELLS; i++) {
      touchedCells[i] = new TouchedCell();
    }
  }

  private void addWallToDraw(int cellX, int cellY, int side, int texture)
  {
    int mask = 2 << side;

    if ((wallsCount >= MAX_WALLS) || ((drawedWalls[cellY][cellX] & mask) != 0)) {
      return;
    }

    drawedWalls[cellY][cellX] |= mask;
    Wall wall = walls[wallsCount++];

    wall.cellX = cellX;
    wall.cellY = cellY;
    wall.fromX = cellX + X_ADD[side];
    wall.fromY = cellY + Y_ADD[side];
    wall.toX = cellX + X_ADD[(side + 1) % 4];
    wall.toY = cellY + Y_ADD[(side + 1) % 4];
    wall.texture = texture;
  }

  public static float getAngle(float dx, float dy)
  {
    float l = (float)Math.sqrt(dx*dx + dy*dy);
    float a = (float)Math.acos(dx / (l < INFINITY ? INFINITY : l));

    return (dy < 0 ? a : (PI_M2F - a));
  }

  private float angleDiff(float fromAngle, float toAngle)
  {
    if (fromAngle > toAngle) {
      return (toAngle - fromAngle + PI_M2F);
    } else {
      return (fromAngle - toAngle);
    }
  }

  private int tToSide = -1;
  private int tFromSide = -1;

  private void addWallBlock(int x, int y, boolean includeDoors)
  {
    tToSide = -1;
    tFromSide = -1;

    float dy = (float)y + 0.5f - heroY;
    float dx = (float)x + 0.5f - heroX;

    boolean vis_0, vis_1, vis_2, vis_3;

    if (includeDoors)
    {
      vis_0 = (dy > 0) && (y > 0) && (level[y-1][x]<=0);
      vis_1 = (dx > 0) && (x > 0) && (level[y][x-1]<=0);
      vis_2 = (dy < 0) && (y < levelHeight-1) && (level[y+1][x]<=0);
      vis_3 = (dx < 0) && (x < levelWidth-1) && (level[y][x+1]<=0);
    }
    else
    {
      vis_0 = (dy > 0) && (y > 0) && (level[y-1][x]==0);
      vis_1 = (dx > 0) && (x > 0) && (level[y][x-1]==0);
      vis_2 = (dy < 0) && (y < levelHeight-1) && (level[y+1][x]==0);
      vis_3 = (dx < 0) && (x < levelWidth-1) && (level[y][x+1]==0);
    }

    if (vis_0 && vis_1) {
      tToSide = 0; tFromSide = 1;
    } else if (vis_1 && vis_2) {
      tToSide = 1; tFromSide = 2;
    } else if (vis_2 && vis_3) {
      tToSide = 2; tFromSide = 3;
    } else if (vis_3 && vis_0) {
      tToSide = 3; tFromSide = 0;
    } else if (vis_0) {
      tToSide = 0; tFromSide = 0;
    } else if (vis_1) {
      tToSide = 1; tFromSide = 1;
    } else if (vis_2) {
      tToSide = 2; tFromSide = 2;
    } else if (vis_3) {
      tToSide = 3; tFromSide = 3;
    }

    if (tToSide >= 0 && level[y][x] > 0) {
      for (int i = tFromSide; i != (tToSide + 3) % 4; i = (i + 3) % 4) {
        addWallToDraw(x, y, i, level[y][x]);
      }
    }
  }

  private void traceCell(int fromX, int fromY, float fromAngle, int toX, int toY, float toAngle)
  {
    boolean repeat = true;

    do
    {
      float fromDx = (float)Math.cos(fromAngle);
      float fromDy = (float)Math.sin(fromAngle);
      float toDx = (float)Math.cos(toAngle);
      float toDy = (float)Math.sin(toAngle);

      if (fromAngle < 0.5 * Math.PI) {
        fromX++;
      } else if (fromAngle >= 0.75 * Math.PI) {
        if (fromAngle < 1.5 * Math.PI) {
          fromX--;
        } else if (fromAngle >= 1.75 * Math.PI) {
          fromX++;
        }
      }

      if (fromAngle >= 0.25 * Math.PI) {
        if (fromAngle < Math.PI) {
          fromY--;
        } else if (fromAngle >= 1.25 * Math.PI) {
          fromY++;
        }
      }

      if (toAngle > 1.5 * Math.PI) {
        toX++;
      } else if (toAngle <= 1.25 * Math.PI) {
        if (toAngle > 0.5 * Math.PI) {
          toX--;
        } else if (toAngle <= 0.25 * Math.PI) {
          toX++;
        }
      }

      if (toAngle <= 1.75 * Math.PI) {
        if (toAngle > Math.PI) {
          toY++;
        } else if (toAngle <= 0.75 * Math.PI) {
          toY--;
        }
      }

      for (;;)
      {
        boolean visible = false;
        int oa = 0;
        int ob = 0;

        if (!touchedCellsMap[fromY][fromX])
        {
          for (int i = 0; i < 4; i++)
          {
            float dx = (float)fromX + X_ADD[i] - heroX;
            float dy = (float)fromY + Y_ADD[i] - heroY;

            float tf = dx * fromDy + dy * fromDx;
            float tt = dx * toDy + dy * toDx;

            if (tf <= 0 && tt >= 0) {
              visible = true;
              break;
            } else if (tf >= 0) {
              oa++;
            } else if (tt <= 0) {
              ob++;
            }
          }
        }

        // if at least one point is between fromAngle and toAngle
        // or fromAngle and toAngle is between cell points
        if (visible || (oa > 0 && ob > 0)) {
          break;
        }

        if (fromX == toX && fromY == toY) {
          repeat = false;
          break;
        } else if (fromY > toY) {
          if (fromX >= toX) {
            fromY--;
          } else {
            fromX++;
          }
        } else if (fromY == toY) {
          if (fromX > toX) {
            fromX--;
          } else {
            fromX++;
          }
        } else {
          if (fromX <= toX) {
            fromY++;
          } else {
            fromX--;
          }
        }
      }

      for (;;)
      {
        boolean visible = false;
        int oa = 0;
        int ob = 0;

        if (!touchedCellsMap[toY][toX])
        {
          for (int i = 0; i < 4; i++)
          {
            float dx = (float)toX + X_ADD[i] - heroX;
            float dy = (float)toY + Y_ADD[i] - heroY;

            float tf = dx * fromDy + dy * fromDx;
            float tt = dx * toDy + dy * toDx;

            if (tf <= 0 && tt >= 0) {
              visible = true;
              break;
            } else if (tf >= 0) {
              oa++;
            } else if (tt <= 0) {
              ob++;
            }
          }
        }

        // if at least one point is between fromAngle and toAngle
        // or fromAngle and toAngle is between cell points
        if (visible || (oa > 0 && ob > 0)) {
          break;
        }

        if (fromX == toX && fromY == toY) {
          repeat = false;
          break;
        } else if (fromY > toY) {
          if (fromX > toX) {
            toX++;
          } else {
            toY++;
          }
        } else if (fromY == toY) {
          if (fromX > toX) {
            toX++;
          } else {
            toX--;
          }
        } else {
          if (fromX < toX) {
            toX--;
          } else {
            toY--;
          }
        }
      }

      int x = fromX;
      int y = fromY;
      int prevX = fromX;
      int prevY = fromY;
      int lastX = fromX;
      int lastY = fromY;
      float portFromX = -1;
      float portFromY = -1;
      float portToX = -1;
      float portToY = -1;
      boolean wall = false;
      boolean portal = false;

      for (;;)
      {
        if (!touchedCellsMap[y][x])  // just for case
        {
          touchedCellsMap[y][x] = true;

          if ((level[y][x] <= 0) && (touchedCellsCount < MAX_TOUCHED_CELLS))
          {
            touchedCells[touchedCellsCount].x = x;
            touchedCells[touchedCellsCount].y = y;
            touchedCellsCount++;
          }
        }

        if (level[y][x] == 0)
        {
          if (wall)
          {
            if (portal)
            {
              float innerToAngle = (portToX >= 0 ? getAngle(portToX - heroX, portToY - heroY) /* + ANG_CORRECT (leaved here just for case) */ : toAngle);

              if (angleDiff(fromAngle, innerToAngle) < Math.PI) {
                traceCell(fromX, fromY, fromAngle, lastX, lastY, innerToAngle);
              }
            }

            if (portFromX >= 0) {
              fromAngle = getAngle(portFromX - heroX, portFromY - heroY) /* - ANG_CORRECT (leaved here just for case) */;
            }

            fromX = x;
            fromY = y;
            wall = false;
            portal = false;
          }
        }
        else
        {
          addWallBlock(x, y, level[y][x] > 0);    // -1 = closed door

          if (!wall)
          {
            lastX = prevX;
            lastY = prevY;
            wall = true;
            portal = (x != fromX || y != fromY);

            if (tToSide >= 0)
            {
              portToX = (float)x + X_ADD[(tFromSide + 1) % 4];
              portToY = (float)y + Y_ADD[(tFromSide + 1) % 4];
            }
          }

          if (tFromSide >= 0)
          {
            portFromX = (float)x + X_ADD[tToSide];
            portFromY = (float)y + Y_ADD[tToSide];
          }
        }

        if (x == toX && y == toY)
        {
          if (portal)
          {
            toX = lastX;
            toY = lastY;

            if (portToX >= 0)
            {
              toAngle = getAngle(portToX - heroX, portToY - heroY) /* + ANG_CORRECT (leaved here just for case) */;

              if (angleDiff(fromAngle, toAngle) > Math.PI) {
                repeat = false;
              }
            }
          }
          else if (wall)
          {
            repeat = false;
          }

          break;
        }

        prevX = x;
        prevY = y;

        if (y > toY) {
          if (x >= toX) {
            y--;
          } else {
            x++;
          }
        } else if (y == toY) {
          if (x > toX) {
            x--;
          } else {
            x++;
          }
        } else {
          if (x <= toX) {
            y++;
          } else {
            x--;
          }
        }
      }
    } while (repeat);
  }

  // halfFov must be between (10 * PI / 180) and (45 * PI / 180)
  public void trace(float x, float y, float heroAngle, float halfFov)
  {
    level = State.wallsMap;
    levelWidth = State.levelWidth;
    levelHeight = State.levelHeight;

    float fromAngle = heroAngle - halfFov;
    float toAngle = heroAngle + halfFov;

    if (fromAngle < 0) {
      fromAngle += PI_M2F;
    } else {
      fromAngle %= PI_M2F;
    }

    if (toAngle < 0) {
      toAngle += PI_M2F;
    } else {
      toAngle %= PI_M2F;
    }

    for (int i = 0; i < levelHeight; i++)
    {
      for (int j = 0; j < levelWidth; j++)
      {
        touchedCellsMap[i][j] = false;
        drawedWalls[i][j] = 0;
      }
    }

    heroX = x;
    heroY = y;
    wallsCount = 0;
    touchedCellsCount = 0;

    touchedCellsMap[(int)y][(int)x] = true;
    touchedCells[touchedCellsCount].x = (int)x;
    touchedCells[touchedCellsCount].y = (int)y;
    touchedCellsCount++;

    int tx = (int)x;
    int ty = (int)y;

    if (fromAngle < 0.25 * Math.PI) {
      tx++;
      ty++;
    } else if (fromAngle < 0.5 * Math.PI) {
      tx++;
    } else if (fromAngle < 0.75 * Math.PI) {
      tx++;
      ty--;
    } else if (fromAngle < Math.PI) {
      ty--;
    } else if (fromAngle < 1.25 * Math.PI) {
      tx--;
      ty--;
    } else if (fromAngle < 1.5 * Math.PI) {
      tx--;
    } else if (fromAngle < 1.75 * Math.PI) {
      tx--;
      ty++;
    } else {
      ty++;
    }

    if (level[ty][tx] > 0)
    {
      addWallBlock(tx, ty, true);
    }
    else
    {
      touchedCellsMap[ty][tx] = true;
      touchedCells[touchedCellsCount].x = tx;
      touchedCells[touchedCellsCount].y = ty;
      touchedCellsCount++;
    }

    tx = (int)x;
    ty = (int)y;

    if (toAngle > 1.75 * Math.PI) {
      tx++;
      ty--;
    } else if (toAngle > 1.5 * Math.PI) {
      tx++;
    } else if (toAngle > 1.25 * Math.PI) {
      tx++;
      ty++;
    } else if (toAngle > Math.PI) {
      ty++;
    } else if (toAngle > 0.75 * Math.PI) {
      tx--;
      ty++;
    } else if (toAngle > 0.5 * Math.PI) {
      tx--;
    } else if (toAngle > 0.25 * Math.PI) {
      tx--;
      ty--;
    } else {
      ty--;
    }

    if (level[ty][tx] > 0)
    {
      addWallBlock(tx, ty, true);
    }
    else
    {
      touchedCellsMap[ty][tx] = true;
      touchedCells[touchedCellsCount].x = tx;
      touchedCells[touchedCellsCount].y = ty;
      touchedCellsCount++;
    }

    traceCell((int)x, (int)y, fromAngle, (int)x, (int)y, toAngle);
  }
}




Java Source Code List

zame.game.AppConfig.java
zame.game.AppConfig.java
zame.game.Common.java
zame.game.ConfigZeemote.java
zame.game.ConfigZeemote.java
zame.game.Config.java
zame.game.GameActivityZeemoteHelper.java
zame.game.GameActivityZeemoteHelper.java
zame.game.GameActivity.java
zame.game.GamePreferencesActivity.java
zame.game.GamePreferencesActivity.java
zame.game.MenuActivityHelper.java
zame.game.MenuActivityHelper.java
zame.game.MenuActivity.java
zame.game.Renderer.java
zame.game.SoundManager.java
zame.game.ZameApplicationAnalyticsHelper.java
zame.game.ZameApplicationAnalyticsHelper.java
zame.game.ZameApplication.java
zame.game.ZameGame.java
zame.game.ZameJniRenderer.java
zame.game.engine.Action.java
zame.game.engine.AutoWall.java
zame.game.engine.Controls.java
zame.game.engine.Door.java
zame.game.engine.GameHelper.java
zame.game.engine.GameHelper.java
zame.game.engine.Game.java
zame.game.engine.Labels.java
zame.game.engine.LevelConfig.java
zame.game.engine.LevelRenderer.java
zame.game.engine.Level.java
zame.game.engine.Mark.java
zame.game.engine.Monster.java
zame.game.engine.Overlay.java
zame.game.engine.PortalTracer.java
zame.game.engine.State.java
zame.game.engine.Stats.java
zame.game.engine.TextureLoader.java
zame.game.engine.Weapons.java
zame.game.views.EndLevelView.java
zame.game.views.GameOverView.java
zame.game.views.GameView.java
zame.game.views.IZameView.java
zame.game.views.MenuViewHelper.java
zame.game.views.MenuViewHelper.java
zame.game.views.MenuView.java
zame.game.views.PreLevelView.java
zame.game.views.ZameGameView.java
zame.libs.FrameLayout.java
zame.libs.GLSurfaceView21.java
zame.libs.Grid.java
zame.libs.KeyMapPreference.java
zame.libs.LabelMaker.java
zame.libs.ListPreference.java
zame.libs.NumericSprite.java
zame.libs.SeekBarPreference.java
zame.promo.PromoView.java