com.jmolina.orb.elements.WorldElement.java Source code

Java tutorial

Introduction

Here is the source code for com.jmolina.orb.elements.WorldElement.java

Source

/*
 * IMPULSE ORB
 * Copyright (C) 2016 Juan M. Molina
 *
 * This file is part of the IMPULSE ORB source code.
 *
 * IMPULSE ORB is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * IMPULSE ORB 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.jmolina.orb.elements;

import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.Shape;
import com.badlogic.gdx.physics.box2d.World;
import com.jmolina.orb.data.UserData;

/**
 * Elemento del mundo fisico, sin visualizacion.
 */
public class WorldElement {

    /**
     * Forma geomtrica del elemento
     *
     * CIRCLE: Crculo
     * SQUARE: Rectngulo
     * TRIANGLE: Tringulo equiltero
     */
    public enum Geometry {
        CIRCLE, SQUARE, TRIANGLE
    }

    /**
     * Tipo de elemento
     *
     * BLACK: Elementos estticos (muros y escenarios estticos)
     * GREEN: Elementos dinmicos (slo el {@link Orb})
     * GREY: Elementos kinticos genricos
     * RED: Elementos kinticos destructivos
     * BLUE: Elementos kinticos etreos visibles
     * VIOLET: Elementos kinticos magnticos
     * AIR: Elementos kinticos etreos invisibles
     */
    public enum Flavor {
        BLACK, GREEN, GREY, RED, BLUE, VIOLET, AIR
    }

    /**
     * Efecto del elemento al contacto con el Orb.
     *
     * NONE: Sin efecto
     * EXIT: Provoca la salida del nivel
     * DESTROY: Provoca la destruccin del orbe
     * HEAT: Provoca el calentamiento del orbe
     */
    public enum Effect {
        NONE, EXIT, DESTROY, HEAT
    }

    private final float DENSITY = 1.0f;
    private final float RESTITUTION = 0.6f;
    private final float FRICTION = 0.8f; // FRICTION = 0 evita rotaciones al colisionar

    /** Dimensiones */
    private float width, height;

    /** Posicion y angulo iniciales */
    private float initialX, initialY, initialAngle;

    /** Cuerpo fisico */
    private Body body;

    /** Datos de usuario */
    private UserData userData;

    /** Geometria */
    private Geometry geometry;

    /** Sabor */
    private Flavor flavor;

    /**
     * Constructor
     *
     * @param world World
     * @param w Width of the element (World units)
     * @param h Heigth of the element (World units)
     * @param x Position x coord (World units)
     * @param y Position y coord (World units)
     * @param angle Rotation of the element in degrees counterclockwise
     * @param geometry Geometry
     * @param flavor Flavor
     */
    public WorldElement(World world, float w, float h, float x, float y, float angle, Geometry geometry,
            Flavor flavor) {
        userData = new UserData();
        FixtureDef fixtureDef = new FixtureDef();
        BodyDef bodyDef = new BodyDef();

        width = w;
        height = h;
        setUserData(flavor);
        this.geometry = geometry;
        this.flavor = flavor;

        fixtureDef.density = DENSITY;
        fixtureDef.restitution = RESTITUTION;
        fixtureDef.friction = FRICTION;
        fixtureDef.shape = shape(geometry);
        bodyDef.type = type(flavor);
        bodyDef.position.set(x, y);
        bodyDef.angle = angle * MathUtils.degreesToRadians;
        body = world.createBody(bodyDef);
        body.createFixture(fixtureDef);
        body.setUserData(getUserData());
        fixtureDef.shape.dispose();

        if (flavor == Flavor.AIR)
            setAsSensor(true);
    }

    /**
     * Devuevel el tipo de cuerpo fisico en funcion del sabor
     *
     * @param flavor Sabor
     */
    private BodyDef.BodyType type(Flavor flavor) {
        switch (flavor) {
        case BLACK:
            return BodyDef.BodyType.StaticBody;
        case GREEN:
            return BodyDef.BodyType.DynamicBody;
        case GREY:
            return BodyDef.BodyType.KinematicBody;
        default:
            return BodyDef.BodyType.KinematicBody;
        }
    }

    /**
     * Devuelve la forma del cuerpo fisico en funcion de la geometria
     *
     * @param geometry Geometria
     */
    private Shape shape(Geometry geometry) {
        switch (geometry) {
        case SQUARE:
            return square();
        case CIRCLE:
            return circle();
        case TRIANGLE:
            return triangle();
        default:
            return square();
        }
    }

    /**
     * Crea un rectngulo. El punto de origen es su centroide.
     */
    private Shape square() {
        PolygonShape shape = new PolygonShape();
        shape.setAsBox(0.5f * width, 0.5f * height);

        return shape;
    }

    /**
     * Crea un crculo de radio = {@link #width}. El parmetro {@link #height} se ignora.
     * El punto de origen es su centro.
     */
    private Shape circle() {
        CircleShape shape = new CircleShape();
        shape.setRadius(0.5f * width);

        return shape;
    }

    /**
     * Crea un tringulo equiltero de lado {@link #width}. El parmetro {@link #height} se ignora.
     * El punto de origen es su centroide (punto de cruce de las 3 alturas).
     */
    private Shape triangle() {
        Vector2[] points = new Vector2[3];
        points[0] = new Vector2(-0.5f * width, -width * MathUtils.sinDeg(60) / 3);
        points[1] = new Vector2(0.5f * width, -width * MathUtils.sinDeg(60) / 3);
        points[2] = new Vector2(0, width * MathUtils.sinDeg(60) / 3 * 2);

        PolygonShape shape = new PolygonShape();
        shape.set(points);

        return shape;
    }

    /**
     * Crea los datos de usuario
     *
     * @param flavor Sabor
     */
    private void setUserData(Flavor flavor) {
        Effect effect;

        switch (flavor) {
        case RED:
            effect = Effect.DESTROY;
            break;
        default:
            effect = Effect.NONE;
        }

        userData.flavor = flavor;
        userData.effect = effect;
    }

    /**
     * Fija el efecto en los datos de usuario
     *
     * @param effect Efecto
     */
    protected void setEffect(Effect effect) {
        userData.effect = effect;
    }

    /**
     * Devuelve los datos de usuario
     */
    protected UserData getUserData() {
        return userData;
    }

    /**
     * Configura el elemento como sensor (o no)
     *
     * @param sensor Si es sensor
     */
    protected void setAsSensor(boolean sensor) {
        getBody().getFixtureList().first().setSensor(sensor);
    }

    /**
     * Devuelve el cuerpo fisico del elemento
     */
    public Body getBody() {
        return body;
    }

    /**
     * Fija la posicin del elemento
     *
     * @param x Coordenada X
     * @param y Coordenada Y
     */
    public void setPosition(float x, float y) {
        setInitialX(x);
        setInitialY(y);
        getBody().setTransform(x, y, getBody().getAngle());
    }

    /**
     * Devuelve la posicion actual del elemento
     */
    public Vector2 getPosition() {
        return new Vector2(getBody().getPosition().x, getBody().getPosition().y);
    }

    /**
     * Devuelve la rotacion del elemento en grados
     */
    public float getRotation() {
        return MathUtils.radiansToDegrees * getBody().getAngle();
    }

    /**
     * Devuelve el ancho del elemento
     */
    public float getWidth() {
        return width;
    }

    /**
     * Devuelve el alto del elemento
     */
    public float getHeight() {
        return height;
    }

    /**
     * Devuelve la geometria del elemento
     */
    public Geometry getGeometry() {
        return this.geometry;
    }

    /**
     * Devuelve el sabor del elemento
     */
    public Flavor getFlavor() {
        return flavor;
    }

    /**
     * Fija la coordenada X del valor inicial de la posicion.
     *
     * Los valores iniciales pueden variar cuando el elemento se aade a una situacin, que tiene
     * una altura base que se sumar a la del elemento. Los valores iniciales se deben restaurar al
     * resetear el elemento (por ejemplo, si es movil).
     *
     * @param x Coordenada X
     */
    public void setInitialX(float x) {
        initialX = x;
    }

    /**
     * Devuelve la coordenada X del valor inicial de la posicion
     */
    public float getInitialX() {
        return initialX;
    }

    /**
     * Fija la coordenada Y del valor inicial de la posicion
     *
     * @param y Coordenada Y
     */
    public void setInitialY(float y) {
        initialY = y;
    }

    /**
     * Devuelve la coordenada Y del valor inicial de la posicion
     * @return
     */
    public float getInitialY() {
        return initialY;
    }

    /**
     * Fija el angulo inicial en grados. Es importante si el elemento es movil, ya que debe resetearse
     * y recuperar su angulo inicial. Si no es movil, nunca se resetea.
     *
     * @param angle Angulo en grados.
     */
    public void setInitialAngle(float angle) {
        initialAngle = angle;
    }

    /**
     * Devuelve el angulo inicial
     */
    public float getInitialAngle() {
        return initialAngle;
    }

}