es.eucm.ead.engine.DefaultGameView.java Source code

Java tutorial

Introduction

Here is the source code for es.eucm.ead.engine.DefaultGameView.java

Source

/**
 * eAdventure is a research project of the
 *    e-UCM research group.
 *
 *    Copyright 2005-2014 e-UCM research group.
 *
 *    You can access a list of all the contributors to eAdventure at:
 *          http://e-adventure.e-ucm.es/contributors
 *
 *    e-UCM is a research group of the Department of Software Engineering
 *          and Artificial Intelligence at the Complutense University of Madrid
 *          (School of Computer Science).
 *
 *          CL Profesor Jose Garcia Santesmases 9,
 *          28040 Madrid (Madrid), Spain.
 *
 *          For more info please visit:  <http://e-adventure.e-ucm.es> or
 *          <http://www.e-ucm.es>
 *
 * ****************************************************************************
 *
 *  This file is part of eAdventure
 *
 *      eAdventure is free software: you can redistribute it and/or modify
 *      it under the terms of the GNU Lesser General Public License as published by
 *      the Free Software Foundation, either version 3 of the License, or
 *      (at your option) any later version.
 *
 *      eAdventure is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU Lesser General Public License for more details.
 *
 *      You should have received a copy of the GNU Lesser General Public License
 *      along with eAdventure.  If not, see <http://www.gnu.org/licenses/>.
 */
package es.eucm.ead.engine;

import com.badlogic.ashley.core.ComponentMapper;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Group;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.Touchable;
import com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.scenes.scene2d.utils.UIUtils;
import com.badlogic.gdx.utils.Pools;
import com.badlogic.gdx.utils.SnapshotArray;
import com.badlogic.gdx.utils.viewport.FitViewport;
import es.eucm.ead.engine.components.KeyPressedComponent;
import es.eucm.ead.engine.components.TouchedComponent;
import es.eucm.ead.engine.components.behaviors.events.RuntimeKey;
import es.eucm.ead.engine.entities.EngineEntity;
import es.eucm.ead.schema.components.behaviors.events.Touch.Type;
import es.eucm.ead.schemax.Layer;

import java.util.HashMap;
import java.util.Map;

/**
 * This class represents the "visual" part of the game, which is structured in
 * layers. Any element that is to be rendered on the screen has to belong to a
 * GameLayer. Adding elements to one layer or another just changes the order (Z)
 * they are painted.
 * <p/>
 * The order of the layers, from top to bottom, is
 * <ol>
 * <li>HUD: displays game controls, on top of everything</li>
 * <li>SCENE_HUD: displays additional controls on top of the scene. For instance
 * if a character speaks some dialogue, the spoken text would appear at this
 * layer</li>
 * <li>SCENE_CONTENT: displays normal scene contents (characters, background)</li>
 * </ol>
 * <p/>
 * Each layer can contain its own internal ordering.
 * <p/>
 * For more information, visit: <a
 * href="https://github.com/e-ucm/ead/wiki/Game-view"
 * target="_blank">https://github.com/e-ucm/ead/wiki/Game-view</a>
 */
public class DefaultGameView extends WidgetGroup implements GameView {

    private GameLoop gameLoop;

    private Map<Layer, EngineLayer> layers;

    protected int worldWidth;

    protected int worldHeight;

    public DefaultGameView(GameLoop gameLoop) {
        layers = new HashMap<Layer, EngineLayer>();
        this.gameLoop = gameLoop;
        initializeLayers();
        initKeyboardListener();
        addListener(new TouchListener());
    }

    /*
     * Just creates the basic layer tree structure by iterating through all
     * layers registered.
     */
    private void initializeLayers() {
        for (Layer layer : Layer.values()) {
            EngineLayer engineLayer = new EngineLayer(gameLoop, layer);
            gameLoop.addEntity(engineLayer);
            layers.put(layer, engineLayer);
            // If it is root layer, add it directly to this group. Otherwise,
            // find its parent and add it to it
            if (layer.getParentLayer() == null) {
                addActor(engineLayer.getGroup());
            } else {
                addEntityToLayer(layer.getParentLayer(), engineLayer);
            }
        }
    }

    private void initKeyboardListener() {
        addListener(new InputListener() {
            final ComponentMapper<KeyPressedComponent> keyPressed = ComponentMapper
                    .getFor(KeyPressedComponent.class);

            public boolean keyDown(InputEvent event, int keycode) {
                EngineEntity entity = getLayer(Layer.SCENE);
                if (!keyPressed.has(entity)) {
                    entity.add(gameLoop.createComponent(KeyPressedComponent.class));
                }
                KeyPressedComponent keyPressedComponent = entity.getComponent(KeyPressedComponent.class);
                RuntimeKey runtimeKeyEvent = Pools.obtain(RuntimeKey.class);
                runtimeKeyEvent.setKeycode(keycode);
                runtimeKeyEvent.setAlt(UIUtils.alt());
                runtimeKeyEvent.setCtrl(UIUtils.ctrl());
                runtimeKeyEvent.setShift(UIUtils.shift());
                keyPressedComponent.getKeyEvents().add(runtimeKeyEvent);
                return true;
            }
        });

    }

    @Override
    public void clearLayer(Layer layer, boolean clearChildrenLayers) {
        EngineEntity layerEntity = layers.get(layer);
        SnapshotArray<Actor> childrenArray = layerEntity.getGroup().getChildren();
        Actor[] children = childrenArray.begin();
        for (int i = 0, n = childrenArray.size; i < n; i++) {
            Actor actor = children[i];
            if (actor.getUserObject() instanceof EngineLayer) {
                if (clearChildrenLayers) {
                    EngineLayer childrenLayer = (EngineLayer) actor.getUserObject();
                    clearLayer(getLayerForEntity(childrenLayer), true);
                }
            } else if (actor.getUserObject() instanceof EngineEntity) {
                EngineEntity childEntityToRemove = (EngineEntity) actor.getUserObject();
                gameLoop.removeEntity(childEntityToRemove);
            } else {
                Gdx.app.error("GameView",
                        "GameView has a child that does not belong to an EngineEntity or its user object is not set.");
            }
        }
        childrenArray.end();

    }

    private Layer getLayerForEntity(EngineLayer anEntity) {
        for (Layer key : layers.keySet()) {
            if (layers.get(key) == anEntity) {
                return key;
            }
        }
        return null;
    }

    @Override
    public void addEntityToLayer(Layer layer, EngineEntity entity) {
        layers.get(layer).getGroup().addActor(entity.getGroup());
    }

    @Override
    public EngineEntity getLayer(Layer layer) {
        return layers.get(layer);
    }

    @Override
    public void updateWorldSize(int width, int height) {
        this.worldWidth = width;
        this.worldHeight = height;
        getStage().setViewport(new FitViewport(width, height, getStage().getViewport().getCamera()));
        getStage().getViewport().update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), true);
    }

    @Override
    public int getWorldWidth() {
        return worldWidth;
    }

    @Override
    public int getWorldHeight() {
        return worldHeight;
    }

    @Override
    public int getPixelsWidth() {
        return getScreenWidth();
    }

    @Override
    public int getPixelsHeight() {
        return getScreenHeight();
    }

    @Override
    public int getScreenX() {
        return getStage().getViewport().getScreenX();
    }

    @Override
    public int getScreenY() {
        return getStage().getViewport().getScreenY();
    }

    @Override
    public int getScreenWidth() {
        return getStage().getViewport().getScreenWidth();
    }

    @Override
    public int getScreenHeight() {
        return getStage().getViewport().getScreenHeight();
    }

    /**
     * Just to differentiate layer entities from regular entities more easily.
     * This also prevents accidental removals since the game loop does not
     * remove these entities.
     */
    public class EngineLayer extends EngineEntity {
        private Layer layer;

        public EngineLayer(GameLoop gameLoop, Layer layer) {
            super(gameLoop);
            this.layer = layer;
            Group group = getGroup();
            group.setName(layer.name());
            group.setTouchable(Touchable.childrenOnly);
        }

        public void clear() {
            clearLayer(layer, true);
        }

        public Layer getLayer() {
            return layer;
        }
    }

    private class TouchListener extends ClickListener {

        @Override
        public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
            process(event.getTarget(), Type.CLICK);
        }

        @Override
        public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
            process(event.getTarget(), Type.PRESS);
            return true;
        }

        private void process(Actor actor, Type type) {
            if (gameLoop.isPlaying()) {
                while (actor != null) {
                    Object o = actor.getUserObject();
                    if (o instanceof EngineEntity) {
                        TouchedComponent component = gameLoop.addAndGetComponent(((EngineEntity) o),
                                TouchedComponent.class);
                        component.event(type);
                    }
                    actor = actor.getParent();
                }
            }
        }
    }
}