Graphics2D

39 respostas
M

Bem eu estou desenvolvendo um jogo e como mapa estou usando tiles, varios quadradinhos dai eu posso usa a mesma imagem em varios lugares mas como eu faço pra carregar só a parte do mapa que eu quero?? eu uso uma ArrayList e o MapEntity guarda sua localização e um sprite,

e outra tem como ficar redesenhando o mapa sem passar pelo meu loop?
pq eu uso assim

Graphics2D g = new Graphics2D();
for(MapEntity a : myMapEntities){
a.draw(g);
}
g.dispose();

e ficar faznedo isso toda hora deixa o jogo mei travando dai o bonequinho aparece aqui depois lá dai mais pra frente =/
alguem tem essas duas respostas??

39 Respostas

V

Se map entity guarda a localização de seus Sprites, então você pode testar com um if e ver se ela deve ser pintada ou não.

Afinal, você também deve ter as coordenadas de onde o seu mapa estiver pintando. Nesse caso, não pinte se:

A figura estiver fora do lado esquerdo do mapa:
sprite.getX() + spritex.width() &lt mapa.minX()

A figura estiver fora para o lado direito do mapa:
sprite.getX() &gt mapa.max()

A figura estiver acima do topo do mapa:
sprite.getY() + spritex.height() &lt mapa.minY()

A figura estiver abaixo da parte inferior do mapa:
sprite.getY() &gt mapa.maxY()

Só se todas essas condições estiverem atingidas, você pinta o sprite.

Note que isso é muito similar ao algoritmo de bounding box, entre o retângulo do sprite e o retângulo do mapa. Se você tiver duas classes Rectangle2D, uma representando o Sprite e outra a área útil do mapa, pode usar o método intersects para testar a mesma coisa.

public class Map { public void draw(Graphics g) { Graphics2D g2d = (Graphics2D) g.create(); for(MapEntity a : myMapEntities){ if (a.rect().intersects(this.getShownRect())) { a.draw(g2d); } } g2d.dispose(); } }

PS: Tá fazendo um jogo? Qual é? No outro tópico você acabou nem me falando. É um RPG? Vai usar java 3D ou só 2D?

M

Só 2D
é algo mais parecido com RPG
e por enquanto o nome é Overseas

M

e pra pintar minha tela tenho que passar toda hora pelo loop? pq fico pesado fica montando todas as imagens

V

Tem sim que passar toda hora pelo loop e desenhar as imagens.

Montar todas as imagens não é tão lento assim. Carregue as imagens que você vai usar na memória (em um BufferedImage). Existem alguns métodos para aumentar as changes do java2D otimizar o desenho das imagens para você (ou seja, mandar a placa de vídeo desenha-las), é o que ensina o tutorial do Space Invaders do Coke and Code.

Agora, tome cuidado com a velocidade de seu jogo. Quando o micro for lento, você pode “pular” uma etapa de desenho das imagens para compensar a velocidade do jogo. É o que descreve este artigo, que escrevi. Da mesma forma, quando o micro for rápido demais, você deve dar alguns sleeps, para que a velocidade de seu jogo permaneça sempre constante.

Assim, é sempre bom separar o desenho de seus sprites (faze de renderização) do processamento da lógica. Dê uma olhada no link que te passei e como aquele algoritmo é aplicado no Vikanoid. :wink:

E qualquer dúvida, pode perguntar! :slight_smile:

M

Eu to usando sobre oque vi no Coke and Code do Space Invaders eu li e to usando aquilo sobre a classe Entity, Sprite, SpriteStore, dai pra mapa e personagens uso classes que extendem Entity
é uma má pratica ter uma Array tão grande pro mapa??
pq olha imagina ter um mapa [100][100]
não ia fica meio lento?? ou meio confuso pra continuar desenhando em Updates?

V

Veja bem. Performance não é tanto o problema, mas sim memória.
Um array de 100x100, vai ocupar pelo menos 40KB.

Agora, a maior parte desse array irá ser ocupado por referências um mesmo tipo de tile, como grama ou o chão de sua caverna. Um desperdício, não?

A solução para isso é usar uma matriz dispersa, que retorna o seu tile default caso não haja um tile cadastrado. Para isso, você cria um map, com outro map dentro.

Eu implementei rapidinho aqui essa classe, que representa esse conceito. Não testei, pode ser que alguns ajustes tenham que ser feitos (não tem como remover um tile, por exemplo). Mas acho que já dá para te dar uma idéia de como funciona uma matriz desse tipo:

public class Matrix<T> {
    private Map<Integer, Map<Integer, T>&gt map;
    private T defaultValue;
    
    public Matrix(T defaultValue) {
        if (defaultValue == null)
            throw new IllegalArgumentException("Default value cannot be null!");
        
        this.defaultValue = defaultValue;
        this.map = new HashMap<Integer, Map><Integer, T>&gt();
    }
    
    public T get(int line, int column) {
        Map<Integer, T> columns = map.get(line);
        if (columns == null)
            return defaultValue;
        
        T tile = columns.get(column);
        if (tile == null)
            return defaultValue;
        
        return tile;
    }
    
    public T put(int line, int column, T value) {
        Map<Integer, T> columns = map.get(line);
        if (columns == null) {
            columns = new HashMap<Integer, T>();
            map.put(line, columns);
        }
        
        T oldValue = columns.put(column, value);
        if (oldValue == null)
            return defaultValue;
        
        return oldValue;
    }
}

Pra usar, basta fazer:

Matrix<Tile> tileMap = new Matrix<Tile>(new GrassTile());
RockWallTile rockWall = new RockWallTile();

tileMap.put(5,5, rockWall);
tileMap.put(6,5, rockWall);
tileMap.put(7,5, rockWall);

tileMap.put(5,6, rockWall);
tileMap.put(7,6, rockWall);

tileMap.put(5,7, rockWall);
tileMap.put(6,7, rockWall);
tileMap.put(7,7, rockWall);

if (tileMap.get(player.getTilePos().getX(), player.getTilePos().getY()) == rockWall) {
   //O jogador colidiu com a parede? Faz alguma coisa...
}
M

private Map<Integer, Map><Integer, T>> map;

da erro nessa parte fala que tem um > amais se tira aparece misplaced Constructors

M

Eu sei que vc disse que podia ter alguns problemas eu nunca vi Map assim^^

V

Tem que tirar o &gt depois da segunda palavra Map.

Já corrigi no post ali em cima. Não sei pq, mas o GUJ colocou isso automático!

V

Na verdade, é um mapa de um inteiro para um outro mapa.

V

Ah sim, outra alternativa (comum em jogos de RPG) é não usar um tilemap, e sim um ArrayList de sprites. Colisões e coisas do tipo você detecta por um algoritmo de Bounding Region qualquer.

M

^^ vlw agora eu entendi aquilo

e outra coisa eu percebi que outro erro meu era usar tiles de 25 por 25 pixels e uma tela de 800 por 600 dai ficava 32 coluna e 24 linhas de tiles isso era pesado pra carrega vou usar agora uns 12 por 8 por ai

M

Mano to tentando usa seu exemplo mas como faço pra desenha?? eu vou explicar mais ou menos como faço

Tenho a classe Tile que tem Um Sprite como atributo(que tem um metodo draw(Graphics g , int x, int y))
dai meus MapsTiles(GrassTile, WaterTile, etc.) extendem Tile e só tem o Sprite como atributo dai a posição x e y to usando do Map no modo que vc passou mas como faço rpa desenha a parte que eu quero(não pela localização, mas desenha as partes tipo da 0 < 12 coluna e da 0 < 8 linha?

V

Cara, não entendi sua dúvida. Testa com um if se o tile está dentro da tela e, se estiver, usa o seu método draw! Não é só fazer isso?

M

o if eu sei pra ve qual desenhar mas ta dando erro no draw fala que tem que da Cast pra Tile mas mesmo assim nada eu vou ve se arrumo hoje eu passei muito mal ontem e vou continua o jogo depois

V

Mark, se der para escrever em português ao invés de internetquês o pessoal do fórum agradeceria…

M

Pois então essa parte eu sei calcula oque ta perto do personagem e desenha mas agora tenho outro problema
o método get só em tetorna o default

olha meu void pra pinta do map

/* Graphics pra da draw, lineI:linha inicial, columnI:coluna inicial, lineF e columnF, linha final e coluna final respectivamente*/ public void draw(Graphics g, int lineI, int columnI, int lineF, int columnF){ for(int i = lineI; i <= lineF;i++){ for(int j = columnI; j <= columnF;j++){ for(int column = 0; column<12;column++){ for(int row = 0; row<8;row++){ ((Tile)this.get(i, j)).draw(g,column*25,row*25); } } } } }

e só pint ao GrassTile

M

Desculpa eu comi umas letra sem ve^^

e outra duvida se eu tive muitos Tiles tipo assin uns 100 vou ter que te 100 classes de Tile? não tem como ter uma classe mais genérica?

EDIT: eu acho que cria uma classe Tile que receba uma string com o nome do arquivo serve^^
dai eu instancio ela e adiciona no Map

e outra como eu resolvo isso de só me retornar o defaultValue?
mesmo se eu adicionar outo tile tipo no 0, 0 e chamar pra pinta só esse me retorna o defaultValue

M

Finalmente resolvi aquilo de só vim o defaultTile ams agora o meu metodo só pinta o mesmo Tile o que se referencia no 0,0 eu sei que é porque to passando umas 1000 vezes no mesmo ponto pra da draw antes de muda de linha dai pinta tudo de azul=/

V

Você pode fazer uma classe de Tile mais reutilizável, passando para ela o link da imagem. Também dá uma olhada no padrão Flyweight, para evitar repetições desnecessárias e consumo excessivo de memória.

M
eu mudei isso:
public void draw(Graphics g, int lineI, int columnI, int lineF, int columnF){
 	    	 for(int i = lineI; i <= lineF;i++){
 	    		 for(int j = columnI; j <= columnF;j++){
 	    			 for(int column = 0; column<12;column++){
 	    				 for(int row = 0; row<8;row++){
 	    					 ((Tile)this.get(i, j)).draw(g,column*25,row*25);
 	    				 }
 	    			 }
 	    		 }
 	    	 }
 	     }
que alem de da errado realmente passava umas 1000 vezes na parte que desenha por isso:
public void draw(Graphics g, int line, int column){
	    	 int row = 0;
	    	 int col = 0;
	    	 int y = line-6;
	    	 int x = column-8;
	    	 
	    	 while(row<12){
	    		 while(col<16){
	    			 	((Tile)this.get(y,x)).draw(g, col*25, row*25);
	    			 col++;
	    			 x++;
	    		 }
	    		 col=0;
	    		 x = column-8;
	    		 y++;
	    		 row++;
	    	 }
	     }
que agora alem de não ter mais lentidão deixa mais bonito meu código e eu não preciso calcula aonde ta meu boneco só dow a cordenada do meio da tela e o método faz o resto
M

Cara não tem outra maneira de coloca os quadrados?? porque olha só minha classe que ta desenhando o mapa(só um quadrado de grama com agua em volta^^)

import java.awt.Graphics;

public class MyMap {
public Matrix myMap;
public void draw(Graphics g, int line, int column){
	myMap.draw(g, line, column);
}
public MyMap(){
	WalkableTile  diagonal;
	myMap = new Matrix(new WalkableTile("sprites/grass.jpg"));
	NoWalkableTile waterWall = new NoWalkableTile("sprites/water.jpg");
	for(int i=0;i<16;i++){
		myMap.put(0, i, waterWall);
		myMap.put(11, i, waterWall);
	}
	for(int i=0;i<12;i++){
		myMap.put(i, 0, waterWall);
		myMap.put(i, 15, waterWall);
	}
	WalkableTile waterUpWall = new WalkableTile("sprites/grasswithwaterup.jpg");
	WalkableTile waterDownWall = new WalkableTile("sprites/grasswithwaterdown.jpg");
	for(int i=1;i<15;i++){
		myMap.put(1, i, waterUpWall);
		myMap.put(10, i, waterDownWall);
	}
	WalkableTile waterRightWall = new WalkableTile("sprites/grasswithwaterright.jpg");
	WalkableTile waterLeftWall = new WalkableTile("sprites/grasswithwaterleft.jpg");
	for(int i = 1;i<11;i++){
		myMap.put(i, 1, waterLeftWall);
		myMap.put(i, 14, waterRightWall);
	}
	diagonal = new WalkableTile("sprites/grasswithwaterleftdown.jpg");
	myMap.put(10, 1, diagonal);
	diagonal = new WalkableTile("sprites/grasswithwaterleftup.jpg");
	myMap.put(1, 1, diagonal);
	diagonal = new WalkableTile("sprites/grasswithwaterrightdown.jpg");
	myMap.put(10, 14, diagonal);
	diagonal = new WalkableTile("sprites/grasswithwaterrightup.bmp");
	myMap.put(1, 14, diagonal);
}
}
e eu coloquei um código pra ve se eu posso anda ou não ve
public void tryWalkUp() {
		if(this.myMap.myMap.get(y-1, x) instanceof NoWalkableTile){
		return;
		}else{--y;
		}
		}
	public void tryWalkDown() {
		if(this.myMap.myMap.get(y+1, x) instanceof NoWalkableTile){
		return;
		}else{++y;
		}
		}
	public void tryWalkRight() {
		if(this.myMap.myMap.get(y, x+1) instanceof NoWalkableTile){
		return;
		}else{++x;
		}
		}
	public void tryWalkLeft() {
		if(this.myMap.myMap.get(y, x-1) instanceof NoWalkableTile){
		return;
		}else{--x;
		}
		}
agora só faltaeu aplica todos os conceitos no jogo depois^^ e desenha o mapa
V

Agora faça uma classe que leia o seu mapa de tiles de um arquivo.

E depois, faça um editorzinho para esse arquivo. Teu código vai ficar mais limpo e flexível.

Depois, pense um pouco melhor na sua classe de tile, pra evitar tanto InstanceOf. Talvez o WalkableTile ao invés de ser uma classe tivesse de ser um atributo.

Dá também uma refatorada nessas funções tryToWalk, criando uma tryToWalkTo passando x e y relativos, assim:

private void tryToWalkTo(int relX, int relY) {
   if (this.myMap.myMap.get(y + relY, x + relX) instanceof NoWalkableTile) {
      return;
   }
   y += relY;
   x += relX;
}

public void tryWalkUp() {
   tryToWalkTo(0, -1);
}

public void tryWalkDown() {
   tryToWalkTo(0, 1);
}

public void tryWalkRight() {
   tryToWalkTo(1,0);
}

public void tryWalkLeft() {
   tryToWalkTo(-1,0);
}
M

ViniGodoy:
Agora faça uma classe que leia o seu mapa de tiles de um arquivo.

E depois, faça um editorzinho para esse arquivo. Teu código vai ficar mais limpo e flexível.

Ler por exemplo de um xml??
dai como seria esse editor?

V

Exatamente. De um XML, ou de um arquivo de formato definido por você, tanto faz.

Basicamente, no editor você coloca um grid, uma barra de menu e coloca os tiles no local onde você clicar. É muito útil quando você quer fazer várias vazes, chega realmente a compensar o esforço.

Se seu jogo pode ter uma fase só, então simplesmente deixe o código macarrão por lá e ponha um comentário do tipo:
//Um editor deve ser feito para substituir a criação manual, como feita nessa classe.

Se for um trabalho de graduação, fazendo desse jeito nenhum professor poderá te criticar… Se te perguntarem o pq que vc não fez o editor, pode dizer que não era do escopo do trabalho. Aliás, o ideal é até colocar a construção do editor num capítulo final, chamado de “Sugestão de Melhorias”, “Modificações Futuras” ou qualquer coisa do gênero (fale com seu orientador para ver o nome que ele gosta).

Outras dicas:

  1. Atributos devem ser sempre private: Quando muito, protected. Deu para ver que o atributo MyMap da classe MyMap não está seguindo essa regra, porém, ela é muitíssimo importante.
  2. Independente de fazer ou não uma classe MapBuilder (que lê do arquivo), separe a construção do mapa numa classe separada. Assim, esse código macarrão fica encapsulado e fica fácil de substitui-lo por algo mais eficiente depois. É o uso do padrão AbstractFactory.
  3. Quando tiver alguma coisa rodando, zipa e manda para mim! Aí posso olhar com mais carinho o seu código e te dar dicas mais aprofundadas.
M

Tipo eu já separei o mapa do resto ele só constroi o mapa mas seria bem legal se vc me ajudasse no editor^^

Eu tenho só uma parte pronto com uma nave andando pelo macarrão^^, ta tudo na minha casa depois eu te mando pra você ve tudo bem?

e o acesso public é por não ser definitivo essa classe eu vou por depois e ageita as coisas.

sobre XML só vi o tutorial do GUJ e não entendi muito bem mas vou continuar aprendenso essa parte

Obs:Eu joguei o seu joguinho BatalhaEstelar e achei legal oque você fez e ia fica mais legal a nave laranja ter AI^^

V

Não precisa necessariamente ser XML. Se quiser só serializar os objetos, já deve servir.

Vou colocar AI na nave do computador, não só na laranja. Estou pensando numa versão single player do jogo, também com alguns parâmetros configuráveis por scripts LUA.

Você viu o e-mail que te passei no hotmail com a apostila de Game Design?

M

To Lendo a apostila agora

e mesmo com XML ou não preciso de ajuda com o editor, não tenho nen idéia de onde começar

L

ViniGodoy onde ta o arquivo do seu jogo? faz um upload denovo dele ai pra galera :wink:

V

Está aqui:
http://vinigodoy.wordpress.com/meus-jogos

M

Ei ViniGodoy por favor uma ideia pro editor^^
ah eu aprendi a mexe com XML com o xstream de acordo com o GUJ sera que é o suficiente?

alias eu sei pra que ser e como escreve XML só não sei lê nen grava com Java(sabia)

L

ViniGodoy:
Está aqui:
http://rapidshare.com/files/30158512/BatalhaEstelar_v2.0.zip

As teclas são
Nave laranja:
A D W - Movimentação
N - Tiro
M - Poder especial: Invisibilidade

Setas - Movimentação da nave verde
Shift - Tiro (desligue as teclas de aderência do Windows antes de entrar no jogo)
Control - Poder especial: Recupera vida

Quem jogar, favor comentar em MP! :slight_smile:

Em casa eu pego, aqui não tenho acesso ao rapidshare, ai dou uma jogada e lhe dou um feedback, mas já aviso que farei no mínimo o dobro de pontos que vc já fez… rsrs

Acho muito legal a parte de 3D, talvez um dia eu perca o medo e comece fazer alguma coisa com Java 3D.

V

Mark_Ameba:
Ei ViniGodoy por favor uma ideia pro editor^^
ah eu aprendi a mexe com XML com o xstream de acordo com o GUJ sera que é o suficiente?

alias eu sei pra que ser e como escreve XML só não sei lê nen grava com Java(sabia)

Você pode fazer algo similar a esse aqui (espero que o link ainda funcione):
http://www.guj.com.br/posts/list/15/53776.java#285675

V

Luiz Aguiar:
Em casa eu pego, aqui não tenho acesso ao rapidshare, ai dou uma jogada e lhe dou um feedback, mas já aviso que farei no mínimo o dobro de pontos que vc já fez… rsrs

Acho muito legal a parte de 3D, talvez um dia eu perca o medo e comece fazer alguma coisa com Java 3D.

Ufa! Ainda bem que meu jogo não se baseia em pontos. :slight_smile:

Primeiro vou ver a parte de IA (é a ordem da pós), depois entro em OpenGL e DirectX. Lá é tudo focado em C++, vemos java só para a parte de J2ME.

Não adianta, para jogos o C++ é muito bom, tem muitas APIs mega conceituadas e é a única linguagem suportada pelos consoles. Fora o fato dele ser mais otimizável do que o Java, seja em performance, uso de memória ou aproveitamento do hardware.

Mas para quem quer aprender Java 3D, o Killer Game Programming in Java já dá uma ótima introdução. E tem o tutorial do Asteroids, no Coke and Code também, que é muito bom e simples, pois apresenta um jogo 2D em tecnologia 3D.

M

ViniGodoy:
Mark_Ameba:
Ei ViniGodoy por favor uma ideia pro editor^^
ah eu aprendi a mexe com XML com o xstream de acordo com o GUJ sera que é o suficiente?

alias eu sei pra que ser e como escreve XML só não sei lê nen grava com Java(sabia)

Você pode fazer algo similar a esse aqui (espero que o link ainda funcione):
http://www.guj.com.br/posts/list/15/53776.java#285675

O link funciona mas o Link nesse link não =/
manda pro megaupload e mostra que a pagina não pode ser exibida
nen no 4shared

V

Tenta entrar em contato com o dono do jogo. O seu editor será realmente muito parecido com o dele… e os fontes já podem te ajudar. Lembro-me que os dele estavam muito bem organizados.

M

Mais tarde eu vou te mandar o básico que eu fiz ok?

V

Ok, fico aguardando.

T

Recuperando post das antigas…

Gostaria de saber onde acho um livro, ou tutorial bom pra exibir meu mapa tiled.
Eu usei um programa para desenhar e exportei como XML, então já estou no passo pelo visto, só preciso entender como manipular esses arquivos XML e montar meu mapinha na tela.

Baixei deste site o programa que monta mapa

Criado 29 de maio de 2007
Ultima resposta 26 de ago. de 2008
Respostas 39
Participantes 4