Como fazer ArrayList bidimensional?

11 respostas
M

Olá,

Estou fazendo um jogo do tipo “warcraft”/“age of empires” e tenho que gerenciar a posição das unidades(objeto Unidade) nas cordenadas X e Y.

Pensei em usar um ArrayList bidimensional, onde as cordenadas seriam os indices, mas eu não sei como fazer isso, alguem poderia me mostrar como iniciar, ler e regravar um array assim?

Obrigado.

11 Respostas

V

um jogo deste tipo provavelmente terá o tamanho do mapa fixo

certo ?

se o tamanho é fixo você terá um array bi dimensional (não uma lista)

int[][] i = new int[TAMANHO_X][TAMANHO_Y];

a diferença de um array normal para uma lista em java e que lista tem a capacidade de aumentar o tamanho, quanto o array não

M

Se eu usar um tamanho fixo usando array normal, vou ter um array gigante…

O que eu queria era armazenar a posição SOMENTE das unidades ativas…as cordenadas onde não tem nenhuma unidade eu deixaria nulo…

V

Listas são bons de usar em cada caso mas tenha cuidado sua aplicação pode perde desempenho se usadas de forma incorreta, como eu disse se o tamanho do objeto que você está trabalhando é fixo então não há necessidade de criar uma lista

V

se você quer armazenar a posição do personagem use números normais

int x;
int y;

eles são mais que o suficiente para dizer onde o personagem se localiza no mapa

V

tipo no seu objeto Unidade crie dois campos para informar onde ela se localiza.

se o seu objetivo é armazenar as unidades que estão ativas não faça isso usando a posição delas armazene a referencia dos objetos é melhor

M

Então Victor, o lance é que o mapa, diferente do warcraft, é monstruoso de grande, se eu usar tamanho fixo tipo um array de 1000x1000 acho que vai travar tudo.

Eu já tentei armazenar as cordenadas da unidade em int normal dentro do objeto Unidade…o problema é que na inteligencia artificial, a unidade procura a unidade inimiga mais próxima para atacar, e se as cordenadas estiverem dentro dos objetos unidade eu teria que ler TODAS as cordenadas das unidades inimigas pra ver quem está mais perto, alem de ler TODAS as unidades amigas pra não passar por cima, lembrando que essa leitura é a cada passo que a unidade der…imagine um combate entre 600 unidades, não vai rodar…

Já se eu usar ArrayList, eu posso armazenar o objeto Unidade dentro da cordenada que ela está somente, ai com 600 unidades eu armazenaria bem menos informação do que um array gigante…

Não acha q meu caso é pra ArrayList mesmo? Sabe como fazer bidimensional?

B

Boa tarde

Acho que é mais ou menos isso que quer…

/*
  Este é apenas um teste, por isso o javabean está junto
*/
import java.util.ArrayList;
import java.util.List;

/**
*  objeto javabean irá guardar a posicao x e y, aconselho criar em outro pacote 
*/
class Localizacao{

	public Localizacao(int x,int y) {
		this.x=x;
		this.y=y;
	}

	private int x;
	private int y;
	/**
	 * @return the x
	 */
	public int getX() {
		return x;
	}
	/**
	 * @param x the x to set
	 */
	public void setX(int x) {
		this.x = x;
	}
	/**
	 * @return the y
	 */
	public int getY() {
		return y;
	}
	/**
	 * @param y the y to set
	 */
	public void setY(int y) {
		this.y = y;
	}

	/*
         *é só para exibir no console
          (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "Localizacao [x=" + x + ", y=" + y + "]";
	}


}

public class LocalizacaoList {
	public static void main(String[] args) {
                 //é um List generico, quer dizer seu conteudo será somente o objeto javabean Localizacao
		List<Localizacao> locals=new ArrayList<Localizacao>();
		locals.add(new Localizacao(10, 15));
		locals.add(new Localizacao(20, 25));
		locals.add(new Localizacao(30, 35));
		locals.add(new Localizacao(40, 45));
		locals.add(new Localizacao(50, 55));

		System.out.println(locals);
	}
}

faloww :wink:

V

existe algorítimos de optimização que acho que você deveria ler
http://www.caelum.com.br/apostila-java-estrutura-dados/armazenamento-sem-repeticao-com-busca-rapida/
aqui pode te ajudar

não te recomendo você fazer o que o BTO disse pois você vai está duplicando informação no seu programa, o mais correto seria você manter todas unidades no mesmo lugar

a dica é mais ou menos assim pense numa lista telefônica como é possível acharmos facilmente o telefone do meu amigo Gustavo ?
eu não preciso procurar na minha lista toda pois ele é dividida em partes essas partes é a letra que o nome começa
significa que se eu tiver 240 amigos 10 em cada letra eu não vou precisar procurar e olhar as 240 pessoas sou vou ter que procurar em 10 pessoas isso contenteza optimiza a procura das unidades corretas

no seu caso você pode fazer várias divisões uma deles é entre unidades inimigos e unidades suas (dai 50% das unidades já serão eliminas da pesquisa) alem também de dividir o seu mapa em regiões seu mapa é 1000x1000 divida em regiões de 100x100 e depois subdivida em regiões de 10x10, assim você melhora o processo
mas se fizer isso você deverá ter alguns métodos para mudar as posições entre as listas dos objetos dos seus personagens de acordo com o movimento deles

essa seria a forma correta de fazer o que você quer

(antes das criticas esse é só um exemplo claro que você deverá fazer isso dinamicamente)

ArrayList[] Soldados = new ArrayList[2];
        
        ArrayList Aliados = new ArrayList();
        
        
        ArrayList Posisão1_de100 = new ArrayList();//esse representa o primeiro 100x100
        ArrayList Posisão2_de100 = new ArrayList();//esse representa o segundo 100x100
        ArrayList Posisão3_de100 = new ArrayList();//esse representa o terceiro 100x100
        ArrayList Posisão4_de100 = new ArrayList();//esse representa o quarto 100x100
        ArrayList Posisão5_de100 = new ArrayList();//esse representa o quint 100x100
        Aliados.add(Posisão1_de100);
        Aliados.add(Posisão2_de100);
        Aliados.add(Posisão3_de100);
        Aliados.add(Posisão4_de100);
        Aliados.add(Posisão5_de100);

        Soldados[0] = Aliados;

Isso se assemelha a um sistema de arvore, a as folhas dessa arvore sempre deverá ser o objeto da unidade

rmendes08

moskaBR, eu diria que a solução (ao menos parcial) do seu problema combina as 2 respostas anteriores:

1 - Crie uma classe Localizacao, ou Posicao com as coordenadas da unidade:

class Posicao{ 
   int x, int y; 
   //get,set ...

   //pulo do gato: sobrescreve hashCode
   public int hashCode(){
      return x + 3 * y; //o eclipse gera esse algoritmo pra você
   }

2 - Mantenha em cada unidade sua própria posição

class Unidade{ Posicao posicao; }

3 - Mantenha um Map(HashMap, TreeMap, etc.) para cada posicao

class Cenario{
   Map<Posicao,Unidade> posicoes = new HashMap<>();
}

Ou seja, o efeito é semelhante a manter um array de Unidades indexados por x/y. Com a HashMap você pode simplesmente fornecer um objeto do tipo Posicao que ela te retorna a Unidade naquela posicao ou null, com a vantagem de que essa busca executa em tempo constante, e sem precisar alocar um array desse tamanho. Mas para isso funcionar é imprescindível que você sobrescreva o método hashCode.

V

Utilizar o HashMap e a forma “Pre fabricado” do java para fazer isso.

procure evitar informação duplicada isso pode deixar a sua aplicação lenta, e as vesse tão lento que nem vale a pena duplicar

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package teste;

import java.util.HashMap;

public class Teste {

    /**
     * @param args the command line arguments
     */
    static HashMap<Posicao, Unidade> map = new HashMap();

    public static void main(String[] args) {
        criaUnidade(10, 200);
        criaUnidade(30, 245);
        criaUnidade(70, 753);
        criaUnidade(54, 127);
        criaUnidade(86, 290);
        criaUnidade(134, 583);

        Posicao pos = new Posicao(54, 127);//posição que você quer procurar
        Unidade get = map.get(pos);//pega a unidade na posição citada

        System.out.println(get.nome);
    }

    static public Unidade criaUnidade(int x, int y) {
        Unidade unidade = new Unidade(x, y);
        map.put(unidade.getPos(), unidade);
        return unidade;
    }
}

class Unidade {

    static int count = 0;
    String nome;
    Posicao pos;

    public Unidade(int x, int y) {
        nome = Integer.toString(count++);
        pos = new Posicao(this, x, y);
    }

    public Posicao getPos() {
        return pos;
    }
}

class Posicao {

    public Posicao(int x, int y) {
        this(null, x, y);
    }

    public Posicao(Unidade unidade, int x, int y) {
        this.unidade = unidade;
        this.x = x;
        this.y = y;
    }
    Unidade unidade;
    int x;
    int y;
    //get,set ...  

    //pulo do gato: sobrescreve hashCode  
    @Override
    public int hashCode() {
        return x + 3 * y; //o eclipse gera esse algoritmo pra você  
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Posicao other = (Posicao) obj;
        if (this.x != other.x) {
            return false;
        }
        if (this.y != other.y) {
            return false;
        }
        return true;
    }
}

se for para criar uma classe que represente a posição do seu personagem reaproveite a mesma para armazenar a posição dele (assim uma instancia da posição seria criada, que o gastaria menos memoria RAM)

alem disse a classe posição pode ter uma referencia a unidade que ela mostra a posição, assim quando você procurar no HashMap seria mais ou menos assim

Basicamente isso ficou sendo o que “rmendes08” disse

B

Uma outra opção é usar Quadtrees.

Criado 15 de julho de 2013
Ultima resposta 15 de jul. de 2013
Respostas 11
Participantes 5