Na aula anterior vimos como serializar avatares (seus submeshes) e podemos colocá-los, com as texturas, disponíveis na Rede (internet).
O que vamos fazer para completar nosso sistema (o tal Metaverso, onde os avatares de jogos são independentes) é ver como o jogador pode definir qual "corpo teleportável" vai assuimir a "alma" designada para ele pelo seu número de "entrante".
Vamos ver como ficam os dois scripts: o do Compacto Duplo (que chamamos de : ServCli e o script controlador do movimento do avatar e instancialização. Dê uma olhada geral, que depois vamos analisar os detalhes. Primeiro o ServCli:
var IPServidor = "127.0.0.1";
var IPServ = "";
var endSubmeshTroncoI="www.dmu.com/troncoAVATAR1.data";
var endTexturaTroncoI="www.dmu.com/troncoAVATAR1.jpg";
var endSubmeshBracosI="www.dmu.com/bracosAVATAR1.data";
var endTexturaBracosI="www.dmu.com/bracosAVATAR1.jpg";
var endTexturaPernasI="www.dmu.com/pernasAVATAR1.jpg";
var escalaTroncoI = "0.30";
var escalaBracosI = "0.30";
var endSubmeshTronco =" ";
var endTexturaTronco =" ";
var endSubmeshBracos =" ";
var endTexturaBracos =" ";
var endTexturaPernas =" ";
var escalaTronco= 0.30;
var escalaBracos = 0.30;
function OnGUI (){
if (Network.peerType == NetworkPeerType.Disconnected){
IPServidor = GUI.TextField(new Rect(120,10,100,20),IPServidor);
GUI.Label(new Rect(10,90,400,20),"Corpo: endereco dos meshes, textura e escala");
endSubmeshTroncoI = GUI.TextField(new Rect(10,110,300,20),endSubmeshTroncoI );
endTexturaTroncoI = GUI.TextField(new Rect(10,130,300,20),endTexturaTroncoI);
escalaTroncoI = GUI.TextField(new Rect(10,150,50,20),escalaTroncoI);
GUI.Label(new Rect(10,170,400,20),"Bracos: endereco dos meshes,textura e escala");
endSubmeshBracosI = GUI.TextField(new Rect(10,190,300,20),endSubmeshBracosI);
endTexturaBracosI = GUI.TextField(new Rect(10,210,300,20),endTexturaBracosI);
escalaBracosI = GUI.TextField(new Rect(10,230,50,20),escalaBracosI);
GUI.Label(new Rect(10,250,250,20),"Pernas: endereco da textura");
endTexturaPernasI = GUI.TextField(new Rect(10,270,300,20),endTexturaPernasI);
if (GUI.Button (new Rect(10,10,100,30),"Conectar")){
Carregar();
Network.Connect(IPServidor, 25000);
}
if (GUI.Button (new Rect(10,50,100,30),"Start Servidor")){
Carregar();
Network.InitializeServer(5, 25000,false);
// Proclamação no Servidor de que foi iniciado o servidor
for (var go : GameObject in FindObjectsOfType(GameObject)){
go.SendMessage("noAr", SendMessageOptions.DontRequireReceiver);
}
}
}
else{ //Se startou ou conectou
if(Network.isServer){
IPServ = Network.player.ipAddress;
GUI.Label(new Rect(140,20,250,40),"Para jogador usar: "+IPServ );
}
if (GUI.Button (new Rect(10,10,100,30),"Sair")){
if(Network.isServer){
networkView.RPC("DesligarCL", RPCMode.Others,"Vai desligar");
}
Network.Disconnect();
Application.Quit();
}
}
}
function Carregar(){
endSubmeshTronco =endSubmeshTroncoI;
endTexturaTronco =endTexturaTroncoI;
endSubmeshBracos =endSubmeshBracosI;
endTexturaBracos =endTexturaBracosI;
endTexturaPernas =endTexturaPernasI;
escalaTronco = parseFloat(escalaTroncoI);
escalaBracos= parseFloat(escalaBracosI);
}
function OnConnectedToServer() {
// Proclamação gerada no Clente quando feita conexão
for (var go : GameObject in FindObjectsOfType(GameObject))
go.SendMessage("noAr", SendMessageOptions.DontRequireReceiver);
}
@RPC
function DesligarCL(recebido : String){
Application.Quit();
}
@RPC
function CarregaCL(ent: String,mT: String,tT: String,mB: String,tB: String,tP: String,eT: float,eB: float){
//mesh headbody
var GOH = GameObject.Find("headbody" + ent);
var urlH= mT;
var downloadH = WWW(urlH);
yield downloadH;
var meshH = MeshSerializer.ReadMeshFromWWW(downloadH );
if (!meshH) return;
var meshFilterH : MeshFilter = GOH.GetComponent(MeshFilter);
meshFilterH.mesh = meshH;
GOH.transform.localScale =Vector3.Scale(GOH.transform.localScale,Vector3(eT,eT,eT));
//textura headbody
var urlTH = tT;
var downloadTH = WWW(urlTH);
yield downloadTH;
GOH.renderer.materials[0].mainTexture = downloadTH.texture;
//mesh arms
var GOA =GameObject.Find("arms" +ent);
var urlA = mB;
var downloadA = WWW(urlA);
yield downloadA;
var meshA = MeshSerializer.ReadMeshFromWWW( downloadA );
if (!meshA) return;
var meshFilterA : MeshFilter = GOA.GetComponent(MeshFilter);
meshFilterA.mesh = meshA;
GOA.transform.localScale =Vector3.Scale(GOA.transform.localScale,Vector3(eB,eB,eB));
//textura arms
var urlTA = tB;
var downloadTA = WWW(urlTA);
yield downloadTA;
GOA.renderer.materials[0].mainTexture = downloadTA.texture;
//textura legs
var GOL =GameObject.Find("legs" +ent);
var urlTL = tP;
var downloadTL = WWW(urlTL);
yield downloadTL;
GOL.renderer.materials[0].mainTexture = downloadTL.texture;
}
Vamos ver então o script controlador de avatares, que também cuida da instancialização.var velocidade = 6.0; var velSalto = 8.0; var gravidade = 20.0; private var deltaDirecao : Vector3; var Player : GameObject; var contr : CharacterController; var playerClone = ""; var avatar0: Transform; var avatar1: Transform; var avatar2: Transform; var avatar3: Transform; var avatar4: Transform; var avatar5: Transform; var avatar6: Transform; var avatar7: Transform; var avatar8: Transform; var avatar9: Transform; var avatar10: Transform; var entrante = ""; var servcli: ServCli; function noAr(){ if(Network.isServer){ Network.Instantiate(avatar0, transform.position, transform.rotation, 0); playerClone = "Player0(Clone)"; } else{ entrante = Network.player.ToString(); if(entrante =="1")Network.Instantiate(avatar1, transform.position, transform.rotation, 0); if(entrante =="2") Network.Instantiate(avatar2, transform.position, transform.rotation, 0); if(entrante =="3")Network.Instantiate(avatar3, transform.position, transform.rotation, 0); if(entrante =="4")Network.Instantiate(avatar4, transform.position, transform.rotation, 0); if(entrante =="5")Network.Instantiate(avatar5, transform.position, transform.rotation, 0); if(entrante =="6")Network.Instantiate(avatar6, transform.position, transform.rotation, 0); if(entrante =="7")Network.Instantiate(avatar7, transform.position, transform.rotation, 0); if(entrante =="8")Network.Instantiate(avatar8, transform.position, transform.rotation, 0); if(entrante =="9")Network.Instantiate(avatar9, transform.position, transform.rotation, 0); if(entrante =="10")Network.Instantiate(avatar10, transform.position, transform.rotation, 0); playerClone = "Player"+entrante+"(Clone)"; } Player = GameObject.Find(playerClone); contr = Player.GetComponent(CharacterController); if(Network.isClient)networkView.RPC("CarregaCL", RPCMode.AllBuffered,entrante, servcli.endSubmeshTronco,servcli.endTexturaTronco,servcli.endSubmeshBracos,servcli.endTexturaBracos,servcli.endTexturaPernas,servcli.escalaTronco,servcli.escalaBracos); } function Update(){ if (contr.isGrounded){ Player.transform.eulerAngles.y += Input.GetAxis("Horizontal"); //para girar deltaDirecao = Vector3(0, 0,Input.GetAxis("Vertical")); deltaDirecao = Player.transform.TransformDirection(deltaDirecao); deltaDirecao *= velocidade; if (Input.GetButton ("Jump")) { deltaDirecao.y = velSalto; } } deltaDirecao.y -= gravidade * Time.deltaTime; contr.Move(deltaDirecao * Time.deltaTime); } function OnPlayerDisconnected (player : NetworkPlayer){ Network.RemoveRPCs(player, 0); Network.DestroyPlayerObjects(player); }Esse segundo script só tem de diferente as linhas em azul, em que, primeiro criamos um prefixo (objeto referência) para acessar variáveis do outro script.
var servcli: ServCli;(Lembrar de fazer a conexão no Editor, como já vimos em outros casos.)
E usamos essas variáveis, que contém os endereços dos submeshes teleportáveis e texturas, numa RPC que vai ser executada em cada cópia de cliente, carregando o avatar do entrante, já customizado.
Melhor então vermos como tudo começa no script Servidor/Cliente:
Nas primeiras linhas, montamos a interface inicial, com os campos onde o jogador vai entrar com os endereços antes de apertar "Conectar". Ja vem com uns endereços:
Importante notar que, além dos endereços dos dois submeshes ("headbody" e "arms"), temos que dizer qual sua escala de ampliação ou redução de tamanho. Normalmente o valor 0.30 é adequado mas, conforme determinadas situações (se o criador de modelos não é o Blender, por exemplo), o modelo pode ser serializado num tamanho muito aumentado ou diminuido em relação ao adequado. E o modelador terá que descobrir e informar qual o valor de "escala" para corrigir isso. Se isso acontecer com você, lembre-se desse aviso.
Entrados os endereços e feita a conexão (ou start do Servidor) vamos para a instancialização das "almas" (no outro script) e, só depois de termos as "almas", podemos convocar os "corpos teleportáveis", o que é feito pela RPC: CarregaCL.
Nessa RPC é usado novamente o "número de entrante" para pegar os submeshes equivalentes do "demiurgo prateado" que está com a "alma" e substituí-los pelos submeshes do "corpo teleportável", que chega num download e é "de-serializado". É aplicada nessa hora o índice de "escalagem", para aumentar ou diminuir o tamanho dos submeshes. As texturas também sofrem downloads e são aplicadas.
NOTA: Colocar uma cópia do script MeshSerializer no "Administracao">
No fim das contas, o sistema é relativamente simples. Mas o resultado é muito bom. Você pode fazer testes com nossa demo, usando avatares e texturas que encontra na sessão de nosso site chamada: "Galeria de Avatares e Roupas" - ver link na parte superior da página. Mas, o ideal é que você crie seu avatar customizado e faça testes com ele. Veja só: você vai criar uma avatar a seu gosto e entrar na nossa aplicação, nosso espaço. Isso é o chamado: "Metaverso".
Baixe a demo zipada :

Nenhum comentário:
Postar um comentário