How to prevent the object to exceed the limits of the screen?

Asked

Viewed 465 times

0

I started programming a little game where an object moves across the screen via the arrow keys on the keyboard. The difficulty I found is the fact that the object surpasses the JFrame, that is, there is nothing to block the passage at the border of JFrame.

I would like to know how I can solve this problem, or at least an indication of a path I should take to achieve success in this goal.

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class Jogo1 extends JFrame{ //Herda para usar JFrame

String n = "0";
JLabel labelFlappy = new JLabel(n);

int posPrincX = 300;
int posPrincY = 300;

public Jogo1(){
    editarJanela();
    editarComponentes();
    addMovimento();
}

public void addMovimento(){
    addKeyListener(new KeyListener(){ //Teclado
        public void keyPressed(KeyEvent e) {
            System.out.println(e.getKeyCode()); //Exibe código da tecla pressionada
            if(e.getKeyCode() == 38){
                posPrincY -= 20;
            }
            if(e.getKeyCode() == 40){
                posPrincY += 20;
            }
            if(e.getKeyCode() == 37){
                posPrincX -= 20;
            }
            if(e.getKeyCode() == 39){
                posPrincX += 20;
            }
            labelFlappy.setBounds(posPrincX, posPrincY, 180, 90); //Atualiza posição
        }
        public void keyReleased(KeyEvent e) {   

        }           
        public void keyTyped(KeyEvent e) {

        }
    });
    addMouseListener(new MouseListener() {

        public void mouseClicked(MouseEvent e) { //Ao clicar no objeto em questão
            posPrincX = (int)(Math.random() * 650);
            posPrincY = (int)(Math.random() * 700);
            labelFlappy.setBounds(posPrincX, posPrincY, 180, 90);
        }
        public void mouseEntered(MouseEvent e) {

        }
        public void mouseExited(MouseEvent e) {

        }
        public void mousePressed(MouseEvent e) {

        }
        public void mouseReleased(MouseEvent e) {

        }   
    });
}

public void editarComponentes(){
    labelFlappy.setBounds(posPrincX, posPrincY, 180, 90);
}

public void editarJanela(){
    setDefaultCloseOperation(EXIT_ON_CLOSE); //Encerra ao fechar 
    setSize(750, 700); //Tamanho 
    setLocationRelativeTo(null); //Centraliza
    setVisible(true); //Torna visível
    setLayout(null); //Permite redimensionamento de cada componente
    setResizable(false); //Impossibilita o redimensionamento pelo usuário
    setTitle("Magisterix"); //Título

    add(labelFlappy);
}

public static void main(String[] args){
    new Jogo1();
}}
  • 1

    Provides a [mcve] so that it is possible to run your code and detect the problem, without it it is difficult to help

  • Clarify your specific issue or add other details to highlight exactly what you need. The way it’s written here, it’s hard to know exactly what you’re asking. See the [Ask] page for help clarifying this question.

  • These icons don’t let the code run, which can disrupt the problem. Try to edit the form code that is possible to execute without the icons.

  • 1

    @Guilhermecostamilam undoes its edition because it removed important excerpts from the code, and this is not recommended to be done in the editions.

  • Import is important? I never put the Imports in my questions, sometimes they are several and several lines and I consider irrelevant in the question, at least in that

  • @Guilhermecostamilam yes, it is important, if added, should not be removed.

  • how can I edit to not need images?

  • @Eddunic ai vc needs to test its own code without the images in the Abels and see if you can reproduce the problem in the same way.

  • I just edited

  • I executed and did not identify the problem mentioned in the question, if possible, explain how Voce did so that the object leaves the area of the screen.

  • I believe the problem is in the addMovimento method. My goal is to make the object can go to the edge of the Jframe and do not pass from there. When I compile and guide the object, it crosses the edge of the Jframe. I want to impose a limit on the edge of that screen for the movement of the object.

  • @Eddunic your code does not reproduce very well and has other problems, but see the answer below where I suggest a solution, even without having managed to understand the purpose of this code.

  • @Guilhermecostamilam I particularly think imports help. I’ve seen some issues where the error was in the import because there are classes with equal names in different packages. In addition, to be a 100% neat MVCE you have to have the Imports, even to save the respondent from having to fix the given code to reproduce the problem.

  • I found the solution, what should be done was simple. Just create pause and return conditions according to the coordinates of the object on the screen. Thanks for all your help!

Show 9 more comments

2 answers

5

To prevent moving components from exceeding the screen area, you can use a method that checks whether new X and Y positions, summed with the width and overall height of the component, exceed the screen size in both directions, and when they exceed, no longer move the component or apply some negative value so it does not get stuck in the corner. The method to verify this, based on your code, can be more or less like this:

private boolean excedeuAreaDaTela(int posX, int posY) {
    return posX < 0 || posX + 180 > 750 || posY < 0 || posY + 90 > 700;
}

To use, just involve with a conditional the line you change the position of the component:

if (!excedeuAreaDaTela(posPrincX, posPrincY)) {
    labelFlappy.setBounds(posPrincX, posPrincY, 180, 90); // Atualiza posição
}

When the method returns true, means that if the component moves to the given coordinates, it will exceed the size you set for the screen, the conditional will not allow movement in this case.

  • I believe it’s right to limit the Sun to the size of the screen, similar to what Victor did. Correct me if I’m wrong, but it seems to me that the code above is not doing this.

  • @Piovezan the code above does just that, I was more simplistic.

  • I get it. It just seems to me that it avoids going over the maximum size but doesn’t exactly position the Sprite at the maximum size. So this one always stays just before the maximum size.

  • 3

    Downvoter, if Voce really understands the subject, why don’t you show me where the error in the code is? ;) show that you voted conscientiously and not because you are a blunt and obnoxious person.

2


I managed to do so:

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class Jogo1 {

    private static final int KEY_CODE_DOWN = 38;
    private static final int KEY_CODE_UP = 40;
    private static final int KEY_CODE_LEFT = 37;
    private static final int KEY_CODE_RIGHT = 39;

    private static final int DISTANCIA_PASSO = 20;
    private static final int LARGURA_INICIAL_TELA = 750;
    private static final int ALTURA_INICIAL_TELA = 700;
    private static final int POSICAO_X_INICIAL = 300;
    private static final int POSICAO_Y_INICIAL = 300;
    private static final int LARGURA_FLAPPY_INICIAL = 180;
    private static final int ALTURA_FLAPPY_INICIAL = 90;

    private int posicaoX;
    private int posicaoY;

    public Jogo1() {
        JFrame tela = new JFrame("Magisterix");
        tela.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Encerra ao fechar.
        tela.setSize(LARGURA_INICIAL_TELA, ALTURA_INICIAL_TELA); // Ajusta o tamanho.
        tela.setLocationRelativeTo(null); // Centraliza.
        tela.setVisible(true); // Torna visível.
        tela.setResizable(false); // Impossibilita o redimensionamento pelo usuário.
        tela.setLayout(null); // Permite redimensionamento de cada componente.

        JLabel labelFlappy = new JLabel("0");
        labelFlappy.setOpaque(true);
        labelFlappy.setBackground(Color.YELLOW);
        tela.add(labelFlappy);
        posicaoX = POSICAO_X_INICIAL;
        posicaoY = POSICAO_Y_INICIAL;
        labelFlappy.setBounds(posicaoX, posicaoY, LARGURA_FLAPPY_INICIAL, ALTURA_FLAPPY_INICIAL);

        tela.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                System.out.println(e.getKeyCode());
                if (e.getKeyCode() == KEY_CODE_DOWN) {
                    posicaoY -= DISTANCIA_PASSO;
                } else if (e.getKeyCode() == KEY_CODE_UP) {
                    posicaoY += DISTANCIA_PASSO;
                } else if (e.getKeyCode() == KEY_CODE_LEFT) {
                    posicaoX -= DISTANCIA_PASSO;
                } else if (e.getKeyCode() == KEY_CODE_RIGHT) {
                    posicaoX += DISTANCIA_PASSO;
                }
                posicaoX = limitar(0, posicaoX, tela.getContentPane().getWidth() - labelFlappy.getWidth());
                posicaoY = limitar(0, posicaoY, tela.getContentPane().getHeight() - labelFlappy.getHeight());
                labelFlappy.setBounds(posicaoX, posicaoY, labelFlappy.getWidth(), labelFlappy.getHeight());
            }
        });

        tela.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                posicaoX = (int) (Math.random() * (tela.getContentPane().getWidth() - labelFlappy.getWidth()));
                posicaoY = (int) (Math.random() * (tela.getContentPane().getHeight() - labelFlappy.getHeight()));
                labelFlappy.setBounds(posicaoX, posicaoY, labelFlappy.getWidth(), labelFlappy.getHeight());
            }
        });
    }

    private static int limitar(int min, int meio, int max) {
        return meio < min ? min : meio > max ? max : meio;
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(Jogo1::new);
    }
}

The trick is to limit posPrincX and posPrincY the size of the window (or posicaoX and posicaoY, since I renamed the variables). For this, I use the method limitar(int, int, int).

I made some other changes to your code:

  • Only create, interact, use and access Swing components within the EDT. For this, I use the EventQueue.invokeLater(Runnable). See more about this in that question and in that reply.

  • Prefer to use composition rather than inheritance, and therefore not inherit from JFrame. I talk about it in that reply. I also address this issue (and many other things) in that other answer.

  • Use magic numbers is not good programming practice. I made your code without using magic numbers and also in a way that if the screen size or label size change, it will not get messy and will adjust to the change alone.

  • I painted the JLabel yellow so you can see exactly where it is and what its size.

  • I changed the name of some variables to be more representative.

  • Use KeyAdapter and MouseAdapter instead of implementing directly KeyListener and MouseListener not to need to have that lot of empty methods.

  • Man, thanks for that great tip! I’ll start changing some modes of programming.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.