Java tutorial
/* * 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; } }