Android Open Source - CircleWorldGDX Universe View Camera






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.universeview;
/*from  ww  w .  j a  va2 s . c  om*/
import com.badlogic.gdx.Application.ApplicationType;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Camera;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.fdangelo.circleworld.GameLogic;
import com.fdangelo.circleworld.GameLogicState;
import com.fdangelo.circleworld.universeview.objects.AvatarInputMode;
import com.fdangelo.circleworld.universeview.objects.AvatarViewInput;
import com.fdangelo.circleworld.universeview.objects.InputAreas;
import com.fdangelo.circleworld.universeview.objects.ShipInputMode;
import com.fdangelo.circleworld.universeview.objects.ShipViewInput;
import com.fdangelo.circleworld.universeview.tilemap.PlanetView;
import com.fdangelo.circleworld.utils.Mathf;

public final class UniverseViewCamera {
  private static UniverseViewCamera instance;

  private static final float SMOOTH_TIME = 0.5f;
  private static final float ZOOM_SMOOTH_TIME = 0.15f;

  private static final float MIN_CAMERA_DISTANCE = 0.01f;
  private static final float MAX_CAMERA_DISTANCE = 100;

  private float cameraDistance = 0.02f;
  private final float zoomSpeed = 10;
  private float scale = 1.0f;
  private final OrthographicCamera cam;
  private float camRotation;
  private boolean moving;

  private float movingFromInputPositionX;
  private float movingFromInputPositionY;

  private boolean zooming;
  private float zoomingTouchFinger1FromPositionX;
  private float zoomingTouchFinger1FromPositionY;
  private float zoomingTouchFinger2FromPositionX;
  private float zoomingTouchFinger2FromPositionY;

  private float zoomingCameraDistanceDelta;

  private Actor followingObject;
  private boolean followRotation;
  private boolean followScale;

  private final Vector2 followingObjectPositionDelta = new Vector2();
  // private Vector2 followingObjectPositionDeltaVelocity = new Vector2();

  private float followingObjectScaleDelta;
  // private float followingObjectScaleDeltaVelocity;

  private float followingObjectCameraDistanceDelta;
  // private float followingObjectCameraDistanceDeltaVelocity;

  private float followingObjectRotationDelta;

  private float followObjectSmoothTime;

  static private Vector3 tmpv3 = new Vector3();

  public static UniverseViewCamera getInstance() {
    return instance;
  }

  public final Actor getFollowingObject() {
    return followingObject;
  }

  public final Camera getCamera() {
    return cam;
  }

  public UniverseViewCamera(final OrthographicCamera camera) {
    instance = this;

    cam = camera;
  }

  public final void update(final float deltaTime) {
    switch (GameLogic.getInstace().getState()) {
      case PlayingAvatar:
      case PlayingShip:
        updatePosition(deltaTime);
        updateZoomInput(deltaTime);
        updateZoom();
        break;

      case Travelling:
        updatePositionSmooth(deltaTime);
        updateZoom();
        break;

      case Loading:
        // Do nothing
        break;
    }
  }

  private final void updatePosition(final float deltaTime) {
    followObjectSmoothTime = 0;

    if (followingObject != null) {
      if (GameLogic.getInstace().getState() == GameLogicState.PlayingAvatar && AvatarViewInput.mode == AvatarInputMode.Move
          || GameLogic.getInstace().getState() == GameLogicState.PlayingShip && ShipViewInput.mode == ShipInputMode.Move) {
        
        followingObjectPositionDelta.set(Mathf.lerp(followingObjectPositionDelta, Vector2.Zero, deltaTime * (1.0f / SMOOTH_TIME)));
        followingObjectScaleDelta = Mathf.lerp(followingObjectScaleDelta, 0, deltaTime * (1.0f / SMOOTH_TIME));
        followingObjectRotationDelta = Mathf.lerp(followingObjectRotationDelta, 0, deltaTime * (1.0f / SMOOTH_TIME));
        followingObjectCameraDistanceDelta = Mathf.lerp(followingObjectCameraDistanceDelta, 0, deltaTime * (1.0f / SMOOTH_TIME));
      }

      float newPositionX, newPositionY;

      if (GameLogic.getInstace().getState() == GameLogicState.PlayingAvatar) {
        // newPosition = followingObject.position + trans.up *
        // followingObjectPositionDelta.y + trans.right *
        // followingObjectPositionDelta.x;

        newPositionX = followingObject.getX();
        newPositionY = followingObject.getY();

        tmpv3.set(cam.up).scl(followingObjectPositionDelta.y);
        newPositionX += tmpv3.x;
        newPositionY += tmpv3.y;

        // Calculate "right" direction by making the cross product
        // between the camera's foward and up vectors
        tmpv3.set(cam.up).crs(cam.direction).scl(followingObjectPositionDelta.x);
        newPositionX += tmpv3.x;
        newPositionY += tmpv3.y;
      } else {
        newPositionX = followingObject.getX() + followingObjectPositionDelta.x;
        newPositionY = followingObject.getY() + followingObjectPositionDelta.y;
      }

      float newRotation;

      if (followRotation) {
        newRotation = followingObject.getRotation();
      } else {
        newRotation = 0;
      }

      float newScale;

      if (followScale) {
        newScale = followingObject.getScaleX();
      } else {
        newScale = 1.0f;
      }

      // Update camera position
      cam.position.x = newPositionX;
      cam.position.y = newPositionY;

      // Update camera rotation
      camRotation = newRotation + followingObjectRotationDelta;
      while (camRotation > 360.0f) {
        camRotation -= 360.0f;
      }
      while (camRotation < 0) {
        camRotation += 360.0f;
      }
      cam.up.set(0, 1, 0).rotate(camRotation, 0, 0, -1);

      // Update camera scale
      scale = newScale + followingObjectScaleDelta;
    }
  }

  // Called by GameLogic
  private final boolean updatePositionSmooth(final float deltaTime) {
    followObjectSmoothTime += deltaTime;

    // followingObjectPositionDelta =
    // Vector3.SmoothDamp(followingObjectPositionDelta, Vector2.zero, ref
    // followingObjectPositionDeltaVelocity, SMOOTH_TIME);

    float newPositionX, newPositionY;

    if (followingObject != null) {
      followingObjectPositionDelta.set(Mathf.lerp(followingObjectPositionDelta, Vector2.Zero, followObjectSmoothTime / 1.0f));

      newPositionX = followingObject.getX();
      newPositionY = followingObject.getY();

      tmpv3.set(cam.up).scl(followingObjectPositionDelta.y);
      newPositionX += tmpv3.x;
      newPositionX += tmpv3.y;

      // Calculate "right" direction by making the cross product between
      // the camera's foward and up vectors
      tmpv3.set(cam.up).crs(cam.direction).scl(followingObjectPositionDelta.x);
      newPositionX += tmpv3.x;
      newPositionX += tmpv3.y;

      // TODO: Implemented camera rotation on libgdx
      // Quaternion newRotation = followingObject.rotation;

      final float newScale = followingObject.getScaleX();

      cam.position.x = Mathf.lerp(cam.position.x, newPositionX, followObjectSmoothTime / 1.0f);
      cam.position.y = Mathf.lerp(cam.position.y, newPositionY, followObjectSmoothTime / 1.0f);
      ;

      // trans.rotation = Quaternion.Lerp(trans.rotation, newRotation,
      // followObjectSmoothTime / 1.0f);

      scale = Mathf.lerp(scale, newScale, followObjectSmoothTime / 1.0f);

      return followObjectSmoothTime > 1.0f;
    } else {
      return true;
    }
  }

  public final void updateZoomInput(final float deltaTime) {
    if (Gdx.app.getType() == ApplicationType.Android || Gdx.app.getType() == ApplicationType.iOS) {
      int touchCount = 0;
      int touch1x = -1, touch1y = -1;
      int touch2x = -1, touch2y = -1;

      if (Gdx.input.isTouched(0)) {
        touch1x = Gdx.input.getX(0);
        touch1y = Gdx.input.getY(0);
        touchCount++;
      }

      if (Gdx.input.isTouched(1)) {
        touch2x = Gdx.input.getX(1);
        touch2y = Gdx.input.getY(1);
        touchCount++;
      }

      if (touchCount == 2) {
        if (!zooming) {
          zooming = true;
        } else {
          final float deltaFrom = Mathf.len(zoomingTouchFinger1FromPositionX - zoomingTouchFinger2FromPositionX, zoomingTouchFinger1FromPositionY
              - zoomingTouchFinger2FromPositionY);
          final float deltaTo = Mathf.len(touch1x - touch2x, touch1y - touch2y);

          final float zoom = (deltaTo - deltaFrom) / Mathf.len(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

          zoomingCameraDistanceDelta -= (cameraDistance + zoomingCameraDistanceDelta) * zoom * 4;
        }

        zoomingTouchFinger1FromPositionX = touch1x;
        zoomingTouchFinger1FromPositionY = touch1y;
        zoomingTouchFinger2FromPositionX = touch2x;
        zoomingTouchFinger2FromPositionY = touch2y;
      } else {
        zooming = false;
      }

    } else {
      // Use mouse
      // TODO: Fix scroll wheel rotation detection!
      // float zoom = Input.GetAxis("Mouse ScrollWheel");
      // zoomingCameraDistanceDelta -= (cameraDistance +
      // zoomingCameraDistanceDelta) * zoom * zoomSpeed * deltaTime;

      if (Gdx.input.isKeyPressed(Input.Keys.Z)) {
        zoomingCameraDistanceDelta -= (cameraDistance + zoomingCameraDistanceDelta) * -1.0f * zoomSpeed * deltaTime * 0.1f;
      } else if (Gdx.input.isKeyPressed(Input.Keys.X)) {
        zoomingCameraDistanceDelta -= (cameraDistance + zoomingCameraDistanceDelta) * 1.0f * zoomSpeed * deltaTime * 0.1f;
      }
    }
  }

  private final void updateZoom() {
    final float oldDelta = zoomingCameraDistanceDelta;
    zoomingCameraDistanceDelta = Mathf.lerp(zoomingCameraDistanceDelta, 0.0f, ZOOM_SMOOTH_TIME / 1.0f);
    cameraDistance += (oldDelta - zoomingCameraDistanceDelta);
    cameraDistance = MathUtils.clamp(cameraDistance, MIN_CAMERA_DISTANCE, MAX_CAMERA_DISTANCE);

    cam.zoom = (cameraDistance + followingObjectCameraDistanceDelta) * scale;
  }

  public final void updateMove() {
    float movingToInputPositionX = movingFromInputPositionX;
    float movingToInputPositionY = movingFromInputPositionY;

    if (Gdx.app.getType() == ApplicationType.Android || Gdx.app.getType() == ApplicationType.iOS) {
      int touchCount = 0;
      int touch1x = -1, touch1y = -1;

      if (Gdx.input.isTouched(0)) {
        touch1x = Gdx.input.getX(0);
        touch1y = Gdx.input.getY(0);
        touchCount++;
      }

      if (Gdx.input.isTouched(1)) {
        touchCount++;
      }

      if (touchCount == 1) {
        if (!moving) {
          moving = true;
          movingFromInputPositionX = touch1x;
          movingFromInputPositionY = touch1y;
          movingToInputPositionX = movingFromInputPositionX;
          movingToInputPositionY = movingFromInputPositionY;
        } else {
          movingToInputPositionX = touch1x;
          movingToInputPositionY = touch1y;
        }
      } else {
        moving = false;
      }
    } else {
      // Use mouse
      if (Gdx.input.isTouched()) {
        if (!moving) {
          moving = true;
          movingFromInputPositionX = Gdx.input.getX();
          movingFromInputPositionY = Gdx.input.getY();
          movingToInputPositionX = movingFromInputPositionX;
          movingToInputPositionY = movingFromInputPositionY;
        } else {
          movingToInputPositionX = Gdx.input.getX();
          movingToInputPositionY = Gdx.input.getY();
        }
      } else {
        moving = false;
      }
    }

    if (moving) {
      if (movingFromInputPositionX != movingToInputPositionX || movingFromInputPositionY != movingToInputPositionY) {
        
        cam.unproject(tmpv3.set(movingFromInputPositionX, movingFromInputPositionY, 0));
        final float movingFromWorldPositionX = tmpv3.x;
        final float movingFromWorldPositionY = tmpv3.y;

        cam.unproject(tmpv3.set(movingToInputPositionX, movingToInputPositionY, 0));
        final float movingToWorldPositionX = tmpv3.x;
        final float movingToWorldPositionY = tmpv3.y;

        final float dx = movingToWorldPositionX - movingFromWorldPositionX;
        final float dy = movingToWorldPositionY - movingFromWorldPositionY;

        if (followingObject != null) {
          // Calculate "right" direction by making the cross product
          // between the camera's forward and up vectors
          tmpv3.set(cam.up).crs(cam.direction);

          final float deltaX = Vector3.dot(dx, dy, 0, tmpv3.x, tmpv3.y, tmpv3.z);
          final float deltaY = Vector3.dot(dx, dy, 0, cam.up.x, cam.up.y, cam.up.z);

          followingObjectPositionDelta.x -= deltaX;
          followingObjectPositionDelta.y -= deltaY;

          float newPositionX, newPositionY;
          // Vector3 newPosition = followingObject.position + trans.up
          // * followingObjectPositionDelta.y + trans.right *
          // followingObjectPositionDelta.x;
          // newPosition.z = CAMERA_Z;

          newPositionX = followingObject.getX();
          newPositionY = followingObject.getY();

          tmpv3.set(cam.up).scl(followingObjectPositionDelta.y);
          newPositionX += tmpv3.x;
          newPositionY += tmpv3.y;

          // Calculate "right" direction by making the cross product
          // between the camera's foward and up vectors
          tmpv3.set(cam.up).crs(cam.direction).scl(followingObjectPositionDelta.x);
          newPositionX += tmpv3.x;
          newPositionY += tmpv3.y;

          cam.position.x = newPositionX;
          cam.position.y = newPositionY;
        }

        movingFromInputPositionX = movingToInputPositionX;
        movingFromInputPositionY = movingToInputPositionY;
      }
    }
  }

  private boolean travelInput;
  private float travelInputStartPositionX;
  private float travelInputStartPositionY;
  private float travelInputLastPositionX;
  private float travelInputLastPositionY;

  public final void updateClickOnPlanetToTravel(final UniverseView universeView) {
    boolean clickTravel = false;
    float clickPositionX = 0;
    float clickPositionY = 0;

    int touchCount = 0;
    int touch1x = -1, touch1y = -1;

    if (Gdx.input.isTouched(0)) {
      touch1x = Gdx.input.getX(0);
      touch1y = Gdx.input.getY(0);
      touchCount++;
    }

    if (Gdx.input.isTouched(1)) {
      touchCount++;
    }

    if (touchCount == 1 && !InputAreas.isInputArea(touch1x, touch1y)) {
      if (!travelInput) {
        travelInput = true;
        travelInputStartPositionX = touch1x;
        travelInputStartPositionY = touch1y;
      } else {
        travelInputLastPositionX = touch1x;
        travelInputLastPositionY = touch1y;
      }
    } else {
      if (travelInput) {
        if (Mathf.len(travelInputStartPositionX - travelInputLastPositionX, travelInputStartPositionY - travelInputLastPositionY) < 10) {
          clickTravel = true;
          clickPositionX = travelInputLastPositionX;
          clickPositionY = travelInputLastPositionY;
        }

        travelInput = false;
      }
    }

    if (clickTravel) {
      cam.unproject(tmpv3.set(clickPositionX, clickPositionY, 0));

      final float worldPosX = tmpv3.x;
      final float worldPosY = tmpv3.y;

      float dpi = Gdx.graphics.getDensity() * 160.0f;
      if (dpi == 0) {
        dpi = 72.0f;
      }
      final float clickTolerance = (dpi / cam.zoom) / 2.54f; // 1cm click
                                  // tolerance

      final int clickedThingIndex = universeView.getUniverse().findClosestRenderedThing(worldPosX, worldPosY, clickTolerance);

      if (clickedThingIndex >= 0) {
        final PlanetView targetPlanetView = universeView.getPlanetView((short) clickedThingIndex);
        if (universeView.getAvatarView().getUniverseObject().getParent() != targetPlanetView.getTilemapCircle()) {
          GameLogic.getInstace().travelToPlanet(targetPlanetView);
        }
      }
    }
  }

  public final void followObject(final Actor toFollow, final int followCameraParameters, final boolean smoothTransition) {
    followRotation = (followCameraParameters & FollowCameraParameters.FollowRotation) != 0;
    followScale = (followCameraParameters & FollowCameraParameters.FollowScale) != 0;

    if (followingObject != toFollow) {
      if (smoothTransition && followingObject != null && toFollow != null) {
        followingObjectPositionDelta.set(cam.position.x - toFollow.getX(), cam.position.y - toFollow.getY());

        if (followScale) {
          followingObjectScaleDelta = scale - toFollow.getScaleX();

          followingObjectCameraDistanceDelta = cameraDistance - cameraDistance * (scale / toFollow.getScaleX());
          cameraDistance = cameraDistance * (scale / toFollow.getScaleX());
        } else {
          followingObjectScaleDelta = scale - 1.0f;

          followingObjectCameraDistanceDelta = cameraDistance - cameraDistance * (scale / 1.0f);
          cameraDistance = cameraDistance * (scale / 1.0f);
        }

        if (followRotation) {
          followingObjectRotationDelta = camRotation - toFollow.getRotation();
        } else {
          followingObjectRotationDelta = camRotation - 0;
        }
      }

      followingObject = toFollow;
    }
  }
}




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