Graphics e seleção de string

56 respostas
melffagundes

Olá, Pessoal.

É o meu primeiro post no fórum e gostaria de saber se alguém pode me ajudar. Preciso de um diagrama de letras para um jogo. Utilizei a classe Graphics e o método drawString para desenhar as letras. Meu problema é que preciso selecionar com o mouse e retornar essas letras. No entanto, vi que não há nenhum método em Graphics para isso. Alguém tem alguma sugestão?

56 Respostas

A

Oi mel, td bem!!!

como esta seu programa? so pra ter uma ideia, mas ha principio vc tera que usar uma actionEvent pra fz isso, mas gostaria de dar uma olhada pra ter certeza

abrçs

melffagundes
Alessandro_Alves:
Oi mel, td bem!!!

como esta seu programa? so pra ter uma ideia, mas ha principio vc tera que usar uma actionEvent pra fz isso, mas gostaria de dar uma olhada pra ter certeza

abrçs

Oi!

Essa é o método que uso para "criar" o diagrama de letras:

private ImageIcon criarImagem() {
		
		BufferedImage buffer = new BufferedImage( 400, 400, BufferedImage.TYPE_INT_RGB );
		Graphics g = buffer.createGraphics();
		
		int tamanhoDiagrama = Math.min(getSize().height/atorJogador.retornarColunas(),getSize().width/atorJogador.retornarLinhas());
		System.out.println(tamanhoDiagrama);
		
		g.setFont(new Font("SansSerif", Font.BOLD, tamanhoDiagrama/2));

		 FontMetrics fm = g.getFontMetrics();
		 int offset = fm.getAscent();

		for (int r = 0; r <= atorJogador.retornarColunas()-1; r++){
		    for (int c = 0; c <= atorJogador.retornarLinhas()-1; c++){
			g.drawString(String.valueOf(atorJogador.retornarLetra(r, c)), tamanhoDiagrama * c,tamanhoDiagrama * r + offset);
		    }
		}
		
		return new ImageIcon( buffer );
	}
A

Mel, seguinte vc ja ouviu falar do metodo mouseEvent, la vc podera implementar esse metodo, para que no momento em que a pessoa clicar numa letra pra retorna a letra selecionada pra uma String ow um char, dai vc mostraria numa JLabel a letra selecionada.

naum sei se eh isso que vc esta querendo mas da uma olhada no metodo que eu te falei

abrçs precisando estamos ae!!!

melffagundes

Alessandro_Alves:
Mel, seguinte vc ja ouviu falar do metodo mouseEvent, la vc podera implementar esse metodo, para que no momento em que a pessoa clicar numa letra pra retorna a letra selecionada pra uma String ow um char, dai vc mostraria numa JLabel a letra selecionada.

naum sei se eh isso que vc esta querendo mas da uma olhada no metodo que eu te falei

abrçs precisando estamos ae!!!

Oi!
Foi ótima sua dica! Era realmente isso que eu precisava. Ainda não implementei, porque primeiro preciso “criar” o diagrama. Ainda está dando um erro estranho. :slight_smile:

A

Ok, espero ter ajudado

abrçs

ViniGodoy

Oi!

Só de curiosidade, que jogo é?
Para que você está desenvolvendo? Gosto pessoal, faculdade ou algum trabalho?

Quanto ao seu problema, acho que a solução é mesmo a que o colega falou. Dependendo do jogo, também pode ser uma boa olhar na biblioteca JInput.

melffagundes

Oi, Vini!

O jogo é o Caça-Palavras. É um trabalha da faculdade que pretendo aperfeiçoar :slight_smile:

Essa classe me ajudaria como? :slight_smile:

ViniGodoy

Para o seu caso, talvez não seja vantagem mesmo. Só o mouse listener e/ou o mouse motion listener já são suficientes. Eu mesmo usei os próprios listeners no Vikanoid.

O JInput é uma biblioteca que lida com diferentes tipos de entrada, incluindo joysticks.

Legal, bom saber de mais gente desenvolvendo jogos por aí. Depois de pronto, posta aqui no GUJ! :slight_smile:

melffagundes

Quando terminar, eu posto aqui :slight_smile:
Valeu pela ajuda, pessoal! Ainda tenho muito que fazer :slight_smile:
Ainda tenho um outro probleminha com relação a interface. Quando o jogador selecionar no diagrama, o mouse deverá “riscar” a palavra, como fazemos no caça-palavras convencional. Ainda não tenho a mínima idéia de como farei isso. Se souberem de alguma coisa, pode avisar:)

ViniGodoy

O objeto Graphics que você obtém com o BufferedImage tem o método drawLine.

Você ainda pode selecionar a largura da linha com o setStroke.

melffagundes

Oi Pessoal!

Ainda estou com um problema no meu jogo. Quando o jogador seleciona com o mouse uma string no diagrama, eu preciso armazenar essa string e formar uma palavra. Com essa palavra eu faço uma busca numa lista de palavras e, caso eu a encontre, eu devo “riscar” essa palavra da lista. O problema é que o Graphics não tem nenhum método getString() que eu possa utilizar. Como solução, tentei criar um hashmap que recebe, na criação do diagrama, a posicao e a letra. A cada movimento do mouse, eu busco a posicao dentro desse hashmap, que me devolve a letra corresponde, e então eu armazeno. Só que não está funcionando. O que estou fazendo de errado?

ViniGodoy

Acho que o jeito mais fácil é gravar todas as letras numa matriz NxM.

Depois, converta as coordenadas dessa matriz na tela para desenhar as letras.
Defina um espaço fixo entre elas (como é realmente num caça palavras), digamos de 15x15 pixels. Então, o indice 0x0 da sua matriz virará a coordenada 0,0, o 1x1 virará a coordenada 15,15, o 1x2 a coordenada 15x30 e assim por diante.

Assim, fica fácil de converter a posição do clique de volta num índice de sua matriz. E saber que letra está por lá. :slight_smile:

melffagundes

ViniGodoy:
Acho que o jeito mais fácil é gravar todas as letras numa matriz NxM.

Depois, converta as coordenadas dessa matriz na tela para desenhar as letras.
Defina um espaço fixo entre elas (como é realmente num caça palavras), digamos de 15x15 pixels. Então, o indice 0x0 da sua matriz virará a coordenada 0,0, o 1x1 virará a coordenada 15,15, o 1x2 a coordenada 15x30 e assim por diante.

Assim, fica fácil de converter a posição do clique de volta num índice de sua matriz. E saber que letra está por lá. :)

Oi Vini!

Realmente acho que isso vai funcionar :slight_smile:
Depois eu coloco aqui o que fiz :slight_smile:

ViniGodoy

A formula mesmo é essa aqui:

/** Pega a letra pelo índice da matriz*/
char getLetra(int pixelX, int pixelY) {
   int indX = (pixelX / AREA) - OFFSET_X;
   int indY = (pixelY / AREA) - OFFSET_Y;
   return matrix[x][y];
}

/** Pega o pixel relacionado aos índices da matriz */
Point2D getPositionToDraw(int indX, int indY) {
   int pixelX = OFFSET_X + indX * AREA;
   int pixelY = OFFSET_Y + indY * AREA;
   return new Point2D.Float(pixelX, pixelY);
}

Onde:
AREA representa o espaço para letra (por exemplo 15x15, seria área 15);
OFFSET_X = É a posição X da primeira letra, em pixels
OFFSET_Y = É a posicão Y da primeira letra, em pixels

Para ficar mais bonito, mais difícil para o jogador e mais fácil para você, use uma fonte monospaced, como Courier New. Assim você não precisa centralizar em sua área de 15x15, já que todas as letras terão exatamente a mesma largura.

melffagundes
ViniGodoy:
A formula mesmo é essa aqui:
/** Pega a letra pelo índice da matriz*/
char getLetra(int pixelX, int pixelY) {
   int indX = (pixelX / AREA) - OFFSET_X;
   int indY = (pixelY / AREA) - OFFSET_Y;
   return matrix[x][y];
}

/** Pega o pixel relacionado aos índices da matriz */
Point2D getPositionToDraw(int indX, int indY) {
   int pixelX = OFFSET_X + indX * AREA;
   int pixelY = OFFSET_Y + indY * AREA;
   return new Point2D.Float(pixelX, pixelY);
}

Onde:
AREA representa o espaço para letra (por exemplo 15x15, seria área 15);
OFFSET_X = É a posição X da primeira letra, em pixels
OFFSET_Y = É a posicão Y da primeira letra, em pixels

Para ficar mais bonito, mais difícil para o jogador e mais fácil para você, use uma fonte monospaced, como Courier New. Assim você não precisa centralizar em sua área de 15x15, já que todas as letras terão exatamente a mesma largura.

No getLetra eu pego a letra pelo pixel, nao? Por exemplo, quando clicar com o mouse e começar a arrastar, devo pegar o pixel correspondente e depois passá-lo para o getLetra, é isso?

ViniGodoy

É isso mesmo. :slight_smile:

ViniGodoy

Agora que eu vi que o getLetra está errada.

A fórmula é

int indX = (pixelX - OFFSET_X) / AREA;

Mas nada que uma matemática não conseguiria ver sozinha. :smiley:

melffagundes

Eu não entendi o segundo método. Ele pega um ponto correspondente do Graphics? E pra que vou usá-lo?

ViniGodoy

Ele pega o índice x e y da sua matriz, e transforma no pixel onde você deve desenhar a letra.

melffagundes

hehe entendi. Eu já estava fazendo direto no método que desenha :slight_smile: Mas vou utilizar o método então :slight_smile:

melffagundes

Oi, Vini!

Ainda estou com um probleminha. Acho que o pixel que estou retornando do método e.getX, sendo e um mouseEvent, não é da coordenada do diagrama e sim do label o qual o graphic está inserido :?

ViniGodoy

Eu vi que você está desenhando num bufferedImage.

Talvez o melhor seja você criar um filho de JPanel, sobrescrever o método paintComponent, e colocar o método de pintura por lá.
Aí os eventos que forem capturados no MouseListener do painel darão as coordenadas relativas ao painel. :slight_smile:

Ou então, obtenha a coordenada do seu componente com o getBounds() e ajuste seus calculos.

melffagundes

Poxa, pensei que uma vez inserido o Graphics dentro do label ele retornaria a mesma coordenada :frowning:

ViniGodoy

Associe o seu mouseListener ao label.
Acho que daí sai a coordenada relativa ao label.

melffagundes
ViniGodoy:
Associe o seu mouseListener ao label. Acho que daí sai a coordenada relativa ao label.

Eu fiz assim:

labelDiagrama.addMouseMotionListener(new MouseMotionAdapter() {
			 public void mouseDragged(MouseEvent e) {
				
				x = e.getX();
				y = e.getY();
				
				palavra = palavra + getLetra(x,y,offset);
				
				System.out.println(palavra);
			 }
ViniGodoy

Engraçado, já devia ser relativo ao label…

melffagundes

Pois é! Eu comparei os valores gerados com o do e.getX e e.getY e são totalmente diferentes. Pensei que o método de tornar pixel em indice da matriz estivesse errado mas não está :frowning: :frowning:

melffagundes

Acho que vou ter que pensar outra maneira de fazer isso :frowning: E eu que pensei que o Graphics era a melhor forma :frowning:

ViniGodoy

O Graphics é a melhor forma.

Só usar um JLabel desse jeito que não.

Continue usando o Graphics, mas no lugar de desenhar num BufferedImage, desenhe num JPanel.

Para isso, crie um filho de JPanel e sobrescreva o método paintComponent.

public class PanelDoJogo extends JPanel { public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); //Faça a pintura aqui, usando o objeto g2d g2d.dispose(); } }

A vantagem é que, registrando o listener no painel os eventos são com certeza relativos a origem do seu JPanel.

Lembre-se também de ajustar a propriedade preferredSize do seu JPanel para o tamanho que você quer seu caça palavras.

E com isso vc nem precisa da BufferedImage.

melffagundes

ViniGodoy:
O Graphics é a melhor forma.

Só usar um JLabel desse jeito que não.

Continue usando o Graphics, mas no lugar de desenhar num BufferedImage, desenhe num JPanel.

Para isso, crie um filho de JPanel e sobrescreva o método paintComponent.

public class PanelDoJogo extends JPanel { public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); //Faça a pintura aqui, usando o objeto g2d g2d.dispose(); } }

A vantagem é que, registrando o listener no painel os eventos são com certeza relativos a origem do seu JPanel.

Lembre-se também de ajustar a propriedade preferredSize do seu JPanel para o tamanho que você quer seu caça palavras.

E com isso vc nem precisa da BufferedImage.

Oi, Vini!
Funcionou! Quer dizer, agora só estou com outro probleminha…hehehe
Ele retorna a letra, só que repete várias vezes. Acho que é o mouseDragged. Tem alguma sugestão?

davidbuzatto

Olá, vou me meter na conversa :smiley:

Então, realmente, pelo que lí do tópico (li rapidamente) realmente o seu problema com repetição é o mouseDragged. O que você pode fazer é no método mouseDragged verificar se realmente ele está em uma nova letra. Eu implementaria um método que retorna um boolean indicando se ainda estou com o mouse em cima da letra que eu estava, para isso vc precisa verificar se o mouse ainda está dentro das “fronteiras” daquela letra. Não vi se vc usou, mas um ponto de partida é a classe FontMetrics.

Até mais!

melffagundes

davidbuzatto:
Olá, vou me meter na conversa :smiley:

Então, realmente, pelo que lí do tópico (li rapidamente) realmente o seu problema com repetição é o mouseDragged. O que você pode fazer é no método mouseDragged verificar se realmente ele está em uma nova letra. Eu implementaria um método que retorna um boolean indicando se ainda estou com o mouse em cima da letra que eu estava, para isso vc precisa verificar se o mouse ainda está dentro das “fronteiras” daquela letra. Não vi se vc usou, mas um ponto de partida é a classe FontMetrics.

Até mais!


Oi, David!

Toda ajuda é bem vinda:)
O que eu queria mesmo era capturar somente a coordenada correspondente a letra.

melffagundes

Eu pensei também no seguinte:
Quando desenhar a String, delimitá-la dentro de um retângulo(área). Quando passasse o mouse, retornaria somente a posição da String, calculando-se o centroX e centroY. Mas não sei fazer isso ainda :slight_smile:

ViniGodoy

Você tem algumas alternativas:

Use um mouseListener (não um mouseMotionListener) e capture o evento MouseDown para saber onde ele desceu o botão do mouse e mouseUp para saber onde ele subiu. O mouse motion reserve tratar movimento do mouse, se necessário.

Use o click, ao invés de tentar implementar arrasto.

:wink:

melffagundes

ViniGodoy:
Você tem algumas alternativas:

Use um mouseListener (não um mouseMotionListener) e capture o evento MouseDown para saber onde ele desceu o botão do mouse e mouseUp para saber onde ele subiu. O mouse motion reserve tratar movimento do mouse, se necessário.

Use o click, ao invés de tentar implementar arrasto.

;)

Oi, Vini!
Eu so tenho uma duvida: se o jogador clicar em várias letras no diagrama e essas corresponderem a palavra que esta na lista, o jogo vai aceitar e marcar como encontrada. Isso não pode acontecer! hehehe Ai…como faço isso…tem alguma sugestão?

ViniGodoy

Eu faria assim:

No mousePressed, capturaria o índice da letra onde o mouse foi pressionado.
No mouseReleased, pegaria o índice da letra onde o mouse foi solto.

Com isso, é possível saber exatamente qual palavra ele quis marcar.

Na prática, isso deve ficar muito similar mouse motion que você queria fazer.

melffagundes

Oi, Vini

Eu acho que ainda sim pode dar problema. :frowning: Porque se o jogador clicar em 1X1 e depois 6X0, ele ainda pode forma r uma palavra (é remota a possibilidade, mas pode acontecer).

ViniGodoy

É só levar em conta que nenhuma letra a mais foi colocada.
Ele tem que acertar exatamente o primeiro índice da letra quando apertar o botão do mouse, e exatamente o último ao soltar o botão do mouse. Caso contrário, ele não marcou a palavra.

melffagundes

Mas da forma como fiz já acontece isso. O problema é que não sei em qual método formar a palavra.

ViniGodoy

Acho que não entendi exatamente o problema. :?

Pode tentar explicar melhor o que acontece?

melffagundes

ViniGodoy:
Acho que não entendi exatamente o problema. :?

Pode tentar explicar melhor o que acontece?

Desculpe-me, eu expliquei mal dessa vez :wink:
Bem, o que não sei ainda é como formar a palavra:
Por exemplo, eu tenho a coordenada inicial e a final, mas não sei o que fazer com isso…como formar a palavra…:frowning:

ViniGodoy

Bom, há várias maneiras de se fazer isso.

A primeira é criar uma lista das palavras e das coordenadas iniciais e finais de cada uma delas. Um jeito meio bruto de se fazer isso, mas ainda sim, válido.

O segundo é implementar um algoritmo que faça a busca dentro dessas coordenadas.

Digamos que você lin1 e col1 e também lin2 e col2. Onde as variáveis terminadas com 1 são a primeira coordenada e as criadas com 2 são a segunda coordenada. Esses valores já estão convertidos para os índices de sua matriz, não as coordenadas de tela.

Sinto que o seguinte for resolveria sua situação:

StringBuilder palavra = new StringBuilder(); for (int lin = lin1; lin < lin2; lin++) for (int col = col1; col < col2; col++) palavra.append(letras[lin][col]);

Isso captura a palavra selecionada pelo usuário. Agora, é necessário busca-la na lista de palavras:

if (listaDePalavras.contains(palavra.toString()) || listaDePalavras.contains(palavra.reverse().toString())) ) { //Marcou ponto! }

Essa lista de palavras teria todas as palavras corretas que estão desenhadas na matriz.
Você pode estar se questionando o porque do reverse. É por causa do que você falou. O usuário pode ter clicado primeiro em 5x5 e depois em 0x0 e esses serem índices de uma palavra correta. E isso faria o for pegar as letras do avesso.

ViniGodoy

Agora me toquei de um outro detalhe.

Caso o número de linhas e colunas seja diferente é necessário validar se o mouse estava realmente na diagonal (acho que agora entendi o seu problema).

Então, faça o seguinte teste:

public boolean eDiagonal(int lin1, int col1, int lin2, int col2) { return (lin1 != lin2 && col1 != col2) && // numa diagonal, o número de linhas e colunas não são iguais Math.abs(lin1 - lin2) == Math.abs(col1 - col2); // e para cada linha deslocada, há também uma coluna }

A função Math.abs retorna o valor absoluto (módulo) da subtração.

melffagundes

Mas onde eu formo a palavra? No mouseClicked?

ViniGodoy

Eu faria no MouseReleased mesmo.

Não haverá um click. Só um pressionamento (na primeira letra) e um release (na última).

melffagundes

ViniGodoy:
Eu faria no MouseReleased mesmo.

Não haverá um click. Só um pressionamento (na primeira letra) e um release (na última).

O problema é que o MouseRelease é logo invocado quando clico em outra posicao então, ao invés dele salvar a próxima posição, ele guarda a da primeira posição. Ou seja, as coordenadas x1/y1 e x2/y2 ficam com valores iguais.

ViniGodoy

A idéia é que ele pressione, arraste até a última letra e então solte o mouse.

Não que ele clique em duas posições.

Por isso eu disse que essa solução é parecida com a do MouseMotion que vc tava tentando implementar.

melffagundes

Acho que a solução pra mim é MouseDragged…agora tenho que achar uma forma de pegar somente as coordenadas correspondentes a minha matriz…isso que é meu problema…já tentei várias formas e não deu certo…:frowning: :cry:

ViniGodoy

De qualquer forma, vc também poderia fazer com cliques.
Mas daí teria que guardar o primeiro clique numa variável e o segundo clique em outra.

Use então uma pequena máquina de estados no seu programa para saber se ele está “clicando no primeiro elemento” ou “clicando no último”.

Aí é uma questão de preferência sua, o que você achar mais natural.

ViniGodoy

Mouse Dragged ocorre quando há Drag&Drop. Até por isso ele te dá as coordenadas da tela (o usuário poderia soltar o mouse em outros componentes).

Se o usuário clicar num local, arrastar o mouse, e depois soltar o botão você vai ter uma coordenada para o mousePressed e outra para o mouseReleased. Isso ainda usando um mouse listener.

ViniGodoy

O que estou tentando dizer é:

Use o mouse pressed para identificar quando o usuário APERTOU o botão. Ele não deve SOLTAR o botão. Mas mante-lo apertado.

Então, ele arrasta o mouse até a última letra e só então solta o botão. Nessa hora, o java te dispara um evento mouseReleased, e você pode testar que palavra ele selecionou.

Na prática, você usa um mouse listener, mas obtém o um efeito muito similar ao mouse dragged.

O mouse dragged seria usado se você quisesse que seu usuário “pegasse” a letra e a movesse para algum lugar… como acontece quando vc move um arquivo no windows explorer.

melffagundes

ViniGodoy:
O que estou tentando dizer é:

Use o mouse pressed para identificar quando o usuário APERTOU o botão. Ele não deve SOLTAR o botão. Mas mante-lo apertado.

Então, ele arrasta o mouse até a última letra e só então solta o botão. Nessa hora, o java te dispara um evento mouseReleased, e você pode testar que palavra ele selecionou.

Na prática, você usa um mouse listener, mas obtém o um efeito muito similar ao mouse dragged.

O mouse dragged seria usado se você quisesse que seu usuário “pegasse” a letra e a movesse para algum lugar… como acontece quando vc move um arquivo no windows explorer.


Realmente entendi agora o que deve ser feito :smiley: :smiley:
Só estou com problemas ainda com as coordenadas…mas tentarei acertar.

melffagundes

Vini

Está ocorrendo o mesmo problema do MouseDragged! hehehe
Repete as letras!
E agora?

Ironlynx
Mel, não sei se servirá para vc, mas quando eu precisei de uma palavra cruzada, eu me baseei nesse exemplo(créditos ao autor que eu não lembro quem é):
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.applet.Applet;
import java.awt.image.BufferStrategy;
import java.util.Random;

public class CrossWord extends Applet implements MouseListener, MouseMotionListener, Runnable {
	// Game Setup Variables
	static final Random rnd = new Random();
    static final Canvas canvas = new Canvas();

    BufferStrategy bufferStrategy;
    int 		width, height;

    // Game Variables
    Image 		box, box2;
    int         state, level;
    int			gapy;
    int[]       posx, posy;
    int 		startx=-1, starty=-1, endx=-1, endy=-1;  // head & tail position
    char[][]    huruf;
    String[]	soal;
    Point[][]   posSoal;
    boolean[]   answered;
    int       	totalAnswer;
    String[] 	kumpulanSoal = { "MONKEY","HORSE","COW","BUFFALO","WORM","MOUSE","CAT","DOG",
					"ANT","FLY","MOSQUITO","CROCODILE","SHEEP","GOAT","DRAGONFLY","LIZARD",
					"TIGER","PANTHER","LION","ANTELOPE","ELEPHANT","FISH","PANDA","GORILLA","BEAR","SNAKE",
					"DEER","RABBIT","PORCUPINE","BULL","FROG","ZEBRA","BAT" };

    static final String STRING = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // all alphabet string
    static final String CATEGORY = "CATEGORY: ANIMALS";
    static final String SOLVED = "SOLVED.. EXCELLENT!!!";

    //static final BasicStroke stroke = new BasicStroke(2.7f,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
    static final Font font1 = new Font("Verdana",Font.BOLD,20);
    static final Font font2 = new Font("Verdana",Font.BOLD,12);

    public void start() {
		if (bufferStrategy != null) return;

		setIgnoreRepaint(true);
		width = getSize().width;
		height = getSize().height;

		canvas.setIgnoreRepaint(true);
		canvas.setSize(width,height);

		setLayout(null);
		add(canvas);

		// using buffer strategy as backbuffer
		canvas.createBufferStrategy(2);
		bufferStrategy = canvas.getBufferStrategy();

		createQuestion();

		Graphics g = (box = canvas.createImage(40,40)).getGraphics();
		g.setColor(Color.GREEN); g.fillRect(0,0,40,40);
		g.setColor(Color.BLACK); g.drawRect(0,0,40,40);
		g = (box2 = canvas.createImage(40,40)).getGraphics();
		g.setColor(Color.GREEN.darker()); g.fillRect(0,0,40,40);
		g.setColor(Color.BLACK); g.drawRect(0,0,40,40);
		canvas.addMouseListener(this);
		canvas.addMouseMotionListener(this);

		new Thread(this).start();
		canvas.requestFocus();
    }
	public void stop() { bufferStrategy = null; }

    public void run() {
        while (bufferStrategy != null) {
            try { Thread.sleep(25);
			} catch (InterruptedException e) { }

			Graphics2D g = (Graphics2D) bufferStrategy.getDrawGraphics();
			g.setColor(Color.ORANGE);
			g.fillRect(0,0,width,height);

			for (int j=0;j < posy.length;j++)
			for (int i=0;i < posx.length;i++) // draw box
				g.drawImage(box,posx[i],posy[j],null);

			g.setFont(font1);
			g.setColor(Color.black);
			if (state == 0) {
				if (startx >= 0) g.drawImage(box2,posx[startx],posy[starty],null);
			} else if (state == 1) {
				g.drawImage(box2,posx[startx],posy[starty],null);
				if (endx >= 0) {
					if (endx == startx) { // vertical
						int y1 = (starty < endy) ? starty : endy;
						int y2 = (starty < endy) ? endy : starty;
						for (int j=y1;j <= y2;j++)
							g.drawImage(box2,posx[startx],posy[j],null);
					} else if (endy == starty) { // horizontal
						int x1 = (startx < endx) ? startx : endx;
						int x2 = (startx < endx) ? endx : startx;
						for (int i=x1;i <= x2;i++)
							g.drawImage(box2,posx[i],posy[starty],null);
					} else { // diagonal
						int x1, y1, x2, y2;
						if (startx < endx) {
							x1 = startx; y1 = starty;
							x2 = endx; y2 = endy;
						} else {
							x1 = endx; y1 = endy;
							x2 = startx; y2 = starty;
						}
						for (int i=0;i <= x2-x1;i++) {
							if (y1 < y2)
								g.drawImage(box2,posx[x1+i],posy[y1+i],null); // diagonal down
								else g.drawImage(box2,posx[x1+i],posy[y1-i],null); // diagonal up
						}
					}
				}
				//for (int i=0;i < soal.length;i++)
				//	g.drawString(soal[i],400,40+(i*45));
			} else g.drawString(SOLVED,110,390+gapy);

			// draw char
			for (int j=0;j < posy.length;j++)
			for (int i=0;i < posx.length;i++)
				g.drawString(String.valueOf(huruf[i][j]),posx[i]+15,posy[j]+28);

			// draw answered question
			g.setColor(Color.RED);
			//g.setStroke(stroke);
			for (int i=0;i < soal.length;i++) {
				int x1 = posSoal[i][0].x, y1 = posSoal[i][0].y,
					x2 = posSoal[i][1].x, y2 = posSoal[i][1].y;
				if (answered[i]) {
					if (x1 == x2 || y1 == y2) {
						// horizontal or vertical
						g.drawRect(posx[x1]+5, posy[y1]+5,
							((x2-x1)*40)+30, ((y2-y1)*40)+30);
					} else { // diagonal
						if (y1 < y2) { // diagonal down
							g.drawLine(posx[x1]+20,posy[y1],posx[x2]+40,posy[y2]+20);
							g.drawLine(posx[x1],posy[y1]+20,posx[x2]+20,posy[y2]+40);
							g.drawLine(posx[x1]+20,posy[y1],posx[x1],posy[y1]+20);
							g.drawLine(posx[x2]+40,posy[y2]+20,posx[x2]+20,posy[y2]+40);
						} else { // diagonal up
							g.drawLine(posx[x1],posy[y1]+20,posx[x2]+20,posy[y2]);
							g.drawLine(posx[x1]+20,posy[y1]+40,posx[x2]+40,posy[y2]+20);
							g.drawLine(posx[x1],posy[y1]+20,posx[x1]+20,posy[y1]+40);
							g.drawLine(posx[x2]+20,posy[y2],posx[x2]+40,posy[y2]+20);
						}
					}
				}
			}

			// level
			g.drawString(CATEGORY,30,30);
			g.drawString("Lv. "+level,30,390+gapy);

			// questions remaining
			g.setColor(Color.black);
			g.setFont(font2);
			g.drawString("Remaining : "+(soal.length-totalAnswer),300+gapy,35);

			g.dispose();
			bufferStrategy.show();
        }
    }

    public void mouseClicked(MouseEvent e) {
        if (checkPosMouse(e,29,372+gapy,84,392+gapy)) createQuestion();
	}
    public void mousePressed(MouseEvent e) {
	    if (state == 0 && e.getButton() == MouseEvent.BUTTON1 && startx != -1) {
			state = 1;
        } else if (state == 1) {
			if (e.getButton() == MouseEvent.BUTTON1) {
				state = 0;
	            if (endx != -1) { // valid
					if ((startx == endx && starty > endy) ||
						(starty == endy && startx > endx) ||
						(startx != endx && starty != endy && startx > endx)) {
						// reverse head to tail
						int tempx, tempy;
						tempx = startx; tempy = starty;
						startx = endx; starty = endy;
						endx = tempx; endy = tempy;
					}

	                // check is true
	                for (int i=0;i < soal.length;i++)
	                    if (!answered[i]) {
	                        if (startx == posSoal[i][0].x && starty == posSoal[i][0].y &&
	                            endx == posSoal[i][1].x && endy == posSoal[i][1].y) {
	                            answered[i] = true;
	                            if (++totalAnswer >= answered.length) state = 3;
	                            break;
	                        }
	                    }
				}
				startx = -1;
				endx = -1;
	        }
	        if (e.getButton() == MouseEvent.BUTTON3) { startx = -1; endx = -1; state = 0; }
		}
	}
    public void mouseReleased(MouseEvent e) { }
    public void mouseEntered(MouseEvent e) { }
    public void mouseExited(MouseEvent e) { }
    public void mouseDragged(MouseEvent e) { }
    public void mouseMoved(MouseEvent e) {
		if (state == 0 || state == 1) {
			if (checkPosMouse(e, 30, 40, posx[posx.length-1]+40, posy[posy.length-1]+40)) {
				out:
				for (int j=0;j < posy.length;j++)
				for (int i=0;i < posx.length;i++)
					if (checkPosMouse(e, posx[i], posy[j], posx[i]+40, posy[j]+40)) {
						// head or tail find
						if (state == 0) { startx = i; starty = j; } else { endx = i; endy = j; }
						break out;
					}

				if (state == 1) {
					// tail validation
					if (startx == endx && starty == endy) endx = -1;
					if (endx != startx && endy != starty) // check diagonal validity
						if (Math.abs(endx-startx) != Math.abs(endy-starty))
							endx = -1; // not valid
				}
			} else { if (state == 0) startx = -1; else endx = -1; }
		}
	}

	boolean checkPosMouse(MouseEvent e, int x1, int y1, int x2, int y2) {
		return (e.getX() >= x1 && e.getX() <= x2 &&
				e.getY() >= y1 && e.getY() <= y2);
	}

    void createQuestion() {
		if (++level > 3) level = 1; // change level

        posx = new int[(level == 1) ? 9 : 10]; posy = new int[(level == 1) ? 8 : 9];
        for (int i=0;i < posx.length;i++) posx[i] = 30+(40*i);
        for (int i=0;i < posy.length;i++) posy[i] = 40+(40*i);
        huruf = new char[posx.length][posy.length];
        gapy = (level > 1) ? 40 : 0;

		// mix elements
		int size = kumpulanSoal.length;
		String tempval; int temppos;
		for (int i=0;i < size;i++) {
			temppos = getRandom(i,size-1);
			tempval = kumpulanSoal[temppos];
			kumpulanSoal[temppos] = kumpulanSoal[i];
			kumpulanSoal[i] = tempval;
		}

        // variables to avoid dead lock
        boolean valid;              // position validity
        int trycount, globaltry;    // try count on a word and global try on each word

        String tmpsoal;
        int soalke, jlhsoal = 6;
        int xsoal, ysoal;   // posisi x, y soal
        int arah;           // posisi arah soal (horizontal, vertikal, diagonal)

        state = 0;
        jlhsoal = getRandom(5+level,6+level);
        soal = new String[jlhsoal];
        size = soal.length;
        for (int i=0;i < size;i++)
			soal[i] = kumpulanSoal[i];
        posSoal = new Point[size][2];
        answered = new boolean[size];
        totalAnswer = 0;

        soalke = 0; globaltry = 0;
        xsoal = 0; ysoal = 0;
        while (soalke < soal.length) {
            if (++globaltry > 10) { // exceed maximum try (10 globaltry x 10 trycount)
                // try another combination
				for (int j=0;j < posy.length;j++)
				for (int i=0;i < posx.length;i++)
					huruf[i][j] = ' ';
                globaltry = 0;
                soalke = 0;
            }

            arah = 1;
            int rndVal = getRandom(1,20);
			if (rndVal >= 21-(level*2)) arah = 4; else if (rndVal >= 21-(level*2)-3) arah = 3;
				else if (rndVal >= 9-level) arah = 2; else arah = 1;

            tmpsoal = soal[soalke];
            trycount = 0;
            valid = true;
            int a = 0, b = 0;
            if (arah == 1) { a = 1; 				// horizontal
			} else if (arah == 2) { b = 1;			// vertical
			} else if (arah == 3) { a = 1; b = 1;	// diagonal down
			} else { a = 1; b = -1;	}				// diagonal up

			int tmpsoallen = tmpsoal.length();
			try {
				do {
					valid = true;
					xsoal = getRandom(0,posx.length-((a==0) ? 1 : tmpsoallen));
					ysoal = getRandom(0,posy.length-((b==0) ? 1 : tmpsoallen));
					if (arah == 4) ysoal += tmpsoallen-1;
					for (int i=0;i < tmpsoallen;i++)
						if (huruf[xsoal+(i*a)][ysoal+(i*b)] != ' ')
						if (huruf[xsoal+(i*a)][ysoal+(i*b)] != tmpsoal.charAt(i))
							{ trycount++; valid = false; break; }
				} while (!valid && trycount < 10);
			} catch(Exception e) { valid = false; }
			if (valid) {
				int len = tmpsoallen-1;
				for (int i=0;i <= len;i++)
					huruf[xsoal+(i*a)][ysoal+(i*b)] = tmpsoal.charAt(i);
				posSoal[soalke][0] = new Point(xsoal,ysoal);
				posSoal[soalke][1] = new Point(xsoal+(len*a),ysoal+(len*b));
				soalke++; globaltry = 0;
			}
        }

        startx = -1; endx = -1; // refresh

        // draw random string
        for (int j=0;j < posy.length;j++)
        for (int i=0;i < posx.length;i++)
            if (huruf[i][j] == ' ')
                huruf[i][j] = STRING.charAt(getRandom(0,STRING.length()-1));
    }

	int getRandom(int lo, int hi) { return lo + rnd.nextInt(hi-lo+1); }
}
É uma applet, mas não há grandes dificuldades em passá-la para Swing.(OBS.Pena que eu não achei o que eu fiz baseado nesse, que funcionava legal, mas não tô achando)
melffagundes

Nossa…não entendi nada! hehehe
Mas vou tentar pegar pelo menos a idéia do mouseListener.

melffagundes

Nossa estou quase desistindo do Graphics :frowning: Penso em implementar usando botões. O que acha?

Criado 7 de novembro de 2007
Ultima resposta 16 de nov. de 2007
Respostas 56
Participantes 5