/* * Copyright (c) 2012. HappyDroids LLC, All rights reserved. */ package com.happydroids.droidtowers.input; import aurelienribon.tweenengine.Tween; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.input.GestureDetector; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.math.collision.BoundingBox; import com.badlogic.gdx.utils.Pools; import com.google.common.eventbus.EventBus; import com.happydroids.droidtowers.TowerConsts; import com.happydroids.droidtowers.achievements.TutorialEngine; import com.happydroids.droidtowers.events.SafeEventBus; import com.happydroids.droidtowers.gui.events.CameraControllerEvent; import com.happydroids.droidtowers.platform.Display; import com.happydroids.droidtowers.tween.TweenSystem; public class CameraController implements GestureDetector.GestureListener { public static final float ZOOM_MAX = 3f; public static final float ZOOM_MIN = 0.75f; private OrthographicCamera camera; private BoundingBox cameraBounds; private EventBus events = new SafeEventBus(CameraController.class.getSimpleName()); private float initialScale = 1.0f; private boolean flinging = false; private float velX; private float velY; private Vector2 worldSize; private Vector3 lastCameraPosition; public CameraController(OrthographicCamera camera_, Vector2 worldSize) { camera = camera_; camera.position.set(worldSize.x / 2, TowerConsts.GROUND_HEIGHT + (TowerConsts.GRID_UNIT_SIZE * 2), 0); lastCameraPosition = new Vector3(camera.position); updateCameraConstraints(worldSize); } public void updateCameraConstraints(Vector2 newWorldSize) { worldSize = newWorldSize; int gameWorldPadding = Display.getBiggestScreenDimension(); this.cameraBounds = new BoundingBox(new Vector3(-gameWorldPadding, -gameWorldPadding, 0), new Vector3(worldSize.x + gameWorldPadding, worldSize.y + gameWorldPadding, 0)); checkBounds(); } public boolean touchDown(float x, float y, int pointer) { flinging = false; initialScale = camera.zoom; return false; } public boolean tap(float x, float y, int count, int pointer, int button) { return false; } @Override public boolean touchDown(float x, float y, int pointer, int button) { return false; } @Override public boolean tap(float x, float y, int count, int button) { return false; } public boolean longPress(float x, float y) { return false; } public boolean fling(float velocityX, float velocityY, int button) { if (Math.abs(velocityX) >= 300) { flinging = true; velX = camera.zoom * velocityX * 0.5f; } if (Math.abs(velocityY) >= 300) { flinging = true; velY = camera.zoom * velocityY * 0.5f; } return false; } public boolean pan(float x, float y, float changeX, float changeY) { float deltaX = -changeX * camera.zoom; float deltaY = changeY * camera.zoom; camera.position.add(deltaX, deltaY, 0); checkBounds(); TutorialEngine.instance().moveToStepWhenReady("tutorial-zoom"); return false; } @Override public boolean panStop(float x, float y, int pointer, int button) { return false; } public boolean zoom(float originalDistance, float currentDistance) { float ratio = originalDistance / currentDistance; camera.zoom = initialScale * ratio; checkZoom(); checkBounds(); TutorialEngine.instance().moveToStepWhenReady("tutorial-turn-on-population-overlay"); return true; } public boolean pinch(Vector2 vector2, Vector2 vector21, Vector2 vector22, Vector2 vector23) { return false; } public boolean scrolled(int amount) { camera.zoom += (float) amount / 10; checkZoom(); checkBounds(); TutorialEngine.instance().moveToStepWhenReady("tutorial-turn-on-population-overlay"); return true; } public void update(float deltaTime) { if (flinging) { velX *= 0.95f; velY *= 0.95f; float deltaX = -velX * deltaTime; float deltaY = velY * deltaTime; if (Math.abs(velX) < 0.01f) { velX = 0; } if (Math.abs(velY) < 0.01f) { velY = 0; } camera.position.add(deltaX, deltaY, 0); checkBounds(); } if (!lastCameraPosition.equals(camera.position)) { CameraControllerEvent event = Pools.obtain(CameraControllerEvent.class); event.setPosition(camera.position); event.setDelta(lastCameraPosition.sub(camera.position)); event.setZoom(camera.zoom); events.post(event); Pools.free(event); lastCameraPosition.set(camera.position); } } private void checkZoom() { camera.zoom = MathUtils.clamp(camera.zoom, ZOOM_MIN / Display.getScaledDensity(), ZOOM_MAX / Display.getScaledDensity()); } public void checkBounds() { float halfWidth = Display.getWidth() / 2 * camera.zoom; float halfHeight = Display.getHeight() / 2 * camera.zoom; camera.position.x = MathUtils.clamp(camera.position.x, cameraBounds.getMin().x + halfWidth, cameraBounds.getMax().x - halfWidth); camera.position.y = MathUtils.clamp(camera.position.y, cameraBounds.getMin().y + halfHeight, cameraBounds.getMax().y - halfHeight); } public BoundingBox getCameraBounds() { return cameraBounds; } public OrthographicCamera getCamera() { return camera; } public EventBus events() { return events; } public void panTo(float x, float y, boolean animate) { panTo(new Vector3(x, y, 0), animate); } public void panTo(Vector3 position, boolean animate) { if (animate) { TweenSystem.manager().killTarget(this); Tween.to(this, CameraControllerAccessor.PAN, 750) .target(position.x, position.y) .start(TweenSystem.manager()); } else { camera.position.set(position.x, position.y, 0f); checkBounds(); } } public void stopMovement() { velX = 0f; velY = 0f; } }