Kilka JPanel w JFrame

0

Witam, od jakiegoś czasu uczę się programować w Javie. Chciałem napisać grę, typu Atari Breakout. W tym celu utworzyłem klasę rozszerzającą JFrame:

import javax.swing.*;
import java.awt.*;

public class ActionFrame extends JFrame
{
    ActionFrame()
    {
        super("Brick Breaker 2D");

        setPreferredSize(new Dimension(1080,720));
        setResizable(false);


        JPanel ball = new Ball();
        JPanel platform = new Platform();


        add(platform);
        add(ball);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
        setVisible(true);
    }
}

Oraz dwa JPanele. "Ball" oraz "Platform"

import javax.swing.*;
import java.awt.*;

public class Ball extends JPanel
{
    private int x=460, y=550;


    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setPaint(new Color(220, 220, 220));
        g2d.fillOval(x, y, 30, 30);
    }


}
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class Platform extends JPanel implements KeyListener
{
    private int x=460, y=650;

    public Platform()
    {
        setBackground(new Color(30, 30, 30));
        setFocusable(true);
        addKeyListener(this);
    }

    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setPaint(new Color(220, 220, 220));
        g2d.fillRect(x, y, 100, 10);

    }

    @Override
    public void keyPressed(KeyEvent evt)
    {
        char k = evt.getKeyChar();
        if(k == 'd')
        {
            x+=20;
            if(x + 20 >= 1030)
                x=-50;
        }

        if(k == 'a')
        {
            x-=20;
            if(x - 20 <= -50)
                x=1030;
        }

        repaint();
    }
    @Override
    public void keyReleased(KeyEvent evt) {

    }
    @Override
    public void keyTyped(KeyEvent evt) {

    }
}

Problem pojawia się, gdy w klasie ActionFrame, próbuję dodać i piłkę i platformę, ponieważ wyświetla się tylko ten obiekt, który został dodany ostatni. Kombinowałem trochę z setLayout(), ale nie wyszło.

1
  1. Nie rób tak:
public class Platform extends JPanel implements KeyListener

tylko zrób osobną klasę z tego key listenera...
2. Ten pomysł jest raczej słaby bo dużo wygodniej byłoby ci po prostu rysować wszystko w jednym panelu...
3. Pokaż kod który nie działą bo coś kręcisz. Po ustawieniu layoutu wszystko powinno być widoczne.

1

Domyślny layout dla klasy JFrame to BorderLayout. W oknie jest pięć obszarów, w metodzie add potrzebny jest drugi argument - gdzie dodać panel, domyślny jest obszar centralny.

        add(platform,BorderLayout.CENTER);
        add(ball,BorderLayout.NORTH);

Obszary to: CENTER, NORTH, SOUTH, EAST i WEST.

0
Shalom napisał(a):
  1. Nie rób tak:
public class Platform extends JPanel implements KeyListener

tylko zrób osobną klasę z tego key listenera...
2. Ten pomysł jest raczej słaby bo dużo wygodniej byłoby ci po prostu rysować wszystko w jednym panelu...
3. Pokaż kod który nie działą bo coś kręcisz. Po ustawieniu layoutu wszystko powinno być widoczne.

  1. O czym dokładnie mówisz, jak mam zrobić osobną klasę, z KeyListenera?
  2. Zdaję sobie z tego sprawę, jednak myślę trochę przyszłościowo, miałem w planach zrobienia też gry, typu Space Invaders, a tam nie wygodnie byłoby dodawać wszystko w jednym JPanelu.
  3. Wysłałem wszystko z wyjątkiem Main, ale tam jest tylko:
import java.awt.*;

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

Usunąłem setLayout(...), z JFrame, bo nie działał. ( new FlowLayout(), (new BoxLayout(....) ).
Napisz może, jaki to powinien być Layout.

0

Bogdans, zrobiłem tak, ale piłka dalej się nie wyświetla.

1

Warto dla obu paneli ustalić rozmiar:

    public Platform()
    {
        setBackground(new Color(30, 30, 30));
        setFocusable(true);
        addKeyListener(this);
        setPreferredSize(new Dimension(400,300));
    }

W klasie Ball musisz dopisać konstruktor. Jeśli chodzi o osobną klasę Listenera, to możesz to zrobić tak:

        addKeyListener(new KeyAdapter()
        {
            public void keyPressed(KeyEvent ke)
            {
                char k = evt.getKeyChar();
                if(k == 'd')
                {
                   x+=20;
                   if(x + 20 >= 1030)
                       x=-50;
               }
 
               if(k == 'a')
               {
                   x-=20;
                  if(x - 20 <= -50)
                     x=1030;
              }
              repaint();
            }
        });
0
bogdans napisał(a):

Warto dla obu paneli ustalić rozmiar:

    public Platform()
    {
        setBackground(new Color(30, 30, 30));
        setFocusable(true);
        addKeyListener(this);
        setPreferredSize(new Dimension(400,300));
    }

W klasie Ball musisz dopisać konstruktor. Jeśli chodzi o osobną klasę Listenera, to możesz to zrobić tak:

        addKeyListener(new KeyAdapter()
        {
            public void keyPressed(KeyEvent ke)
            {
                char k = evt.getKeyChar();
                if(k == 'd')
                {
                   x+=20;
                   if(x + 20 >= 1030)
                       x=-50;
               }
 
               if(k == 'a')
               {
                   x-=20;
                  if(x - 20 <= -50)
                     x=1030;
              }
              repaint();
            }
        });

Nie działa, nie chce się skompilować. Dodałem preferowany rozmiar, w konstruktorze, Piłki i Platformy, ale nie wiem, do końca do czego służy.

1

Niekonsekwentna nazwa zmiennej

public void keyPressed(KeyEvent evt)

Usuń też niepotrzebne metody.

public class Platform extends JPanel
{
    private int x=460, y=650;
 
    public Platform()
    {
        setBackground(new Color(30, 30, 30));
        setFocusable(true);
        addKeyListener(new KeyAdapter()
        {
            public void keyPressed(KeyEvent evt)
            {
                char k = evt.getKeyChar();
                if(k == 'd')
                {
                   x+=20;
                   if(x + 20 >= 1030)
                       x=-50;
                }
 
                if(k == 'a')
                {
                   x-=20;
                  if(x - 20 <= -50)
                     x=1030;
                }
                repaint();
            }
        });        
        setPreferredSize(new Dimension(1080,720));
    }
 
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setPaint(new Color(220, 220, 220));
        g2d.fillRect(x, y, 100, 10);
    }
}

W głównej klasie metody setPreferredSize i pack się gryzą. pack() to żądanie by okno było jak najmniejsze i pomieściło wszystkie komponenty. Usuń setPreferredSize.

0

Zrobiłem to, Platforma, działa jak powinna, ale nadal nie rozwiązuje to mojego problemu. Jedyny moment, w którym udało mi się wyświetlić i piłkę i platformę, na raz, był wtedy kiedy dodałem je w taki sposób:
add(platform,BorderLayout.CENTER);
add(ball,BorderLayout.EAST);
lub
add(platform,BorderLayout.CENTER);
add(ball,BorderLayout.WEST);
Jednak, nie były wtedy one nad sobą, i nie mogłem "Podjechać" platformą pod piłkę.

1

Bo masz błędną koncepcję. Powinieneś mieć jeden panel i w nim rysować paletkę, piłkę i cegły. Kiedyś dla zabawy napisałem prostą wersję gry Arkanoid (ta się nazywała na PC). Był jeden panel z taką metodą rysującą:

        public void paintComponent(Graphics g)                                                       
        {                                                                                           
            super.paintComponent(g);                                                                 
            Graphics2D g2 = (Graphics2D)g;
            g2.setColor(ball.getColor());
            g2.fill(ball);                                                                
            g2.setColor(platform.getColor());
            g2.fill(platform);
            for(ColoredRectangle brick: bricks)
            {
                g2.setColor(brick.getColor());
                g2.fill(brick);
            }
        }

Prócz tego był Timer, który przesuwał piłkę i MouseMoveListener, który przesuwał paletkę.

0

No ok. Tak czy siak, bardzo dziękuję za pomoc. :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1