19
Jogos de tabuleiro Multiplayer Marco Antonio

Apostila de Jogos em Rede com Java

Embed Size (px)

DESCRIPTION

Como criar o jogo da velha usando Java. Pode ser jogado em rede, utilizando sockets. As telas são feitas com Swing.

Citation preview

Page 1: Apostila de Jogos em Rede com Java

Jogos de tabuleiroMultiplayerMarco Antonio

Page 2: Apostila de Jogos em Rede com Java

Apresentação

• Jogos multiplayer fazem uso de threads para gerenciar múltiplas tarefas, além de sockets para envio de pacotes entre computadores.

• Na aplicação a seguir temos vários exemplos de como isso pode ser implementado.

Page 3: Apostila de Jogos em Rede com Java

DadosDeConexao

package com.javagames.tabuleiro;

/** * Armazena os dados de conexao da aplicacao * * Porta local - utilizada para o ServerSocket * Porta remota - utilizada para o socket cliente * Servidor - nome/ip da maquina remota * O servidor + porta remota sao utilizados para enviar os dados a cada jogada * Nao e necessario indicar o nome/ip da maquina local * Nome do usuario - utilizado para personalizar sua partida * * @author marcoreis * */public class DadosDeConexao { private int portaLocal; private int portaRemota; private String servidor; private String nomeDoUsuario; {...Metodos de acesso...}}

Page 4: Apostila de Jogos em Rede com Java

UtilComunicacaopackage com.javagames.tabuleiro;import java.io.*;import java.net.*;import java.util.*;/** * Transporta os dados entre duas maquinas utilizando socket * Deve ser atualizada para suportar diferentes tipos de dados * Os metodos tem suporte apenas a Map * * @author marcoreis * */public class UtilComunicacao { /** * Abre um socket entre o cliente e o servidor * O servidor deve estar esperando (accept) esta requisicao * * @param dadosDeConexao Nome do servidor remoto e porta * @param mapa - dados que serao enviados */ public void enviaDadosParaComputadorRemoto(DadosDeConexao dadosDeConexao, Map mapa) { try { Socket socket = new Socket(dadosDeConexao.getServidor(), dadosDeConexao .getPortaRemota()); OutputStream outSocket = socket.getOutputStream(); ObjectOutputStream saida = new ObjectOutputStream(outSocket); saida.writeObject(mapa); saida.close(); outSocket.close(); } catch (Exception e) { e.printStackTrace(); } }

Page 5: Apostila de Jogos em Rede com Java

UtilComunicacao

/** * Sincroniza dois mapas * Por definicao, um mapa nao tem repeticao de chaves (keys) * Isso garante que nao havera posicoes repetidas * * @param mapaRecuperado * @return Mapa sincronizado */ public Map sincronizaMapas(Map<String, String> mapaRecuperado) { Map mapa = new HashMap(); for (Object o : mapaRecuperado.keySet()) { mapa.put(o.toString(), mapaRecuperado.get(o)); } return mapa; }

Page 6: Apostila de Jogos em Rede com Java

UtilComunicacao

/** * * E o outro lado do metodo enviaDadosParaComputadorRemoto * Enquanto o primeiro esta no cliente, este esta no servidor * Converte os dadso em Map, ou seja, nao suporta outros tipos de dados * * @param socket Conexao aberta entre cliente e servidor * @return Mapa enviado */ public Map extrairMapa(Socket socket) { try { InputStream dados = socket.getInputStream(); ObjectInputStream ois = new ObjectInputStream(dados); Object o = ois.readObject(); Map<String, String> mapaRecuperado = (Map<String, String>) o; return mapaRecuperado; } catch (Exception e) { e.printStackTrace(); return null; } }}

Page 7: Apostila de Jogos em Rede com Java

JogoDaVelha

package com.javagames.tabuleiro;

import java.awt.*;import java.awt.event.*;import java.util.*;

import javax.swing.*;

import com.javagames.util.*;

/** * Jogo da velha multiplayer * Utiliza sockets para comunicar as jogadas entre jogadores * * @author marcoreis * */@SuppressWarnings("serial")public class JogoDaVelha extends JFrame { private static final int QUANTIDADE_DE_CASAS = 3; private int ALTURA = 350; private int LARGURA = 300; private Map<String, String> mapaDeCasas; private String jogadorAtual; private Point pontoClicado; private DadosDeConexao dadosDeConexao; private UtilComunicacao utilComunicacao;

Page 8: Apostila de Jogos em Rede com Java

JogoDaVelha /** * MŽtodo construtor * Inicializacao dos parametros obrigatorios */ public JogoDaVelha() { setSize(LARGURA, ALTURA); setBackground(Color.BLUE); adicionaEventoCliqueDoMouse(); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); }

/** * Chama o construtor padrao * @param dados - Dados de conexao informado pelo usuario */ public JogoDaVelha(DadosDeConexao dados) { this(); this.dadosDeConexao = dados; setTitle("Bem-vindo, " + dados.getNomeDoUsuario()); }

/** * Adicionar listener para cliques do mouse */ private void adicionaEventoCliqueDoMouse() { addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { eventoCliqueDoMouse(e); } }); }

Page 9: Apostila de Jogos em Rede com Java

JogoDaVelha

/** * Algoritmo a ser implementado * @return Se o jogador atual ganhou ou nao */ private boolean ganhou() { try { int contador = 0; //Verifica se ganhou na vertical for (int i = 0; i < 3; i++) { //Verifica se as posicoes estao ocupadas pelo jogador atual for (int j = 0; j < 3; j++) {

if (getMapaDeCasas().get(i + "," + j) != null && getMapaDeCasas().get(i + "," + j).equals(jogadorAtual)) {

contador++;

}

//Caso tenha as tres posicoes ocupadas, retorna true, jogador atual ganhou

if (contador == 3) {

return true;

}

} //Quando muda de coluna, zera o contador contador = 0; } } catch (Exception e) { } return false; }

Page 10: Apostila de Jogos em Rede com Java

JogoDaVelha

/** * Calcula a celular que deve ser utilizada a partir do ponto clicado na tela * @param pontoClicado */ private void marcaPosicao(Point pontoClicado) { int indiceX = pontoClicado.x / (getTamanhoDaCasaX()); int indiceY = pontoClicado.y / (getTamanhoDaCasaY()); String posicao = indiceX + "," + indiceY; getMapaDeCasas().put(posicao, jogadorAtual); //Envia os dados para a thread do oponente, que esta esperando getUtilComunicacao().enviaDadosParaComputadorRemoto(dadosDeConexao, getMapaDeCasas()); setTitle(dadosDeConexao.getNomeDoUsuario() + ", voce jogou. Aguarde."); }

/** * * @return {@link} */ private UtilComunicacao getUtilComunicacao() { if (utilComunicacao == null) { utilComunicacao = new UtilComunicacao(); } return utilComunicacao; }

Page 11: Apostila de Jogos em Rede com Java

JogoDaVelha

/** * * @param pontoClicado Coordenadas do clique do usuario * @return Se o quadrante clicado est‡ ou nao ocupado */ private boolean posicaoJahMarcada(Point pontoClicado) { int indiceX = pontoClicado.x / (getTamanhoDaCasaX()); int indiceY = pontoClicado.y / (getTamanhoDaCasaY()); String posicao = indiceX + "," + indiceY; if (getMapaDeCasas().get(posicao) != null) { return true; } return false; }

/** * Calculo para definir o tamanho das celulas utilizadas. * Jamais utilize valores fixos, pois isso impede a evolucao do sistema * @return Tamanhos */ private int getTamanhoDaCasaY() { return ALTURA / QUANTIDADE_DE_CASAS; }

private int getTamanhoDaCasaX() { return LARGURA / QUANTIDADE_DE_CASAS; }

Page 12: Apostila de Jogos em Rede com Java

JogoDaVelha /** * Desenha/redesenha a tela a cada clique * Ou, na versao multiplayer, a cada jogada */ public void paint(Graphics g) { super.paint(g); //Vertical g.drawLine((LARGURA / 3), 30, (LARGURA / 3), ALTURA - 10); g.drawLine((LARGURA / 3) * 2, 30, (LARGURA / 3) * 2, ALTURA - 10); //Horizontal g.drawLine(10, ALTURA / 3, LARGURA - 10, ALTURA / 3); g.drawLine(10, (ALTURA / 3) * 2, LARGURA - 10, (ALTURA / 3) * 2); imprimeMapaNoTabuleiro(); // }

/** * Imprime o mapa no tabuleiro * A chave (key) do mapa esta no formato 'x,y' * Por isso temos o stringtokenizer que recupera cada valor separado pela ',' * Em seguida le cada posicao marcada do mapa, recuperando o jogador marcado * Por fim, desenha na celula x,y a imagem respectiva * O loop le todos os elementos que compoe o mapa naquele momento * */ public void imprimeMapaNoTabuleiro() { for (Object o : getMapaDeCasas().keySet()) { //o (formato x,y) try { StringTokenizer s = new StringTokenizer(o.toString(), ","); int posicaoX = new Integer(s.nextToken()) * getTamanhoDaCasaX() + 30; int posicaoY = new Integer(s.nextToken()) * getTamanhoDaCasaY() + 50; // String jogador = getMapaDeCasas().get(o); desenhaIcone(posicaoX, posicaoY, jogador); // } catch (Exception e) { System.out.println(e); } } }

Page 13: Apostila de Jogos em Rede com Java

JogoDaVelha

/** * Desenha a respectiva imagem dada uma posicao e um jogador * @param posicaoX * @param posicaoY * @param jogador */ private void desenhaIcone(int posicaoX, int posicaoY, String jogador) { Graphics g = getGraphics(); if (jogador.equals("X")) { g.drawImage(UtilImagem.getImagem("xis.png"), posicaoX, posicaoY, this); } else { g.drawImage(UtilImagem.getImagem("zero.png"), posicaoX, posicaoY, this); } }

/** * Armazena todas as jogadas ate o presente instante * @return Mapa atual */ public Map<String, String> getMapaDeCasas() { if (mapaDeCasas == null) { mapaDeCasas = new HashMap<String, String>(); } return mapaDeCasas; }

public void setMapaDeCasas(Map<String, String> mapaDeCasas) { this.mapaDeCasas = mapaDeCasas; }

Page 14: Apostila de Jogos em Rede com Java

JogoDaVelha /** * Efetua todas as operacoes referentes ao evento clique do mouse * A cada jogada do usuario, o jogo deve aplicar todas as regras definidas * Alem de informar se algo nao esta correto * @param e Ponto clicado na tela */ private void eventoCliqueDoMouse(MouseEvent e) { pontoClicado = e.getPoint(); defineJogador(); if (posicaoJahMarcada(pontoClicado)) { JOptionPane.showMessageDialog(null, "Posicao ja ocupada.", "Atencao", JOptionPane.WARNING_MESSAGE); } else { repaint(); marcaPosicao(pontoClicado); } if (ganhou()) { JOptionPane.showMessageDialog(null, "Ganhou"); } }

/** * Nas duas primeiras jogadas da partida verifica quem e quem * O primeiro jogador sera '0' * O segundo sera 'X' */ private void defineJogador() { if (getMapaDeCasas().keySet().size() == 0 && jogadorAtual == null) { jogadorAtual = "0"; } else if (getMapaDeCasas().keySet().size() == 1 && jogadorAtual == null) { jogadorAtual = "X"; } }}

Page 15: Apostila de Jogos em Rede com Java

ThreadJogoDaVelha

package com.javagames.tabuleiro;

import java.net.*;import java.util.*;

public class ThreadJogoDaVelha extends Thread { private DadosDeConexao dadosDeConexao; private JogoDaVelha jogo; private UtilComunicacao utilComunicacao;

/** * Metodo construtor que exige os dados de conexao e o seu tabuleiro * * Esta classe gerencia as jogadas do oponente atraves do socket * Observacao: Nao ha controle para bloquear o jogador depois do clique * Isso permite que alguem jogue duas vezes * * @param jogo Tabuleiro do seu jogo * @param dados Informacoes necessarias para conectar os tabuleiros */ public ThreadJogoDaVelha(JogoDaVelha jogo, DadosDeConexao dados) { this.dadosDeConexao = dados; this.jogo = jogo; }

Page 16: Apostila de Jogos em Rede com Java

ThreadJogoDaVelha /** * A thread fica aguardando ate a jogada do oponente * Apos a jogada, bloqueia a thread (accept) * Assim que o oponente jogar, sincroniza os mapas * */ @SuppressWarnings("unchecked") public void run() { // while (true) { try { jogo.repaint(); Thread.sleep(1000); //Aguarda jogada do oponente //Bloqueia a thread ServerSocket server = new ServerSocket(dadosDeConexao.getPortaLocal()); Socket socket = server.accept(); //O oponente jogou jogo.setTitle(dadosDeConexao.getNomeDoUsuario() + ", agora Ž sua vez."); //Processa jogada //Recupera o mapa de jogadas do oponente Map<String, String> mapaRecuperado = getUtilComunicacao().extrairMapa( socket); //Sincroniza o seu tabuleiro Map mapaDeCasas = getUtilComunicacao().sincronizaMapas(mapaRecuperado); jogo.setMapaDeCasas(mapaDeCasas); jogo.imprimeMapaNoTabuleiro(); //Desbloquear os recursos apos sua utilizacao socket.close(); server.close(); // } catch (Exception e) { System.out.print("..."); } } }

Page 17: Apostila de Jogos em Rede com Java

ThreadJogoDaVelha

private UtilComunicacao getUtilComunicacao() {

if (utilComunicacao == null) {

utilComunicacao = new UtilComunicacao();

}

return utilComunicacao;

}

}

Page 18: Apostila de Jogos em Rede com Java

Splash Screen

• No Netbeans, crie uma tela com os componentes indicados.

• Inicie seu jogo e informe os dados do oponente.

• O botão de conectar deve iniciar uma thread do JogoDaVelha passando todos os dados necessários (veja o próximo slide).

Page 19: Apostila de Jogos em Rede com Java

Conexão

private void btnConectarActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnConectarActionPerformed

DadosDeConexao dados = new DadosDeConexao();

dados.setPortaLocal(new Integer(txtPortaLocal.getText()));

dados.setPortaRemota(new Integer(txtPortaServidor.getText()));

dados.setServidor(txtServidor.getText());

dados.setNomeDoUsuario(txtNome.getText());

JogoDaVelha jogo = new JogoDaVelha(dados);

new ThreadJogoDaVelha(jogo, dados).start();

setVisible(false);

}//GEN-LAST:event_btnConectarActionPerformed