package com.gdxjam.systems;
import com.badlogic.ashley.core.Engine;
import com.badlogic.ashley.core.EntitySystem;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.IntMap;
import com.badlogic.gdx.utils.IntMap.Entry;
import com.badlogic.gdx.utils.Scaling;
import com.badlogic.gdx.utils.viewport.ScalingViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
public class CameraSystem extends EntitySystem {
private OrthographicCamera camera;
private IntMap<ParalaxLayer> paralaxLayers = new IntMap<CameraSystem.ParalaxLayer>();
private Viewport viewport;
private Vector2 target;
boolean smooth = false;
private float minZoom;
private float maxZoom;
private float panScalar = 0.25f;
private float zoomScalar = 0.25f;
private Rectangle worldBounds;
private boolean clampToBounds = true;
public CameraSystem(float viewportWidth, float viewportHeight) {
camera = new OrthographicCamera(viewportWidth, viewportHeight);
viewport = new ScalingViewport(Scaling.stretch, viewportWidth, viewportHeight, camera);
addParalaxLayer(0, 0.0f);
addParalaxLayer(1, 0.10f);
addParalaxLayer(2, 0.50f);
}
public void setWorldBounds(float worldWidth, float worldHeight) {
worldBounds = new Rectangle(0, 0, worldWidth, worldHeight);
maxZoom = (1.0f / worldWidth) * camera.viewportWidth;
minZoom = worldWidth / camera.viewportWidth;
updateCameras();
}
public void addParalaxLayer(int layerIndex, float paralaxCoeffeciant) {
ParalaxLayer layer = new ParalaxLayer(layerIndex, paralaxCoeffeciant, camera.viewportWidth, camera.viewportHeight);
paralaxLayers.put(layerIndex, layer);
}
@Override
public void addedToEngine(Engine engine) {
super.addedToEngine(engine);
}
@Override
public void update(float deltaTime) {
super.update(deltaTime);
if (smooth && target != null) {
camera.position.set(target.x, target.y, camera.zoom);
camera.update();
}
}
public OrthographicCamera getCamera() {
return camera;
}
public OrthographicCamera getParalaxCamera(int layer) {
return paralaxLayers.get(layer).getCamera();
}
public Viewport getViewport() {
return viewport;
}
public Vector2 screenToWorldCords(float screenX, float screenY) {
Vector3 pos = new Vector3(screenX, screenY, 0);
pos.set(camera.unproject(pos));
return new Vector2(pos.x, pos.y);
}
// Camera Controller Methods
public void zoom(float amount) {
amount *= (camera.zoom / maxZoom) * zoomScalar;
camera.zoom += amount;
clamp();
updateCameras();
}
private void updateCameras() {
camera.update();
for (Entry<ParalaxLayer> entry : paralaxLayers.entries()) {
float coeffeciant = entry.value.coeffeciant;
float zoom = 1.0f + (camera.zoom * coeffeciant);
float x = ((camera.position.x / worldBounds.width) * camera.viewportWidth * coeffeciant) + (camera.viewportWidth * 0.5f);
float y = ((camera.position.y / worldBounds.height) * camera.viewportHeight * coeffeciant) + (camera.viewportHeight * 0.5f);
OrthographicCamera camera = entry.value.getCamera();
camera.position.set(x, y, 0);
camera.zoom = zoom;
camera.update();
}
}
private void clamp() {
if (clampToBounds) {
camera.zoom = MathUtils.clamp(camera.zoom, maxZoom, minZoom);
float xMin = (camera.viewportWidth * camera.zoom * 0.5f);
float xMax = worldBounds.width - xMin;
float yMin = (camera.viewportHeight * camera.zoom * 0.5f);
float yMax = worldBounds.height - yMin;
float x = MathUtils.clamp(camera.position.x, xMin, xMax);
float y = MathUtils.clamp(camera.position.y, yMin, yMax);
camera.position.set(x, y, 0);
}
}
public void translate(float deltaX, float deltaY) {
deltaX *= (camera.zoom / maxZoom) * panScalar;
deltaY *= (camera.zoom / maxZoom) * panScalar;
camera.translate(deltaX, deltaY);
clamp();
updateCameras();
}
public void setTarget(Vector2 target) {
this.target = target;
}
public void smoothFollow(Vector2 target) {
smooth = true;
this.target = target;
}
public void goTo(float posX, float posY) {
target = null;
camera.position.set(posX, posY, 0);
}
public void goToSmooth(Vector2 position) {
target = position.cpy();
smooth = true;
}
public class ParalaxLayer {
private int index;
private float coeffeciant;
private OrthographicCamera camera;
public ParalaxLayer(int index, float coeffeciant, float viewportWidth, float viewportHeight) {
this.index = index;
this.coeffeciant = coeffeciant;
camera = new OrthographicCamera(viewportWidth, viewportHeight);
camera.position.set(viewportWidth * 0.5f, viewportHeight * 0.5f, 0);
camera.update();
}
public OrthographicCamera getCamera() {
return camera;
}
}
}