Como rotacionar uma imagem

43 respostas
java
S

Olá, eu gostaria de saber como eu posso rotacionar uma imagem, a imagem vai ficar em um ponto e quando mover o mouse, a imagem gire sempre companhando o cursor do mouse. Para poderem visualizar melhor, o código que adiciona a imagem no JFrame, é o que está em um tópico que fiz a cerca de um mês, este aqui:

tópico

43 Respostas

D

É muito difícil fazer isso usando JLabel, recomendo que use JComponent

class Imagem extends JComponent {
  static final int ESPACO_INTERNO = 45; // necessário um espaço para girar a imagem, pois os componentes swing são todos retangulares
  final BufferedImage image;

  // double angulo;

  public Imagem(File arquivo) {
    image = ImageIO.read(arquivo);
    Dimension size = new Dimension(image.getWidth()+ESPACO_INTERNO*2, image.getHeight()+ESPACO_INTERNO*2);
    setPreferredSize(dimension);
    setMinimumSize(dimension);
  }
  public void paintComponent(Graphics g) {
    if (g != null) {
      Graphics2D g2d = (Graphics2D)g;
      // g2d.rotate(angulo, ESPACO_INTERNO + image.getWidth() / 2, ESPACO_INTERNO + image.getHeight() / 2);
      g2d.drawImage(image, ESPACO_INTERNO, ESPACO_INTERNO, null);
    }
  }
 // void setAngulo(double angulo) {
 //   this.angulo = ângulo;
 //   repaint(); // atualiza o component
 // }
}

Para girar a imagem, deixei em comentário porque não sei se vai funcionar, acho que o ângulo é em radianos.

S

Bem, eu ainda to aprendendo sobres os recursos do java, então eu ainda não sei como funciona o JComponent e não entendi muito bem ainda como trabalhar com Graphics e bufferedImage.

E pode me tirar uma duvida, eu não entendi bem o que seria essa variavel “espaco_interno”.

D

Se girar a seguinte imagem:

image

ficará assim, cortada nas pontas:

image

então o JComponent precisa ter um espaço maior para poder ficar assim:

image

Acho que o calculo desse espaço seria:

maiorLadoDaImagem * raizQuadrada(2) / 2

O BufferedImage é um Image capaz de manipular os dados da imagem, Image armazena os dados de uma imagem para exibição. Basicamente o Image é uma imagem não editável e o BufferedImage é uma imagem editável.

O Graphics e o Graphics2D são ferramentas para desenhar. Todos os comonentes Swing tem um método paint que desenha a imagem deles. Sobrescrever o método permite a manipulação dessa imagem. O BufferedImage também tem o método createGraphics que permite a edição.

No link abaixo explica como usar o graphics
http://www.pontov.com.br/site/index.php/java/48-java2d


O JComponent é a base para todos os tipos de componentes do Swing, também usada para criar componentes, portanto é a implementação mais simples que se tem. Poderia usar o JPanel se quiser.

S

ok, muito obg por me explicar, me esclareceu bastante coisa sobre o que eu não entendia. Vou começar a estudar mais afundo usando o link que vc me passou.

S

Essa classe que é extendida pro JComponente, para poder modificar a imagem que será inserida no JFrame, deve ser adicionado ao JFrame com a funcao add()? Da mesma forma que se faz com JLabel, JPane e entre outros…

D

Sim, exatamente igual.

S

O File seria tipo isso:

File diretorio = new File(getClass().getResource(nomeDaImagem.png));

ou é outra forma? não conheço muito bem essa classe, ja vi algumas vezes serem usados, li no site da Oracle.

D

Tem varias formas, essa é uma.

Vc estava usando Stream, então poderia fazer:

InputStream stream = getClass().getResourceAsStream("/imagens/Habitante_Zul.png");
image = ImageIO.read(stream);
S

Cara, eu criei a classe imagem, coloquei os metodos e as variaveis, criei uma classe que é extendida do JFrame e adicionei a classe imagem, agr o que eu preciso fazer pra que quando eu inicie o JFrame a imagem apareca ou só isso ja faz com que ela esteja aparecendo no JFrame?

D

A imagem deveria aparecer, se não apareceu é porque falta algo. Talvez ela não gire no momento.

S

Talvez eu esteja fazendo errado kkkk, vou postar aqui tudo e o que estou usando, menos a classe que está chamando pq não tem nada, ela só faz a chamada.

Essa é a classe da janela que vou adicionar a imagem, ela só tem isso:

package testes;

import java.awt.Dimension;
import java.io.IOException;
import javax.swing.JFrame;

public class JanelaImagens extends JFrame{
    Dimension dimensao;
    Imagens2D imagem;
    
    public JanelaImagens() throws IOException {
        dimensao = new Dimension(800,600);
        imagem = new Imagens2D("imagem_giratoria.png");
        setLayout(null);
        setPreferredSize(dimensao);
        setSize(getPreferredSize());
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().add(imagem);
    }
}

Essa é a classe que iria girar a imagem, eu só não modifiquei nada pra girar ainda pra eu poder aprender devagar como se faz a implementação:

package testes;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
import javax.swing.JComponent;

public class Imagens2D extends JComponent {
    int espaco;
    BufferedImage image;
    double angulo;
    
    public Imagens2D(String diretorio) throws IOException {
        InputStream stream = getClass().getResourceAsStream(diretorio);
        image = ImageIO.read(stream);
        espaco = (int) (Math.max(image.getWidth(), image.getHeight())*Math.pow(2,0.5)/2);
        Dimension dimensoes = new Dimension(image.getWidth() + espaco*2, image.getHeight() + espaco*2);
        setPreferredSize(dimensoes);
        setMinimumSize(dimensoes);
    }
    
    @Override
    public void paintComponent(Graphics g) {
        if(g != null) {
            Graphics2D g2d = (Graphics2D)g;
            g2d.rotate(angulo, espaco + image.getWidth()/2, espaco + image.getHeight()/2);
            g2d.drawImage(image,espaco,espaco,null);
        }
    }
    
    public void setAngulo(double angulo) {
        this.angulo = angulo;
        repaint();
    }
}

por enquanto só tem isso, pra poder girar ela e fazer com que ele pinte se não me engano, eu deveria chamar os métodos paintComponent e setAngule toda vez que eu quise-se girar certo?

Com apenas ele não gera a imagem no JFrame, o que falta? a unica forma que aprendi a colocar uma imagem no JFrame foi da forma como está no link que eu citei nesse tópico, usando o JLabel.

D

Quase, é o método repaint que já está no setAngulo e não o paintComponent, portanto só chamar o setAngulo.

Não está funcionando pq vc está usando layout nulo, adicione o setSize no Imagens2D

setPreferredSize(dimensoes);
    setMinimumSize(dimensoes);
    setSize(dimensoes);
S

ok, não posso colocar nulo, porém se eu não fizer isso, a imagem não se move caso eu queira fazer isso ou ela gera outros tipos de problema.Bom, pelo menos foi isso que presenciei nas outras vezes que eu tentei mover a imagem no JFrame usando o JLabel, a não ser que dessa forma não tenha esse problema, vou fazer alguns testes aqui.

D

O layout executa automaticamente o setSize, se o layout é nulo então precisa faze manualmente

S

A sim, entendo, como eu faço para pegar a posicao da imagem? eu pego a posicao do JComponent com getX() e getY()?
É ou eu não preciso? Pois eu tenho q definir um angulo em radianos, então eu preciso fazer com que ele gire conforme as coordenadas do mouse em relação ao centro da imagem certo?

D

Sim, essas são as posições relativas ao “contentPane” do JFrame, aí vc teria que pegar as coordenadas do mouse relativa ao “contentPane” do JFrame também. Um componente pode estar dentro de outro, então as posições relativas são sempre com o “parentComponent”.

O Swing não foi feito para fazer isso, por isso é complicado. O código abaixo é para TESTE:

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import java.awt.*;

public class Imagens2D extends JComponent {
    int espaco;
    BufferedImage image;
    double angulo;
    
    public Imagens2D() throws IOException {
        //InputStream stream = getClass().getResourceAsStream(diretorio);
        //image = ImageIO.read(stream);
        
        image = new BufferedImage(100,100, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = image.createGraphics();
        g2d.setColor(Color.BLACK);
        g2d.fillRect(0,0,100,100);
        g2d.setColor(Color.RED);
        g2d.fillRect(4,4,100 - 8,100 - 8);
        g2d.dispose();
        
        espaco = (int) (Math.max(image.getWidth(), image.getHeight())*Math.pow(2,0.5)/2);
        Dimension dimensoes = new Dimension(image.getWidth() + espaco*2, image.getHeight() + espaco*2);
        setPreferredSize(dimensoes);
        setMinimumSize(dimensoes);
        setSize(dimensoes);
    }
    
    @Override
    public void paintComponent(Graphics g) {
        if(g != null) {
            Graphics2D g2d = (Graphics2D)g;
            g2d.rotate(angulo, espaco + image.getWidth()/2, espaco + image.getHeight()/2);
            g2d.drawImage(image,espaco,espaco,null);
        }
    }
    
    public void setAngulo(double angulo) {
        this.angulo = angulo;
        repaint();
    }
}

import java.awt.Dimension;
import java.io.IOException;
import javax.swing.JFrame;
import java.awt.*;
import java.awt.event.*;

public class JanelaImagens extends JFrame{
    Dimension dimensao;
    Imagens2D imagem;
    
    public JanelaImagens() throws IOException {
        dimensao = new Dimension(800,600);
        imagem = new Imagens2D();
        
        long  eventMask = AWTEvent.MOUSE_MOTION_EVENT_MASK;
        Toolkit.getDefaultToolkit().addAWTEventListener(
            new AWTEventListener(){
                public void eventDispatched(AWTEvent event) {
                    if (!imagem.isVisible()) return;
                    MouseEvent mouseEvent = (MouseEvent) event;
                    int mouse_x = mouseEvent.getXOnScreen();
                    int mouse_y = mouseEvent.getYOnScreen();
                    int imagem_x = imagem.getLocationOnScreen().x;
                    int imagem_y = imagem.getLocationOnScreen().y;
                    imagem_x = imagem_x + imagem.getWidth() / 2; // desloca para o centro
                    imagem_y = imagem_y + imagem.getHeight() / 2; // desloca para o centro

                    double d = Point.distance(imagem_x, imagem_y, mouse_x, mouse_y);
                    if (mouse_x - imagem_x > 0)
                        imagem.setAngulo(Math.asin((mouse_y - imagem_y) / d));
                    else
                        imagem.setAngulo(Math.asin((imagem_y - mouse_y) / d));
                }
            }, eventMask);
        
        setLayout(null);
        setPreferredSize(dimensao);
        setSize(getPreferredSize());
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().add(imagem);
        setVisible(true);
    }
    
}

No código usei a posição relativa ao Screen, pois ambas as posições, do mouse e da imagem, estão relativas a mesma coisa.

S

Pq do Toolkit e da variavel long? Eu não entendi muito bem o pq deles.

H

Geralmente em java2D é usado o Panel e não o JFrame, o melhor jeito de aprender a usar esses recursos é pegando jogos com código e vendo como funciona. Tem vários jogos simples com pouco código que ajuda muito a aprender a usar, depois é só substituir a imagem do jogo pela sua.

D

Nem eu sei direito a resposta. Os eventos do mouse são sobre os componentes, portanto para cada componente teria que colocar um MouseMotionListener para capturar o evento. Essa foi a forma que encontrei para capturar o evento criando apenas um único listener para que funcionasse sobre todos os componentes.

Sobre o long, usei pq estava no link onde achei sobre o assunto, acho que pode ser int:

A variável eventMask é um filtro, existem inúmeros eventos e somente o evento do mouse é necessário, observe que no artigo acima o filtro é diferente.

Como foi dito antes, swing não foi feito para ter efeitos e animações.

Se usasse JavaFx, seria muito mais simples.

S

Eu já até pensei em pegar algum jogo simples para poder ver isso, mas primeiro que não faço idéia de como é a organização dos códigos, então eu fico meio perdido onde devo ir pra procurar o que eu quero, qual arquivo e tals e segundo que mesmo que eu encontre, vai ter muitos recursos que eu não conheço sendo usado, então eu continuaria perdido na hora de aprender. Prefiro deixar pra fazer isso quando tiver mais conhecimento dos outros recursos. Mas obg pela sugestão.

S

Tipo, eu não coloquei isso e continuou funcionando, porém tem um problema que eu não sei se esse é o motivo, toda vez que o cursor do mouse passa da coordenada do X do centro da imagem, ele retorna pra posição inicial, ele não continua girando para o outro lado.

Em relação ao JavaFX, eu já ouvi falar mas eu queria aprender primeiro o Java bem, saber como os recursos trabalham e agem no código, entender como deve ser feito a implementação de cada classe, como devo organizar o código para funcionar bem, para ai sim ir pro JavaFX, que acredito eu ser mais facil de programar, porém eu não fico muito confortável em usar algo que facilite pra min, sem antes eu entender bem como funciona. Eu pretendo depois ir pro JavaFX, pois me deixou bem interessado mas ainda não :slight_smile: .

D

O JavaFX já faz parte do Java e não precisa baixar.

Deve ser um problema no cálculo. O que eu postei antes funciona para uma imagem quadrada.

S

Eu to usando uma imagem quadrada, 100x100.

S

Acho que já descobrir o problema, na verdade é a condição if que ta errada, pois não é quando a variação de x é negativa mas sim quando a variação de y é negativa

mas agr ele ta girando todo errado, a cada um quarto q mouse percorre ele muda de direção

acho que entendi, eu fiz alguns testes e tipo:

se eu deixo da forma como está o código, toda vez que a variacao de X chega a 0 ele muda pra yc - y porém isso faz com que os valores se tornem igual ao y - yc só que começando pelo lado negativo, então tem uma mudança muito repentina no angulo, então ele espelha a imagem.

se eu deixo apenas fazendo os calculos com y - yc ele some toda vez que o valor do arco seno passa de 1,5 se não me engano e volta quando o valor é igual a -1,5 ou menor

se eu faço y + yc quando x passa a ser menor ou igual a zero, então ele para de girar no sentido do mous pra girar pro outro lado

complicado isso, como é q funciona essa parada de rotate da classe Graphics2D?

S

Consegui corrigir, vou postar aqui somente parte que mudei:

Obs.: criei uma variavel chamada anguloBase que possui o vlaor de pi/2, pois esse é o valor limite do método Math.asin(), nele só podem ser inseridos valores de -pi/2 até pi/2.

public void girarImagem(int x, int y) {
    definirAnguloBase();
    
    double xc, yc, diferenca;

    xc = imagem.getLocationOnScreen().getX() + (imagem.getWidth())/(2.0);
    yc = imagem.getLocationOnScreen().getY() + (imagem.getHeight())/(2.0);

    double d = Point.distance(xc, yc, x, y);
    double angulo = Math.asin((y-yc)/d);
    
    if(x - xc <= 0) {
        if(angulo > 0) {
            diferenca = anguloBase - angulo;
            angulo = anguloBase + diferenca;
        } else if(angulo < 0) {
            diferenca = anguloBase - angulo;
            angulo = anguloBase + diferenca;
        }
    }

    imagem.setAngulo(angulo);
}
S

Desculpa voltar aqui, mas acabei de me depara com essa duvida, mas esses dois valores depois de angulo? eles representam oq?

D

É a origem da transformação, se mudar para:

g2d.rotate(angulo, espaco, espaco);

não irá girar no centro, faça o teste.

S

Entendi agr.
Eu testei com uma imagem que não tenha todos os lados iguais, mas ele parece que mudou um pouco a posição, então como eu poderia confirmar a área que ele ocupa? pois se eu quiser fazer dois objetos se colidirem, a imagem deles vão acabar se sobrepondo uma a outra? ou nada disso interfere?

D

Calculando, geralmente criasse uma representação em forma de retângulo ou circulo.

Sim, por isso que se usa motor de game (“game engine”), é muito complicado esses cálculos. OS mais simples são quando os objetos são círculos e retangulares, mas sem girar.

Se quiser dar continuidade a isso, recomendo que busque um motor de jogo. Vc poderia o JavaFX, facilitaria bastante, mas não tem cálculos prontos de colisão.

S

Eu troquei só a imagem pra fazer alguns testes e pra min a imagem ficou muito distante das bordas, como poderia mover a imagem dentro do JComponent

A imagem ta logo a baixo:

D

É meio complicado de resolver esse problema, então vou ser um pouco chato e pedir para refazer, também tem um “bug” que não descobri como arrumar, por isso é importante refazer:

Classe Canvas, componente responsável por desenhar, deve ser exatamente:

public class Canvas extends JComponent implements MouseListener, MouseMotionListener, MouseWheelListener {

    private final List<Entity> entities = new ArrayList<>();

    public Canvas() {
        // prepara o fundo do componente
        setOpaque(true);
        setBackground(Color.BLACK);

        // configura os listeners
        addMouseListener(this);
        addMouseMotionListener(this);
        addMouseWheelListener(this);
    }

    @Override
    public void paint(Graphics g) {
        if (g != null) {
            try {
                // limpa o componente
                Graphics2D g2d = (Graphics2D) g;
                g2d.setBackground(getBackground());
                g2d.clearRect(0, 0, getWidth(), getHeight());

                // desenha
                draw(g2d);
            } finally {
                g.dispose();
            }
        }

    }

    public void draw(Graphics2D g) {
        for (Entity e : entities) {
            Graphics2D g2 = (Graphics2D) g.create();
            e.draw(g2);
            g2.dispose();
        }
    }

    public void addEntity(Entity e) {
        entities.add(e);
    }

    public void removeEntity(Entity e) {
        entities.remove(e);
    }

    @Override
    public void mouseDragged(MouseEvent e) {
    }

    @Override
    public void mouseMoved(MouseEvent e) {
    }

    @Override
    public void mouseWheelMoved(MouseWheelEvent e) {
    }

    @Override
    public void mouseClicked(MouseEvent e) {
    }

    @Override
    public void mousePressed(MouseEvent e) {
    }

    @Override
    public void mouseReleased(MouseEvent e) {
    }

    @Override
    public void mouseEntered(MouseEvent e) {
    }

    @Override
    public void mouseExited(MouseEvent e) {
    }
}

Interface Entity, objeto que é desenhado no Canvas, deve ser exatamente (pode conter outros métodos se quiser):

public interface Entity {

    public void draw(Graphics2D g);

}

Classe App, geralmente tem o nome do programa, não precisa ser exatamente assim, este é só exemplo:

public class App extends Canvas {

    Personagem personagem;

    public App() {
        super(); // inicializa o canvas
        personagem = new Personagem();
        addEntity(personagem);
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        int mouse_x = e.getX();
        int mouse_y = e.getY();
        int personagem_x = personagem.position.x;
        int personagem_y = personagem.position.y;

        double d = Point.distance(personagem_x, personagem_y, mouse_x, mouse_y);
        if (mouse_x - personagem_x > 0) {
            personagem.angulo = Math.asin((mouse_y - personagem_y) / d);
        } else {
            personagem.angulo = Math.asin((personagem_y - mouse_y) / d);
        }
    }

    @Override
    public void mousePressed(MouseEvent e) { // método que testa movimento
        personagem.position.x = e.getX();
        personagem.position.y = e.getY();
        repaint(); // atualiza
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setSize(500, 400);
        frame.getContentPane().add(new App());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

}

Classe Personagem, também para teste:

public class Personagem implements Entity {

    BufferedImage image;
    Point position = new Point(50, 50); // precisa mudar aqui, a posição será o centro da imagem, que será 100 x 100
    double angulo;

    public Personagem() {
        //InputStream stream = getClass().getResourceAsStream(diretorio);
        //image = ImageIO.read(stream);

        image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);

        // cria um retângulo, somente para teste
        Graphics2D g2d = image.createGraphics();
        g2d.setColor(Color.WHITE);
        g2d.fillRect(0, 0, 100, 100);
        g2d.setColor(Color.RED);
        g2d.fillRect(4, 4, 100 - 8, 100 - 8);
        g2d.dispose();
    }

    @Override
    public void draw(Graphics2D g) {
        g.rotate(angulo, position.x, position.y);
        g.drawImage(image, position.x - image.getWidth() / 2, position.y - image.getHeight() / 2, null);
    }

}
D

Cada elemento deve implementar a interface Entity que deve ser adicionada no Canvas para ser desenhado, o Canvas também tem o método removeEntity para remover os elementos que não precisam ser mais desenhados.

S

Eu entendo, vou pegar o código que vc escreveu e vou estudar em cima dele, mas da uma olhada, eu reescrevir o código do Imagem2d que tava antes, na verdade só mudei alguns valores e acrescentei 2 variaveis x e y pra adaptar melhor esse valores, por enquanto eu consegui resolver o que eu queria, agr só falta eu entender melhor como que essas variaveis interferem na imagem, pra eu poder adaptar e implementar um método que vai corrigir os problemas com a imagem ficar cortada, que eu acho que vai ser um pouco simples, pois é só um pouco de matemática e matemática pra min não tanto problema assim

public class Imagens2D extends JComponent {
    int espaco;
    BufferedImage image;
    double angulo;
    int x,y;
    
    public Imagens2D(String diretorio) throws IOException {
        InputStream stream = getClass().getResourceAsStream(diretorio);
        image = ImageIO.read(stream);
        espaco = (int) (Math.max(image.getWidth(), image.getHeight())*Math.pow(2,0.5)/2);
        //mudei a dimensão para o tamanho da imagem
        Dimension dimensoes = new Dimension(image.getWidth(), image.getHeight());
        setPreferredSize(dimensoes);
        setMinimumSize(dimensoes);
        setSize(dimensoes);
        x = 0;
        y = 0;
    }
    
    @Override
    public void paintComponent(Graphics g) {
        if(g != null) {
            Graphics2D g2d = (Graphics2D)g;
             //coloquei o centro de rotação no centro da imagem;
            g2d.rotate(angulo,image.getWidth()/2,image.getHeight()/2);
            //desenha a imagem a partir do ponto 0,0 dentro do JComponent, o ponto 0,0 é relativo ao JComponent
            g2d.drawImage(image,0,0,null);
        }
    }
    //um método pra sempre que eu precisar atualizar o desenho sem precisar mudar outras coisa, ainda ou acrescentar mais algumas formas para cada ação nescessária
    public void atualizarImagem() {
        //repaint();
        //outra forma de usar o mesmo metodo que encontrei e que se adapta melhor pras mudanças
        repaint(0, 0, image.getWidth(),image.getHeight());
    }
    public void setAngulo(double angulo) {
        this.angulo = angulo;
        atualizarImagem();
    }
}
D

Da forma como está não seria necessário o x,y, usaria o setBounds ou setLocation do componente.

O que eu refiz lá corrige vários problemas, o da imagem cortada, não precisar mais da variável “espaço” que dificulta os cálculos, sem o espaço o calculo da rotação será mais precisa, eventos do mouse podia causar erros quando o evento acontecer antes do componente estar pronto, não será mais necessário usar o x,y relativos no Screen que facilitam os cálculos, imagens sobrepostas podiam cortar outras imagem que estivessem atrás, …

Agora para mover, basta fazer como no seguinte trecho:

public void mousePressed(MouseEvent e) { // método que testa movimento
    personagem.position.x = e.getX();
    personagem.position.y = e.getY();
    repaint(); // atualiza
}

Neste caso, quando clicar irá mover o “personagem”.

Outra coisa, não consegui alterar lá:

Point position;
double angulo;

public Personagem() {
    //InputStream stream = getClass().getResourceAsStream(diretorio);
    //image = ImageIO.read(stream);

    image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
    position = new Point(image.getWidth()/2, image.getHeight()/2);
S

Eu vou escrever os dois e vou comparar os dois. Eu preciso entender bem o código ainda, pq por enquanto eu entendo o que vc ta falando, mas eu ainda não sei utilizar o código ainda, então eu o pega o código e estudar bem como funciona cada classe, método que vc usa, como eu vou usar. Obg por me ajudar :), to conseguindo entender bem como funciona a parte de Graphics, BufferedImage e sobre JComponent, que eu ainda tenho que me aprofundar, no seu código vc já adiantou uma questão que eu tava começando a querer entender é sobre tipo, eu tenho varias coisa para desenhar, player, itens, inimigos e por ai vai, todos eles tem a sua imagem, posicão e tals, ai que vem problema, na hora organizar o código, eu gostaria de uma classe que fosse responsável por desenhar a imagem, outra por conter as informações da imagem e outra seria a entidade (jogador, iten, inimigo), a minha idéia era que tudo que precisa-se ser desenhado, passaria pela classe responsável por desenhar, sendo que só seria inserido as informações nescessária e o problema é sobre o JComponent, que é ele que é adicionado no JFrame(mais precisamente no JPane dele), eu tava meio confuso em como organizar o código, quem iria se extender ao JComponent, quem iria chamar quem no JFrame.

S

Primeiro esse g.dispose faz oq?
Segundo eu até hj não consgui entender o sobre o List, eu queria muito sabe o que faz, como eu uso, e geralmente como ele é usado.

List<Entity> entities = new ArrayList<>();
D

Libera os recursos do graphics. O graphics guarda muitas informações e isso pode deixar o programa lento, então quando não precisar mais, use o dispose.

Tem muita informação sobre o List e ArrayList na web, basta pesquisar. Tem varias tipos de List, o ArrayList usa uma estrutura de array (vetor) que permite adicionar ou remover elementos sem um tamanho definido, portanto pode-se dizer que o ArrayList é um Array com mais recursos. O outro tipo de List também muito usado é o LinkedList, que usa a estrutura de lista ligada ou encadeada.

O “<Entity>” é chamado de “generics” que diz o tipo dos elementos da lista, exemplo o array Integer[] tem elementos do tipo Integer, o List<Integer> tem os elementos também do tipo Integer, o “<>” no ArrayList é equivalente a “<Entity>”.

S

Acho que entendi um pouco melhor, vou procurar me aprofundar mais, mas antes quero resolver bem essa parte de imagens

Me deparei com um problema que não tinha visto antes ou ele não tinha esse problema e agora tem, mas como pode ver na imagem a baixo, o ponto I é o centro em que a imagem vai girar, até ai ta funcionando certinho, ele gira entorno desse ponto, porém o movimento de girar em relação o mouse não é referente ao ponto I mas sim ao ponto II, eu não consigo ver onde está o problema, mas acredito que seja a questão da posição do mouse ser totalmente diferente em relação ao JFrame, eu ja tive um problema com isso antes, e o que eu fiz foi descobrir essa diferença na tentativa e erro, mas eu gostaria de saber se tem um jeito melhor de resolver isso.

Eu fui na tentativa e erro e encontrei aproximadamente o quanto que tenho de retirar do ponto, pior que foi diferente da outra vez que tive esse problema, eu tava usando o setlocation, e lá eu adicionava +8 no x e + 31 no y de toda imagem que eu colocava, nesse eu tiver que tirar 62 no x e 39 do y nessa parte:

public void girarImagem(double x, double y) {
    definirAnguloBase();
    
    double xc, yc, diferenca;
    xc = imagem.getX() - 62 + (imagem.getWidth())/(2.0);
    yc = imagem.getY() - 39 + (imagem.getHeight())/(2.0);
    double d = Point.distance(xc, yc, x, y);
    if(d == 0) {
        System.out.println("X: " + x + "Y: " + y);
    }
    double angulo = Math.asin((y-yc)/d);
    
    if(x - xc <= 0) {
        if(angulo > 0) {
            diferenca = anguloBase - angulo;
            angulo = anguloBase + diferenca;
        } else {
            diferenca = anguloBase - angulo;
            angulo = anguloBase + diferenca;
        }
    }
    imagem.setAngulo(angulo);
}
D

Foi feito assim antes. A posição do mouse é relativo ao Screen então a posição a posição da imagem também precisa ser relativo ao Screen, o getX/getY da Imagem é relativa ao contentPane do JFrame e o getX/getY do mouse eu não sei, mas acho que é relativo ao componente em que o ponteiro está em cima, que pode ser o contentPane ou da Imagem.

S

Sim, estava dessa forma como vc pos, mas tava dando o mesmo erro, eu mudei pra forma que eu coloquei que eu sei mais ou menos quanto que eu tinha de aproximar, além disso, usando o getLocationOnScreen o ponto fica mais em baixo ainda.

Cara, eu deixei a dimensão do JComponent do tamanho da imagem ai na parte onde eu tinha colocado - 62 e - 33 ou algo assim, foi pra como é no meu outro código que tive o mesmo problema, + 8 em x e + 31 em y, então é fixo, ara x + 8 e para y + 31. Agr ou pensar em um jeito de fazer a imagem aparecer por completo, se aparecer o problema de novo já sei onde é, é pq as dimensões estavam com o tamanho da imagem mais o espaço. Se eu voltar com a forma anterior usando getLocationOnScreen, eu não preciso fazer a soma, obg, o problema era q as diemensoes do JComponent estava errado pro que eu estava fazendo. No final de tudo eu que fui responsável kkkkkkkk

D

Por isso que recomendo que refaça, no ultimo que postei não usa o Screen e dá menos problemas. Antes eu achei que vc estava fazendo algo que integrasse a um componente do Swing (JButton, JTextField, …), e para fazer funcionar a rotação seria necessário usar o ponto relativo ao Screen. Se não for usar outros componentes, então refaça como essa nova “versão”.

S

Sim, eu ao mesmo tempo to refazendo o código toodo, me baseando na outra versão que vc me passou mas da forma que eu me entenda melhor, pois tem algumas coisa que tem nesse ultimo que vc me passou que eu ainda não tenho experiência e não entendo muito bem como funciona, como por exemplo a classe Interface, mas por enquanto vou me focar em melhorar esse código de agora e depois me aprofundar nessas outras coisas.

D

Nesta apostila tem quase tudo sobre Java, os capítulos 9, 10 e 11 são os mais importantes sobre herança e interface.

O capítulo 15 fala sobre o List

Criado 4 de abril de 2018
Ultima resposta 14 de abr. de 2018
Respostas 43
Participantes 3