Android Open Source - CircleWorldGDX Tilemap Circle






From Project

Back to project page CircleWorldGDX.

License

The source code is released under:

MIT License

If you think the Android project CircleWorldGDX 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 com.fdangelo.circleworld.universeengine.tilemap;
/*  www .j ava 2 s .c o  m*/
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.fdangelo.circleworld.universeengine.utils.DataPools;
import com.fdangelo.circleworld.utils.Mathf;
import com.fdangelo.circleworld.utils.Vector2I;

public abstract class TilemapCircle {
  public static final float TILE_SIZE = 0.5f;
  public static final float TILE_SIZE_INV = 1.0f / TILE_SIZE;

  protected int seed;
  protected int height;
  protected int width;

  protected byte[] tiles;

  protected Vector2[] circleNormals;
  protected float[] circleHeights;

  // Used when finding tileY positions!
  private float height0;
  private float k;
  private float logk;

  protected ITilemapCircleListener listener;

  protected float positionX;
  protected float positionY;
  protected float rotation;

  static private TileHitInfo tmpHitInfo = new TileHitInfo();
  static private Vector2 tmpv1 = new Vector2();

  public final int getHeight() {
    return height;
  }

  public final int getWidth() {
    return width;
  }

  public final int getSeed() {
    return seed;
  }

  public final float getPositionX() {
    return positionX;
  }

  public final float getPositionY() {
    return positionY;
  }

  public final void setPosition(final float x, final float y) {
    positionX = x;
    positionY = y;
  }

  public final float getRotation() {
    return rotation;
  }

  public final void setRotation(final float value) {
    rotation = value;
  }

  public final Vector2[] getCircleNormals() {
    return circleNormals;
  }

  public float[] getCircleHeights() {
    return circleHeights;
  }

  public final ITilemapCircleListener getListener() {
    return listener;
  }

  public final void setListener(final ITilemapCircleListener value) {
    listener = value;
  }

  public final void init(final int seed, int height) {
    if (height < 5) {
      height = 5;
    }

    this.seed = seed;
    this.height = height;

    initData();

    updateTiles();
  }

  protected abstract void updateTiles();

  private final void initData() {
    width = (((int) (height * MathUtils.PI * 2.0f)) / 4) * 4;

    circleNormals = DataPools.poolVector2.getArray(width);
    circleHeights = DataPools.poolFloat.getArray(height + 1);
    tiles = DataPools.poolByte.getArray(width * height);

    final float angleStep = ((2.0f * MathUtils.PI) / width);

    for (int i = 0; i < width; i++) {
      final float angle = i * angleStep;
      circleNormals[i] = new Vector2(Mathf.sin(angle), Mathf.cos(angle));
    }

    height0 = (height - 1) * TILE_SIZE;
    k = -((width / (MathUtils.PI * 2.0f))) / (1 - (width / (MathUtils.PI * 2.0f)));
    logk = (float) Math.log(k);

    circleHeights[0] = height0;

    for (int i = 1; i <= height; i++) {
      final float r1 = circleHeights[i - 1];

      // float r2 = ((-r1 * width) / (Mathf.PI * 2.0f)) / (1 - (width /
      // (Mathf.PI * 2.0f)));
      final float r2 = r1 * k;

      circleHeights[i] = r2;
    }
  }

  public final byte getTile(final int tileX, final int tileY) {
    return tiles[tileX + tileY * width];
  }

  public final void getTile(final int tileX, final int tileY, final byte tile) {
    if (tiles[tileX + tileY * width] != tile) {
      tiles[tileX + tileY * width] = tile;
      if (listener != null) {
        listener.onTilemapTileChanged(tileX, tileY);
      }
    }
  }

  public final int getTileYFromDistance(final float distance) {
    // This was taken from wolfram-alpha, by solving the radius relationship
    // function
    // Original function:
    // http://www.wolframalpha.com/input/?i=g%280%29%3Dk%2C+g%28n%2B1%29%3Dl+*+g%28n%29
    // Solution:
    // http://www.wolframalpha.com/input/?i=y+%3D+k+*+l%CB%86x+find+x (we
    // use the solution over reals with y > 0)

    // int tileY = (int) (Mathf.Log (distance / height0) / Mathf.Log (k));
    final int tileY = (int) (Math.log(distance / height0) / logk);

    return tileY;
  }

  public final float getDistanceFromTileY(final int tileY) {
    return (float) (height0 * Math.pow(k, tileY));
  }

  public final float getDistanceFromPosition(final float positionX, final float positionY) {
    final float dx = positionX - this.positionX;
    final float dy = positionY - this.positionY;

    return (float) Math.sqrt(dx * dx + dy * dy);
  }

  public final int getTileXFromAngle(final float angle) {
    int tileX = MathUtils.floor((angle / (MathUtils.PI * 2.0f)) * width);

    tileX = tileX % width;
    if (tileX < 0) {
      tileX += width;
    }

    return tileX;
  }

  public final Vector2 getPositionFromTileCoordinate(final int tileX, final int tileY) {
    // return position + GetNormalFromTileX(tileX) *
    // GetDistanceFromTileY(tileY);

    return getNormalFromTileX(tileX).scl(getDistanceFromTileY(tileY)).add(positionX, positionY);
  }

  public final Vector2 getPositionFromDistanceAndAngle(final float distance, final float angle) {
    // return position + GetNormalFromAngle(angle) * distance;

    final Vector2 normal = getNormalFromAngle(angle);
    normal.scl(distance);
    normal.add(positionX, positionY);

    return normal;
  }

  public final boolean getTileCoordinatesFromPosition(final float positionX, final float positionY, final Vector2I tileCoordinate) {
    final float dx = positionX - this.positionX;
    final float dy = positionY - this.positionY;

    final float distance = (float) Math.sqrt(dx * dx + dy * dy);
    final float angle = -Mathf.atan2(dy, dx) + MathUtils.PI * 0.5f;

    tileCoordinate.y = getTileYFromDistance(distance);
    tileCoordinate.x = getTileXFromAngle(angle);

    if (tileCoordinate.y >= height || tileCoordinate.y < 0) {
      return false;
    }

    return true;
  }

  public final float getScaleFromPosition(final float positionX, final float positionY) {
    final float dx = positionX - this.positionX;
    final float dy = positionY - this.positionY;
    final float distance = (float) Math.sqrt(dx * dx + dy * dy);

    final float scale = MathUtils.clamp((distance * 2.0f * MathUtils.PI) / width, (circleHeights[0] * 2.0f * MathUtils.PI) / width,
        (circleHeights[circleHeights.length - 1] * 2.0f * MathUtils.PI) / width) * TILE_SIZE_INV;

    return scale;
  }

  public final Vector2 getNormalFromPosition(final float positionX, final float positionY) {
    final float dx = positionX - this.positionX;
    final float dy = positionY - this.positionY;
    final float distance = (float) Math.sqrt(dx * dx + dy * dy);

    return tmpv1.set(dx / distance, dy / distance);
  }

  public final Vector2 getNormalFromAngle(final float angle) {
    return tmpv1.set(Mathf.sin(angle), Mathf.cos(angle));
  }

  public final float getAngleFromPosition(final float positionX, final float positionY) {
    final float dx = positionX - this.positionX;
    final float dy = positionY - this.positionY;

    final float angle = -Mathf.atan2(dy, dx) + MathUtils.PI * 0.5f;

    return angle;
  }

  public final Vector2 getNormalFromTileX(int tileX) {
    tileX = tileX % width;

    return tmpv1.set(circleNormals[tileX]);
  }

  public final Vector2 getTangentFromPosition(final float positionX, final float positionY) {
    final Vector2 normal = getNormalFromPosition(positionX, positionY);

    return tmpv1.set(normal.y, -normal.x);
  }

  public final Vector2 getTangentFromTileCoordinate(final int tileX, final int tileY) {
    final Vector2 normal = getNormalFromTileX(tileX);

    return tmpv1.set(normal.y, -normal.x);
  }

  public final boolean raycastSquare(final float originX, final float originY, float size, final TileDirection direction, final float len,
      final TileHitInfo hitInfo) {
    size *= 0.95f;

    final int iterations = Math.max(MathUtils.ceil(size / TILE_SIZE), 1);

    // Vector2 from = origin - GetTanget(origin, direction) * (size * 0.5f);
    Vector2 from = getTanget(originX, originY, direction);
    from.scl(size * 0.5f);
    from.add(originX, originY);
    float fromX = from.x;
    float fromY = from.y;
    from = null;

    // Vector2 step = GetTanget(origin, direction) * (size / iterations);
    Vector2 step = getTanget(originX, originY, direction);
    step.scl(size / iterations);
    final float stepX = step.x;
    final float stepY = step.y;
    step = null;

    boolean hitAny = false;

    final TileHitInfo localHitInfo = tmpHitInfo;

    for (int i = 0; i <= iterations; i++) {
      if (raycast(fromX, fromY, direction, len, localHitInfo)) {
        if (!hitAny) {
          hitAny = true;
          hitInfo.set(localHitInfo);
        } else if (localHitInfo.hitDistance < hitInfo.hitDistance) {
          hitInfo.set(localHitInfo);
        }
      }

      fromX += stepX;
      fromY += stepY;
    }

    return hitAny;
  }

  public final Vector2 getDirection(final float originX, final float originY, final TileDirection direction) {
    switch (direction) {
      case Down:
        return getNormalFromPosition(originX, originY).scl(-1);

      case Up:
        return getNormalFromPosition(originX, originY);

      case Right:
        return getTangentFromPosition(originX, originY);

      case Left:
        return getTangentFromPosition(originX, originY).scl(-1);

      default:
        return tmpv1.set(0, 0);
    }
  }

  public final Vector2 getTanget(final float originX, final float originY, final TileDirection direction) {
    switch (direction) {
      case Down:
        return getTangentFromPosition(originX, originY);

      case Up:
        return getTangentFromPosition(originX, originY);

      case Right:
        return getNormalFromPosition(originX, originY);

      case Left:
        return getNormalFromPosition(originX, originY);

      default:
        return tmpv1.set(0, 0);
    }
  }

  public final boolean raycast(final float originX, final float originY, final TileDirection direction, float len, final TileHitInfo hitInfo) {
    final float dx = originX - positionX;
    final float dy = originY - positionY;
    float originDistance = (float) Math.sqrt(dx * dx + dy * dy);

    float targetX;
    float targetY;
    float targetdx;
    float targetdy;
    float targetDistance;
    float tangentDistance;

    float segmentSize;

    if (originDistance < 0.001f) {
      originDistance = 0.001f;
    }

    float originMapAngle = -Mathf.atan2(dy, dx) + MathUtils.PI * 0.5f;

    while (originMapAngle > MathUtils.PI2) {
      originMapAngle -= MathUtils.PI2;
    }

    while (originMapAngle < 0.0f) {
      originMapAngle += MathUtils.PI2;
    }

    final float originNormalX = dx / originDistance;
    final float originNormalY = dy / originDistance;
    final float originTangentX = originNormalY;
    final float originTangentY = -originNormalX;

    if (direction == TileDirection.Right) {
      targetX = originX + originTangentX * len;
      targetY = originY + originTangentY * len;
      targetdx = targetX - positionX;
      targetdy = targetY - positionY;
      targetDistance = (float) Math.sqrt(targetdx * targetdx + targetdy * targetdy);

      if (originDistance > circleHeights[circleHeights.length - 1]) {
        // Origin point outside, not hit!
        return false;
      }

      for (int i = 1; i < circleHeights.length; i++) {
        if (originDistance < circleHeights[i]) {
          hitInfo.hitTileY = i - 1;
          break;
        }
      }

      segmentSize = (circleHeights[hitInfo.hitTileY] * 2.0f * MathUtils.PI) / width;
      tangentDistance = ((originMapAngle / (MathUtils.PI2)) * width);

      hitInfo.hitTileX = (int) tangentDistance;
      hitInfo.hitTileX = (hitInfo.hitTileX + 1) % width;

      len -= segmentSize * (MathUtils.ceil(tangentDistance) - tangentDistance);

      while (hitInfo.hitTileX < width && len >= 0) {
        if (getTile(hitInfo.hitTileX, hitInfo.hitTileY) != 0) {
          final Vector2 tanget = getTangentFromTileCoordinate(hitInfo.hitTileX, hitInfo.hitTileY);

          hitInfo.hitNormalX = -tanget.x;
          hitInfo.hitNormalY = -tanget.y;
          hitInfo.hitPositionX = positionX + circleNormals[hitInfo.hitTileX].x * originDistance;
          hitInfo.hitPositionY = positionY + circleNormals[hitInfo.hitTileX].y * originDistance;
          hitInfo.hitDistance = Mathf.len(originX - hitInfo.hitPositionX, originY - hitInfo.hitPositionY);

          return true;
        }

        len -= segmentSize;

        hitInfo.hitTileX++;
      }
    } else if (direction == TileDirection.Left) {
      targetX = originX + originTangentX * len;
      targetY = originY + originTangentY * len;
      targetdx = targetX - positionX;
      targetdy = targetY - positionY;
      targetDistance = (float) Math.sqrt(targetdx * targetdx + targetdy * targetdy);

      if (originDistance > circleHeights[circleHeights.length - 1]) {
        // Origin point outside, not hit!
        return false;
      }

      for (int i = 1; i < circleHeights.length; i++) {
        if (originDistance < circleHeights[i]) {
          hitInfo.hitTileY = i - 1;
          break;
        }
      }

      segmentSize = (circleHeights[hitInfo.hitTileY] * 2.0f * MathUtils.PI) / width;
      tangentDistance = ((originMapAngle / (MathUtils.PI2)) * width);

      hitInfo.hitTileX = (int) tangentDistance;
      hitInfo.hitTileX = (hitInfo.hitTileX - 1) % width;
      if (hitInfo.hitTileX < 0) {
        hitInfo.hitTileX += width;
      }

      len -= segmentSize * (tangentDistance - MathUtils.floor(tangentDistance));

      while (hitInfo.hitTileX >= 0 && len >= 0) {
        if (getTile(hitInfo.hitTileX, hitInfo.hitTileY) != 0) {
          final Vector2 tangent = getTangentFromTileCoordinate(hitInfo.hitTileX + 1, hitInfo.hitTileY);

          hitInfo.hitNormalX = tangent.x;
          hitInfo.hitNormalY = tangent.y;
          hitInfo.hitPositionX = positionX + circleNormals[(hitInfo.hitTileX + 1) % width].x * originDistance;
          hitInfo.hitPositionX = positionY + circleNormals[(hitInfo.hitTileX + 1) % width].y * originDistance;
          hitInfo.hitDistance = Mathf.len(originX - hitInfo.hitPositionX, originY - hitInfo.hitPositionY);
          return true;
        }

        len -= segmentSize;

        hitInfo.hitTileX--;
      }
    } else if (direction == TileDirection.Up) {
      targetX = originX + originNormalX * len;
      targetY = originY + originNormalY * len;
      targetdx = targetX - positionX;
      targetdy = targetY - positionY;
      targetDistance = (float) Math.sqrt(targetdx * targetdx + targetdy * targetdy);

      if (originDistance > circleHeights[circleHeights.length - 1]) {
        // Origin point outside, not hit!
        return false;
      }

      hitInfo.hitTileX = (int) ((originMapAngle / (MathUtils.PI * 2.0f)) * width);
      hitInfo.hitTileX = hitInfo.hitTileX % width;

      for (int i = 1; i < circleHeights.length; i++) {
        if (originDistance < circleHeights[i]) {
          hitInfo.hitTileY = i;
          len -= circleHeights[i] - originDistance;
          break;
        }
      }

      while (hitInfo.hitTileY < height && len >= 0) {
        if (getTile(hitInfo.hitTileX, hitInfo.hitTileY) != 0) {
          hitInfo.hitNormalX = -originNormalX;
          hitInfo.hitNormalY = -originNormalY;
          hitInfo.hitPositionX = positionX + originNormalX * circleHeights[hitInfo.hitTileY];
          hitInfo.hitPositionY = positionY + originNormalY * circleHeights[hitInfo.hitTileY];
          hitInfo.hitDistance = Mathf.len(originX - hitInfo.hitPositionX, originY - hitInfo.hitPositionY);

          return true;
        }

        if (hitInfo.hitTileY < height - 1) {
          len -= (circleHeights[hitInfo.hitTileY + 1] - circleHeights[hitInfo.hitTileY]);
        }

        hitInfo.hitTileY++;
      }
    } else if (direction == TileDirection.Down) {
      targetX = originX - originNormalX * len;
      targetY = originY - originNormalY * len;
      targetdx = targetX - positionX;
      targetdy = targetY - positionY;
      targetDistance = (float) Math.sqrt(targetdx * targetdx + targetdy * targetdy);

      if (/* originDistance > circleHeights[circleHeights.Length - 1] && */
      targetDistance > circleHeights[circleHeights.length - 1]) {
        // Target outside, no hit!
        return false;
      } else if (targetDistance < circleHeights[0]) {
        // Target inside core, core hit!
        hitInfo.hitTileY = 0;
        hitInfo.hitNormalX = originNormalX;
        hitInfo.hitNormalY = originNormalY;
        hitInfo.hitPositionX = positionX + originNormalX * circleHeights[hitInfo.hitTileY + 1];
        hitInfo.hitPositionY = positionY + originNormalY * circleHeights[hitInfo.hitTileY + 1];
        hitInfo.hitDistance = Mathf.len(originX - hitInfo.hitPositionX, originY - hitInfo.hitPositionY);

        return true;
      }

      hitInfo.hitTileX = (int) ((originMapAngle / (MathUtils.PI * 2.0f)) * width);
      hitInfo.hitTileX = hitInfo.hitTileX % width;

      for (int i = circleHeights.length - 1; i >= 1; i--) {
        if (originDistance > circleHeights[i]) {
          hitInfo.hitTileY = i - 1;
          len -= originDistance - circleHeights[i];
          break;
        }
      }

      while (hitInfo.hitTileY >= 0 && len > 0) {
        if (getTile(hitInfo.hitTileX, hitInfo.hitTileY) != 0) {
          hitInfo.hitNormalX = originNormalX;
          hitInfo.hitNormalY = originNormalY;
          hitInfo.hitPositionX = positionX + originNormalX * circleHeights[hitInfo.hitTileY + 1];
          hitInfo.hitPositionY = positionY + originNormalY * circleHeights[hitInfo.hitTileY + 1];
          hitInfo.hitDistance = Mathf.len(originX - hitInfo.hitPositionX, originY - hitInfo.hitPositionY);

          return true;
        }

        if (hitInfo.hitTileY > 0) {
          len -= (circleHeights[hitInfo.hitTileY] - circleHeights[hitInfo.hitTileY - 1]);
        }
        hitInfo.hitTileY--;
      }
    }

    return false;
  }

  public void recycle() {
    DataPools.poolVector2.returnArray(circleNormals);
    circleNormals = null;

    DataPools.poolFloat.returnArray(circleHeights);
    circleHeights = null;

    DataPools.poolByte.returnArray(tiles);
    tiles = null;

    listener = null;
  }
}




Java Source Code List

.AssetsUpdater.java
com.fdangelo.circleworld.GameLogicState.java
com.fdangelo.circleworld.GameLogic.java
com.fdangelo.circleworld.MainActivity.java
com.fdangelo.circleworld.Main.java
com.fdangelo.circleworld.MyGdxGame.java
com.fdangelo.circleworld.RobovmLauncher.java
com.fdangelo.circleworld.client.GwtLauncher.java
com.fdangelo.circleworld.gui.AvatarEditControlScreen.java
com.fdangelo.circleworld.gui.AvatarMoveControlScreen.java
com.fdangelo.circleworld.gui.HudScreen.java
com.fdangelo.circleworld.gui.core.Gui.java
com.fdangelo.circleworld.gui.core.ScreenTable.java
com.fdangelo.circleworld.gui.core.Screen.java
com.fdangelo.circleworld.universeengine.IUniverseListener.java
com.fdangelo.circleworld.universeengine.ThingPosition.java
com.fdangelo.circleworld.universeengine.ThingType.java
com.fdangelo.circleworld.universeengine.Thing.java
com.fdangelo.circleworld.universeengine.UniverseFactory.java
com.fdangelo.circleworld.universeengine.UniverseGeneratorDefault.java
com.fdangelo.circleworld.universeengine.UniverseGenerator.java
com.fdangelo.circleworld.universeengine.Universe.java
com.fdangelo.circleworld.universeengine.objects.AvatarInput.java
com.fdangelo.circleworld.universeengine.objects.Avatar.java
com.fdangelo.circleworld.universeengine.objects.FollowParentParameters.java
com.fdangelo.circleworld.universeengine.objects.IUniverseObjectListener.java
com.fdangelo.circleworld.universeengine.objects.ShipInput.java
com.fdangelo.circleworld.universeengine.objects.Ship.java
com.fdangelo.circleworld.universeengine.objects.UniverseObject.java
com.fdangelo.circleworld.universeengine.tilemap.ITilemapCircleListener.java
com.fdangelo.circleworld.universeengine.tilemap.PlanetType.java
com.fdangelo.circleworld.universeengine.tilemap.PlanetTypes.java
com.fdangelo.circleworld.universeengine.tilemap.Planet.java
com.fdangelo.circleworld.universeengine.tilemap.TileDirection.java
com.fdangelo.circleworld.universeengine.tilemap.TileHitFlags.java
com.fdangelo.circleworld.universeengine.tilemap.TileHitInfo.java
com.fdangelo.circleworld.universeengine.tilemap.TileSubtype.java
com.fdangelo.circleworld.universeengine.tilemap.TileType.java
com.fdangelo.circleworld.universeengine.tilemap.TileTypes.java
com.fdangelo.circleworld.universeengine.tilemap.TilemapCircle.java
com.fdangelo.circleworld.universeengine.utils.DataPools.java
com.fdangelo.circleworld.universeengine.utils.PoolByte.java
com.fdangelo.circleworld.universeengine.utils.PoolColor.java
com.fdangelo.circleworld.universeengine.utils.PoolFloat.java
com.fdangelo.circleworld.universeengine.utils.PoolInt.java
com.fdangelo.circleworld.universeengine.utils.PoolVector2.java
com.fdangelo.circleworld.universeengine.utils.PoolVector3.java
com.fdangelo.circleworld.universeengine.utils.UEProfilerSample.java
com.fdangelo.circleworld.universeengine.utils.UEProfiler.java
com.fdangelo.circleworld.universeview.FollowCameraParameters.java
com.fdangelo.circleworld.universeview.UniverseViewCamera.java
com.fdangelo.circleworld.universeview.UniverseViewFactory.java
com.fdangelo.circleworld.universeview.UniverseView.java
com.fdangelo.circleworld.universeview.objects.AvatarInputEditTool.java
com.fdangelo.circleworld.universeview.objects.AvatarInputMode.java
com.fdangelo.circleworld.universeview.objects.AvatarViewInput.java
com.fdangelo.circleworld.universeview.objects.AvatarView.java
com.fdangelo.circleworld.universeview.objects.InputAreas.java
com.fdangelo.circleworld.universeview.objects.ShipInputMode.java
com.fdangelo.circleworld.universeview.objects.ShipViewInput.java
com.fdangelo.circleworld.universeview.objects.ShipView.java
com.fdangelo.circleworld.universeview.objects.UniverseObjectView.java
com.fdangelo.circleworld.universeview.tilemap.PlanetView.java
com.fdangelo.circleworld.universeview.tilemap.TilemapCircleViewBackgroundRenderer.java
com.fdangelo.circleworld.universeview.tilemap.TilemapCircleViewRenderer.java
com.fdangelo.circleworld.universeview.tilemap.TilemapCircleView.java
com.fdangelo.circleworld.utils.Mathf.java
com.fdangelo.circleworld.utils.Vector2I.java