Central Habbo Forum
Ainda não está Registrado ? , Então está esperando o que ? , Registre-se e disfrute do melhor do Fórum, se já for registrado, só faça o login

(Observações : Usuários não registrados não tem direitos a nenhum conteúdo)
Buscar
 
 

Resultados por:
 


Rechercher Busca avançada

Conectar-se

Esqueci minha senha

Últimos assuntos
» gente o melhor habbo q existe
Seg Jan 30 2012, 12:27 por lucas-nobile@hotmail.com

» [Tutorial GameMaker] Variáveis
Sex Nov 18 2011, 09:12 por admin

» Survival of the Ball 1.0
Sex Out 07 2011, 00:54 por admin

» Criando Habbo Retro (Sem Hamachi)
Dom Set 11 2011, 13:54 por -Desconectado

» Como criar um habbo V65 com Bling + Valentim 2011 + Bola + Freeze e sem Bug
Dom Ago 28 2011, 15:46 por admin

» Master emulator 100% fixado r63.2
Ter Ago 23 2011, 19:52 por idiegofelicio

» Server Habbo Pirata com VIP Club e HC Club
Sab Ago 20 2011, 11:39 por admin

» Calculadoras no Delphi 7
Dom Ago 14 2011, 20:49 por ♥Giulia♥

» [TutorialGamemaker]Criando Jogo de plataforma simples
Qua Ago 10 2011, 13:05 por admin

Palavras chave

Flux RSS


Yahoo! 
MSN 
AOL 
Netvibes 
Bloglines 


Social bookmarking

Social bookmarking digg  Social bookmarking delicious  Social bookmarking reddit  Social bookmarking stumbleupon  Social bookmarking slashdot  Social bookmarking yahoo  Social bookmarking google  Social bookmarking blogmarks  Social bookmarking live      

Conservar e compartilhar o endereço de Central Habbo Forum em seu site de social bookmarking

Conservar e compartilhar o endereço de Central Habbo Forum em seu site de social bookmarking


[Game Maker]Tutorial - Como fazer um jogo multiplayer online - Parte II

Ir em baixo

[Game Maker]Tutorial - Como fazer um jogo multiplayer online - Parte II

Mensagem  admin em Dom Fev 27 2011, 01:14

Tutorial – Como fazer um jogo multiplayer online
Por Janx
Parte II: Fazendo um Jogo

Antes de iniciar:
Na primeira parte já aprendemos bem como é o conceito para fazer um jogo online, agora iremos ver a parte pratica. Usaremos a 39Dll e o Game Maker 7 PRO.
É necessário saber GML em nível intermediário ou superior para completar o tutorial sem grandes dificuldades. Todo o código é explicado em maior parte direto nos comentários, apenas alguns detalhes são explicados fora do código.

Um novo projeto:
Para fazer o jogo, vamos precisar importar alguns scrips, mas como são vários e o Game Maker não importa eles separando por pastas vou disponibilizar um projeto com os scripts já prontos.

Primeiramente precisaremos desse pacote: Download [Contem: Projeto.gmk e 39Dll.dll]
Depois de baixá-lo, extraia para uma pasta qualquer. Serão extraídos dois arquivos:

Projeto.gmk
: Projeto já iniciado contendo apenas as funções da 39Dll.

39Dll.dll: A DLL deve estar sempre acompanhada do executável do jogo, é nela que o jogo encontra as funções a serem executadas.

Abra o Projeto e de uma olhada nos scripts, são vários não é mesmo? A maioria nós nem iremos usar, mas não iremos apagar nenhum porque não sabemos se vamos precisar deles no futuro.

O menu:
Antes de qualquer coisa, vamos fazer um menu bem simples só para testar mesmo. Faça 2 objetos: obj_btmHost e obj_btmClient e crie uma sprite para cada um. Para isso você talvez queira saber o que eles farão então aqui vai uma pequena explicação:

obj_btmHost: Esse botão será usado para criar um Servidor, fazer um Host. Lembra da primeira aula? O Servidor é onde os jogadores conectam.

obj_btmClient: Agora ficou fácil, esse é o Client, ao clicar nesse botão será possível conectar em algum servidor.

Esses são apenas botões, não terão funções muito complexas. Antes de começarmos a adicionar código, crie mais 2 objetos (Esses não precisam de sprites) e marque-os como Persistent:
obj_Host
obj_Client



Vamos começar pelo botão de host:
Faça um evento “Mouse Left Released” e nele adicione um “Execute a piece of Code”.
Escreva o seguinte:

<gml class="brush: gml;">//Botão para fazer um Servidor
global.ServerName = get_string("Digite o nome do Servidor","");
instance_create(0,0,obj_Host);</gml>
Não tem muito segredo, é um código bem simples. Não vou explicar, pois se você não entendeu o que foi feito aqui você deve estudar mais GML antes de querer fazer um jogo online.
O botão do Client é praticamente a mesma coisa, só mude o código dele para o seguinte:

<gml class="brush: gml;">//Botão para conectar em um Servidor
global.connectIP = get_string("Digite o IP do Servidor","127.0.0.1");
instance_create(0,0,obj_Client);</gml>
Simples também.
Agora crie um outro objeto “Controlador” de sua preferência, eu gosto de chamá-lo de GAME (Deixe ele como Persistent). Nesse novo objeto, adicione um evento Create e coloque o seguinte código:

<gml class="brush: gml;">global.Nick = get_string("Digite seu Nick: ",""); //Pegar o nick do jogador
global.Server = 0; //Guarda o Socket do Servidor.
global.MyID = -1; //ID online do jogador
global.MaxPlayers = 0;

dllinit("39dll.dll",1); //Inicializar funções de Sockets da DLL.</gml>
O código junto dos comentários já está explicado, não vou entrar em mais detalhes aqui.
Feito isso coloque esse objeto na PRIMEIRA room do jogo, se você ainda não criou nenhuma, faça-o agora, vou usar ela como menu então a minha vai ter nome rm_Menu. O GAME deve ser o primeiro objeto a ser criado. Aproveite e monte o seu menu como quiser o meu ficou assim:

[Você precisa estar registrado e conectado para ver esta imagem.]

Já estamos prontos para iniciar a programar o Servidor.

Iniciando o Servidor:
Vamos para o objeto obj_Host. No evento Create adicione o seguinte:
<gml class="brush: gml;">
//Criar servidor
global.Server = tcplisten(5068,5,1); //Inicializa o Servidor, fica em espera por conexões na porta 5068.
//Você pode mudar os argumentos dessa função como preferir.
//tcplisten(PORTA,CONEXÕES SIMUNTANEAS, MODO);
//PORTA -> Porta para conectar
//CONEXÕES SIMUNTANEAS -> Antes do jogador entrar mesmo no jogo, sua conexão deve ser aceita, enquanto isso ele ficara na "espera".
//Isso é para quantos você quer deixar na espera. Não é preciso um valor muito alto.
//MODO -> deixe o valor em 1, senão seu servidor ficará travado até alguem conectar

if (!global.Server) //Caso não tenha inicializado corretamente passar uma mensagem de erro.
{instance_destroy();
show_message("Erro ao criar o servidor");
exit;}

global.MaxPlayers = 10; //Limite de jogadores

//Criar lista de Jogadores.
for (i = 0; i < global.MaxPlayers; i += 1)
{
players[i,PL_SOCK] = -3; //Socket do player [Só usado no Host]
players[i,PL_NICK] = ""; //Nick do player
}

//Adicionar informações do servidor na lista [Servidor sempre é o 0]
players[0,PL_SOCK] = global.Server;
players[0,PL_NICK] = global.Nick;
global.MyID = 0;

room_goto(rm_WaitingRoom); //Depois de inicializar tudo corretamente ir para a tela de espera.
//Esse objeto é "Persistent", pois isso não será destruido na troca de rooms.</gml>
Comentei bastante o código para ficar fácil de entender. Mas temos que adicionar algumas Constantes ao nosso jogo, repare que ao criar a lista de jogadores foram usados os seguintes valores: PL_SOCK e PL_NICK, esses são Constantes e devem ser declarados para o Game Maker.
Vá em Global Game Settings, aba Constants. Insira os 3 valores da seguinte forma:
Name (Nome) Value (Valor)
PL_NICK 1
PL_SOCK 0

Muito bem, o evento Create está completo.


Conectando no Servidor:
Vamos para o obj_Client para iniciar a conexão, no Create coloque o código:<gml class="brush: gml;">
global.Server = tcpconnect(global.connectIP,5068,1);

if (!global.Server) //Se não conectarmos sair e exibir mensagem de erro
{instance_destroy();
show_message("Erro ao conectar");
exit;}

room_goto(rm_WaitingRoom);</gml>
Esse é bem curto, apenas conectamos no servidor e verificamos se foi possível a conexão. Se conectar vamos para a próxima tela, senão ficamos por aqui e exibimos uma mensagem de erro.


A estrutura de uma mensagem:
Antes de seguirmos para o próximo item, é preciso saber como é a estrutura das mensagens trocadas entre Client e Servidor. Na verdade é muito simples, mas sempre varia de mensagem para mensagem. A estrutura básica é assim:

Primeiros dois bytes = Tamanho da mensagem em bytes.
Terceiro byte = ID da mensagem. Serve para identificar qual o tipo de mensagem é essa, para que possamos manipulá-la corretamente.
Restantes = “Mensagem”.

Vamos ver um exemplo em que eu envio uma String “Testando” que tem ID de mensagem 5:
<gml class="brush: gml;">
clearbuffer(); //Limpa o buffer interno, aqui é como uma Carta que vamos enviar, primeiro precisamos de um papel em branco, não é?
writebyte(5); //ID
writestring(“Testando”); //Mensagem
sendmessage(SOCKET); //Envia a mensagem para o Socket</gml>

Ué, mas cade os dois primeiros bytes de tamanho?
Esses são adicionados automaticamente pela DLL. Você não precisa se preocupar com eles.

Mas eles não são inúteis? Vou usar eles só para deixar a mensagem maior?
2 Bytes é pouca coisa, eles não vão te atrapalhar, eles também são lidos automaticamente. Se você acha que esses 2 bytes vão causar lags, está enganado. Esses bytes são necessários, é com eles que a DLL pode saber qual é o tamanho da mensagem para poder escrevê-la no buffer (Para podermos manipular depois). Imagine a mensagem recebida:

[Tamanho Total = 11 bytes]
Byte1 Valor: 9 (11 bytes contando esses 2, mas para o buffer eles não são contados)
Byte2

Os seguintes são carregados no buffer:
Byte3 ---- Valor: 5
Byte4 até Byte 11 ---- Valor: “Testando”

Nosso buffer ficaria assim:
Byte1 = 5
Byte2 = T
Byte3 = e
Byte4 = s
Byte5 = t
Byte6 = a
Byte7 = n
Byte8 = d
Byte9 = o

A leitura do buffer seria dessa forma:
IDdaMensagem = readbyte(); //Le o primeiro byte
Mensagem = readstring(); //Le todo o resto

No final teríamos os valores:
IDdaMensagem = 5
Mensagem = “Testando”

Ao usar o readbyte, readshort ou qualquer outra função de leitura os bytes são lidos e RETIRADOS do buffer (As funções retornam esses bytes removidos do buffer).
Então em muitos casos é preciso guardar esses bytes em alguma variável, mesmo que temporária.


Aceitando novas conexões:
Para aceitar novas conexões não é muito difícil, o código é bem curto. Vamos para o evento Step do objeto obj_Host e adicione o seguinte código:
<gml class="brush: gml;">//Aceitar novas conexões
var i, sock, newPL;
sock = tcpaccept(global.Server, 1);
if (!sock) //Se não existirem novas conexões
{exit;} //sair do script

for (i = 0; i < global.MaxPlayers; i+=1)
{
if (!players[i,PL_SOCK])
{
newPL = i;
break;
}
}

if newPL //Tem vagas no servidor
{
players[newPL,PL_SOCK] = sock;

//Enviar uma mensagem para o jogador, falando que ele foi aceito
clearbuffer(); //Limpar o buffer
writebyte(MSG_CONEXAO_ACEITA); //Byte identificador da mensagem
writebyte(newPL); //Enviar o ID do jogador
writebyte(global.MaxPlayers); //Enviar quantidade maxima de jogadores
sendmessage(sock); //Enviar mensagem
}
else //Servidor cheio
{
//Enviar uma mensagem para o jogador, falando que o servidor já está cheio e ele não pode se conectar.
clearbuffer(); //Limpar o buffer
writebyte(MSG_SERVIDOR_CHEIO); //Byte identificador da mensagem
sendmessage(sock); //Enviar mensagem

closesocket(sock);
}</gml>
Esse código é um pouquinho mais complicado. Agora nós recebemos a conexão do jogador e se houver espaço no servidor permitimos que ele entre, caso contrário enviamos uma mensagem falando que o servidor está cheio e terminamos a conexão com ele.
Note que aqui temos mais duas constantes:
MSG_CONEXAO_ACEITA
MSG_SERVIDOR_CHEIO


Crie elas também, os valores você que escolhe, mas eles NÃO podem ser maiores que 255 nem menores do que 0! Ou seja, são valores entre 0 e 255. Perceba que essas constantes tem um prefixo diferente das outras duas, elas começam com um “MSG_”, fizemos isso para identificar o tipo de uso para ela. Então para identificar as mensagens vamos usar constantes com prefixo MSG_. Logo não faz diferença se elas possuem o mesmo valor de outra constante, contando que não seja uma constante do tipo MSG_. Criei as minhas assim:
Nome Valor
MSG_CONEXAO_ACEITA 0
MSG_SERVIDOR_CHEIO 255

Recebendo as mensagens iniciais:
Ok, agora precisamos programar para o Client receber as mensagens do servidor, no evento Step do obj_Client coloque o seguinte:
<gml class="brush: gml;">//Receber mensagens do servidor
var size, msgID;
size = 1;

while (size)
{
size = receivemessage(global.Server); //Retorna a quantidade de bytes recebidos

if (!size) //Se não recebermos nada, sair desse script.
{exit;}

msgID = readbyte(); //Lemos o primeiro byte da mensagem, ou seja o ID da mensagem.

switch (msgID)
{
case MSG_CONEXAO_ACEITA: //Fui aceito no servidor
global.MyID = readbyte(); //Pegamos o meu ID
global.MaxPlayers = readbyte(); //Lemos a quantidade de jogadores maxima no servidor

//Criar lista de Jogadores.
for (i = 0; i < global.MaxPlayers; i += 1)
{
//players[i,PL_SOCK] = -3; //Socket do player [Só usado no Host]
players[i,PL_NICK] = ""; //Nick do player
}
players[global.MyID,PL_NICK] = global.Nick;

//Para dar continuidade agora vamos enviar o meu nick para o servidor
//e ele retornara com o nick de todos os jogadores
clearbuffer();
writebyte(MSG_PLDATA);
writestring(global.Nick);
sendmessage(global.Server);
break;

case MSG_SERVIDOR_CHEIO:
closesocket(global.Servidor); //Fechamos a conexão
show_message("Servidor lotado"); //Exibimos o erro
instance_destroy();
room_goto(rm_Menu); //Voltamos para o menu
exit;
break;
}
}</gml>
Lembre-se de adicionar a constante: MSG_PLDATA.
Agora já temos o sistema inicial pronto, agora é só troca de mensagens. Ainda precisamos fazer para o Servidor receber as mensagens, mas é bem parecido com o sistema do Client, possui apenas algumas mudanças.

Recebendo as mensagem do Client:
Para receber as mensagens do client vamos usar o obj_Host, no step adicione outro execute a piece of code, para não deixar o primeiro muito comprido e facilitar a procura de partes especificas no código depois se for necessário.
Assim como o do client, adicionando apenas um loop for e editando a mensagem recebida como necessário:
<gml class="brush: gml;">//Receber mensagens do Client
var size, msgID;

for (iPL = 1; iPL < global.MaxPlayers; iPL += 1) //Precisamos receber a mensagem de cada jogador
{ //Usamos "iPL" pois depois serão feitos outros loops e usar a variavel "i" pode gerar conflitos
size = 1;
while (size)
{
size = receivemessage(players[iPL,PL_SOCK]); //Receber a mensagem do socket de cada player

if (!size) //Se não recebermos nada, sair desse script e passar para o próximo player
{break;}

msgID = readbyte(); //Lemos o primeiro byte da mensagem, ou seja o ID da mensagem.

switch (msgID)
{
case MSG_PLDATA: //Pegar dados do jogador
var nick;
nick = readstring(); //Ler o nick do jogador.

//Agora guardamos o nick na variavel do jogador:
players[iPL, PL_NICK] = nick;
//Não precisamos guardar o ID porque isso já foi feito quando ele se conectou!

//Agora vamos repassar para os outros jogadores:
clearbuffer();
writebyte(MSG_PLDATA);
writebyte(iPL); //Os outros jogadores só recebem dados do servidor, então precisam saber o ID de qual player são esses dados
writestring(nick);
for (i=1; i < global.MaxPlayers; i+=1) //Como são varios jogadores, precisamos enviar para todos eles
{ //Usando um loop for isso fica bem facil! Repare que começamos do 1, porque o 0 é sempre o servidor.
if (i != iPL) //Não precisamos repassar a mensagem para quem a enviou
{sendmessage(players[i,PL_SOCK]);}
}

//O Hoster possui os dados de todos os jogadores então ele mesmo pode repassar os nicks dos demais players
for (i = 0; i < global.MaxPlayers; i += 1)
{
if (i != iPL) //Não enviar o nick do proprio jogador para ele mesmo
{
clearbuffer();
writebyte(MSG_PLDATA);
writebyte(i);
writestring(players[i,PL_NICK]);
sendmessage(players[iPL,PL_SOCK]);
}
}
break;
}
}
}</gml>
Agora precisamos fazer os Clients receberem essa mensagem, vamos voltar para o obj_Client e adicionar uma outra mensagem a ser recebida, dessa vez vou passar apenas a parte que será adicionada:
<gml class="brush: gml;">
case MSG_PLDATA:
players[readbyte(), PL_NICK] = readstring();
break;
</gml>
Esse é bem curto, não é? Acho que nem precisamos de explicação. Apenas pegamos o ID de quem enviou a mensagem e usamos o valor na posição da array, depois lemos o Nick enviado par atribuir o valor na array.

A partir desse momento já são recebidos todos os dados de cada jogador e a base está pronta. Vamos adicionar um evento Draw no objeto GAME apenas para visualizar a lista e testarmos o código:
<gml class="brush: gml;">
if room = rm_WaitingRoom
{
draw_text(200,16,"Tela de Espera");
}

if instance_exists(obj_Client)
{
for (i=0; i < global.MaxPlayers; i += 1)
{
draw_text(5,32+i*16, string(i)+" "+obj_Client.players[i,PL_NICK]);
}
}
else if instance_exists(obj_Host)
{
for (i=0; i < global.MaxPlayers; i += 1)
{
draw_text(5,32+i*16, string(i)+" Sock: "+string(obj_Host.players[i,PL_SOCK])+" Nick: "+obj_Host.players[i,PL_NICK]);
}
}</gml>

Para testar, crie o executável do jogo, copie ele e a DLL para outra pasta, de forma que você tenha duas cópias do jogo. Abra as 2, em cada uma você coloca um Nick diferente, em uma das telas você Cria um servidor, na outra Conecta com o IP 127.0.0.1.
Se tudo correr bem você verá uma lista nas duas telas, na do servidor contendo o valor do socket e Nick de cada jogador, na do client uma lista contendo apenas os Nicks. Se você recebeu algum erro, volte o tutorial e confira todos os códigos novamente.


Vou terminar essa aula por aqui. Na próxima colocaremos um chat e um botão na sala para começarmos o “jogo”, que será apenas um circulo de cada jogador se movendo pela tela. Finalizando o tutorial por completo.

Recomendo que você leia as descrições das funções dos scripts Buffer -> Writing e Reading. Para entender melhor como funciona cada um dos tipos de dados.

Você não vai postar uma engine do tutorial?
Não! Se eu postar uma engine a grande maioria irá apenas baixá-la e editar como quiser. Postando apenas o tutorial vocês terão que ler para fazer a engine! Assim sei que meu tempo para escrever o tutorial não foi desperdiçado e vocês aprenderão muito mais.
Se você seguir o tutorial a risca, não terá problemas para fazer a mesma engine que eu fui fazendo conforme escrevia o tutorial. Está tudo explicado passo a passo, exatamente da forma que eu fiz.

Creditos:Janx ADM do Gmbr Forum
Linck do Tuto na GMBR

__________________________

Sou Fãn De:
[Você precisa estar registrado e conectado para ver esta imagem.]
avatar
admin
Administradores
Administradores

Mensagens Mensagens : 201
Pontos Pontos : 572
Reputação Reputação : 64
Data de inscrição Data de inscrição : 15/06/2010
Idade Idade : 23
Localização Localização : Curitiba-PR

Ver perfil do usuário http://centralhabbo.forumbrasil.net

Voltar ao Topo Ir em baixo

Voltar ao Topo

- Tópicos similares

 
Permissão deste fórum:
Você não pode responder aos tópicos neste fórum