Vamos a segunda parte do tutorial de construir um jogo de damas com JavaFX.
Em relação à primeira parte do tutorial fiz algumas mudanças no código necessárias à continuação do joguinho.
O resultado visual dessa parte do tutorial é esse:
Notem o mouse controlando uma das peças azuis (que estão mais brilhosas exatamente porque é a vez do azul jogar). Algumas peças estão faltando porque já foram comidas.
Vamos ao tutorial… =D
O código base:
import javafx.stage.*; import javafx.scene.*; import javafx.scene.paint.*; import javafx.scene.effect.*; import javafx.scene.effect.light.*; import javafx.scene.shape.*; import javafx.scene.input.*; import javafx.ext.swing.*; import javafx.animation.*; import java.lang.*; import java.util.*; def SIZE = 30; //tamanho de uma casa def SIZE2 = SIZE/2; //metade de uma casa def SIZEP = 12; //raio de uma peca class Peca extends CustomNode{ var x: Number;//posicao na tela var y: Number;//posicao na tela var i: Integer;//posicao no tabuleiro var j: Integer;//posicao no tabuleiro var jogador: Integer;//numero do jogador (1 ou 2) init{//chamado quando criar o objeto updateXY();//atualiza XY em relaçao a IJ } public function toIJ(valor: Number):Integer{//converter de XY para IJ return Math.round((valor - SIZE2) / SIZE).intValue(); } public function toXY(valor: Integer):Number{//converter de IJ para XY return valor * SIZE + SIZE2; } public function updateXY():Void{//atualiza XY em relaçao a IJ x = toXY(i); y = toXY(j); } public function updateIJ():Void{//atualiza IJ em relaçao a XY i = toIJ(x); j = toIJ(y); } override function create():Node{ return Circle{ centerX: bind x centerY: bind y radius: SIZEP fill: bind RadialGradient{ centerX: 0.5 centerY: 0.5 focusX: 0.3 focusY: 0.3 radius: 0.5 proportional: true stops:[ Stop{ offset: 0.0 color: if(jogador == 1)Color.color(1,0.8,0.8)else Color.LIGHTBLUE } Stop{ offset: 0.4 color: if(jogador == 1)Color.RED else Color.BLUE } Stop{ offset: 0.8 color: if(jogador == 1)Color.DARKRED else Color.DARKBLUE } ] } effect: DropShadow{ offsetX: 1 offsetY: 1 radius:3 spread: 0.1 } } } } Stage{ title: "Damas" scene: Scene{ width: SIZE*8 height: SIZE*8 fill: Color.WHITE content: [ for(i in [0..4]) for(j in [0..4])[ Rectangle{ x: i*2*SIZE y: j*2*SIZE width: SIZE height: SIZE fill: Color.GRAY } Rectangle{ x: i*2*SIZE+SIZE y: j*2*SIZE+SIZE width: SIZE height: SIZE fill: Color.GRAY } ] for(i in [0..4]) for(j in [0..2])[ Peca{ i: if((j mod 2) == 0) i*2 else i*2+1 j: j jogador: 1 } Peca{ i: 7 - (if((j mod 2) == 0) i*2 else i*2+1) j: j + 5 jogador: 2 } ] ] } }
E o resultado desse código são peças bonitas porém bem mais leves que antes. Os efeitos de luz que tinha na primeira parte do tutorial eram muito pesados e quando ia movimentar as peças ficava muito lento. Então criei outro efeito parecido com luz (RadialGradient) soh que bem mais leve =D
Também removi os ‘bind’s porque não pode existir ‘bind’ entre duas variáveis ao mesmo tempo. (a bind b e b bind a). No lugar deles criei duas funções updateXY() e updateIJ() que fazem a mesma função dos binds (atualizar as variaveis XY em relação a IJ e vice-versa). Usar essas funções em vez dos bind’s é util porque posso controlar quando quero atualizar as variáveis. Com o bind não tenho esse controle, elas são atualizadas automaticamente (as vezes isso é util, mas nesse caso não).
A ideia dessa parte do tutorial é fazer as peças se movimentarem! Então vamos adicionar ao Circle das peças a funçao onMouseDragged que controla quando vc arrasta algum componente com o mouse!
Na função create da Peca adicione a funçao para a variavel onMouseDragged:
override function create():Node{ return Circle{ ... onMouseDragged: function(e: MouseEvent):Void{ x = e.sceneX; y = e.sceneY; } } }
Essa função vai pega a posição do mouse na cena, e atribui à posição da peça na tela! Assim quando vc arrastar algum componente, ele vai seguir a posição do mouse na tela! Com isso vc já pode movimentar as peças no tabuleiro! Mas as peças estão sem controle! Vc pode colocar a peça em qualquer posiçao! Vamos corrigir isso adicionando a funçao onMouseReleased que controla quando o botão do mouse for solto! Nessa função vc vai calcular a posição da peça quando foi solta, e ajusta-la pra ficar centralizada em alguma casa.
onMouseReleased: function(e: MouseEvent):Void{ x = e.sceneX; y = e.sceneY; updateIJ(); updateXY(); }
A lógica é a seguinte, vc coloca a peça na posição onde o botão do mouse foi solto, quando atualizar a posição da peça no tabuleiro (updateIJ()) vc vai ter (i,j) como numeros inteiros, e quando atualizar a posição da peça na tela (updateXY()) vc centraliza a peça numa casa, porque estará atualizando (x,y) em relaçao à (i,j) que jah estão atualizados. Dessa forma, quando vc soltar uma peça, ela vai ficar centralizada na casa mais próxima.
Vamos agora criar uma classe Jogo que vai armazenar algumas variáveis importantes.
class Jogo{ var tabuleiro: Hashtable = new Hashtable(); var jogador = 2;//começa com o jogador azul var pecas: Peca[]; init{ pecas = for(i in [0..3]) for(j in [0..2])[ Peca{ i: if((j mod 2) == 0) i*2 else i*2+1 j: j jogador: 1 jogo: this } Peca{ i: 7 - (if((j mod 2) == 0) i*2 else i*2+1) j: j + 5 jogador: 2 jogo: this } ]; } public function mudarJogador():Void{ if(jogador == 1){ jogador = 2; }else{ jogador = 1; } } }
Essa classe possui um tabuleiro (tabuleiro:Hashtable) que armazena quais peças ainda estão no jogo (quando uma peça for comida, ela será removida desse Hashtable), uma variavel jogador que controla de quem é a vez de jogar (azul ou vermelho) e um array de peças. A função mudarJogador() o nome já diz pra que serve =D. Na inicialização todas as peças são criadas e recebem uma referencia à variavel jogo. Para isso é necessário adicionar a variável ‘jogo’ na classe Peca.
class Peca extends CustomNode{ ... var jogo: Jogo;//referencia ao jogo ... }
Criamos uma variável para guardar o jogo e como as peças foram criadas dentro do jogo, não precisamos cria-las dentro do Scene:
var jogo: Jogo = Jogo{}; Stage{ title: "Damas" scene: Scene{ ... content: [ //criação dos retangulos do tabuleiro ... jogo.pecas ] } }
O código tah começando a ficar organizado =D
Agora que temos a variavel tabuleiro que controla quais variaveis estão no jogo, no init da classe Peca vamos colocar o comando pra peça ser adicionada ao tabuleiro, e criamos também a funçao IJtoIndex(i,j) que converte as coordenadas (i,j) num índice de um array unidimensional.
init{ updateXY(); jogo.tabuleiro.put( IJtoIndex(i,j) , this); } public function IJtoIndex(i: Integer, j: Integer):Integer{ return j*8 + i; }
Também adicionamos à classe Peca a variavel dama:Boolean que controla se a peça é uma dama (ou seja, chegou ao outro lado do tabuleiro). Criamos a função comer() que faz com que a peça seja removida do tabuleiro:Hashtable e fique invisível. Também adicionamos a função podeComer() que verifica se uma peça pode comer alguma outra em volta, isso serve para que se possa comer 2 peças ou mais numa única jogada. Cada vez que termina uma jogada, é chamada a função mudarJogador() que passa a vez para o outro jogador. Veja como fica o código com esse monte de modificação:
import javafx.stage.*; import javafx.scene.*; import javafx.scene.paint.*; import javafx.scene.effect.*; import javafx.scene.effect.light.*; import javafx.scene.shape.*; import javafx.scene.input.*; import javafx.ext.swing.*; import javafx.animation.*; import java.lang.*; import java.util.*; def SIZE = 30; //tamanho de uma casa def SIZE2 = SIZE/2; //metade de uma casa def SIZEP = 12; //raio de uma peca class Peca extends CustomNode{ var x: Number; var y: Number; var i: Integer; var j: Integer; var jogador: Integer; var jogo: Jogo; var dama: Boolean = false; init{ updateXY(); jogo.tabuleiro.put( IJtoIndex(i,j) , this); } public function podeComer():Boolean{ if(i+2 <= 7 and j+2 = 0 and j+2 = 0 and j-2 >= 0){ if(jogo.tabuleiro.containsKey(IJtoIndex(i-1,j-1))){ var peca: Peca = jogo.tabuleiro.get(IJtoIndex(i-1,j-1)) as Peca; if(peca.jogador != this.jogador){ if(not jogo.tabuleiro.containsKey(IJtoIndex(i-2,j-2))){ return true; } } } } if(i+2 = 0){ if(jogo.tabuleiro.containsKey(IJtoIndex(i+1,j-1))){ var peca: Peca = jogo.tabuleiro.get(IJtoIndex(i+1,j-1)) as Peca; if(peca.jogador != this.jogador){ if(not jogo.tabuleiro.containsKey(IJtoIndex(i+2,j-2))){ return true; } } } } return false; } public function IJtoIndex(i: Integer, j: Integer):Integer{ return j*8 + i; } public function toIJ(valor: Number):Integer{ return Math.round((valor - SIZE2) / SIZE).intValue(); } public function toXY(valor: Integer):Number{ return valor * SIZE + SIZE2; } public function updateXY():Void{ x = toXY(i); y = toXY(j); } public function updateIJ():Void{ jogo.tabuleiro.remove(IJtoIndex(i,j)); i = toIJ(x); j = toIJ(y); jogo.tabuleiro.put(IJtoIndex(i,j), this); if((jogador == 1 and j == 7) or (jogador == 2 and j == 0)){ dama = true; } } public function comer():Void{ jogo.tabuleiro.remove(IJtoIndex(i,j)); this.visible = false; } override function create():Node{ return Circle{ centerX: bind x centerY: bind y radius: SIZEP fill: bind RadialGradient{ centerX: 0.5 centerY: 0.5 focusX: 0.3 focusY: 0.3 radius: 0.5 proportional: true stops:[ Stop{ offset: 0.0 color: if(jogador == 1)Color.color(1,0.8,0.8)else Color.LIGHTBLUE } Stop{ offset: 0.4 color: if(jogador == 1)Color.RED else Color.BLUE } Stop{ offset: 0.8 color: if(jogador == 1)Color.DARKRED else Color.DARKBLUE } Stop{ offset: 1.0 color: if(dama)Color.YELLOW else Color.BLACK } ] } effect: DropShadow{ offsetX: 1 offsetY: 1 radius:3 spread: 0.1 } //1 movendo onMouseDragged: function(e: MouseEvent):Void{ if(this.jogador != jogo.jogador){ return; } x = e.sceneX; y = e.sceneY; } //2 movendo e soltando no lugar correto onMouseReleased: function(e: MouseEvent):Void{ if(this.jogador != jogo.jogador){ return; } x = e.sceneX; y = e.sceneY; var ii = toIJ(x); var jj = toIJ(y); var dx = Math.abs(ii-i); var dy = Math.abs(jj-j); var index = IJtoIndex(ii,jj); if( (dx > 0 or dy > 0) and dx == dy ){//se moveu (e na diagonal) if( ii >= 0 and ii = 0 and jj j) or (jogador == 2 and jj < j)){// andou pra frente updateIJ(); updateXY(); jogo.mudarJogador(); }else{//andou pra traz updateXY(); } } }else{//mais que uma casa if(dx == 2){//2 casas var i_med = (ii+i)/2; var j_med = (jj+j)/2; var index_med = IJtoIndex(i_med,j_med); if(jogo.tabuleiro.containsKey(index_med)){//pulou peça var peca: Peca = jogo.tabuleiro.get(index_med) as Peca; if(peca.jogador != this.jogador){//outro jogador peca.comer(); updateIJ(); updateXY(); if(not podeComer()){ jogo.mudarJogador(); } }else{ updateXY(); } }else{//nao pulou peça updateXY(); } }else{//mais que duas casas updateXY(); } } } }else{//fora do tabuleiro updateXY(); } }else{//se nao moveu ou nao foi na diagonal updateXY(); } } } } } class Jogo{ var tabuleiro: Hashtable = new Hashtable(); var jogador = 2;//azul var pecas: Peca[]; init{ pecas = for(i in [0..3]) for(j in [0..2])[ Peca{ i: if((j mod 2) == 0) i*2 else i*2+1 j: j jogador: 1 jogo: this } Peca{ i: 7 - (if((j mod 2) == 0) i*2 else i*2+1) j: j + 5 jogador: 2 jogo: this } ]; } public function mudarJogador():Void{ if(jogador == 1){ jogador = 2; }else{ jogador = 1; } } } var jogo: Jogo = Jogo{}; Stage{ title: "Damas" scene: Scene{ width: SIZE*8 height: SIZE*8 fill: Color.WHITE content: [ Group{ content: for(i in [0..4]) for(j in [0..4])[ Rectangle{ x: i*2*SIZE y: j*2*SIZE width: SIZE height: SIZE fill: Color.GRAY } Rectangle{ x: i*2*SIZE+SIZE y: j*2*SIZE+SIZE width: SIZE height: SIZE fill: Color.GRAY } ] } jogo.pecas ] } }[/sourcecode] Algumas explicações: <ul> <li><strong>jogo.tabuleiro.containsKey(IJtoIndex(i,j))</strong>: verifica se existe uma peça na posição (i,j)</li> <li><strong>jogo.tabuleiro.get(IJtoIndex(i,j)) as Peca</strong>: petorna a peça na posiçao (i,j)</li> <li><strong>if(peca.jogador != jogo.jogador)</strong>: verifica se a peça atual é do jogador da vez (azul ou vermelho)</li> <li><strong>updateIJ()</strong> e <strong>updateXY()</strong>: move a peça para a posição escolhida</li> <li>apenas <strong>updateXY()</strong>: move a peça de volta à posição inicial</li> </ul> Agora as peças se movem apenas nas posições corretas, uma peça pode comer outra, peças não podem andar para traz, e quando chegam ao outro lado do tabuleiro viram damas (contorno amarelo). Vejam a imagem: <img class="aligncenter size-full wp-image-163" title="tutorial_damas_2_003" src="https://raphaelmarques.wordpress.com/wp-content/uploads/2008/12/tutorial_damas_2_003.jpg" alt="tutorial_damas_2_003" width="248" height="268" /> Agora vamos melhorar alguns detalhes. Quando vc arrasta uma peça, ela pode ficar por baixo de outra, dependendo das peças. Vamos resolver isso adicionando à peça a função onMousePressed que controla quando o botão do mouse é pressionado. A lógica é quando clicar sobre uma peça ela fica sobre todas as outras peças. override function create():Node{ return Circle{ ... //3 movendo pra frente onMousePressed: function(e: MouseEvent):Void{ this.toFront(); } } }
E falta agora destacar as peças as vez (azuis ou vermelhas). Podemos fazer isso deixando as outras peças (que não são da vez) menos brilhosa deixado-as meio transparentes. Para isso precisamos apenas adicionar a variavel opacity das peças:
override function create():Node{ return Circle{ ... opacity: bind if(jogo.jogador == jogador) 1.0 else 0.5 ... } }
O resultado é que as peças que não sao da vez ficam menos brilhosas:
Dessa forma, quando for a vez da peça ela tera opacidade total (1.0) e quando não for a vez da peça, ela ficará meio transparente (0.5).
Agora vamos adicionar a opção de resetar o jogo. Para que quando o jogo termine possa voltar ao estado inicial. Para isso adicionamos a função reset() à classe Jogo e adicionamos a função onKeyPressed ao grupo que contém os elementos do tabuleiro para quando o usuário pressionar ESPAÇO jogo volte ao estado inicial.
class Jogo{ ... public function reset():Void{ tabuleiro.clear(); var index = 0; for(i in [0..3]){ for(j in [0..2]){ var peca: Peca = pecas[index++]; peca.i = if((j mod 2) == 0) i*2 else i*2+1; peca.j = j; peca.updateXY(); peca.visible = true; peca.dama = false; tabuleiro.put(peca.IJtoIndex(peca.i,peca.j), peca); peca = pecas[index++]; peca.i = 7 - (if((j mod 2) == 0) i*2 else i*2+1); peca.j = j + 5; peca.updateXY(); peca.visible = true; peca.dama = false; tabuleiro.put(peca.IJtoIndex(peca.i,peca.j), peca); } } } } var jogo: Jogo = Jogo{}; Stage{ ... scene: Scene{ ... content: [ Group{ content: ... onKeyPressed: function(e: KeyEvent):Void{ if(e.code == KeyCode.VK_SPACE){ jogo.reset(); } } } jogo.pecas ] } }
Terminado =D
Agora vejam o código completo com alguns printlns que mostram a lógica do onMouseReleased.
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.paint.*;
import javafx.scene.effect.*;
import javafx.scene.effect.light.*;
import javafx.scene.shape.*;
import javafx.scene.input.*;
import javafx.ext.swing.*;
import javafx.animation.*;
import java.lang.*;
import java.util.*;
def SIZE = 30; //tamanho de uma casa
def SIZE2 = SIZE/2; //metade de uma casa
def SIZEP = 12; //raio de uma peca
def DEBUG = true;
class Peca extends CustomNode{
var x: Number;
var y: Number;
var i: Integer;
var j: Integer;
var jogador: Integer;
var jogo: Jogo;
var dama: Boolean = false;
init{
updateXY();
jogo.tabuleiro.put( IJtoIndex(i,j) , this);
}
public function podeComer():Boolean{
if(i+2 <= 7 and j+2 = 0 and j+2 = 0 and j-2 >= 0){
if(jogo.tabuleiro.containsKey(IJtoIndex(i-1,j-1))){
var peca: Peca = jogo.tabuleiro.get(IJtoIndex(i-1,j-1)) as Peca;
if(peca.jogador != this.jogador){
if(not jogo.tabuleiro.containsKey(IJtoIndex(i-2,j-2))){
return true;
}
}
}
}
if(i+2 = 0){
if(jogo.tabuleiro.containsKey(IJtoIndex(i+1,j-1))){
var peca: Peca = jogo.tabuleiro.get(IJtoIndex(i+1,j-1)) as Peca;
if(peca.jogador != this.jogador){
if(not jogo.tabuleiro.containsKey(IJtoIndex(i+2,j-2))){
return true;
}
}
}
}
return false;
}
public function IJtoIndex(i: Integer, j: Integer):Integer{
return j*8 + i;
}
public function toIJ(valor: Number):Integer{
return Math.round((valor – SIZE2) / SIZE).intValue();
}
public function toXY(valor: Integer):Number{
return valor * SIZE + SIZE2;
}
public function updateXY():Void{
x = toXY(i);
y = toXY(j);
}
public function updateIJ():Void{
jogo.tabuleiro.remove(IJtoIndex(i,j));
i = toIJ(x);
j = toIJ(y);
jogo.tabuleiro.put(IJtoIndex(i,j), this);
if((jogador == 1 and j == 7) or (jogador == 2 and j == 0)){
dama = true;
}
}
public function comer():Void{
jogo.tabuleiro.remove(IJtoIndex(i,j));
this.visible = false;
}
override function create():Node{
return Circle{
centerX: bind x centerY: bind y radius: SIZEP
opacity: bind if(jogo.jogador == jogador) 1.0 else 0.5
fill: bind RadialGradient{
centerX: 0.5 centerY: 0.5
focusX: 0.3 focusY: 0.3
radius: 0.5
proportional: true
stops:[
Stop{
offset: 0.0
color: if(jogador == 1)Color.color(1,0.8,0.8)else Color.LIGHTBLUE
}
Stop{
offset: 0.4
color: if(jogador == 1)Color.RED else Color.BLUE
}
Stop{
offset: 0.8
color: if(jogador == 1)Color.DARKRED else Color.DARKBLUE
}
Stop{
offset: 1.0
color: if(dama)Color.YELLOW else Color.BLACK
}
]
}
effect: DropShadow{
offsetX: 1 offsetY: 1
radius:3
spread: 0.1
}
//1 movendo
onMouseDragged: function(e: MouseEvent):Void{
if(this.jogador != jogo.jogador){
return;
}
x = e.sceneX;
y = e.sceneY;
}
//2 movendo e soltando no lugar correto
onMouseReleased: function(e: MouseEvent):Void{
if(this.jogador != jogo.jogador){
return;
}
x = e.sceneX;
y = e.sceneY;
var ii = toIJ(x);
var jj = toIJ(y);
var dx = Math.abs(ii-i);
var dy = Math.abs(jj-j);
var index = IJtoIndex(ii,jj);
if(DEBUG)println(“nmoveto {ii},{jj}”);
if( (dx > 0 or dy > 0) and dx == dy ){//se moveu (e na diagonal)
if(DEBUG)println(“moveu”);
if( ii >= 0 and ii = 0 and jj j) or
(jogador == 2 and jj < j)){// andou pra frente
if(DEBUG)println("andou pra frente");
updateIJ();
updateXY();
jogo.mudarJogador();
}else{//andou pra traz
if(DEBUG)println("andou pra traz");
updateXY();
}
}
}else{//mais que uma casa
if(DEBUG)println("mais que 1 casa");
if(dx == 2){//2 casas
if(DEBUG)println("2 casas");
var i_med = (ii+i)/2;
var j_med = (jj+j)/2;
var index_med = IJtoIndex(i_med,j_med);
if(jogo.tabuleiro.containsKey(index_med)){//pulou peça
if(DEBUG)println("pulou peça");
var peca: Peca = jogo.tabuleiro.get(index_med) as Peca;
if(peca.jogador != this.jogador){//outro jogador
if(DEBUG)println("pulou peça de outro jogador");
peca.comer();
updateIJ();
updateXY();
if(not podeComer()){
jogo.mudarJogador();
}
}else{
if(DEBUG)println("pulou peça do mesmo jogador");
updateXY();
}
}else{//nao pulou peça
if(DEBUG)println("nao pulou peça");
updateXY();
}
}else{
if(DEBUG)println("mais que 2 casas");
updateXY();
}
}
}
}else{//fora do tabuleiro
if(DEBUG)println("fora do tabuleiro");
updateXY();
}
}else{//se nao moveu ou nao foi na diagonal
if(DEBUG)println("nao moveu");
updateXY();
}
}
//3 movendo pra frente
onMousePressed: function(e: MouseEvent):Void{
this.toFront();
}
}
}
}
class Jogo{
var tabuleiro: Hashtable = new Hashtable();
var jogador = 2;//azul
var pecas: Peca[];
init{
pecas = for(i in [0..3])
for(j in [0..2])[
Peca{
i: if((j mod 2) == 0) i*2 else i*2+1
j: j
jogador: 1
jogo: this
}
Peca{
i: 7 - (if((j mod 2) == 0) i*2 else i*2+1)
j: j + 5
jogador: 2
jogo: this
}
];
}
public function mudarJogador():Void{
if(jogador == 1){
jogador = 2;
}else{
jogador = 1;
}
}
public function reset():Void{
tabuleiro.clear();
var index = 0;
for(i in [0..3]){
for(j in [0..2]){
var peca: Peca = pecas[index++];
peca.i = if((j mod 2) == 0) i*2 else i*2+1;
peca.j = j;
peca.updateXY();
peca.visible = true;
peca.dama = false;
tabuleiro.put(peca.IJtoIndex(peca.i,peca.j), peca);
peca = pecas[index++];
peca.i = 7 - (if((j mod 2) == 0) i*2 else i*2+1);
peca.j = j + 5;
peca.updateXY();
peca.visible = true;
peca.dama = false;
tabuleiro.put(peca.IJtoIndex(peca.i,peca.j), peca);
}
}
}
}
var jogo: Jogo = Jogo{};
Stage{
title: "Damas"
scene: Scene{
width: SIZE*8
height: SIZE*8
fill: Color.WHITE
content: [
Group{
content: for(i in [0..4])
for(j in [0..4])[
Rectangle{
x: i*2*SIZE y: j*2*SIZE
width: SIZE height: SIZE
fill: Color.GRAY
}
Rectangle{
x: i*2*SIZE+SIZE y: j*2*SIZE+SIZE
width: SIZE height: SIZE
fill: Color.GRAY
}
]
onKeyPressed: function(e: KeyEvent):Void{
if(e.code == KeyCode.VK_SPACE){
jogo.reset();
}
}
}
jogo.pecas
]
}
}[/sourcecode]
Terminamos a segunda parte desse tutorial! (segunda parte bem gigante neh...)
O segredo é estudar esse código, principalmente a funçao onMouseReleased que possui quase toda a lógica de funcionamento do jogo de damas. Só está faltando obrigar um jogador a comer uma peça do adversário quando puder. Atualmente isso só acontece se o jogador comeu a 1ª peça e é obrigado a comer a 2ª.
Até a próxima (e última) parte desse tutorial. o/
Meu amigo, sou iniciante em JavaFx, gostei muito desse tutorial de damas, Parabéns!
Você tem algum material que possa me passar de como chamar outra tela em JavaFx (um form que chame outro) e como fazer conexão com banco de dados?
Um abraço!
Mayckon Domingues.
nunca vi como abrir outra janela com JavaFX
mas a comunicaçao dom BD é igual java (JDBC ou Hibernate)
parece ser show
eu não entendi nada…eu queria saber de um jogo de damas que coma para trás,vce pode me arrumar um sem baixar?? se vce botasse isso no seu site com certeza ia entrar várias pessoas…eu posso até indicar para bastantes amigos…bjjjjss,faz isso por mim
quαl é o nome do jogo de dαmαs que come pαrα trαs??
bjuuuuss!!!
bem pessoal eu trabalhei o estagio todo a fazer a minha pap que era o jogo de dama e hoje no dia de entrega encontro isto. fdx que merda
Onde podemos baixar o código completo? No corpo do método que trata o evento do mouseReleased tem chaves (}) sobrando.
muito bem so tem um erro é a regra as peças devem esta nas casas brancas digo porq conheço a regra mais muito bem feito o seu trabalho
Poderia colocar o projeto para todos nós podermos baixa lo. Grato
Oi amigo, pode publicar seu projeto completo?