All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.codingame.gameengine.module.camera.CameraModule Maven / Gradle / Ivy

package com.codingame.gameengine.module.camera;

import com.codingame.gameengine.core.AbstractPlayer;
import com.codingame.gameengine.core.GameManager;
import com.codingame.gameengine.core.Module;
import com.codingame.gameengine.module.entities.Entity;
import com.codingame.gameengine.module.entities.GraphicEntityModule;
import com.google.inject.Inject;
import com.google.inject.Singleton;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * The CameraModule allow you to have a dynamic camera following a set of objects
 */
@Singleton
public class CameraModule implements Module {

    GameManager gameManager;
    @Inject
    GraphicEntityModule entityModule;
    Map registered, newRegistration;
    ArrayList> trackedEntities;
    Double cameraOffset;
    Integer container, sizeX, sizeY = -1;
    boolean sentContainer = false;
    double previousOffset = -1;
    boolean active = true;
    boolean oldActive = false;


    @Inject
    CameraModule(GameManager gameManager) {
        trackedEntities = new ArrayList<>();
        this.gameManager = gameManager;
        gameManager.registerModule(this);
        registered = new HashMap<>();
        newRegistration = new HashMap<>();
        cameraOffset = 10.;
    }

    @Override
    public void onGameInit() {
        sendFrameData();
    }

    @Override
    public void onAfterGameTurn() {
        sendFrameData();
    }

    @Override
    public void onAfterOnEnd() {
    }


    private void sendFrameData() {
        Object[] data = {null, null, null, null};
        Object[] empty = {null, null, null, null};
        if (!newRegistration.isEmpty()) {
            data[0] = new HashMap<>(newRegistration);
            newRegistration.clear();
        }
        if (cameraOffset != previousOffset) {
            data[1] = cameraOffset;
            previousOffset = cameraOffset;
        }
        if (!sentContainer && container >= 0) {
            data[2] = new Integer[]{container, sizeX, sizeY};
            sentContainer = true;
        }
        if (oldActive != active) {
            oldActive = active;
            data[3] = active;
        }
        if (!Arrays.equals(data, empty)) {
            gameManager.setViewData("c", data);
        }
    }

    private boolean isContainerChild(Entity entity, int _container) {
        boolean t = false;
        Entity root = entity;
        while ((!t) && root.getParent().isPresent()) {
            root = root.getParent().get();
            t = root.getId() == _container;
        }
        return t;
    }

    /**
     * Make the camera include the entity in its field of view
     *
     * @param entity the Entity to add to the tracked entities
     */
    public void addTrackedEntity(Entity entity) {
        if (isContainerChild(entity, container)) {
            int id = entity.getId();
            trackedEntities.add(entity);
            if (!registered.getOrDefault(id, false)) {
                newRegistration.put(id, true);
                registered.put(id, true);
            }
        } else {
            throw new RuntimeException("The entity given can't be tracked because it's not a child/successor of the tracked container!\n" +
                    "Don't forget to init the camera with the setContainer method");
        }
    }

    /**
     * @param entity the Entity that you want to know if it's tracked
     * @return if the entity is tracked by the camera or not
     */
    public Boolean isTracked(Entity entity) {
        return registered.getOrDefault(entity.getId(), false);
    }

    /**
     * Make the camera stop tracking this entity
     *
     * @param entity the Entity that you don't want to be tracked anymore
     */
    public void removeTrackedEntity(Entity entity) {
        int id = entity.getId();
        trackedEntities.remove(entity);
        if (registered.getOrDefault(id, false)) {
            newRegistration.put(id, false);
            registered.remove(id);
        }
    }

    /**
     * Sets the camera offset to the given value. It's the length in pixel between the edge of the screen and the
     * closest to border entity
     *
     * @param value the new camera offset, a positive double
     */
    public void setCameraOffset(double value) {
        cameraOffset = value;
    }

    /**
     * Initialize the camera with container which has to contain all the other entities tracked by the camera
     *
     * @param container   the Entity to set as the container
     * @param viewerSizeX the x size (in pixel) in the viewer of the smallest rectangle that could include your container if the scale is 1
     * @param viewerSizeY the y size (in pixel) in the viewer of the smallest rectangle that could include your container if the scale is 1
     */
    public void setContainer(Entity container, int viewerSizeX, int viewerSizeY) {
        if (trackedEntities.stream().allMatch((Entity e) -> isContainerChild(e, container.getId()))) {
            this.container = container.getId();
            this.sizeX = viewerSizeX;
            this.sizeY = viewerSizeY;
        } else {
            throw new RuntimeException("You can't change the container if there are tracked that are not child of the new container");
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy