A comunidade brasileira de desenvolvimento e programação de jogos.
Bem-vindo: Qui Fev 25, 2021 4:01 pm

Todos os horários são GMT - 3 horas




Criar novo tópico Responder  [ 1 mensagem ] 
Autor Mensagem
 Título: Exemplo de algoritmo de detecção e movimentação em JAVA.
MensagemEnviado: Sáb Nov 03, 2007 3:41 pm 
Offline
Membro novo

Registrado em: Sáb Nov 03, 2007 3:33 pm
Mensagens: 2
Fala galera.

Sou novo por aqui, tenho alguma experiência em programação. Trabalho a mais ou menos 8 anos na área e gostaria de dar uma pequena contribuição para esse fórum JAVA.

O exemplo que darei é sobre algoritmos de detecção e algoritmos de movimentação. Tenham em mente que esse exemplo serve para qualquer jogo, mas quando o desenvolvi, tinha em mente um jogo de estratégia.

Imaginem um jogo igual Starcraft ou Warcraft, onde eu tenha unidades de combate, e elas devem ter consciência de presença, ou seja, se um inimigo se aproximar, ela tem que saber disso. Além disso, ela deve poder se movimentar.

Fiz um pequeno projeto com 5 classes. Ficou bem simples o código e usei OO para que fique melhor ainda de entender. Abaixo, uma breve descrição das classes do projeto:


clsUnidade.java => Representa a unidade de combate. Nessa classe, ficará toda a lógica de estratégia, combate, defesa, ataque, DETECÇÃO DE INIMIGOS, MOVIMENTAÇÃO e etc. Enfim, tudo que for pertinente a "auto-suficiência", será implementado nessa classe.

clsDesenhaUnidade => Essa classe ficará responsável por desenhar na tela a unidade e possivelmente tudo que acontece com ela. Se ela se movimentar, esta classe deve fazer isso acontecer na tela, se ela explodir, mais uma vez essa classe deverá entrar em ação e desenhar ela explodindo. Enfim, ela vai ficar responsável por APENAS desenhar na tela o que está acontecendo na classe da unidade.

clsLocaisUnidade => Guardará todas as informações que forem "globais", ou seja, localização de unidades, depósitos de minérios, enfim. Tudo para orientar as unidades durante o jogo.

clsFrame => Desenha o "form" na tela.

Main => Dispara todo o processo.

Na lógica OO, as classes se comunicam da seguinte maneira:


Código:

[clsUnidade]
        |
        | } ENVIA DADOS (COORDENADAS X,Y).
        |
[clsDesenhaUnidade]
        |
        | } PEGA OS DADOS ENVIADOS E DESENHA NO JPANEL.
        |
[clsFrame] } ADICIONA A clsDesenhaUnidade E CONSEQUENTEMENTE DESENHA O JPG DA UNIDADE.
       



Como podem ver, as classes se comunicam em 3 camadas, deixando cada uma com sua tarefa, facilitando bastante a compreensão do código. Legal tb é que esse projeto usa Threads, ou seja, para aqueles que não sabem implementar threads em java (imprecindível para desenvolvimento de jogos), poderão aprender aqui. O resto das explicações estão em comentários no próprio código. Espero que consigam entender.

Vamos ao código:


Classe Unidade:


Código:

package radar;

public class clsUnidade
{
    private int X; // Coordenada X.
    private int Y; // Coordenada Y.
    private int X2; // Largura.
    private int Y2; // Altura.
    private String ArquivoImagem; // Local onde se encontra o arquivo de imagem (JPG).
    private int RaioRadar; //Raio de ação do radar da unidade.
    private String Nome; // Uma identificação qualquer.
    private int NovoX; // Destino de movimentação em X.
    private int NovoY; // Destino de movimentação em Y.
       
   
    // Faz com que a unidade se mova até os pontos indicados em NovoX,NovoY.
    public void Mover()
    {
        // Movimento em X
        if ((this.getNovoX()>0) && (this.getNovoX()>this.getX()))
        {
            // O novo ponto está a direita da unidade. Executa movimento --->
            this.setX(this.getX()+1);           
        }
        if ((this.getNovoX()>0) && (this.getNovoX()<this.getX()))
        {
            // O novo ponto está a esquerda da unidade. Executa movimento <---
            this.setX(this.getX()-1);           
        }
        if ((this.getNovoX()>0) && (this.getNovoX()==this.getX()))
        {
            // O novo ponto em X foi alcançado. Pode parar de andar em X.
            this.setNovoX(0);
        }                       
       
        // Movimento em Y.
        if ((this.getNovoY()>0) && (this.getNovoY()>this.getY()))
        {   //                                                       
            // O novo ponto está abaixo da unidade. Executa movimento para baixo.
            this.setY(this.getY()+1);           
        }
        if ((this.getNovoY()>0) && (this.getNovoY()<this.getY()))
        {
            // O novo ponto está acima da unidade. Executa movimento para cima.
            this.setY(this.getY()-1);           
        }
        if ((this.getNovoY()>0) && (this.getNovoY()==this.getY()))
        {
            // O novo ponto em Y foi alcançado. Pode parar de andar em Y.
            this.setNovoY(0);
        }                       
    }
   
    // Sobreposição de toString, para poder "exibir" o objeto.
    public String toString()
    {
        return this.getNome()+" em " + this.getX()+ ","+this.getY();       
    }
   
    // Retorna TRUE, se a unidade passada em pUnidade estiver no raio de ação deste objeto (this).
    public boolean EstahNoRaio(clsUnidade pUnidade)
    {
        // Verifica se a coordenada X está dentro do raio de ação.
        boolean XDentro = ((pUnidade.getX() >= this.getX()-this.getRaioRadar()) && (pUnidade.getX() <= this.getX()+this.getRaioRadar()));
        boolean YDentro = ((pUnidade.getY() >= this.getY()-this.getRaioRadar()) && (pUnidade.getY() <= this.getY()+this.getRaioRadar()));
        return (XDentro && YDentro);
    }
   
    // Faz loop no array de objetos registrados e verifica se há algum no raio de ação.
    public void Detectar()
    {
        for(clsUnidade u: clsLocaisUnidades.Unidades)
        {
            if (!u.equals(this))
            {
                if (this.EstahNoRaio(u))
                {
                    System.out.println(this+" detectou objeto "+u+".");
                }                               
            }                                   
        }
    }
   
    public clsUnidade(int pX,int pY,int pX2,int pY2, String pArquivoImagem)
    {
        this.setX(pX);
        this.setY(pY);
        this.setX2(pX2);
        this.setY2(pY2);
        this.setArquivoImagem(pArquivoImagem);                       
        clsLocaisUnidades.RegistrarUnidade(this);
        // Não adiciono esta unidada no painel agora pq eu estaria indo de encontro
        // a orientação a objeto. Essa classe deve apenas cuidar de cálculos,
        // estratégias de combate, deteção de inimigos e etc. Colocar algo sobre
        // imagens aqui seria quebrar esta regra.
    }
   
    // Métodos Get e Set das variáveis da classe. Nada especial.
    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 String getArquivoImagem()
    {
        return ArquivoImagem;
    }

    public void setArquivoImagem(String ArquivoImagem)
    {
        this.ArquivoImagem = ArquivoImagem;
    }

    public int getX2()
    {
        return X2;
    }

    public void setX2(int X2)
    {
        this.X2 = X2;
    }

    public int getY2()
    {
        return Y2;
    }

    public void setY2(int Y2)
    {
        this.Y2 = Y2;
    }

    public int getRaioRadar()
    {
        return RaioRadar;
    }

    public void setRaioRadar(int RaioRadar)
    {
        this.RaioRadar = RaioRadar;
    }

    public String getNome()
    {
        return Nome;
    }

    public void setNome(String Nome)
    {
        this.Nome = Nome;
    }

    public int getNovoX()
    {
        return NovoX;
    }

    public void setNovoX(int NovoX)
    {
        this.NovoX = NovoX;
    }

    public int getNovoY()
    {
        return NovoY;
    }

    public void setNovoY(int NovoY)
    {
        this.NovoY = NovoY;
    }



Agora, a classe clsDesenhaUnidade:

Código:
package radar;

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

public class clsDesenhaUnidade extends JPanel implements Runnable
{
   
    private clsUnidade Unidade; // Unidade que o painel usa para desenhar.
    private ImageIcon Img; // Objeto que desenha o JPG da unidade.
    private Thread threadRadar; // Thread responsável por dar "vida" a unidade.
   
    // Faz uma pausa em pN segundos, na execução do loop de "vida" da unidade.
    private void Pausa(int pN)
    {
        try
        {
            Thread.sleep(pN);               
        }
        catch(Exception e)
        {               
        }                                           
    }   
       
    // Atualiza as dimensões e localização da unidade.
    private void AtualizarDimensoes()
    {
        this.setBounds(Unidade.getX(),Unidade.getY(),Unidade.getX()+Unidade.getX2(),Unidade.getY2()+Unidade.getY());       
    }
   
    public clsDesenhaUnidade(clsUnidade pUnidade)
    {       
        this.setUnidade(pUnidade);
        this.AtualizarDimensoes(); // Aqui sim, eu posso "pintar" na tela a vontade.
        threadRadar = new Thread(this);
        threadRadar.start();       
       
    }
   
    // Override necessário para que a unidade seja "pintada" com seu JPG.
    public void paintComponent(Graphics g)
    {
        this.AtualizarDimensoes();
        Img = new ImageIcon(Unidade.getArquivoImagem());
        ((Graphics2D) g).drawImage(Img.getImage(),Unidade.getX(),Unidade.getY(),this);       
    }
       
    // Tem que ser obrigatoriamente sobrescrito, para classes que implementam RUNNABLE.
    // Aqui fica o loop de vida da unidade. Todos os "estímulos" que ela deve responder,
    // devem estar aqui. Essa é a principal parte do código.
   
    public void run()
    {
        while (true)
        {
            Unidade.Detectar();
            if ((Unidade.getNovoX()>0) || (Unidade.getNovoY()>0))               
            {
                Unidade.Mover();
                this.repaint();
            }                         
            this.Pausa(100); // Preciso dessa pausa, para que o gerenciador de segmentos da
                       // JVM possa executar outros segmentos. Este número pode ser reduzido.           
        }               
       
    }
   
    // Métodos get e set das variáveis da classe. Nada especial.
    public clsUnidade getUnidade()
    {
        return Unidade;
    }

    public void setUnidade(clsUnidade Unidade)
    {
        this.Unidade = Unidade;
    }
}



Agora, a classe que sabe tudo no jogo:

Código:

package radar;

import java.util.*;

// Esta classe armazena as informações que devem ser "globais", para todo o jogo,
// como por exemplo: posicionamento de unidades.
public class clsLocaisUnidades
{
    // Esta variável armazena todas as unidades do jogo, para que o algortimo de
    // radar possa detectar quando uma unidade entra no radar de outra unidade.
    static public ArrayList<clsUnidade> Unidades = new ArrayList<clsUnidade>();
   
    // Deve ser atualizada toda vez que uma nova unidade for criada.
    static public void RegistrarUnidade(clsUnidade pUnidade)
    {
        Unidades.add(pUnidade);
    }
       
    public clsLocaisUnidades()
    {
       
    }   
}



A classe do JFrame:

Código:

package radar;

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

public class clsFrame
{
    // Classe responsável por criar e exibir o frame.
    private JFrame Frame;
       
    public clsFrame()
    {
        Frame = new JFrame("Teste de Radar");
        Frame.setLayout(null);
        Frame.setBounds(10,10,600,600);               
        Frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Frame.setVisible(true);       
    }
   
    public void Adicionar(clsDesenhaUnidade pDu)
    {
               
        Frame.add(pDu);
    }               
   
}



E por fim, a classe Main, responsável por disparar tudo isso:


Código:

package radar;

public class Main
{
   
    public Main()
    {
               
    }
   
    public static void main(String[] args)
    {       
        // Cria e exibe o form.
        clsFrame frm = new clsFrame();

        //Cria unidade na memória. Indique um arquivo que exista!
        clsUnidade u = new clsUnidade(60,100,30,30,"c:\\img.jpg");     
        u.setNome("Azul");
        u.setRaioRadar(80);
               
        clsDesenhaUnidade du = new clsDesenhaUnidade(u);
                               
        // Adiciona unidade no form.
        frm.Adicionar(du);
       
        // Envia comando para pintar a unidade na tela.
        du.repaint();
       
        // Cria unidade 2 na memória. Indique um arquivo que exista!
        clsUnidade u2 = new clsUnidade(60,0,30,30,"c:\\img2.jpg");
        u2.setNome("Vermelho");
        u2.setRaioRadar(0);       
       
        // Atrela unidade 2 no painel desenhador.
        clsDesenhaUnidade du2 = new clsDesenhaUnidade(u2);
                               
        // Adiciona unidade 2 no form.
        frm.Adicionar(du2);
                       
        // Envia comando para pintar a unidade na tela.
        du2.repaint();
       
        // Depois de 2 segundos...
        try {Thread.sleep(2000);}catch(Exception e){}       
        // ...anda com a unidade até o ponto X=70,Y=200.
        u2.setNovoX(70);
        u2.setNovoY(200);
    }
   
}



OBS: na classe Main, não esqueçam de colocar arquivos JPG que existam!

Quando vc executar o projeto, ele vai exibir um form e em seguida, os dois arquivos JPG que vc indicou. Dois segundos depois, a unidade de cima irá se aproximar da unidade que está mais abaixo. Assim que a unidade que está se movimentado entrar no radar da unidade que esta parada, mensagens vão aparecer no seu console, indicando que a unidade azul X,Y detectou unidade vermelha em X,Y.

Com isso, temos dois exemplos aqui: um algoritmo de movimentação e outro de detecção.

Qualquer dúvida, não exitem em perguntar!

Então é isso, até a próxima!


Voltar ao topo
 Perfil  
 
Exibir mensagens anteriores:  Ordenar por  
Criar novo tópico Responder  [ 1 mensagem ] 

Todos os horários são GMT - 3 horas


Quem está online

Usuários navegando neste fórum: Nenhum usuário registrado e 1 visitante


Enviar mensagens: Proibido
Responder mensagens: Proibido
Editar mensagens: Proibido
Excluir mensagens: Proibido
Enviar anexos: Proibido

Ir para:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Traduzido por: Suporte phpBB