sketchwars.scenes.Camera.java Source code

Java tutorial

Introduction

Here is the source code for sketchwars.scenes.Camera.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package sketchwars.scenes;

import org.joml.Vector2d;
import org.lwjgl.opengl.GL11;
import sketchwars.game.GameObject;
import sketchwars.input.MouseState;
import sketchwars.input.MouseHandler;

/**
 *
 * @author Najash Najimudeen <najash.najm@gmail.com>
 */
public class Camera implements GameObject {
    private static final float SLOW_RADIUS = 0.05f;
    private static final float REACHED_RADIUS = 0.01f;

    private static final float MAX_PAN_ACCEL = 0.01f;
    private static final float MAX_ZOOM_ACCEL = 0.01f;
    private static final float PAN_SPEED = 0.0020f;
    private static final float ZOOM_SPEED = 0.0020f;

    private float panSpeed;
    private float zoomSpeed;
    private Vector2d panVelocity;
    private Vector2d zoomVelocity;

    private final float worldLeft;
    private final float worldRight;
    private final float worldTop;
    private final float worldBottom;

    private final float worldWidth;
    private final float worldHeight;

    private float left;
    private float top;

    private float nextLeft;
    private float nextTop;

    private float width;
    private float height;
    private float nextWidth;
    private float nextHeight;

    private boolean panning;
    private boolean zooming;
    private float xMouseFalling;
    private float yMouseFalling;

    private boolean expired;

    private boolean dragReset;

    public Camera(float worldLeft, float worldTop, float worldWidth, float worldHeight) {
        this.worldLeft = worldLeft;
        this.worldRight = worldLeft + worldWidth;
        this.worldTop = worldTop;
        this.worldBottom = worldTop - worldHeight;

        this.panSpeed = PAN_SPEED;
        this.zoomSpeed = ZOOM_SPEED;

        this.worldWidth = worldWidth;
        this.worldHeight = worldHeight;
        this.width = this.worldWidth;
        this.height = this.worldHeight;
        this.nextWidth = this.width;
        this.nextHeight = this.height;

        this.left = this.worldLeft;
        this.top = this.worldTop;

        this.nextLeft = this.left;
        this.nextTop = this.top;

        this.expired = false;

        this.panVelocity = new Vector2d();
        this.zoomVelocity = new Vector2d();
        this.dragReset = true;
    }

    public void toggleDragReset() {
        dragReset = !dragReset;
    }

    public void setDragReset(boolean value) {
        dragReset = value;
    }

    public boolean isDragResetOn() {
        return dragReset;
    }

    public boolean isPanning() {
        return panning;
    }

    public boolean isZooming() {
        return zooming;
    }

    public float getPanSpeed() {
        return panSpeed;
    }

    public void setPanSpeed(float panSpeed) {
        this.panSpeed = panSpeed;
    }

    public void setZoomSpeed(float zoomSpeed) {
        this.zoomSpeed = zoomSpeed;
    }

    public void setCameraSize(float width, float height) {
        this.width = width;
        this.height = height;
    }

    public void setNextCameraSize(float width, float height) {
        this.nextWidth = width;
        this.nextHeight = height;
        zooming = true;
    }

    public void setCameraPosition(float xCenter, float yCenter) {
        left = getBoundedXFromCenter(xCenter);
        top = getBoundedYFromCenter(yCenter);
    }

    private float getBoundedXFromCenter(float xCenter) {
        float xOffset = width / 2.0f;
        float maxLeft = worldRight - width;
        return (float) Math.min(Math.max(xCenter - xOffset, worldLeft), maxLeft);
    }

    private float getBoundedYFromCenter(float yCenter) {
        float yOffset = height / 2.0f;
        float minTop = worldBottom + height;
        return (float) Math.max(Math.min(yCenter + yOffset, worldTop), minTop);
    }

    private float getBoundedX(float x) {
        float maxLeft = worldRight - width;
        float minLeft = worldLeft;
        return (float) Math.min(Math.max(x, minLeft), maxLeft);
    }

    private float getBoundedY(float y) {
        float minTop = worldBottom + height;
        float maxTop = worldTop;
        return (float) Math.max(Math.min(y, maxTop), minTop);
    }

    public void setNextCameraPosition(float xCenter, float yCenter) {
        nextLeft = getBoundedXFromCenter(xCenter);
        nextTop = getBoundedYFromCenter(yCenter);
        panning = true;
    }

    @Override
    public void update(double delta) {
        if (zooming) {
            handleCameraZooming(delta);
        }

        if (panning && !zooming) {
            handleCameraPan(delta);
        }
    }

    public void applyCameraSettings() {
        Vector2d offset = getOffset();

        GL11.glLoadIdentity();
        GL11.glOrtho(worldLeft, worldRight, worldBottom, worldTop, -1.0, 1.0);

        GL11.glScalef(worldWidth / width, worldHeight / height, 1);
        GL11.glTranslatef((float) offset.x, (float) offset.y, 0);
    }

    private Vector2d getOffset() {
        if (MouseHandler.rightBtnState == MouseState.FALLING) {
            xMouseFalling = MouseHandler.xNormalized;
            yMouseFalling = MouseHandler.yNormalized;
        } else if (MouseHandler.rightBtnState == MouseState.DOWN) {
            float xMouse = MouseHandler.xNormalized;
            float yMouse = MouseHandler.yNormalized;
            float xDragOffset = xMouseFalling - xMouse;
            float yDragOffset = yMouseFalling - yMouse;

            left = getBoundedX(left + xDragOffset);
            top = getBoundedY(top + yDragOffset);
        }

        Vector2d offset = new Vector2d();
        float xOffset = -(left + (width / 2.0f));
        float yOffset = -(top - (height / 2.0f));
        offset.set(xOffset, yOffset);

        return offset;
    }

    private void handleCameraPan(double delta) {
        Vector2d distance = new Vector2d(nextLeft - left, nextTop - top);

        Vector2d direction = new Vector2d();
        distance.normalize(direction);

        float dist = (float) distance.length();

        float targetSpeed = panSpeed;
        if (dist < SLOW_RADIUS) {
            targetSpeed = (panSpeed * dist / SLOW_RADIUS);
        }

        if (dist < REACHED_RADIUS) {
            panning = false;
            panVelocity = new Vector2d();
        } else {
            Vector2d linearAccel = new Vector2d(direction.x * MAX_PAN_ACCEL, direction.y * MAX_PAN_ACCEL);

            panVelocity.x += linearAccel.x * delta;
            panVelocity.y += linearAccel.y * delta;

            if (panVelocity.length() > targetSpeed) {
                panVelocity.normalize();
                panVelocity = new Vector2d(panVelocity.x * targetSpeed, panVelocity.y * targetSpeed);
            }

            left += panVelocity.x * delta;
            top += panVelocity.y * delta;
        }
    }

    public void setExpired(boolean expired) {
        this.expired = expired;
    }

    @Override
    public boolean hasExpired() {
        return expired;
    }

    public float getWidth() {
        return width;
    }

    public float getHeight() {
        return height;
    }

    public float getWorldLeft() {
        return worldLeft;
    }

    public float getWorldTop() {
        return worldTop;
    }

    public float getLeft() {
        return left;
    }

    public float getTop() {
        return top;
    }

    public float getWorldWidth() {
        return worldWidth;
    }

    public float getWorldHeight() {
        return worldHeight;
    }

    private void handleCameraZooming(double delta) {
        Vector2d distance = new Vector2d(nextWidth - width, nextHeight - height);

        Vector2d direction = new Vector2d();
        distance.normalize(direction);

        float targetSpeed = zoomSpeed;

        float dist = (float) distance.length();

        if (dist < SLOW_RADIUS) {
            targetSpeed = (zoomSpeed * dist / SLOW_RADIUS);
        }

        if (dist < REACHED_RADIUS) {
            zooming = false;
            zoomVelocity = new Vector2d();
        } else {
            Vector2d linearAccel = new Vector2d(direction.x * MAX_ZOOM_ACCEL, direction.y * MAX_ZOOM_ACCEL);

            zoomVelocity.x += linearAccel.x * delta;
            zoomVelocity.y += linearAccel.y * delta;

            if (zoomVelocity.length() > targetSpeed) {
                zoomVelocity.normalize();
                zoomVelocity = new Vector2d(zoomVelocity.x * targetSpeed, zoomVelocity.y * targetSpeed);
            }

            float xVelocity = (float) (zoomVelocity.x * delta);
            float yVelocity = (float) (zoomVelocity.y * delta);

            width += xVelocity;
            height += yVelocity;

            left -= xVelocity / 2.0f;
            top += yVelocity / 2.0f;
        }
    }

    public float getWorldRight() {
        return worldRight;
    }

    public float getWorldBottom() {
        return worldBottom;
    }

    public float getCenterX() {
        return left + width / 2.0f;
    }

    public float getCenterY() {
        return top - height / 2.0f;
    }
}