Mostrar Mensajes

Esta sección te permite ver todos los posts escritos por este usuario. Ten en cuenta que sólo puedes ver los posts escritos en zonas a las que tienes acceso en este momento.


Mensajes - manuromero73

Páginas: [1] 2
1
Uno de los problemas que he encontrado es que en ocasiones la bola va cayendo despacio y muy horizontal, casi imperceptiblemente, y en este caso hay que esperar un buen tiempo hasta que llega a la parte inferior para poder rebotar o caer. En estos casos aunque pulso el botón + para tratar de acelerar la velocidad del movimiento la bola no acelera, o al menos no se percibe que acelere.
Tambien ocurre que si la bola esta cayendo rapido y pulso el - para ralentizarla, puedo hacer que se mueva muy muy despacio. Sin embargo si tras hacer esto pulso + para acelerar ya no se incrementa la velocidad sino que sigue cayendo igual de lenta que iba, no responde si intento acelerarla.

2
Hola gracias ya he logrado que compile y la ejecucion del juego modificando

            if (o instanceof Ball ball) {

por

            if (o instanceof Ball) {
                Ball ball=(Ball)o;


o lo mismo en otra parte donde aparece en lugar de una o, una a.

Es bastante parecido con lo que queria hacer aunque aqui van apareciendo varias bolas conforme se avanza en el juego, no hay una sola bola. El boton + seria similar a acelerar, el boton - seria similar a frenar. Aunque el boton - parece que responde bien sin embargo hay ocasiones en que por mucho que pulso el boton + no acelera.

Por otro lado el mando de la barra de rebote no esta en las teclas del cursor, sino en el ratón. Y una cosa con la que me he encontrado es que a veces aunque yo intente mover la barra para colocarla en determinada posicion, no puedo moverla porque se queda como si estuviera bloqueada en un sitio y no responde y cuando voy a colocarla para lograr el rebote de la bola ya la bola ha tocado el fondo y no se puede continuar la partida.


3
Hola, me da un error de compilación en public class GameBoard en el metodo

Código: [Seleccionar]
    public void slow() {
        for (GameObject o : getWorld().getContent()) {
            if (o instanceof Ball ball) {
                float ballSpeed = ball.getSpeedVector().lenght();

                if (ballSpeed > MIN_SPEED) {
                    ball.getSpeedVector().mult(0.8f);
                }
            }
        }
    }

En la línea if (o instanceof Ball ball) marca el error --------  ')' expected

4
HOla, sí, sigo interesado en poder resolver esto pero no tengo nivel de programacion suficiente en cuanto a codigo y también en cuanto a conceptos como tomar el control del renderizado o vectorVelocidad creo que hay partes matematicas que no son faciles

5
Hola me gustaría recabar ayuda con el ejercicio siguiente en Java.

Arcade retro basics

Debe iniciar un programa con una ventana gráfica que ocupe aproximadamente la mitad de la pantalla del usuario, centrada sobre la misma. La ventana tendrá un panel izquierdo con borde marcado donde tendrá lugar la animación gráfica, que ocupará aproximadamente 4/5 partes de la ventana gráfica. Y un panel derecho con cinco botones: "Iniciar", "Acelerar", "Frenar", "Detener/Continuar" y "Resetear" que será 1/5 parte aproximadamente de la ventana gráfica.

Inicialmente deben aparecer dos elementos gráficos sobre el tablero: uno circular ("la bola") centrado sobre el borde superior del panel de animación o tablero. Otro rectangular ("la barra") centrado sobre el borde inferior del panel de animación o tablero. El comportamiento debe ser el siguiente:

1. Si se pulsa "Iniciar", la bola deberá moverse hacia abajo en una dirección aleatoria con una velocidad inicial predeterminada y avanzar. Si alcanza una pared lateral o la superior, debe rebotar. Si alcanza la parte inferior y choca con la barra, debe rebotar. En cambio si alcanza la parte inferior y no choca con la barra debe detenerse el movimiento y aparecer el mensaje "Game over". Inicialmente la bola va hacia abajo y rebota hacia abajo, con lo cual no podrá volver a la pared superior si antes no ha rebotado en la barra.

2. La barra deberá moverse hacia izquierda o derecha cuando el usuario pulse las teclas del cursor "flecha derecha" (la barra se mueve hacia la derecha mientras pueda. Cuando alcanza la pared, ya no se puede mover más.) o "flecha izquierda" (idem pero hacia la izquierda). De esta manera, el jugador tiene que intentar que la bola rebote en la barra para seguir jugando. Si no lo logra, llega al game over y termina el juego (aunque podrá iniciar otro juego pulsando en iniciar).

3. Si se pulsa "Acelerar" la bola incrementa su velocidad. Sucesivas pulsaciones generarán nuevos incrementos de velocidad hasta el valor tope que se determine.

4. Si se pulsa "Frenar" el comportamiento es análogo al de acelerar, pero en este caso disminuyendo la velocidad hasta el valor límite que se determine.

5. Si se pulsa "Detener/Continuar" la bola quedará quieta (detener) o reanudará su movimiento si estaba quieta (continuar)

6. Si se pulsa "Resetear" se vuelve al estado inicial (bola y barra centradas sobre el panel de animación y a la espera de que se pulse un botón).

Las pulsaciones sin sentido no generarán ninguna respuesta. Por ejemplo si la bola no ha iniciado su movimiento o si está en pausa, al pulsar en acelerar no habrá ninguna respuesta puesto que no se puede acelerar. Si se pulsa detener/continuar antes de "Iniciar" no habrá respuesta, etc.

Deberá realizar un diseño orientado a objetos con las clases que estime oportunas respetando siempre:

a) Que exista orientación a objetos (distintas clases con distintas responsabilidades)
b) Funcionalidad: un elemento circular que se mueve por la pantalla y rebota en los bordes.

6
He estado haciendo pruebas y me cuesta bastante depende de las matematicas y la vision espacial que cada uno tengamos jeje. Lo que he entendido es que se hacen estas ejecuciones.

Establece el ángulo de partida en 325º (en grados sexagesimales es más fácil de ver, aunque luego para el cálculo matemático usa radianes porque es la forma de trabajar los grados que se suele usar en matemáticas y que usa Java, pero para la lógica nos podemos olvidar de los radianes).

Si establecemos el ángulo de partida en 0, la bola sale en horizontal hacia la derecha y rebota en la pared derecha adoptando movimiento en sentido 180º (pi radianes) con lo que sale rebotada hacia la izquierda en horizontal, y al llegar a la pared izquierda vuelve a rebotar igual, con lo cual lo que hace es moverse siempre en horizontal.

Si establecemos el ángulo de partida en 90, la bola sale en vertical hacia abajo y rebota en la pared inferior adoptando movimiento en sentido 180º (pi radianes) con lo que sale rebotada hacia arriba en vertical, y al llegar a la pared superior vuelve a rebotar igual, con lo cual lo que hace es moverse siempre en vertical.

Con esto ya tenemos cómo trabaja los ángulos que es 0 horizontal derecha 90 abajo 180 horizontal izquierda 270 arriba 360 equivale a 0 completando "una vuelta", 450 equivale a 90 ya que sería como una vuelta y noventa más con lo cual llegamos al mismo angulo (450%360=90 es decir es el resto y % es el operador módulo que devuelve el resto de una división, 540 equivale a 180 ya que 540%360 = 180 es el resto) y así sucesivamente hasta el valor que queramos. Por ejemplo 1210º equivale a 130º porque el resto de dividir 1210 entre 360 es 130 es decir 1210%360 = 130

Para mover la bola primero comprueba si hay rebote:

Citar

            if (xPosition < radius) { //Bola rebota con pared izquierda
                angle = 540 - angle;
            }

            if (xPosition > drawingPanelDimension.width - radius) { //Bola rebota con pared derecha
                angle = 540 - angle;
            }

            if (yPosition < radius) { //Bola rebota con pared inferior
                angle = 360 - angle;
            }

            if (yPosition > drawingPanelDimension.height - radius) { //Bola rebota con pared superior
                angle = 360 - angle;
            }

           angle %= 360; // Operador modulo resto de division entre 360


Haya habido o no rebote termina calculando el ángulo como angle %= 360; que si no me equivoco es lo mismo que angle = angle % 360, es decir, el valor de angle es el resto de dividir angle entre 360. Para el valor de partida 325 al dividir entre 360 el resto es 325, de modo que la bola sigue siempre en el ángulo en que esté hasta llegar a rebotar con una pared.
Dado que 270 equivale a vertical y 360 hacia la derecha, con 325 está tomando un ángulo que no es exactamente el intermedio entre ambos que seria 315º, sino un poco superior, con lo cual la bola sale hacia arriba y hacia la derecha (ligeramente más hacia arriba que hacia la derecha).

La primera pared a la que llega es la derecha y cuando esto ocurre hace el calculo angle = 540 - angle; que devuelve 215º y al aplicar  angle %= 360; lo que hace es transformarlo a un valor entre 0 y 360 pero aquí sigue resultando 215. Aqui 540 equivale a 180. Si la bola fuera con 0 de partida, al restar 0 a 540, queda 540, que al ser 180, implica un rebote formando un angulo de 180º respecto al ángulo inicial. Lo que hace es calcular un ángulo simétrico respecto al angulo que traía respecto al eje y. Por ejemplo para 30º el simétrico sería 180-30 = 150º y esto es lo que ocurre si hacemos 540-30 = 510 y si ahora hacemos el módulo entre 360 tenemos 510%360 = 150º. Así restando a 540 el angulo con el que venía obtenemos el ángulo "simétrico" respecto al eje y, lo cual genera un efecto de rebote natural.

La idea como yo la veo es: si la bola rebota con pared derecha o izquierda, el nuevo ángulo es la diferencia entre 540 (equivale a 180) y el ángulo que traía, lo que equivale a mantener la componente vertical y hacer opuesta la componente horizontal, es hacer una simetría respecto al eje vertical. Si la bola va con 0º la componente vertical es nula, con lo cual al hacerse opuesta sale en dirección 180. Si la bola va con 10º ya existe una cierta componente vertical y el rebote que se genera en lugar de ser de 180º es a 170º que es hacia la izquierda y ligeramente hacia abajo en este caso. Si la bola va con 20º el rebote es a 160º. Si la bola va con 30º el rebote es a 150º y así sucesivamente.

Usar 540º nos permite poder operar con cualquier ángulo entre 0 y 360 obteniendo unos resultados correctos y sin tener que operar con ángulos negativos.

Si la bola choca con la pared superior o inferior, por ejemplo llevando un angulo de avance de 80º genera la simetria en este caso respecto al eje x haciendo la resta angle = 360 - angle; por ejemplo para 80 el angulo de rebote es 280 que es una simetria respecto al eje x. Para 10º el angulo de rebote sería 350º.

Aqui las simetrias serian el efecto rebote: si rebota con pared lateral, simetria con la vertical para lo cual ha de usarse 540, si rebota con pared superior o inferior, simetria con la horizontal para lo cual ha de usarse 360.

La simetria respecto a la vertical se consigue a partir de 360 grados. En cambio respecto a la horizontal se consigue con 180. Pero si usaramos 180 no funcionaria con angulos mayores de 180. En cambio usando 540 que es lo mismo se obtiene el angulo de rebote sin importar si el angulo es superior a 180. Luego aplicando el modulo se transforma a un valor entre 0 y 360 equivalente y asi se continua.

El problema que le veo a esto es que es una forma de rebotar absolutamente matematica, lo cual es muy bonito y muy perfecto, pero ocurre una cosa, que es que al no existir nada de aleatoriedad los movimientos se repiten siempre exactamente igual. Es decir, en cada ejecución todo se repite porque siempre se producen los mismos calculos matematicos. Por ejemplo si el angulo de partida es 0 lo pondríamos en this.ball = new Ball(4, 325, drawingPanelDimension); cambiándolo por this.ball = new Ball(4, 0, drawingPanelDimension); pues la bola rebota simétricamente respecto al eje vertical y como va perfectamente horizontal, rebota perfectamente horizontal y lo que hace es estar continuamente de un lado a otro repitiendo siempre el mismo movimiento. Para que no se repitiera el movimiento tendriamos que introducir un factor de aleatoriedad. Pero bueno todo depende de los objetivos que se quisieran lograr en unos casos puede ser interesante hacerlo matematico y en otros un poco aleatorio.

Si buscamos explicaciones normalmente nos vienen como es lo mas habitual, con el angulo de 90 hacia arriba, pero por lo dicho anteriormente java lo trabaja hacia abajo lo cual nos complica un poco la vision porque tenemos que girarlo todo pero para ver la idea nos vale igual  8)


Aqui vemos como si choca con la pared superior con angulo 60 tiene que salir rebotado con angulo 300. Si choca con la pared lateral con angulo 60 tiene que salir rebotado con angulo 120 etc.

7
No acabo de verlo claro, por un lado no se si esta equivocado lo que he planteado respecto a la velocidad, pero si no esta equivocado la velocidad no es constante sino que sufre variaciones (pequeñas pero apreciables).
Por otro lado veo que la clase Ellipse2D es una clase abstracta cuyas implementaciones son Ellipse2D.Double y Ellipse2D.Float que en ambos casos parecen trabajar con decimales, de modo que seria posible fijar el avance con decimales, por eso no acabo de entender por qué no se podría trabajar con decimales. He buscado codigo y he encontrado este en que mueve una bola por la pantalla y parece que el avance se calcula con decimales, al menos usa private double xPosition, yPosition; aunque luego tambien usa redondeos

Código: [Seleccionar]
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Point2D;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class BolaDeEjemplo implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new BolaDeEjemplo());
    }

    private final BolaDeEjemploModel model;

    private final DrawingPanel drawingPanel;

    public BolaDeEjemplo() {
        this.model = new BolaDeEjemploModel();
        this.drawingPanel = new DrawingPanel(model);
    }

    @Override
    public void run() {
        JFrame frame = new JFrame("Bola Ejemplo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.add(drawingPanel, BorderLayout.CENTER);

        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);

        Timer timer = new Timer(30, new BallMotionListener(this, model));
        timer.start();
    }

    public void repaint() {
        drawingPanel.repaint();
    }

    public class DrawingPanel extends JPanel {

        private static final long serialVersionUID = 1L;

        private final BolaDeEjemploModel model;

        public DrawingPanel(BolaDeEjemploModel model) {
            this.model = model;
            this.setPreferredSize(model.getDrawingPanelDimension());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            Ball ball = model.getBall();
            Point2D point = ball.getPosition();
            int x = (int) Math.round(point.getX());
            int y = (int) Math.round(point.getY());
            int radius = ball.getRadius();
            int diameter = radius + radius;

            g.setColor(Color.BLUE);
            g.fillOval(x - radius, y - radius, diameter, diameter);
        }

    }

    public class BallMotionListener implements ActionListener {

        private final BolaDeEjemplo view;

        private final BolaDeEjemploModel model;

        public BallMotionListener(BolaDeEjemplo view, BolaDeEjemploModel model) {
            this.view = view;
            this.model = model;
        }

        @Override
        public void actionPerformed(ActionEvent event) {
            model.getBall().calculateNewPosition();
            view.repaint();
        }

    }

    public class BolaDeEjemploModel {

        private final Ball ball;

        private final Dimension drawingPanelDimension;

        public BolaDeEjemploModel() {
            this.drawingPanelDimension = new Dimension(400, 400);
            this.ball = new Ball(4, 325, drawingPanelDimension);
        }

        public Ball getBall() {
            return ball;
        }

        public Dimension getDrawingPanelDimension() {
            return drawingPanelDimension;
        }

    }

    public class Ball {

        private double xPosition, yPosition;

        private int angle, radius, speed;

        private final Dimension drawingPanelDimension;

        public Ball(int speed, int angle, Dimension drawingPanelDimension) {
            this.speed = speed;
            this.radius = 12;
            this.angle = angle;
            this.drawingPanelDimension = drawingPanelDimension;
            this.xPosition = drawingPanelDimension.width / 2;
            this.yPosition = drawingPanelDimension.height / 2;
        }

        public int getAngle() {
            return angle;
        }

        public void setAngle(int angle) {
            this.angle = angle;
        }

        public int getSpeed() {
            return speed;
        }

        public void setSpeed(int speed) {
            this.speed = speed;
        }

        public int getRadius() {
            return radius;
        }

        public void calculateNewPosition() {
            double theta = Math.toRadians(angle);
            double xDifference = Math.cos(theta) * speed;
            double yDifference = Math.sin(theta) * speed;
            xPosition += xDifference;
            yPosition += yDifference;

            if (xPosition < radius) {
                angle = 540 - angle;
            }

            if (xPosition > drawingPanelDimension.width - radius) {
                angle = 540 - angle;
            }

            if (yPosition < radius) {
                angle = 360 - angle;
            }

            if (yPosition > drawingPanelDimension.height - radius) {
                angle = 360 - angle;
            }

            angle %= 360;
        }

        public Point2D getPosition() {
            return new Point2D.Double(xPosition, yPosition);
        }

    }

}

8
Gracias por las explicaciones, uffff. He estado tratando de hacer calculos sobre como se inicia la bola y la velocidad a la que se mueve la bola inicialmente y no se si lo que me sale es así. Si no entiendo mal la bola se desplaza inicialmente una desviacionX y una desviacionY, y en el momento inicial la desviacionX puede tomar valor 5 ó -5, mientras que la desviacionY puede tomar valores entre 5, 4, 3, 2, 1, 0, -1, -2, -3, -4 ó -5. Si esto es asi, supongamos que la x vale 5 y la y vale 0, en ese caso la bola se movería 5 pixeles/ud tiempo. Supongamos que la x vale 5 y la y vale 5, en ese caso la bola se movería siguiendo un triángulo sqr(5^2+5^2) = raiz de 50 = 7,07 pixeles/ud tiempo.
Los angulos en que podría salir la bola serían entre 45 y 315 (-45) si va hacia la derecha. O entre 135 y 225 si va hacia la izquierda. El resto de ángulos no serían posibles en la salida al estar fijados los valores de partida a los rangos especificos.

Cuando se produce una colision una de las dos desviaciones tomaria el valor de VELOCIDAD, es decir, que si no hemos cambiado nada, una de las dos desviaciones vale 5 y la otra puede valer 5, 4, 3, 2, 1, 0, -1, -2, -3, -4 ó -5. De este modo la bola puede moverse o bien a 5 pixeles/ud tiempo en vertical o en horizontal, o con un máximo de 7,07 pixeles/ud tiempo si toma un ángulo de rebote máximo.

Esto explicaría que la bola parezca ralentizarse levemente en algunos momentos y acelerarse levemente en otros. Los cambios máximos de velocidad serian el pasar de 5 a 7,07 o el pasar de 7,07 a 5. Lo cual no es muy apreciable visualmente aunque creo que si se aprecia aunque el ojo puede engañar je je.

Si esto fuera asi (que seguro no estoy) no habria una velocidad constante de la bola en ningun caso, aunque no se pulse acelerar ni frenar, por el mero hecho de que las desviaciones la pueden acelerar o frenar levemente. Y para que la velocidad fuera constante tendria que basarse en un angulo y una distancia a avanzar. Y conocido esto calcular cuanto tiene que ser la desviacionX y la desviacionY. Creo que esto tiene logica en el sentido de que si estamos en un punto y caminamos 5 pasos a la derecha y 5 pasos hacia arriba, no habremos caminado la misma distancia que si caminamos 5 pasos a la derecha y ninguno hacia arriba. Para caminar la misma distancia en cada movimiento tendriamos que coger una cuerda y siendo nosotros el centro trazar una circunferencia de radio 5 y avanzar hasta un punto de esa circunferencia y de esa manera habriamos avanzado 5 pixeles/ud de tiempo y nos estariamos moviendo a una velocidad uniforme o eso creo. No se si tu lo ves igual.

9
Por ese lado creo entenderlo, hay clases de Java que estan creadas por los desarrolladores de Java y que nosotros usamos pero no hemos desarrollado.

Creo entender que el paint de un elemento grafico se ejecutará cada vez que mandemos a redibujar un elemento grafico y que el elemento grafico del Tablero incluye un JPanel por ser la propia clase extend de JFrame y una Bola por ser la Bola un atributo del Tablero. Al invocarse el repaint del tablero, se invoca el paint del Tablero, y el paint del Tablero dibuja todos los elementos gráficos vinculados al tablero bien sean por su propia naturaleza (extensión de JPanel) como por ser atributos del Tablero (en este caso un objeto Bola). Y en realidad podria haber sido la Bola otro elemento grafico distinto pero como indicaste

 
Citar
Mi intención era inicializar la Bola por separado en la clase GestorJuego (que veremos después) y luego pintarla en Tablero. Pero no he conseguido/sabido hacer que el tablero la pinte.

¿Si la clase Bola hubiera sido independiente del Tablero habría tenido un método paint? No veo método paint en la clase Bola, pero supongo que podría existir metodo paint si fuera independiente? ¿la g en la clase Tablero representa el interior del elemento grafico Jpanel para poder manipularlo?

He creado un objeto Tablero sin ejecutar el main y no se muestra nada en pantalla. He creado un objeto Juego sin ejecutar el main y se muestra el tablero con la bola en pantalla, y se pueden pulsar botones y funciona bien. Entiendo que si hacemos esto estariamos ejecutando el programa en el hilo principal, y ademas tenemos el SwingWorker, por lo que estariamos usando dos hilos, mientras que si iniciamos el programa con el main usamos tres hilos, uno el principal otro para los eventos y otro para mover la bola.

Viendo el codigo creo entender que el Tablero no se dibuja hasta que no se crea el Juego, porque el Juego es un JFrame dentro del cual esta el tablero. Asi estaria el JFrame de Juego como elemento de maximo nivel, y dentro de este tenemos el panel de botones y el tablero. Y dentro del tablero tenemos la bola o eso es lo que interpreto.
Gracias por la ayuda.

10
Creo haber entendido todo excepto de donde sale el objeto g ¿la g en la clase Tablero representa el interior del elemento grafico Jpanel para poder manipularlo? No veo ningún lugar donde se invoque paint(objetoPasadoAlMetodo) y no se si estoy equivocado pero ese metodo parace que no se invoca. Si no se invoca ¿cuando se ejecuta y por qué?
Por otro lado, ¿cuando creas un objeto Tablero con tablero = new Tablero((ancho / 5 * 4), alto); este objeto al crearlo no tiene representación grafica en la pantalla? Me refiero a que si estando creado el objeto, este no es visible y pasa a ser visible cuando se invoca una instrucción concreta. ¿En qué momento concreto? Entiendo que con repaint se redibuja el elemento grafico con los nuevos datos. Pero el elemento inicial en que se dibuja el elemento Tablero no lo tengo claro, gracias.

11
Vuelvo mas mar de dudas ¿Por que se incluye @SuppressWarnings("serial") en el codigo?,y el método paint(Graphics g) entiendo que pinta un elemento grafico como un JPanel, ¿la g representa el interior del elemento grafico para poder manipularlo? Y esto que entiendo es una conversión de tipos: Graphics2D G2D = (Graphics2D)g;  ¿Por qué se hace así en lugr de manipular directamente el objeto g? Gracias


12
Hola Kabuto una vez más más que gracias por el codigo y por la explicacion. Creo que es dificil o casi imposible encontrar respuestas con tanta dedicacion y explicaciones tan claras como las que tú haces. Como en otras ocasiones trato de desmenuzar todo el codigo para entenderlo todo, de ahi mis preguntas de aprendizaje empiezan por qué introduces los cinco botones dentro de JPanel, que a su vez se introducen en el JPanel PanelBotones en lugar de colocar los botones directamente sobre el JPanel PanelBotones. Por otro lado por qué usar pack() y por qué usar setLocationRelativeTo(null). Por otro lado lo que yo entiendo es que SwingUtilities.invokeLater(new Runnable() lo que hace es crear un hilo de ejecucion, no sé si es así y también me gustaria preguntar qué pasa si no creas un hilo de ejecución.

13
Hola me gustaría recabar ayuda con el ejercicico siguiente en Java.

Debe iniciar un programa con una ventana gráfica que ocupe aproximadamente la mitad de la pantalla del usuario, centrada sobre la misma. La ventana tendrá un panel izquierdo con borde marcado donde tendrá lugar la animación gráfica, que ocupará aproximadamente 4/5 partes de la ventana gráfica. Y un panel derecho con cinco botones: "Iniciar", "Acelerar", "Frenar", "Detener/Continuar" y "Resetear" que será 1/5 parte aproximadamente de la ventana gráfica.

Inicialmente debe aparecer un elemento gráfico circular ("la bola") centrado sobre el panel de animación o tablero. El comportamiento debe ser el siguiente:

1. Si se pulsa "Iniciar", la bola deberá moverse en una dirección aleatoria con una velocidad inicial predeterminada y continuar hasta alcanzar el borde del panel. En ese momento, deberá rebotar en un ángulo aleatorio de entre 30 y 150 grados sexagesimales, continuando su movimiento hasta chocar con otro borde y así sucesivamente.
2. Si se pulsa "Acelerar" la bola incrementa su velocidad. Sucesivas pulsaciones generarán nuevos incrementos de velocidad hasta el valor tope que se determine.
3. Si se pulsa "Frenar" el comportamiento es análogo al de acelerar, pero en este caso disminuyendo la velocidad hasta el valor límite que se determine.
4. Si se pulsa "Detener/Continuar" la bola quedará quieta (detener) o reanudará su movimiento si estaba quieta (continuar)
5. Si se pulsa "Resetear" se vuelve al estado inicial (bola centrada sobre el panel de animación y a la espera de que se pulse un botón).

Las pulsaciones sin sentido no generarán ninguna respuesta. Por ejemplo si la bola no ha iniciado su movimiento o si está en pausa, al pulsar en acelerar no habrá ninguna respuesta puesto que no se puede acelerar. Si se pulsa detener/continuar antes de "Iniciar" no habrá respuesta, etc.

Deberá realizar un diseño orientado a objetos con clases como las siguientes:

Clase Bola: se encargará de representar y dibujar la bola y de permitir el movimiento de esta (métodos posicionarInicialmente, avanzar (angulo), rebotar(angulo), obtenerPosicion)

Clase Tablero: se encargará de representar y dibujar el tablero (métodos obtenerCoordenadasOrigen, obtenerCoordenadasOpuestasOrigen)

Clase PanelBotones: se encargará de contener los botones e invocar los métodos que correspondan con cada pulsación.

Clase GestorJuego: se encargará de posicionar la bola sobre el tablero en su posición inicial y de hacer que la bola se mueva y rebote cuando deba hacerlo, de que la bola acelere, frene, se detenga/continúe o se resetee.

Clase Juego: contendrá el método main desde donde se generará el tablero, la bola y resto de elementos necesarios. El tablero y bola se pasarán a un GestorJuego que contendrá los métodos operativos de reacción a la pulsación de botones.

El diseño podrá modificarse según lo estime oportuno en cualquiera de sus aspectos, añadiendo o eliminando clases si así se desea, pero respetando:

a) Que exista orientación a objetos (distintas clases con distintas responsabilidades)
b) Funcionalidad: un elemento circular que se mueve por la pantalla y rebota en los bordes.

14
Hola, he introducido los cambios indicados y he modificado un tamaño de texto que cuando cambiaba salía demasiado grande y le he añadido que cuando se pulse borrar se siga mostrando el mensaje inicial de "Escriba y use botones". Muchas gracias por toda la ayuda.

El código en esta última versión:

Código: [Seleccionar]
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.GridLayout;
import java.awt.Font;
import java.awt.Color;
import java.awt.event.*;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingConstants;

public class Main extends JFrame {

    private JTextArea campoTexto;
    private JLabel etMensajes;
    private JButton btProcesar;
    private JButton btBorrar;
    private Dimension dim;

    public Main() {
        dim = Toolkit.getDefaultToolkit().getScreenSize();
        setTitle("Marco Swing");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setContentPane(new PanelPrincipal());
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    private class PanelPrincipal extends JPanel {

        public PanelPrincipal() {
            setPreferredSize(dim);
            int bordeAncho = dim.width * 5 / 100;
            int bordeAlto = dim.height * 5 / 100;
            setBorder(BorderFactory.createEmptyBorder(bordeAlto, bordeAncho, bordeAlto, bordeAncho));

            setLayout(new GridLayout(1,2));
            add(new PanelCampoTexto()); //Panel que va a la izquierda
            add(new PanelDerecho());//Panel que va a la derecha
        }
    }

    private class PanelCampoTexto extends JPanel {

        public PanelCampoTexto() {
            campoTexto = new JTextArea();
            campoTexto.setFont(new Font("Verdana", Font.PLAIN, dim.width * 2 / 100));
            setLayout(new GridLayout(1,1));
            JScrollPane scroll = new JScrollPane(campoTexto);
            add(scroll);
        }
    }

    private class PanelDerecho extends JPanel {

        public PanelDerecho() {

            etMensajes = new JLabel("Escriba y use botones", SwingConstants.CENTER);
            etMensajes.setFont(new Font("Verdana", Font.BOLD, dim.width * 2 / 100));

            //JPanel pnMensajes = new JPanel();
            //pnMensajes.add(etMensajes);

            btProcesar = new JButton("Procesar");
            btProcesar.setFont(new Font("Verdana", Font.PLAIN, dim.width * (3/2) / 100));
            btProcesar.addActionListener(new AccionProcesar());
            btBorrar = new JButton("Borrar");
            btBorrar.setFont(new Font("Verdana", Font.PLAIN, dim.width * (3/2) / 100));
            btBorrar.addActionListener(new AccionBorrar());

            JPanel pnBotonProcesar = new JPanel();
            pnBotonProcesar.add(btProcesar);
            JPanel pnBotonBorrar = new JPanel();
            pnBotonBorrar.add(btBorrar);
            JPanel pnBotones = new JPanel();
            pnBotones.setLayout(new GridLayout(1,2));
            pnBotones.add(pnBotonProcesar);
            pnBotones.add(pnBotonBorrar);

            setLayout(new GridLayout(2,1));
            add(etMensajes);
            add(pnBotones);

        }
    }

    private class AccionProcesar implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
   
         etMensajes.setText("Ha pulsado el botón procesar");
      }
   }
   
   private class AccionBorrar implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {

         etMensajes.setText("Escriba y use botones");
         campoTexto.setText(null);
      }
   }
   
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    new Main();
                }
            });
    }
}


15
Hola al ejecutar este código, que creo coincide con el propuesto aproximadamente, no me hace nada, se muestra la ventana y los botones, pero si escribo algo y pulso "Procesar" no veo que haga nada. Si pulso el botón "Borrar" tampoco veo que haga nada, y tampoco aparece ningún error. ¿Alguna idea de por qué no responde? Gracias

Código: [Seleccionar]
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.GridLayout;
import java.awt.Font;
import java.awt.Color;
import java.awt.event.*;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingConstants;

public class Main extends JFrame {

    private JTextArea campoTexto;
    private JLabel etMensajes;
    private JButton btProcesar;
    private JButton btBorrar;
    private Dimension dim;

    public Main() {
        dim = Toolkit.getDefaultToolkit().getScreenSize();
        setTitle("Marco Swing");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setContentPane(new PanelPrincipal());
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    private class PanelPrincipal extends JPanel {

        public PanelPrincipal() {
            setPreferredSize(dim);
            int bordeAncho = dim.width * 5 / 100;
            int bordeAlto = dim.height * 5 / 100;
            setBorder(BorderFactory.createEmptyBorder(bordeAlto, bordeAncho, bordeAlto, bordeAncho));

            setLayout(new GridLayout(1,2));
            add(new PanelCampoTexto()); //Panel que va a la izquierda
            add(new PanelDerecho());//Panel que va a la derecha
        }
    }

    private class PanelCampoTexto extends JPanel {

        public PanelCampoTexto() {
            campoTexto = new JTextArea();
            campoTexto.setFont(new Font("Verdana", Font.PLAIN, dim.width * 2 / 100));
            setLayout(new GridLayout(1,1));
            JScrollPane scroll = new JScrollPane(campoTexto);
            add(scroll);
        }
    }

    private class PanelDerecho extends JPanel {

        public PanelDerecho() {

            etMensajes = new JLabel("Escriba y use botones", SwingConstants.CENTER);
            etMensajes.setFont(new Font("Verdana", Font.BOLD, dim.width * 3 / 100));

            //JPanel pnMensajes = new JPanel();
            //pnMensajes.add(etMensajes);

            btProcesar = new JButton("Procesar");
            btProcesar.setFont(new Font("Verdana", Font.PLAIN, dim.width * (3/2) / 100));
            btBorrar = new JButton("Borrar");
            btBorrar.setFont(new Font("Verdana", Font.PLAIN, dim.width * (3/2) / 100));

            JPanel pnBotonProcesar = new JPanel();
            pnBotonProcesar.add(btProcesar);
            JPanel pnBotonBorrar = new JPanel();
            pnBotonBorrar.add(btBorrar);
            JPanel pnBotones = new JPanel();
            pnBotones.setLayout(new GridLayout(1,2));
            pnBotones.add(pnBotonProcesar);
            pnBotones.add(pnBotonBorrar);

            setLayout(new GridLayout(2,1));
            add(etMensajes);
            add(pnBotones);

        }
    }

    private class AccionProcesar implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         etMensajes.setText("Ha pulsado el botón procesar");
      }
   }
   
   private class AccionBorrar implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         etMensajes.setText(null);
         campoTexto.setText(null);
      }
   }
   
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    new Main();
                }
            });
    }
}

16
Hola, probando alternativamente con

 setLayout(new GridLayout(2,1));
            pnMensajes.setBackground(Color.green); // Para poder ver el elemento gráfico ponemos color verde
            add(pnMensajes);
            add(pnBotones);

y con

 setLayout(new GridLayout(2,1));
            etMensajes.setBackground(Color.green);
            etMensajes.setOpaque(true); //Añadido porque si no no se ve el color
            add(etMensajes); 
            add(pnBotones);

El resultado que obtengo es similar pero como has comentado añadiendo el panel pnMensajes el texto se va arriba, mientras que añadiendo el label el texto aparece centrado (y así se ve mejor).

Lo que comentaba en el mensaje anterior relativo a fijar los tamaños de letra como una proporción de dim.width crees que puede ser una buena solución para evitar malas visualizaciones según el tamaño de pantalla?


17
Comunidad / Re: Feliz Navidad y Próspero Año Nuevo para todos
« en: 14 de Enero 2023, 19:38 »
Aprovecho para desear feliz año y agradecer la ayuda que prestan, que es muy valiosa y por la que estoy muy agradecido.

18
He retomado un poco esto y he hecho un pequeño cambio.

La línea

Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();

me la he llevado como atributo de la clase Main para que pueda ser accesible desde cualquier lugar.

Como en mi pantalla no se ve el texto completo "Escriba y use botones" sino que se ve "Escriba y use boto..." debido a que el tamaño de fuente resulta excesivo para mi pantalla he cambiado

etMensajes.setFont(new Font("Verdana", Font.BOLD, 54));

Por etMensajes.setFont(new Font("Verdana", Font.BOLD, dim.width * 3 / 100));

Del mismo modo he cambiado el tamaño del texto de los botones.

         btProcesar.setFont(new Font("Verdana", Font.PLAIN, 34));
         btBorrar.setFont(new Font("Verdana", Font.PLAIN, 34));

Quedan como

         btProcesar.setFont(new Font("Verdana", Font.PLAIN, dim.width * (3/2) / 100));
         btBorrar.setFont(new Font("Verdana", Font.PLAIN, dim.width * (3/2) / 100));

Para hacerlo todo igual he cambiado en la clase PanelCampoTexto

         campoTexto.setFont(new Font("Verdana", Font.PLAIN, 44));

por          campoTexto.setFont(new Font("Verdana", Font.PLAIN, dim.width * 2 / 100));

Estos valores de 3/100 y de (3/2)/100 que he escrito así para evitar un warning y no es más que 1.5/100 y 2/100 etc. son valores que he ido probando y que imagino irán bien en casi todas las pantallas, incluso en las muy grandes o muy pequeñas, aunque no estoy seguro.

Esto me parece que puede ser una solución aceptable para evitar que en unas pantallas se vean bien las cosas y en otras no, al quedar relativo a la pantalla parece que en general deberá verse bien, o eso creo. ¿Puede ser una buena estrategia?

El código (sin gestión de eventos) es:

Código: [Seleccionar]
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.GridLayout;
import java.awt.Font;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingConstants;

public class Main extends JFrame {

    private JTextArea campoTexto;
    private JLabel etMensajes;
    private JButton btProcesar;
    private JButton btBorrar;
    private Dimension dim;

    public Main() {
        dim = Toolkit.getDefaultToolkit().getScreenSize();
        setTitle("Marco Swing");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setContentPane(new PanelPrincipal());
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    private class PanelPrincipal extends JPanel {

        public PanelPrincipal() {
            setPreferredSize(dim);
            int bordeAncho = dim.width * 5 / 100;
            int bordeAlto = dim.height * 5 / 100;
            setBorder(BorderFactory.createEmptyBorder(bordeAlto, bordeAncho, bordeAlto, bordeAncho));

            setLayout(new GridLayout(1,2));
            add(new PanelCampoTexto()); //Panel que va a la izquierda
            add(new PanelDerecho());//Panel que va a la derecha
        }
    }

    private class PanelCampoTexto extends JPanel {

        public PanelCampoTexto() {
            campoTexto = new JTextArea();
            campoTexto.setFont(new Font("Verdana", Font.PLAIN, dim.width * 2 / 100));
            setLayout(new GridLayout(1,1));
            JScrollPane scroll = new JScrollPane(campoTexto);
            add(scroll);
        }
    }

    private class PanelDerecho extends JPanel {

        public PanelDerecho() {

            etMensajes = new JLabel("Escriba y use botones", SwingConstants.CENTER);
            etMensajes.setFont(new Font("Verdana", Font.BOLD, dim.width * 3 / 100));

            JPanel pnMensajes = new JPanel();
            pnMensajes.add(etMensajes);

            btProcesar = new JButton("Procesar");
            btProcesar.setFont(new Font("Verdana", Font.PLAIN, dim.width * (3/2) / 100));
            btBorrar = new JButton("Borrar");
            btBorrar.setFont(new Font("Verdana", Font.PLAIN, dim.width * (3/2) / 100));

            JPanel pnBotonProcesar = new JPanel();
            pnBotonProcesar.add(btProcesar);
            JPanel pnBotonBorrar = new JPanel();
            pnBotonBorrar.add(btBorrar);
            JPanel pnBotones = new JPanel();
            pnBotones.setLayout(new GridLayout(1,2));
            pnBotones.add(pnBotonProcesar);
            pnBotones.add(pnBotonBorrar);

            setLayout(new GridLayout(2,1));
            add(etMensajes);
            add(pnBotones);

        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    new Main();
                }
            });
    }
}

Hay una cosa que no me queda muy clara de este código, y es dentro de la clase PanelDerecho

Tenemos
            JPanel pnMensajes = new JPanel();
            pnMensajes.add(etMensajes);

Y tambien JPanel pnBotonProcesar = new JPanel(); que es donde se añaden los botones.

Ahora en el panel derecho se establece un layout con 2 filas, arriba el panel que muestra "Escriba y use botones" y abajo el panel con los propios botones.

            setLayout(new GridLayout(2,1));
            add(etMensajes);
            add(pnBotones);

Pero aquí en lugar de añadir los dos subpaneles (pnMensajes y pnBotones) lo que veo es que se añade el JLabel etMensajes y el panel pnBotones.

¿Por qué no se añaden los dos paneles? Aquí parece que pnMensajes quedara sin uso. ¿Por qué?


19
Aprender a programar desde cero / Re: java swing ventana gráfica
« en: 08 de Octubre 2022, 19:51 »
Gracias ahora en el código que incorpora el lado derecho con los labels y botones las importaciones me quedan así:

Código: [Seleccionar]
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.GridLayout;
import java.awt.Font;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingConstants;

JButton btProcesar entiendo que bt es botón pero no sé qué significado le aplicas a JLabel etMensajes, no sé qué se interpreta con et.

Al ejecutar el código me aparece el texto pero no se muestra entero, lo que me aparece es "Escriba y use bo..." Yo creo que se corta porque el tamaño de fuente excede el tamaño disponible en la pantalla. Pero supongo que a tí no te ocurre eso. Lo que quería preguntar es si podemos establecer un tamaño de fuente relativo de modo que se ajuste al tamaño de pantalla en que se visualice.

La otra cosa que me genera duda es la cantidad de JPanel que veo que creas. PanelDerecho ya es de por sí un JPanel. Dentro de ese JPanel veo que declaras otro JPanel pnMensajes = new JPanel(); otro más  JPanel pnBotonProcesar = new JPanel(); otro más JPanel pnBotonBorrar = new JPanel(); otro más JPanel pnBotones = new JPanel();

Luego creo que añades los JPanel de los botones al Jpanel de pnBotones y finalmente al JPanel PanelDerecho le añades el JLabel etMensajes y el JPanel pnBotones.

El JPanel pnBotones creo que tiene la utilidad de servir para montar los botones pero al JPanel pnMensajes no le veo utilidad ¿tiene uso?

Y la otra pregunta: ¿no podríamos haber montado tanto el JLabel etMensajes como los botones directamente sobre PanelDerecho ahorrándonos pnMensajes, pnBotonProcesar, pnBotonBorrar y pnBotones?

20
Aprender a programar desde cero / Re: java swing ventana gráfica
« en: 03 de Octubre 2022, 17:47 »
Lo agradezco al menos de forma aproximada es como pensaba. Para el código con las dos columnas creadas (paneles izquierdo y derecho) las dudas serian:

- No me compila sin importaciones adicionales supongo que es normal

Código: [Seleccionar]
import javax.swing.JPanel;
import java.awt.GridLayout;
import javax.swing.JScrollPane;

- Aparte hay una aproximacion que no veo muy clara

Como campo de main tenemos un atributo

Código: [Seleccionar]
public class Main extends JFrame {
   private JTextArea campoTexto;

¿No podria haber sido atributo de private class PanelCampoTexto extends JPanel en lugar de atributo de la clase Main?


Páginas: [1] 2

Sobre la educación, sólo puedo decir que es el tema más importante en el que nosotros, como pueblo, debemos involucrarnos.

Abraham Lincoln (1808-1865) Presidente estadounidense.

aprenderaprogramar.com: Desde 2006 comprometidos con la didáctica y divulgación de la programación

Preguntas y respuestas

¿Cómo establecer o cambiar la imagen asociada (avatar) de usuario?
  1. Inicia sesión con tu nombre de usuario y contraseña.
  2. Pulsa en perfil --> perfil del foro
  3. Elige la imagen personalizada que quieras usar. Puedes escogerla de una galería de imágenes o subirla desde tu ordenador.
  4. En la parte final de la página pulsa el botón "cambiar perfil".