Como exibir 2 Objetos Graphics de classes diferentes na tela do programa?

Olá pessoas, sou novo no GUJ e percebi que varias das minhas duvidas eu ja achei resposta aqui. Entao eu decidi criar uma conta e entrar para o club kkkkkkk
Bom eu estou em um projeto simples para por meu conhecimento a prova, e me decepcionei kkkkkkk
Isso deve ser simples para todos mas eu ja estou a dias batendo a cabeça nesse programinha.
Bom vamos deixar as mazelas de lado e vamos ao que interessa xD
Eu quero “recriar” aquele famoso jogo da cobrinha, apenas para colocar meu conhecimento pra fora e praticar um pouco. Neste jogo eu criei 2 classes com objetos de mesma procedencia digamos assim…
Nas duas classes eu gero Graphics. Em uma eu crio a cobrinha por assim dizer( nao esta parecendo uma cobra ainda xD) e na outra eu crio a comida. Esta comida precisa estar em classe diferente so porque sim kkk
O problema esta na hora de juntar os 2… Bom o topico que ensina a colocar SRC aqui esta bugado entao vou apenas colar aqui.

Jogodacobrinha.java

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

public class Jogodacobrinha extends JFrame {

private static final int LARGURA = 800;
private static final int ALTURA = 600;
private static final String NOME = "Cobrinha em Java";

static JFrame jogo = new JFrame(NOME);


static int x;
static int y;

public Jogodacobrinha(){
atualizar();

}
public void atualizar(){
Comida comida = new Comida();
Cobra cobrinha = new Cobra(0,0);
Tela tela = new Tela();

    cobrinha.setBackground(Color.BLACK);     
    
    jogo.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    jogo.setSize(LARGURA, ALTURA);
    jogo.setResizable(false);
    jogo.setLocationRelativeTo(null);
    jogo.setLayout(new BorderLayout());
    jogo.getContentPane().add(cobrinha, BorderLayout.CENTER);
    jogo.getContentPane().add(comida, BorderLayout.CENTER);
   
    jogo.setVisible(true);
    
}

public static void main(String[] args) {
    new Jogodacobrinha();       
}   

}

como jogo = new JFrame eu tentei colocar os 2 dentro utilizando "jogo.getContentPane().add(cobrinha, BorderLayout.CENTER); e nao funcionou =( se eu mudo um dos 2 pra SOUTH aparece um embaixo do outro. vou mandar as 2 classes dos objetos...

classe Cobra.java

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Ellipse2D;
import java.util.Random;
import javax.swing.JPanel;
import javax.swing.Timer;

@SuppressWarnings(“serial”)
public class Cobra extends JPanel implements ActionListener, KeyListener {

Timer t = new Timer(5, (ActionListener) this);

private double velX = 2, velY = 2;
private double x;
private double y;

Color cor = Color.WHITE;

public Cobra(double x, double y) {
    this.x = x;
    this.y = y;
    t.start();
    addKeyListener(this);
    setFocusable(true);
    setFocusTraversalKeysEnabled(true);
}

public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g;
    Ellipse2D circle = new Ellipse2D.Double(x, y, 25, 25);
    g2.setColor(cor);
    g2.fill(circle);
    
}

@Override
public void actionPerformed(ActionEvent e) {
 /* if (x < 0 || x>740){
  *    velX = -velX;
  *   }
  * if(y <0 || y>520){
  *    velY = -velY;
  *   }
  */

    if (x < -30) {
        x = 800;
    }
    if (x > 800) {
        x = 0;
    }
    if (y < -30) {
        y = 600;
    }
    if (y > 600) {
        y = 0;
    }

    x += velX;
    y += velY;
    repaint();

}

public void cima() {
    velY = -1.5;
    velX = 0;
}

public void baixo() {
    velY = 1.5;
    velX = 0;
}

public void esquerda() {
    velX = -1.5;
    velY = 0;
}

public void direita() {
    velX = 1.5;
    velY = 0;
}

@Override
public void keyPressed(KeyEvent e) {
    int teclas = e.getKeyCode();
    if (teclas == KeyEvent.VK_W) {
        cima();
    }
    if (teclas == KeyEvent.VK_S) {
        baixo();
    }
    if (teclas == KeyEvent.VK_D) {
        direita();
    }
    if (teclas == KeyEvent.VK_A) {
        esquerda();
    }
}

@Override
public void keyReleased(KeyEvent e) {

}

@Override
public void keyTyped(KeyEvent e) {

}

}
fim classe Cobra.java
classe Comida.java

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

public class Comida extends JPanel {

private int x;
private int y;
int largura = 800;
int altura = 600;

Random gerador = new Random();

public void paint(Graphics g){
    gerador = new Random();       
    x = gerador.nextInt(700)+1;
    y = gerador.nextInt(500)+1;        
    g.setColor(Color.GREEN);
    g.fillRect(x, y, 20, 20);
    
}


public int getX() {
    return x;
}

public void setX(int x) {
    this.x = x;
}

public int getY() {
    return y;
}

public void setY(int y) {
    this.y = y;
}

}

espero que alguem possa me ajudar =)

Não é recomendável fazer desse jeito, vc teria que inserir no construtor da Comida setOpacity(false) e adicionar a Comida na classe Cobra cobra.add(comida, BorderLayout.CENTER).

A forma mais correta seria usando um único JPanel para exibir o game.

interface Drawable {
  public void paint(Graphics2D g2d);
}

class Comida implements Drawable {}

class Cobra implements Drawable {}

class Game extends JPanel implements ActionListener, KeyListener {
  void paintComponent(g) {
    Graphics2D g2d = g;
    comida.paint(g2d);
    cobra.paint(g2d)
  }
}
1 curtida

ola @diogo12 tudo bem? mto obrigado pela resposta, mas eu nao consegui entender seu raciocinio kkk vc esta falando para que as 2 classes Cobra e Comida sejam interfaces Drawable e nao JPanel certo?
e que eu crie uma classe chamada Game que extenda JPanel e implements ActionListener , Keylistener, para pintar a comida e a cobra?
eu tentei e nao funcionou com seu metodo =/
EDIT: eu preciso que a classe da Cobra seja controlavel pelo teclado e que e que ela ande sozinha como no game real entende? se eu utilizar seu metodo elas iram aparecer apenas. eu tinha uma quarta classe chamada Tela.java que eu criei apos enviar esse post, nela eu fazia a mesma coisa mas nao conseguia controlar a maldita cobra xD
EDIT 2: no metodo nao viavel que vc citou nao existe setOpacity() =( pelo menos eu nao achei xD
EDIT3 : festa de Edit kkkkkkkk o Timer da classe cobra faz ela andar sozinha sem o JPanel na classe Cobra ela nao anda =/ como eu faria ela andar sem o Timer?

Sim.

Sim, mas o Timer ficaria na classe game, o timer chamaria um método na classe cobra, geralmente chamado de step:

public void step() {
    if (x < -30) {
        x = 800;
    }
    if (x > 800) {
        x = 0;
    }
    if (y < -30) {
        y = 600;
    }
    if (y > 600) {
        y = 0;
    }

    x += velX;
    y += velY;
}

e o actionPerformed do timer:

cobra.step();
repaint();.

poderia criar uma interface:

interface Entity {
    void paint(Graphics2D g);
    void step();
}

e no timer usar lista:

for(Entity e: listaDeEntidades) {
  e.step();
}
repaint();

Desculpa, é setOpaque

vou tentar essa forma ai mas primeiro veja se esta correto meu codigo agora

public class Jogodacobrinha extends JFrame {
private static final int LARGURA = 800;
private static final int ALTURA = 600;
private static final String NOME = “Cobrinha em Java”;
static JFrame jogo = new JFrame(NOME);
static Game game = new Game();
static int x;
static int y;
public Jogodacobrinha(){
atualizar();
}
public void atualizar(){
game.setBackground(Color.BLACK);
jogo.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jogo.setSize(LARGURA, ALTURA);
jogo.setResizable(false);
jogo.setLocationRelativeTo(null);
jogo.setLayout(new BorderLayout());
jogo.getContentPane().add(game, BorderLayout.CENTER);
jogo.setVisible(true);
}
public static void main(String[] args) {
new Jogodacobrinha();
}
}


public class Cobra implements Drawable {
private double velX = 2, velY = 2;
private int x;
private int y;
Color cor = Color.WHITE;
public Cobra(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public void paintComponent(Graphics2D g2d) {
Ellipse2D circle = new Ellipse2D.Double(x, y, 20, 20);
g2d.setColor(cor);
g2d.fill(circle);
}
public double getVelX() {
return velX;
}
public void setVelX(double velX) {
this.velX = velX;
}
public double getVelY() {
return velY;
}
public void setVelY(double velY) {
this.velY = velY;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}


public class Comida implements Drawable {
private int x;
private int y;
int largura = 800;
int altura = 600;
Random gerador = new Random();
@Override
public void paintComponent(Graphics2D g2d) {
gerador = new Random();
x = gerador.nextInt(700)+1;
y = gerador.nextInt(500)+1;
g2d.setColor(Color.GREEN);
g2d.fillRect(x, y, 20, 20);
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}


public class Game extends JPanel implements ActionListener, KeyListener{
Timer t = new Timer(5,this);
Cobra cobra = new Cobra(0,100);
Comida comida = new Comida();
public Game() {
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(true);

}    
void paintComponent(Graphics2D g2d){        
    comida.paintComponent(g2d);
    cobra.paintComponent(g2d);
}
@Override
public void actionPerformed(ActionEvent e) {
    if (cobra.getX() < -30) {
           cobra.setX(800); 
    }
    if (cobra.getX() > 800) {
        cobra.setX(0);
    }
    if (cobra.getY() < -30) {
        cobra.setY(600); 
    }
    if (cobra.getY() > 600) {
        cobra.setY(0);
    }
    cobra.setX((int) (cobra.getX() + cobra.getVelX()));
    cobra.setY((int) (cobra.getY() + cobra.getVelY()));
    repaint();
}
public void cima() {
    cobra.setVelY(-1.5);
    cobra.setVelX(0);
}
public void baixo() {
    cobra.setVelY(1.5);
    cobra.setVelX(0);
}
public void esquerda() {
    cobra.setVelX(-1.5);
    cobra.setVelY(0);
}
public void direita() {
    cobra.setVelX(1.5);
    cobra.setVelY(0);
}
@Override
public void keyTyped(KeyEvent e) {
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void keyPressed(KeyEvent e) {
    int teclas = e.getKeyCode();
    if (teclas == KeyEvent.VK_W) {
        cima();
    }
    if (teclas == KeyEvent.VK_S) {
        baixo();
    }
    if (teclas == KeyEvent.VK_D) {
        direita();
    }
    if (teclas == KeyEvent.VK_A) {
        esquerda();
    }
}
@Override
public void keyReleased(KeyEvent e) {
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}    

}


import java.awt.Graphics2D;
public interface Drawable {
public void paintComponent(Graphics2D g2d);
}

EDIT realmente eu n sei enviar codigo nesse forum kkkkk

Estou sem compilador para testar, mas é isso aí.

Recomendo algumas mudanças, na classe Cobra:

public void step() { // ou move
    if (x < -30) {
        x = 800;
    }
    if (x > 800) {
        x = 0;
    }
    if (y < -30) {
        y = 600;
    }
    if (y > 600) {
        y = 0;
    }

    x += velX;
    y += velY;
    // repaint(); exatamente igual a antes mas sem o repaint
}

no actionPerformed

cobra.step();
repaint();// transferido para cá

e no keyPressed:

if (teclas == KeyEvent.VK_W) {
    cobra.cima();
} // o mesmo para os outros

e remova os métodos cima, baixo, esquerda e direita do game, deixa na cobra que é melhor

entao eu fiz a troca como vc explicou mas a cobra nao esta aparecendo na tela e nem a comida kkkkkk
analizando sua explicação ficaria bem mais facil fazer o metodo de colisao mto obrigado seu lindo <3 =)
agora so falta fazer os objetos aparecerem na tela kkkk

A assinatura do método paintComponent está errada:

@Override
public void paintComponent(Graphics g) { // <-- precisa ser Graphics e não Graphics2D
    Graphics2D g2d = (Graphics2D) g;
    comida.paintComponent(g2d);
    cobra.paintComponent(g2d);
}

eita “thats true” =-D eu modifiquei isso em Game.java e agora a comida fica sendo gerada sem parar e nao desaparece da tela kkkk devido ao Timer o metodo paintComponent é atualizado como um todo.
por isso eu pensei antes que deveria separalos entendeu? xD

Porque o random está no paint:

public Comida() {
    reposicionar();
}

public void reposicionar() {
    gerador = new Random();
    x = gerador.nextInt(700) + 1;
    y = gerador.nextInt(500) + 1;
}

@Override // sobrescreve o drawable
public void paintComponent(Graphics2D g2d) {
    // gerador = new Random();
    // x = gerador.nextInt(700) + 1;
    // y = gerador.nextInt(500) + 1;
    g2d.setColor(Color.GREEN);
    g2d.fillRect(x, y, 20, 20);
}

Não desaparece porque precisa limpar o JPanel:

@Override // sobrescreve o JPanel
public void paintComponent(Graphics g) { // <-- precisa ser Graphics e não Graphics2D
    Graphics2D g2d = (Graphics2D) g;
    // limpa
    g2d.setColor(Color.BLACK);
    g2d.fillRect(0,0, 800,800);

    comida.paintComponent(g2d);
    cobra.paintComponent(g2d);
}

Entendi, fazer assim é bem melhor. Pensando em desempenho, criar vários JPanel custa muito memória pois carrega varios gráficos e listeners que nem vai precisar, e desempenho pois os listeners e eventos serão disparados mesmo que não os use.

retirei o gerador e fiz oque vc falou e funcionou eu esqueci desse detalhe que toda vez que chamar o metodo paintComponent ele iria gerar outra comida kkk mano eu queria ter esse conhecimento todo kk
agora a cobra fica com o rastro na tela =X

arrumei era so colocar super.paintComponent(g); no paintComponent do Game.java xD

// na classe game
int time = 0;
List<Comida> listaDeComida = new ArrayList<>();

@Override
public void paintComponent(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;
    g2d.setColor(Color.BLACK);
    g2d.fillRect(0, 0, 800, 800);

    for (Comida c : listaDeComida) {
        c.paintComponent(g2d);
    }

    cobra.paintComponent(g2d);
}

@Override
public void actionPerformed(ActionEvent e) {
    // atualiza time
    time = (time + 1) % 50; // 50 é o tempo para criar nova comida (50 passos)
    if (time == 0) {
        listaDeComida.add(new Comida());
    }
    
    // atualiza movimento
    if (cobra.getX() < -30) {
        cobra.setX(800);
    }
    if (cobra.getX() > 800) {
        cobra.setX(0);
    }
    if (cobra.getY() < -30) {
        cobra.setY(600);
    }
    if (cobra.getY() > 600) {
        cobra.setY(0);
    }
    cobra.setX((int) (cobra.getX() + cobra.getVelX()));
    cobra.setY((int) (cobra.getY() + cobra.getVelY()));
    repaint();
}

eu tentei criar a ArrayList mas a IDE netbeans acusa “tipe List does not take parameters” e nao me deixa criar a lista =(
eu acho melhor fazer a comida reaparecer apenas quando a cobra comer utilizando o metodo comida.reposicionar(); xD

cara eu queria ser um gênio como vc mano kkkkk vc tirou todas minhas duvidas kk
agora eu preciso fazer a colisão q envolve muita matematica que nao é meu forte kkk vamos as mazelas kkkkk

mano mto obrigado d vdd eu simplesmente nao sei como te agradecer devidamente

me recomenda um livro ai pra tentar chegar perto do seu nivel kkk sou seu fã xD

Livro: killer game programming
Site: http://www.pontov.com.br/site/

Aprendi a fazer games com GameMaker.

O ArrayList não tem parâmetros, se quer que comece o jogo com uma comida, troque para 1 a linha "if (time == 1) {"

Recomendo que troque aquele “50” para “2000” ou um número maior.

Sobre colisões, use a classe Point, exemplo:

// na classe cobra
boolean colide(Comida c) {
  return Point2D.distance(x, y, c.x, c.y) < 30;
}

no timer:

// recomendável adicionar numa lista e depois remover
ArrayList<Comida> removidos = new ArrayList<>();
for (Comida c: lista) {
  if (cobra.colide(c)) removidos.add(c); // ou c.reposicionar();
}
lista.removeAll(removidos);

mano deixa eu pega teu contato quero te dar um beijo kkkkk zoas xD
mano funcionou tudo so tem uma comida que aparece na tela e nao colide kk tirando isso ta perfeito kkkk
te amo cara mto obrigado d verdade =) agora eu acho q consigo me virar kk
eu n conhecia esse Point2D eu tava fazendo uns calculos enormes fauehfauefh tinha funcionado meus calculos mas tinha que ser precisamente no ponto x e y mas com esse Point2D vc mudou minha vida kkkk praticamente vc fez o jogo todo vei pqp que decepção para um cara q estudou por mto tempo como eu to ficando velho kkkkkkk vou ler esse livro que vc mandou mano mto obrigado d verdade <3

utilizando seu codigo eu modifiquei e tive um leve sucesso mas ao mesmo tempo me frustrou auefh
eu add a linha pra adicionar um quadradinho da cobra e um contador de pontos. ate ai tudo bem mas na hora de executar o quadrado da cobra aparece e some instantaneamente SAD

public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
Graphics2D ponto = (Graphics2D)g;
ponto.setFont(fonte);
ponto.drawString("Pontos: " + pontos, 30, 30);
cobra.paintComponent(g2d);
for (Comida c: listaDeComida) {
if (cobra.colide©){
removeComida.add©;
removeCobra.add(cobra);
cobra.paintComponent(cobra.getX()+ 20,cobra.getY()+20,g2d);
pontos++;
}
}
listaDeComida.removeAll(removeComida);
for (Comida comida : listaDeComida){
comida.paintComponent(g2d);
}
}

os pontos contam certinho a comida aparece a cada 1000 ticks como vc mostrou( coisa que eu queria modificar para a comida apenas aparecer quando a cobra comer tipo imediatamente para nao ocorrer de aparecer outra comida se a primeira nao for comida entende xD)
bom eu juro que tentei

com relação ao site e livro recomendados eu nao encontrei o livro no site =/ a pagina da livraria esta off parece sei la

Voltando ao que postei antes:

if (cobra.colide(c)) removidos.add(c); // ou c.reposicionar();

Bastaria trocar por c.reposicionar.

Eu ganhei o livro, vc terá que procurar, não está naquele site. Aquele site tem bons guias para desenhar em componentes do swing (www.pontov.com.br/site/index.php/java/48-java2d)


Crie uma classe Corpo e na classe Cobra:

List<Corpo> unidadesDoCorpo = new ArrayList<>();

public void crescer() {
  unidadesDoCorpo.add(0, new Corpo(x, y));// acho que tem que adicionar no inicio da lista, não sei
}

No método step

for (int i = unidadesdoCorpo.size - 1; i > 0; i--) {
  Corpo atual = unidadesdoCorpo.get(i);
  Corpo frente = unidadesdoCorpo.get(i-1);
  atual.setPosicao(frente.x, frente.y);
}
if (!unidadesdoCorpo.isEmpty())
unidadesdoCorpo.get(0).setPosicao(x,y);

// depois atualiza a posição da cobra(cabeça)

É no paint da cobra que renderiza o corpo

Vc está misturando as coisas, o paintComponent só desenha ou pinta, não faz operações.

Na classe Game, tem um método actionPerformed que é usado pelo timer, nele tem que conter as chamadas das operações

// atualiza a posição da cobra
cobra.mover();
// verifica se colide
if (cobra.colide(comida)) {
  comida.reposicionar();
  cobra.crescer();
}
repaint();

O método mover fará exatamente o que estava no seu primeiro post, mas sem o repaint e com a atualização do corpo da cobra

public void mover() {
    if (x < -30) {
        x = 800;
    }
    if (x > 800) {
        x = 0;
    }
    if (y < -30) {
        y = 600;
    }
    if (y > 600) {
        y = 0;
    }

    x += velX;
    y += velY;
    for (int i = unidadesdoCorpo.size - 1; i > 0; i--) {
      Corpo atual = unidadesdoCorpo.get(i);
      Corpo frente = unidadesdoCorpo.get(i-1);
      atual.setPosicao(frente.x, frente.y);
    }
    if (!unidadesdoCorpo.isEmpty())
    unidadesdoCorpo.get(0).setPosicao(x,y);
}