Jogos de tabuleiro Multiplayer Marco Antonio. Apresentação Jogos multiplayer fazem uso de threads...

19
Jogos de tabuleiro Multiplayer Marco Antonio

Transcript of Jogos de tabuleiro Multiplayer Marco Antonio. Apresentação Jogos multiplayer fazem uso de threads...

Page 1: Jogos de tabuleiro Multiplayer Marco Antonio. Apresentação Jogos multiplayer fazem uso de threads para gerenciar múltiplas tarefas, além de sockets para.

Jogos de tabuleiroMultiplayerMarco Antonio

Page 2: Jogos de tabuleiro Multiplayer Marco Antonio. Apresentação Jogos multiplayer fazem uso de threads para gerenciar múltiplas tarefas, além de sockets para.

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: Jogos de tabuleiro Multiplayer Marco Antonio. Apresentação Jogos multiplayer fazem uso de threads para gerenciar múltiplas tarefas, além de sockets para.

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: Jogos de tabuleiro Multiplayer Marco Antonio. Apresentação Jogos multiplayer fazem uso de threads para gerenciar múltiplas tarefas, além de sockets para.

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: Jogos de tabuleiro Multiplayer Marco Antonio. Apresentação Jogos multiplayer fazem uso de threads para gerenciar múltiplas tarefas, além de sockets para.

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: Jogos de tabuleiro Multiplayer Marco Antonio. Apresentação Jogos multiplayer fazem uso de threads para gerenciar múltiplas tarefas, além de sockets para.

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: Jogos de tabuleiro Multiplayer Marco Antonio. Apresentação Jogos multiplayer fazem uso de threads para gerenciar múltiplas tarefas, além de sockets para.

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: Jogos de tabuleiro Multiplayer Marco Antonio. Apresentação Jogos multiplayer fazem uso de threads para gerenciar múltiplas tarefas, além de sockets para.

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: Jogos de tabuleiro Multiplayer Marco Antonio. Apresentação Jogos multiplayer fazem uso de threads para gerenciar múltiplas tarefas, além de sockets para.

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 (posicao[i][j] != null && posicao[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: Jogos de tabuleiro Multiplayer Marco Antonio. Apresentação Jogos multiplayer fazem uso de threads para gerenciar múltiplas tarefas, além de sockets para.

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: Jogos de tabuleiro Multiplayer Marco Antonio. Apresentação Jogos multiplayer fazem uso de threads para gerenciar múltiplas tarefas, além de sockets para.

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: Jogos de tabuleiro Multiplayer Marco Antonio. Apresentação Jogos multiplayer fazem uso de threads para gerenciar múltiplas tarefas, além de sockets para.

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: Jogos de tabuleiro Multiplayer Marco Antonio. Apresentação Jogos multiplayer fazem uso de threads para gerenciar múltiplas tarefas, além de sockets para.

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("zero.png"), posicaoX, posicaoY, this); } else { g.drawImage(UtilImagem.getImagem("xis.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: Jogos de tabuleiro Multiplayer Marco Antonio. Apresentação Jogos multiplayer fazem uso de threads para gerenciar múltiplas tarefas, além de sockets para.

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: Jogos de tabuleiro Multiplayer Marco Antonio. Apresentação Jogos multiplayer fazem uso de threads para gerenciar múltiplas tarefas, além de sockets para.

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: Jogos de tabuleiro Multiplayer Marco Antonio. Apresentação Jogos multiplayer fazem uso de threads para gerenciar múltiplas tarefas, além de sockets para.

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: Jogos de tabuleiro Multiplayer Marco Antonio. Apresentação Jogos multiplayer fazem uso de threads para gerenciar múltiplas tarefas, além de sockets para.

ThreadJogoDaVelha

private UtilComunicacao getUtilComunicacao() {

if (utilComunicacao == null) {

utilComunicacao = new UtilComunicacao();

}

return utilComunicacao;

}

}

Page 18: Jogos de tabuleiro Multiplayer Marco Antonio. Apresentação Jogos multiplayer fazem uso de threads para gerenciar múltiplas tarefas, além de sockets para.

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: Jogos de tabuleiro Multiplayer Marco Antonio. Apresentação Jogos multiplayer fazem uso de threads para gerenciar múltiplas tarefas, além de sockets para.

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