sábado, 11 de outubro de 2014
Aula 14 EMPURRANDO OBJETOS
EMPURRANDO OBJETOS
Se você jogou "Half-Life", ou outros jogos semelhantes, deve ter se deparado com a situação do vídeo.
Antes de "jogar" nossa demo (que está aí em baixo) leia a lição...
Nós já vimos o uso do "OnTriggerEnter" num objeto para checar sua colisão com outro. Mas, para checar a colisão do avatar (que tem "CharacterController") com um objeto, o mais recomendado é o uso de:
Capturando o "hit", podemos trabalhar com hit.gameObject para saber com quem houve a colisão etc.
Um dos "problemas" do CharacterController é que o avatar com ele não "empurra" objetos. Mas podemos resover isso com o script abaiso, acoplado no avatar:
Se você jogou "Half-Life", ou outros jogos semelhantes, deve ter se deparado com a situação do vídeo.
Antes de "jogar" nossa demo (que está aí em baixo) leia a lição...
Nós já vimos o uso do "OnTriggerEnter" num objeto para checar sua colisão com outro. Mas, para checar a colisão do avatar (que tem "CharacterController") com um objeto, o mais recomendado é o uso de:
function OnControllerColliderHit (hit : ControllerColliderHit)no avatar.
Capturando o "hit", podemos trabalhar com hit.gameObject para saber com quem houve a colisão etc.
Um dos "problemas" do CharacterController é que o avatar com ele não "empurra" objetos. Mas podemos resover isso com o script abaiso, acoplado no avatar:
var grandezaEmpurro : float = 2.0;
function OnControllerColliderHit (hit : ControllerColliderHit) {
var bodyEmpurrado : Rigidbody = hit.collider.attachedRigidbody;
// como só queremos empurrar quem tem rigidbody
if (bodyEmpurrado == null || bodyEmpurrado.isKinematic)
return;
// como não queremos empurrar para baixo
if (hit.moveDirection.y < -0.3)
return;
// A direção do empurro vai ser na horizontal
var direcaoEmpurro : Vector3 = Vector3 (hit.moveDirection.x, 0, hit.moveDirection.z);
// Aplicamos o empurro como uma velocidade dada ao rigidbody do objeto
bodyEmpurrado.velocity = direcaoEmpurro * grandezaEmpurro;
}
Aula 13 VEICULO VOADOR EM AMBIENTE MULTIPLAYER
VEICULO VOADOR EM AMBIENTE MULTIPLAYER
Se os Estados Unidos tinham criado o avião invisível aos radares e agora a China fez o seu, nós estamos criando um "Veículo DMU" que só é visível pelo seu dono.
A idéia que apresentamos nessa lição é termos um jogo em que existem avatares e chat, mas o jogo em si mesmo não é multiplayer! Por exemplo: se o jogador A abre uma porta, ela não é aberta nas outras cópias do jogo!
Nós inventamos isso para diminuir a quantidade de polígonos que têm que ser re-renderizados a cada segundo em todas as cópias dos jogos. O inconveniente é que, por exemplo no caso do exemplo dessa lição, se cada jogador não estaciona seu veículo num lugar determinado (sua "vaga de garagem") um outro avatar, com ou sem seu veículo, pode lhe dar uma bela trombada, o que pode ser dificil de consertar...
No caso da porta aberta/não-aberta, o avatar passará por ela como um fantasma (em quase todas as cópias do jogo). Isso pode ficar meio esquisito...
Mas vamos começar do início. passo a passo:
Com nossa tradicional incapacidade para modelagem e como nossos avatares não sentam (até poderiam ter essa animação), criamos no Blender um veículo voador para um passageiro e que parece um balcão (varanda) ou podemos dizer que é apenas um quadrado voador:
Importante ressaltar que os submeshes ficam uns dentro dos outros na sequência:
RIGHTCLICANDO AQUI
Para nosso veículo ter um comportamento "físico" (trombar, pousar etc.) adicionamos ao "transporte", além de um "box collider", um "rigidbody". Veja na figura que a gravidade está desligada.
Para o "transporte" se movimentar (e com isso o veículo todo), acoplamos um script muito simples que define o uso das teclas: "J","L","I","K","N" e "M". Veja o script:
No "anel" temos que definir um BoxCollider com o "IsTrigger" setado pois, quando o avatar encostar nele, isso vai disparar certas ações que são definidas num script.
Colocamos um NetworkView no "anel" mas trocamos o "Observed", arrastando o nome do script:
Isso faz com que as variáveis etc. do script se propaguem, mas não temos propagação do mesh (o que faz o veículo ficar invisível.)
É possível até nem usar o NetworkView e tornar o veículo MENOS MULTIPLAYER AINDA !
Veja o script acoplado ao "anel":
IMPORTANTE: Nós estabelecemos uma ligação com o script controlador de avatares (que está no GO Administracao) para tirar a gravidade do avatar quando está voando.
Quando se chega ao destino, apertando a tecla "f" (de free), o avatar pode sair do veículo.
Se os Estados Unidos tinham criado o avião invisível aos radares e agora a China fez o seu, nós estamos criando um "Veículo DMU" que só é visível pelo seu dono.
A idéia que apresentamos nessa lição é termos um jogo em que existem avatares e chat, mas o jogo em si mesmo não é multiplayer! Por exemplo: se o jogador A abre uma porta, ela não é aberta nas outras cópias do jogo!
Nós inventamos isso para diminuir a quantidade de polígonos que têm que ser re-renderizados a cada segundo em todas as cópias dos jogos. O inconveniente é que, por exemplo no caso do exemplo dessa lição, se cada jogador não estaciona seu veículo num lugar determinado (sua "vaga de garagem") um outro avatar, com ou sem seu veículo, pode lhe dar uma bela trombada, o que pode ser dificil de consertar...
No caso da porta aberta/não-aberta, o avatar passará por ela como um fantasma (em quase todas as cópias do jogo). Isso pode ficar meio esquisito...
Mas vamos começar do início. passo a passo:
Com nossa tradicional incapacidade para modelagem e como nossos avatares não sentam (até poderiam ter essa animação), criamos no Blender um veículo voador para um passageiro e que parece um balcão (varanda) ou podemos dizer que é apenas um quadrado voador:
- transporte
- anel
- base
function Update(){
rigidbody.angularVelocity.y= Input.GetAxis("JL");
rigidbody.velocity = transform.forward *Input.GetAxis("IK");
rigidbody.velocity.y = Input.GetAxis("NM");
}
Já falamos da criação desses "axes" que é feita abrindo o "Input Manager" (Edit |Project Settings | Input) e aumentando o número de axes, o que cria cópias do último, que devem ser mudadas.Colocamos um NetworkView no "anel" mas trocamos o "Observed", arrastando o nome do script:
Isso faz com que as variáveis etc. do script se propaguem, mas não temos propagação do mesh (o que faz o veículo ficar invisível.)
É possível até nem usar o NetworkView e tornar o veículo MENOS MULTIPLAYER AINDA !
Veja o script acoplado ao "anel":
var contrAv: ControladorAvatares;
var avatar:GameObject;
var ligado = "N";
var entrante: String;
function OnTriggerEnter (other : Collider){
entrante = Network.player.ToString();
if(Network.isServer) entrante ="0";
avatar =other.gameObject;
if(avatar.name == "Player" +entrante+"(Clone)") ligado = "S";
}
function LateUpdate(){
if(ligado =="S" && avatar != null){
contrAv.gravidade = 0;
avatar.transform.position.y = GameObject.Find("transporte").transform.position.y;
avatar.transform.position.x = GameObject.Find("transporte").transform.position.x;
avatar.transform.position.z = GameObject.Find("transporte").transform.position.z;
avatar.transform.localRotation = GameObject.Find("transporte").transform.localRotation;
}
value =Input.GetKey("f");
if(value) networkView.RPC("Desliga", RPCMode.All,entrante);
}
@RPC
function Desliga(ent:String){
entrante = Network.player.ToString();
if(Network.isServer) entrante ="0";
if(entrante==ent){
avatar = null;
ligado = "N";
contrAv.gravidade = 20;
}
}
Repare como as coisas acontecem: quando o avatar entra no veículo (encosta no "anel"), ele seta a variável "ligado" o que faz com que, o movimento do avatar seja o movimento do veículo.IMPORTANTE: Nós estabelecemos uma ligação com o script controlador de avatares (que está no GO Administracao) para tirar a gravidade do avatar quando está voando.
Quando se chega ao destino, apertando a tecla "f" (de free), o avatar pode sair do veículo.
Aula 12 ABRINDO UMA PORTA COM iTWEEN
ABRINDO UMA PORTA COM iTWEEN
Como versões novas podem mudar as coisas, para nosso curso baixe o iTween pelo nosso site (logo abaixo da figura/link):
Você deve criar uma pasta chamada "Plugins" dentro de seu projeto e descompactar o arquivo dentro dela.
Esse nome vem de "between" que significa "no meio". O que o iTween faz é: definidas duas posições de um objeto, ele cria situações intermediárias. É o que vamos fazer com nossa porta pivotante. Veja no novo script como se usa o iTween (que tem uma série de funções que podem ser vistas no site acima referido):
var abertaPorta1 =0;
function OnMouseDown() {
networkView.RPC("AbrePorta1", RPCMode.All);
}
@RPC
function AbrePorta1(){
var porta1 = GameObject.Find("portaBasculante1");
if(abertaPorta1==0){
iTween.RotateTo(porta1,Vector3(0,90,0),8);
abertaPorta1=1;
}
else{
iTween.RotateTo(porta1,Vector3(0,0,0),8);
abertaPorta1=0;
}
}
O último parâmetro do comando:iTween.RotateTo(porta1,Vector3(0,90,0),8);é o tempo que queremos que demore, da posição atual até a nova definida, nesse caso de rotação, pelo ângulo referenciado pelo eixo Y.
Aula 11 porta pivotante
ABRINDO UMA PORTA PIVOTANTE
Alguém muito ingênuo pode pensar que, se colocarmos um objeto num "espaço multiplayer" e um jogador movê-lo ele vai se mover em todos os jogos (dos outros jogadores). Não é nada disso! Não existe "espaço multiplayer"! Isso é uma ilusão que nós programadores de jogos criamos. O que existem são cópias do jogo nos diversos computadores da "rede de jogadores logados". Nõs temos que programar, geralmente usando RPCs, a "propagação" do movimento de um objeto.
NOTA: Eventualmente pode ser interessante criar um objeto cujo comportamento não se propaga. Por exemplo: tem um saco com moedas no cenário. O jogador A pega o saco em sua cópia do game. O saco pode desaparecer em todos os jogos ou ficar nas outras cóias para outros jogadores (B, C etc.)poderem pegar também o dinheiro.
Já apresentamos uma aula em que ensinamos como abrir uma porta. Nessa aula vamos repetir o mesmo ato, só que aqui a porta tem que se abrir em todas as cópias dum jogo.
Reveja aquela aula pois aqui já vamos começar mostrando o script que deve ser acoplado no GameObject que chamamos de "portaBasculante1".
IMPORTANTE: Não deixe de colocar um NetworkView no GO.
Veja então o script, que não tem grandes novidades (se você estudou todas as nossas lições):
Alguém muito ingênuo pode pensar que, se colocarmos um objeto num "espaço multiplayer" e um jogador movê-lo ele vai se mover em todos os jogos (dos outros jogadores). Não é nada disso! Não existe "espaço multiplayer"! Isso é uma ilusão que nós programadores de jogos criamos. O que existem são cópias do jogo nos diversos computadores da "rede de jogadores logados". Nõs temos que programar, geralmente usando RPCs, a "propagação" do movimento de um objeto.
NOTA: Eventualmente pode ser interessante criar um objeto cujo comportamento não se propaga. Por exemplo: tem um saco com moedas no cenário. O jogador A pega o saco em sua cópia do game. O saco pode desaparecer em todos os jogos ou ficar nas outras cóias para outros jogadores (B, C etc.)poderem pegar também o dinheiro.
Já apresentamos uma aula em que ensinamos como abrir uma porta. Nessa aula vamos repetir o mesmo ato, só que aqui a porta tem que se abrir em todas as cópias dum jogo.
Reveja aquela aula pois aqui já vamos começar mostrando o script que deve ser acoplado no GameObject que chamamos de "portaBasculante1".
IMPORTANTE: Não deixe de colocar um NetworkView no GO.
Veja então o script, que não tem grandes novidades (se você estudou todas as nossas lições):
var abertaPorta1 =0;
function OnMouseDown() {
networkView.RPC("AbrePorta1", RPCMode.All);
}
@RPC
function AbrePorta1(){
var porta1 = GameObject.Find("portaBasculante1");
if(abertaPorta1==0){
porta1.transform.Rotate(0,90,0);
abertaPorta1=1;
}
else{
porta1.transform.Rotate(0,-90,0);
abertaPorta1=0;
}
}
Interessante reparar que, se a porta está aberta e um novo jogador entrar no jogo, "sua" porta estará aberta. Isso porque o NetworkView (com a opção default: "Reliable Delta Compressed") cria a "bufferização", continuando a transmitir a posição da porta para novos jogadores. Claro que isso gasta muita CPU e linha... Mas precisa ser feito.Aula 10 MetaVerso
Já vimos como ir carregando até 10 "almas" no nosso jogo (só 5 simultâneas), mas o corpo delas era sempre o mesmo "demiurgo prateado".
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:
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 :
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 :
Aula 9 CRIANDO CORPO TELEPORTÁVEL
CRIANDO CORPO TELEPORTÁVEL
Comentamos na lição anterior que um habitante do Digital Media Universe tem um "corpo teleportável" que lembra aquele teletransporte do "Jornada nas Estrelas.
Para criar e teletransportar um "corpo teleportável" de um habitante do DMU para um jogo "estilo DMU", o caminho é o seguinte:
Você abre o Blender com o "avatar0.blend" que fornecemos
AVATARZERO
que é uma cópia do demiurgo apenas com as pernas (animadas) e uma esfera que chamamos de cérebro (determina mais ou menos a posição dos olhos).
Então, você cria um novo submesh de "headbody" (cabeça+tronco) e depois o converte (vamos ver como daqui a pouco) num arquivo com extensão: data.
Depois, cria um novo submesh de "arms" (braços) e o converte (isso se chama "serialização") também num arquivo com extensão: data.
Finalmente, coloca os dois arquivos, junto com novos arquivos de textura de "arms", "headbody" e "legs" - que você desenhou - num site do Internet (pode ser o http://webs.com que é grátis).
Você vai designar esses arquivos no Login de um jogo criado no "estilo DMU" (como estamos explicando nesse curso) e eles constituirão partes customizadas do seu avatar.
NOTA: Não criamos customização do mesh das pernas (legs) pois elas têm animação. Existe a possibilidade de serializar meshes com animações, mas só na versão Unity PRO, paga).
Isso é uma maneira de criar seu avatar, para um game, diferente do que geralmente se conhece: que é ter vários modelos e selecionar uma combinação de partes. Você tem um grau muito mais alto de liberdade. Qualquer pessoa pode criar um avatar simples, usando o Blender grátis, para um jogo/espaço "estilo DMU". Ou um bom modelador pode criar "avatares DMU" e vender.
DICA: Claro que você pode criar vários modelos (donde arquivos serializados) e colocar seus endereços web à disposição do jogador para ele selecionar.Como se fazia antigamente (antes desse curso...)
Vamos então ao exercício dessa lição, para você ver como se criam e serializam "submeshes DMU".
Abra o Blender com o arquivo "avatar0.blend" e re-salve como "avatar1.blend". Para outros avatares que quiser criar, use: avatar2, avatar3 etc. Na realidade esses nomes são só sugestão, não são requeridos.
Nós já ensinamos a trabalhar com o Blender. Se você não está lembrado, reveja as lições.
Crie um novo "headbody" com sua textura. O "cérebro" é referência para a posição dos olhos.
IMPORTANTE: Antes de dar o Join final, acrescente uma cópia do cérebro (Duplicate com Shift+D) e selecione ele por último. Dado o Join, mude o nome para "headbody".
Se preocupe com a junção perfeita com as partes devidas das pernas (logo abaixo das pirâmides superiores de cada perna - setas vermelhas na figura).
Crie os "arms" com sua textura.
IMPORTANTE: Antes de dar o Join final, acrescente uma cópia do cérebro e selecione ele por último. Dado o Join, mude o nome para "arms".
Salve tudo, sem dar Join dos três submeshes (como fizemos com o "demiurgo").
Vamos ver, passo a passo, como nós serializamos esses submeshes "headbody" e "arms":
1 - Importe seu avatar1.blend numa nova "scene" do seu projeto, tendo importado também os scripts abaixo (rightclick):
CriarTeleportavel.jsMeshSerializer.js
Scripts criados por Aras Prankevicius da Unity e modificados pela DMU.
2 - Arrastamos o "avatar1.blend" para o espaço 3D, donde para Hierarchy.
3 - Arrastamos o script "CriarTeleportavel" para cima de "arms" e de "headbody".
3 - Rodamos a "scene" aqui no editor mesmo. Aparece, na parte inferior, a mensagem de que foram feitas as serializações e o endereço de uma (para se saber a pasta com todas as duas):
Nem é preciso salvar esta "scene".
4 - Mude os nomes dos arquivos para algo que lembre seu avatar. Por exemplo: "bracosAVATAR1.data" etc.
5 - Para terminar o exercício dessa aula, crie uma textura para as pernas (padrão do Demiurgo) condizente com seu novo avatar e coloque os 5 arquivos (dois arquivos .data e três .JPG) num site (como dissemos, pode ser o http://webs.com que é grátis).
Comentamos na lição anterior que um habitante do Digital Media Universe tem um "corpo teleportável" que lembra aquele teletransporte do "Jornada nas Estrelas.
Para criar e teletransportar um "corpo teleportável" de um habitante do DMU para um jogo "estilo DMU", o caminho é o seguinte:
Você abre o Blender com o "avatar0.blend" que fornecemos
Depois, cria um novo submesh de "arms" (braços) e o converte (isso se chama "serialização") também num arquivo com extensão: data.
Finalmente, coloca os dois arquivos, junto com novos arquivos de textura de "arms", "headbody" e "legs" - que você desenhou - num site do Internet (pode ser o http://webs.com que é grátis).
Você vai designar esses arquivos no Login de um jogo criado no "estilo DMU" (como estamos explicando nesse curso) e eles constituirão partes customizadas do seu avatar.
NOTA: Não criamos customização do mesh das pernas (legs) pois elas têm animação. Existe a possibilidade de serializar meshes com animações, mas só na versão Unity PRO, paga).
Isso é uma maneira de criar seu avatar, para um game, diferente do que geralmente se conhece: que é ter vários modelos e selecionar uma combinação de partes. Você tem um grau muito mais alto de liberdade. Qualquer pessoa pode criar um avatar simples, usando o Blender grátis, para um jogo/espaço "estilo DMU". Ou um bom modelador pode criar "avatares DMU" e vender.
DICA: Claro que você pode criar vários modelos (donde arquivos serializados) e colocar seus endereços web à disposição do jogador para ele selecionar.Como se fazia antigamente (antes desse curso...)
Vamos então ao exercício dessa lição, para você ver como se criam e serializam "submeshes DMU".
Abra o Blender com o arquivo "avatar0.blend" e re-salve como "avatar1.blend". Para outros avatares que quiser criar, use: avatar2, avatar3 etc. Na realidade esses nomes são só sugestão, não são requeridos.
Nós já ensinamos a trabalhar com o Blender. Se você não está lembrado, reveja as lições.
Crie um novo "headbody" com sua textura. O "cérebro" é referência para a posição dos olhos.
IMPORTANTE: Antes de dar o Join final, acrescente uma cópia do cérebro (Duplicate com Shift+D) e selecione ele por último. Dado o Join, mude o nome para "headbody".
Se preocupe com a junção perfeita com as partes devidas das pernas (logo abaixo das pirâmides superiores de cada perna - setas vermelhas na figura).
Crie os "arms" com sua textura.
IMPORTANTE: Antes de dar o Join final, acrescente uma cópia do cérebro e selecione ele por último. Dado o Join, mude o nome para "arms".
Vamos ver, passo a passo, como nós serializamos esses submeshes "headbody" e "arms":
1 - Importe seu avatar1.blend numa nova "scene" do seu projeto, tendo importado também os scripts abaixo (rightclick):
2 - Arrastamos o "avatar1.blend" para o espaço 3D, donde para Hierarchy.
3 - Arrastamos o script "CriarTeleportavel" para cima de "arms" e de "headbody".
3 - Rodamos a "scene" aqui no editor mesmo. Aparece, na parte inferior, a mensagem de que foram feitas as serializações e o endereço de uma (para se saber a pasta com todas as duas):
Nem é preciso salvar esta "scene".
4 - Mude os nomes dos arquivos para algo que lembre seu avatar. Por exemplo: "bracosAVATAR1.data" etc.
5 - Para terminar o exercício dessa aula, crie uma textura para as pernas (padrão do Demiurgo) condizente com seu novo avatar e coloque os 5 arquivos (dois arquivos .data e três .JPG) num site (como dissemos, pode ser o http://webs.com que é grátis).
Aula 8 Demiungos fe
O UNIVERSO DA MÍDIA DIGITAL (DMU) E SEUS MISTÉRIOS DE FÉ
Se você aprecia filmes de terror, religião ou esoterismo, vai gostar dessa aula. Vamos falar de possessão de almas e corpos e outras coisas tão bizarras quanto.
Na "vida real", os seres mais evoluídos possuem 2 elementos: corpo e alma (acredite se quiser...). No "universo da mídia digital" (que são mundos/espaços/games criados segundo as técnicas ensinadas aqui em nosso site DMU)) não há dúvidas de fé: os seres mais evoluidos possuem 4 elementos: alma, corpo, jogador e corpo para teletransporte.
Você vai entender melhor isso, se pensarmos no exercício da aula anterior:
Se você aprecia filmes de terror, religião ou esoterismo, vai gostar dessa aula. Vamos falar de possessão de almas e corpos e outras coisas tão bizarras quanto.
Na "vida real", os seres mais evoluídos possuem 2 elementos: corpo e alma (acredite se quiser...). No "universo da mídia digital" (que são mundos/espaços/games criados segundo as técnicas ensinadas aqui em nosso site DMU)) não há dúvidas de fé: os seres mais evoluidos possuem 4 elementos: alma, corpo, jogador e corpo para teletransporte.
Você vai entender melhor isso, se pensarmos no exercício da aula anterior:
- A "alma" chamava-se "Player0";
- A alma possuia um "corpo", que é o modelo criado no Blender e tem 3 "sub-meshes" (outro corpo poderia ter outra quantidade) - headbody, legs e arms, cada um com seu material (que administra a textura).
- IMPORTANTE: Apesar de um "material" estar dentro de um submesh, ele é universal. O que significa que, se eu trocar o material do submesh A, se o material do submesh B tiver mesmo nome, também muda.Outra coisa: o nome do material não tem nada a ver com o nome do arquivo de textura adicionado - é apenas o nome da textura na criação do submesh. O material pode se chamar xyz.tag e a textura adicionada ser abc.jpg.
- O terceiro elemento seria o jogador, que é a "pessoa física" que se apodera de uma alma e seu corpo, quando dá "login".
- O quarto elemento (que não tinha no exercício anterior) lembra "Jornada nas Estrelas": um corpo, que não foi definido num game, pode vir pelo ciberespaço (internet) e se materializar nesse game. Desde que haja uma alma disponivel. Isso parece muito louco, mas vamos explicar melhor nas próximas lições.
A instancialização é uma poderosa mágica, mas que tem seus limites: podemos, com ela, replicar "almas" a serem atribuidas a "jogadores", mas elas possuirão "corpos" idênticos. Isso só seria bom se seu jogo apenas tivesse, como caracteres, ninjas mascarados ou astronautas com capacete ou soldados com a cara camuflada etc.
Num jogo normal, temos que criar "almas" na quantidade igual ao limite de jogadores simultâneos - que, no nosso exercício definimos como "5" em:
Network.InitializeServer(5, 25000,false);
Faça um teste com a demo anterior e vai ver que temos o Servidor e mais 5 jogadores. O sexto não consegue logar:
Jogadores entram e saem do jogo. Quando entram, se apoderam de uma alma e, quando saem, a liberam.
A administração dos reaproveitamentos de "almas", num jogo profissional, é feita num banco de dados, que verificará também se o jogador é cadrastado, sua senha etc.
Isso pode ser feito, de uma maneira mais simples, usando arrays.
Mas, mesmo esse "mais simples", ainda é complexo para o nível aqui de nosso curso. Assim, vamos usar uma outra arquitetura que é fácil, mas que terá algumas restrições. Uma delas é que, numa "sessão" (período em que o Servidor fica ligado) só poderão entrar, no máximo (poderia ser outro número)10 jogadores (o que é diferente do número de jogadores simultâneos que é: 5). A outra coisa (chata) é que teremos que criar uma "alma" para cada um dos 10 "entrantes" (mais a do jogador-Servidor).
Vamos então começar o exercício dessa aula, re-salvando a "scene" anterior com outro nome e passar a criar mais 10 "Players", com 10 corpos diferentes.
Começamos criando 10 prefabs:
Mudar os nomes para "Player1" até "Player10".
Para criar o Player0, já importamos o asset "demiurgo.blend". Para criar os outros temos que importar, mais 10 vezes, o mesmo "demiurgo.blend". Não banque o espertinho tentando fazer Copy etc. Tem que importar mesmo! Eles já vem com numeração sequencial:
Colocamos cada demiurgo no espaço (Hierarchy) e adicionamos um Character Controller (acertar os parâmetros) e um NetworkView.
IMPORTANTE: Use Height = 4, Radius = 1 e Center.Y = 2.
Não vamos adicionar texturas nos demiurgos (eles ficarão como: "demiurgos prateados"). Mas vamos mudar o nome dos submeshes para: arms1, legs1, headbody1 e equivalentes. Terminado o trabalho com um demiurgo, o arrastamos para cima do prefab com seu nome e o apagamos na Hierarchy. Reconheço que isso dá trabalho!
IMPORTANTE: Nossa opção foi adicionar, ao Player0, as texturas "oficiais" do demiurgo DMU. Ele será o avatar do dono do Servidor.
Vamos agora para mais trabalho. Abra o script de controle de avatares, que tem a váriávelAvatar0 e crie novas variáveis: Avatar1, Avatar2 até Avatar10. Veja código abaixo. Faça a conexão entre essas variáveis no Inspector e os prefabs no Project.
A Classe Unity tem uma propriedade onde conseguimos capturar o número sequencial do jogador entrante. Usando-a, modificamos mais ainda (já tinhamos colocado as variáveis) o início do script de controle de avatares, que fica (o início) assim:
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 = "";
function noAr(){
entrante = Network.player.ToString();
if(Network.isServer){
Network.Instantiate(avatar0, transform.position, transform.rotation, 0);
playerClone = "Player0(Clone)";
}
else if(entrante =="1")Network.Instantiate(avatar1, transform.position, transform.rotation, 0);
else if(entrante =="2")Network.Instantiate(avatar2, transform.position, transform.rotation, 0);
else if(entrante =="3")Network.Instantiate(avatar3, transform.position, transform.rotation, 0);
else if(entrante =="4")Network.Instantiate(avatar4, transform.position, transform.rotation, 0);
else if(entrante =="5")Network.Instantiate(avatar5, transform.position, transform.rotation, 0);
else if(entrante =="6")Network.Instantiate(avatar6, transform.position, transform.rotation, 0);
else if(entrante =="7")Network.Instantiate(avatar7, transform.position, transform.rotation, 0);
else if(entrante =="8")Network.Instantiate(avatar8, transform.position, transform.rotation, 0);
else if(entrante =="9")Network.Instantiate(avatar9, transform.position, transform.rotation, 0);
else if(entrante =="10")Network.Instantiate(avatar10, transform.position, transform.rotation, 0);
playerClone = "Player"+entrante+"(Clone)";
Player = GameObject.Find(playerClone);
contr = Player.GetComponent(CharacterController);
}
//....aqui vai o resto, que não muda
O script acoplado à MainCamera também tem seu início modificado:
var target : Transform;
var distance = 10.0;
var height = 4.0;
var heightDamping = 2.0;
var rotationDamping = 3.0;
var playerClone = "";
var entrante = "";
function LateUpdate () {
if(Network.isServer){
playerClone = "Player0(Clone)";
}
else{
entrante = Network.player.ToString();
playerClone = "Player"+entrante+"(Clone)";
}
target = GameObject.Find(playerClone).transform;
if(!target) return;
wantedRotationAngle = target.eulerAngles.y;
wantedHeight = target.position.y + height;
currentRotationAngle = transform.eulerAngles.y;
currentHeight = transform.position.y;
currentRotationAngle = Mathf.LerpAngle (currentRotationAngle, wantedRotationAngle,rotationDamping * Time.deltaTime);
currentHeight = Mathf.Lerp (currentHeight, wantedHeight, heightDamping * Time.deltaTime);
currentRotation = Quaternion.Euler (0, currentRotationAngle, 0);
transform.position = target.position;
transform.position -= currentRotation * Vector3.forward * distance;
transform.position.y = currentHeight;
transform.LookAt (target);
}
O script do Servidor/Cliente não muda.
Você deve testar essas modificações. O teste é semelhante ao da aula anterior, só que os avatares aparecerão "prateados".
Se tudo estiver OK, dê um Save na "scene" que... continuamos na próxima aula.
Aula 7 Controlando Player
CONTROLADOR DO AVATAR MÍNIMO, PREFAB E INSTANCIALIZAÇÃO
Em aulas anteriores, copiamos scripts já prontos para controlar nosso avatar (o Naduana Júnior).
Também você já aprendeu a criar um avatar-demiurgo no Blender e depois colocá-lo num espaço Unity. Agora, vamos fornecer para vocês nosso demiurgo "oficial" e suas três texturas. Baixe (right-clique para as texturas) na pasta de seu projeto e importe:
demiurgo.blendtroncoPADRAO.jpg
bracosPADRAO.jpg
pernasPADRAO.jpg
A partir de agora vamos trabalhar sempre com texturas que são arquivos .JPG. Vamos ver a razão disso mais à frente. O Blender e o GIMP trabalham com arquivos .JPG sem problemas.
Vamos aprender nessa lição como criar um "Controlador de Avatar" (script que o faz andar) básico. Para facilitar, não vamos incluir no script (por enquanto - vamos fazer isso mais à frente) nenhuma animação.
Uma coisa importante que não vimos ainda foi a criação de um "prefab". Que é isso?
Um prefab é um conjunto de um GameObject principal, com vários componentes incluidos (um CharacterController, texturas, um NetworkView etc.) e outros GameObjects secundários (um Script, uma luz etc.).
Um prefab poderá ser carregado, para um espaço 3D, em tempo de construção ou em tempo de execução. Um carregamento em tempo de execução (com o jogo já rodando), se chama:instancialização - não se assuste com o nome...
Para começar o exercício dessa aula, salve a "scene" da aula anterior (com o "compacto duplo") como uma nova "scene" e coloque o "demiurgo", com sua texturas, no espaço 3D (vai aparecer na divisória Hierarchy).
Instale um componente "CharacterController" no avatar e acerte os parâmetros (já ensinamos isso).

Como nosso avatar vai ser usado em jogos multiplayer, vamos acrescentar um NetworkView nele.
Para criar um prefab selecione, na janela Project: Create | Prefab. Aparece o prefab (vazio) na divisória Project com o nome new prefab, que vamos mudar para: Player0. Depois, arrastamos o "demiurgo" com seus acréscimos, da divisória Hierarchy para cima do prefab:
Feito isso, apagamos a "demiurgo" da divisória "Hierarchy".
Esperamos que, como recomendamos em uma lição anterior, você tenha "fuçado" por aí e descoberto como criar planos e colocar luzes e cameras num espaço usando a Barra Superior, pois vamos criar um plano de tamanho razoável (na posição 0,0,0), iluminando o dito cujo e posicionando a câmera para mostrar todo o ambiente.
Pode parecer estranho, mas vamos colocar o GameObject "Administracao" na posição (0,30,0). Na realidade essa vai ser a posição de "entrada" do avatar no espaço (caindo sobre o plano).
Depois disso, vamos colocar no "Administracao" o script:
Vamos agora analisar o script.
1 - Falamos sobre "proclamação" na aula anterior. Quando temos o Servidor startado ou uma nova conexão, será executado todo evento "noAr" que existir no aplicativo. Aqui temos um, que executa a instancialização do "avatar0" que é o prefab "Player0". No espaço, cada avatar terá sempre o nome do prefab com o adendo "(Clone)", donde temos cada avatar se chamando "Player0(Clone)".
Importante lembrar que esse script vai rodar, uma cópia em cada Cliente. Donde, cada Cliente, nesse caso, vai ter um avatar idêntico. Vamos ver, no futuro, como cada Cliente pode ter um avatar diferente.
2 - Para entender a parte do código que controla a movimentação do avatar, precisamos primeiro aprender que a Unity criou um "Input Manager" que pode ser aberto, na divisória Inspector, selecionando: Edit | Project Settings | Input:
Nele, foram definidos (e essas definições podem ser mudadas) vários "axes", o que significa que, com um dado nome, temos a administração do "aperto" de duas teclas para gerar valores numéricos entre "-1" e "+1". Por exemplo (veja na figura): com o nome "Vertical", está representado o aperto de uma das teclas: "down" (seta-para-baixo) ou "up" (seta-para-cima). Teremos, progressivamente, valores, de zero a -1 ou, de zero a +1. Isso é importante para criar movimentos mais suaves dos objetos (eles saem da velocidade zero e vão acelerando). Como usamos isso num script?
Repare acima que, no caso de giro do avatar, a linha de código é:
Para andar para frente/trás, usamos a função Move da Classe CharacterController, que tem funções e propriedades que são refletidas no CharacterController que adicionamos ao avatar:
Usamos uma multiplicação por Time.deltaTime sempre que queremos que algo não se relacione diretamente com a framerate (que varia de máquina para máquina) mas fique dependente da unidade de tempo universal.
3 - Finalmente. temos a função/evento OnPlayerDisconnected, onde removemos tudo que se refere ao avatar desse Cliente.
Como ainda vamos tratar da movimentação da Câmera, quando você chegar nesse ponto do exercíco, teste-o dentro do Editor, para ver se está tudo OK com o avatar do Servidor (dono do jogo). Pode aparecer um erro dizendo que a variável "contr" não foi assinalada, mas isso não tem importância. Lembramos que não estamos administrando animações. No editor o "Sair" não funciona.
Em aulas anteriores, copiamos scripts já prontos para controlar nosso avatar (o Naduana Júnior).
Também você já aprendeu a criar um avatar-demiurgo no Blender e depois colocá-lo num espaço Unity. Agora, vamos fornecer para vocês nosso demiurgo "oficial" e suas três texturas. Baixe (right-clique para as texturas) na pasta de seu projeto e importe:
bracosPADRAO.jpg
pernasPADRAO.jpg
Vamos aprender nessa lição como criar um "Controlador de Avatar" (script que o faz andar) básico. Para facilitar, não vamos incluir no script (por enquanto - vamos fazer isso mais à frente) nenhuma animação.
Uma coisa importante que não vimos ainda foi a criação de um "prefab". Que é isso?
Um prefab é um conjunto de um GameObject principal, com vários componentes incluidos (um CharacterController, texturas, um NetworkView etc.) e outros GameObjects secundários (um Script, uma luz etc.).
Um prefab poderá ser carregado, para um espaço 3D, em tempo de construção ou em tempo de execução. Um carregamento em tempo de execução (com o jogo já rodando), se chama:instancialização - não se assuste com o nome...
Para começar o exercício dessa aula, salve a "scene" da aula anterior (com o "compacto duplo") como uma nova "scene" e coloque o "demiurgo", com sua texturas, no espaço 3D (vai aparecer na divisória Hierarchy).
Instale um componente "CharacterController" no avatar e acerte os parâmetros (já ensinamos isso).

Para criar um prefab selecione, na janela Project: Create | Prefab. Aparece o prefab (vazio) na divisória Project com o nome new prefab, que vamos mudar para: Player0. Depois, arrastamos o "demiurgo" com seus acréscimos, da divisória Hierarchy para cima do prefab:
Esperamos que, como recomendamos em uma lição anterior, você tenha "fuçado" por aí e descoberto como criar planos e colocar luzes e cameras num espaço usando a Barra Superior, pois vamos criar um plano de tamanho razoável (na posição 0,0,0), iluminando o dito cujo e posicionando a câmera para mostrar todo o ambiente.
Depois disso, vamos colocar no "Administracao" o script:
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;
function noAr(){
//Trabalhando com um tipo de avatar só:
Network.Instantiate(avatar0, transform.position, transform.rotation, 0);
playerClone = "Player0(Clone)";
Player = GameObject.Find(playerClone);
contr = Player.GetComponent(CharacterController);
}
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);
}
Na divisória Inspector, aparece (para o Administracao) as propriedades desse script. Temos que arrastar o prefab "Player0" para cima de "avatar0".1 - Falamos sobre "proclamação" na aula anterior. Quando temos o Servidor startado ou uma nova conexão, será executado todo evento "noAr" que existir no aplicativo. Aqui temos um, que executa a instancialização do "avatar0" que é o prefab "Player0". No espaço, cada avatar terá sempre o nome do prefab com o adendo "(Clone)", donde temos cada avatar se chamando "Player0(Clone)".
Importante lembrar que esse script vai rodar, uma cópia em cada Cliente. Donde, cada Cliente, nesse caso, vai ter um avatar idêntico. Vamos ver, no futuro, como cada Cliente pode ter um avatar diferente.
2 - Para entender a parte do código que controla a movimentação do avatar, precisamos primeiro aprender que a Unity criou um "Input Manager" que pode ser aberto, na divisória Inspector, selecionando: Edit | Project Settings | Input:
Nele, foram definidos (e essas definições podem ser mudadas) vários "axes", o que significa que, com um dado nome, temos a administração do "aperto" de duas teclas para gerar valores numéricos entre "-1" e "+1". Por exemplo (veja na figura): com o nome "Vertical", está representado o aperto de uma das teclas: "down" (seta-para-baixo) ou "up" (seta-para-cima). Teremos, progressivamente, valores, de zero a -1 ou, de zero a +1. Isso é importante para criar movimentos mais suaves dos objetos (eles saem da velocidade zero e vão acelerando). Como usamos isso num script?
Repare acima que, no caso de giro do avatar, a linha de código é:
transform.eulerAngles.y += Input.GetAxis("Horizontal");
dentro de um Update. Isso significa que, a cada frame, se a tecla "seta-para-direita" continuar apertada, o ângulo de rotação do avatar, em relação a seu eixo Y, é igual a anterior acrescentada de um valor que vai de 0 a +1.Para andar para frente/trás, usamos a função Move da Classe CharacterController, que tem funções e propriedades que são refletidas no CharacterController que adicionamos ao avatar:
contr.Move(deltaDirecao * Time.deltaTime);que faz o avatar se mover no valor do vetor "deltaDirecao". O valor, no eixo "z" (para frente/trás segundo eixo Local), desse vetor é definido por Input.GetAxis("Vertical") (com valores de -1 a +1) multiplicado pela variável "velocidade". Donde, a velocidade "real" do avatar, vai aumentando aos poucos, suavemente.
Usamos uma multiplicação por Time.deltaTime sempre que queremos que algo não se relacione diretamente com a framerate (que varia de máquina para máquina) mas fique dependente da unidade de tempo universal.
3 - Finalmente. temos a função/evento OnPlayerDisconnected, onde removemos tudo que se refere ao avatar desse Cliente.
Como ainda vamos tratar da movimentação da Câmera, quando você chegar nesse ponto do exercíco, teste-o dentro do Editor, para ver se está tudo OK com o avatar do Servidor (dono do jogo). Pode aparecer um erro dizendo que a variável "contr" não foi assinalada, mas isso não tem importância. Lembramos que não estamos administrando animações. No editor o "Sair" não funciona.
Aula 6 Compacto Duplo
COMPACTO DUPLO - SERVCLIE
Dissemos, numa aula anterior, que, um computador "médio" com uma linha "média" (1 Mbps) consegue administrar uns 5 a 10 jogadores na rede. Então, como a Blizzard tem 6 milhões de jogadores registrados no World of Warcraft?
Primeiro, devem ter "apenas" 1 milhão de caras jogando num mesmo instante. E ela tem que montar uma "plantação" (farm), de milhares de micro-computadores e ter um software que, quando um jogador dá o Login, se não tem mais "vaga" nos computadores que estão "no ar", liga mais um, com uma nova cópia do jogo e coloca o Cliente nele. Esses micro-computadores profissionais (com chip Xeon etc.) suportam uns 50 jogadores.
Outra opção é trabalhar com "mainframes". Muita gente pensa que os mainframes são dinossauros em extinção. Não é nada disso. Um mainframe da IBM equivale a uns 1500 micro-computadores. Custa mais ou menos 1 milhão de dólares, mas sai mais barato que comprar os 1500 micros, além de ocupar menos espaço e gastar menos eletricidade. No Brasil temos uns 200 deles, claro que em grandes empresas com Bradesco, Volkswagem etc.
Mas. voltando a nosso caso: será que vale a pena um cara como você, que não tem dinheiro para montar uma "farm" de servidores, criar um jogo multiplayer?
A Unity sugere um esquema que chamamos de "compacto duplo". Cria-se o jogo dentro de um aplicativo executável que inclui Servidor e Cliente juntos.

É como se você tivesse uma quadra de basquete e convidasse amigos para uma partida. Você coloca o Servidor "no ar" e avisa aos amigos o seu endereço IP. Eles, tendo uma cópia do "compacto duplo", apertam em Conectar (veja figura) e entram no jogo. A Nintendo tem um esquema parecido, para sua console DS, e vende jogos que podem ser compartilhados entre amigos que estejam fisicamente próximos. No caso aqui, cada amigo pode estar em sua casa!
Vamos, nessa aula, fazer um "compacto duplo" desses, que, na realidade, combina código que a gente já aprendeu nas aulas passadas. Mas, vamos passo a passo.
Abra uma nova "scene" e coloque um GO Administracao com um NetworkView.
Nessa Administracao coloque o script:
1 - Na série de linhas:
2 - É possível usar o condicional
3 - O comando
Depois de você desenvolver esse exercício, dê um "build" na "scene" como executável (vimos como em aula anterior) o que vai gerar um arquivo .EXE e uma pasta com várias coisas. Comprima isso tudo num .ZIP file. e disponibilize para ser usado, como estamos fazendo aqui. Baixe, descomprima em seu disco C e teste nosso aplicativo. Pode criar atalho no desktop (aparece com logo da DMU).
Dissemos, numa aula anterior, que, um computador "médio" com uma linha "média" (1 Mbps) consegue administrar uns 5 a 10 jogadores na rede. Então, como a Blizzard tem 6 milhões de jogadores registrados no World of Warcraft?
Primeiro, devem ter "apenas" 1 milhão de caras jogando num mesmo instante. E ela tem que montar uma "plantação" (farm), de milhares de micro-computadores e ter um software que, quando um jogador dá o Login, se não tem mais "vaga" nos computadores que estão "no ar", liga mais um, com uma nova cópia do jogo e coloca o Cliente nele. Esses micro-computadores profissionais (com chip Xeon etc.) suportam uns 50 jogadores.
Outra opção é trabalhar com "mainframes". Muita gente pensa que os mainframes são dinossauros em extinção. Não é nada disso. Um mainframe da IBM equivale a uns 1500 micro-computadores. Custa mais ou menos 1 milhão de dólares, mas sai mais barato que comprar os 1500 micros, além de ocupar menos espaço e gastar menos eletricidade. No Brasil temos uns 200 deles, claro que em grandes empresas com Bradesco, Volkswagem etc.
Mas. voltando a nosso caso: será que vale a pena um cara como você, que não tem dinheiro para montar uma "farm" de servidores, criar um jogo multiplayer?
A Unity sugere um esquema que chamamos de "compacto duplo". Cria-se o jogo dentro de um aplicativo executável que inclui Servidor e Cliente juntos.

Vamos, nessa aula, fazer um "compacto duplo" desses, que, na realidade, combina código que a gente já aprendeu nas aulas passadas. Mas, vamos passo a passo.
Abra uma nova "scene" e coloque um GO Administracao com um NetworkView.
Nessa Administracao coloque o script:
var IPServidor = "127.0.0.1";
var IPServ = "";
function OnGUI (){
if (Network.peerType == NetworkPeerType.Disconnected){
IPServidor = GUI.TextField(new Rect(120,10,100,20),IPServidor);
if (GUI.Button (new Rect(10,10,100,30),"Conectar")){
Network.Connect(IPServidor, 25000);
}
if (GUI.Button (new Rect(10,50,100,30),"Start Servidor")){
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 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();
}
O que temos de novidade aqui:1 - Na série de linhas:
for (var go : GameObject in FindObjectsOfType(GameObject)){
go.SendMessage("noAr", SendMessageOptions.DontRequireReceiver);
}
criamos o que se chama: uma "proclamação". Já vimos que, com uma RPC, podemos dispararuma função em todos os Clientes. Aqui, estamos criando um "evento" chamado noAr, que podemos usar como várias funçõesfunction noAr(){
//linhas de código
}
que vão rodar em quaisquer scripts dentro da aplicação - vamos ver exemplo disso logo: Essas funções vão ser executadas quando for feita a "proclamação": noAr.2 - É possível usar o condicional
if(Network.isServer)para que algo só ocorra no aplicativo rodando como Servidor.
3 - O comando
Application.Quit();derruba o aplicativo. Repare que o usamos aqui de duas formas. Quando o Cliente sai, cai só ele. Mas, quando o Servidor sai, através de uma RPC, todos os Clientes são derrubados.
Depois de você desenvolver esse exercício, dê um "build" na "scene" como executável (vimos como em aula anterior) o que vai gerar um arquivo .EXE e uma pasta com várias coisas. Comprima isso tudo num .ZIP file. e disponibilize para ser usado, como estamos fazendo aqui. Baixe, descomprima em seu disco C e teste nosso aplicativo. Pode criar atalho no desktop (aparece com logo da DMU).
Aula 5 BroadCast e Chat
BROADCAST OU CHAT MÍNIMO
Vimos o uso da RPC para um Cliente mandar uma mensagem para o Servidor. Vamos ver agora como o jogador mandaria uma mensagem para todos os outros jogadores. È assim que se cria um Chat. O nosso é minimo, quase sem nenhum recurso.
Uma coisa que é importante saber é que não precisamos colocar todo o código que fica no Cliente num único script.
Vamos então criar uma nova "scene" para um novo Cliente, com o GO "Administracao" onde vamos colocar aqueles scripts da lição anterior: o que tem as cópias de RPCs do Servidor e o scriptLogin . Lembre-se que esse script tem uma variável chamada "nome" e outra chamada "logado", que vamos acessar num novo script, que podemos chamar de Broadcast e que também fica no GO "Administracao":
O terceiro parâmetro apresenta a variável log.nome sendo "log", o prefixo (objeto-referência) da Classe Login, que é aquele outro script. Como já vimos , é assim que um script acessa uma variável definida em outro script. Lembre-se que temos que arrastar, graficamente, o GO que tem o script com a variável para o Inspector:

Veja que o conteúdo desse script é disparado
Temos que criar uma nova "scene" com um Servidor para esse "jogo", que vai ter os mesmos dois scripts do servidor da aula anterior, mas, no script com as cópias dos RPCs do Cliente temos que acrescentar a RPC: BroadcastCL.
Na demo, dispare o Servidor e dois Clientes. Coloque algo na linha superior de Chat e aperte a tecla. A mensagem deve ir para o outro Cliente. Na "vida real", vai para todos os outros jogadores logados.
NOTA:Na realidade, a demo aqui não é perfeita pois o Servidor não está startado quando a página é carregada. Se o Servidor estiver startado (caso "normal"), quando o Cliente é carregado, ele se conecta sem precisar se apertar nenhum botão e já aparece a janela com o Login. Demo testada no IE com plugin já instalado.
Vimos o uso da RPC para um Cliente mandar uma mensagem para o Servidor. Vamos ver agora como o jogador mandaria uma mensagem para todos os outros jogadores. È assim que se cria um Chat. O nosso é minimo, quase sem nenhum recurso.
Uma coisa que é importante saber é que não precisamos colocar todo o código que fica no Cliente num único script.
Vamos então criar uma nova "scene" para um novo Cliente, com o GO "Administracao" onde vamos colocar aqueles scripts da lição anterior: o que tem as cópias de RPCs do Servidor e o scriptLogin . Lembre-se que esse script tem uma variável chamada "nome" e outra chamada "logado", que vamos acessar num novo script, que podemos chamar de Broadcast e que também fica no GO "Administracao":
var Tf1:String;
var Tf2:String;
var log : Login;
function OnGUI (){
if (Network.peerType != NetworkPeerType.Disconnected && log.logado == 1){
Tf1 = GUI.TextField (Rect(10, 70, 200, 20), Tf1);
if (GUI.Button (Rect (10,95,100,20), "Chat")) {
networkView.RPC("BroadcastCL", RPCMode.Others,(log.nome + ": " +Tf1));
}
Tf2 = GUI.TextField(Rect (10, 120, 200, 20), Tf2);
}
}
@RPC
function BroadcastCL(recebido : String){
Tf2 = recebido;
}
Repare que aqui, a linhanetworkView.RPC("BroadcastCL", RPCMode.Others,(log.nome + ": " +Tf1));
chama uma RPC que está aqui mesmo nesse script. O "mode" desse RPC é "Others", o que significa que serão chamados os clones desse script em todos os clones dessa "scene" (os jogos nas máquinas dos outros jogadores).O terceiro parâmetro apresenta a variável log.nome sendo "log", o prefixo (objeto-referência) da Classe Login, que é aquele outro script. Como já vimos , é assim que um script acessa uma variável definida em outro script. Lembre-se que temos que arrastar, graficamente, o GO que tem o script com a variável para o Inspector:

if (Network.peerType != NetworkPeerType.Disconnected && log.logado == 1)o que significa: só quando o Cliente está conectado e logado.
Temos que criar uma nova "scene" com um Servidor para esse "jogo", que vai ter os mesmos dois scripts do servidor da aula anterior, mas, no script com as cópias dos RPCs do Cliente temos que acrescentar a RPC: BroadcastCL.
Na demo, dispare o Servidor e dois Clientes. Coloque algo na linha superior de Chat e aperte a tecla. A mensagem deve ir para o outro Cliente. Na "vida real", vai para todos os outros jogadores logados.
NOTA:Na realidade, a demo aqui não é perfeita pois o Servidor não está startado quando a página é carregada. Se o Servidor estiver startado (caso "normal"), quando o Cliente é carregado, ele se conecta sem precisar se apertar nenhum botão e já aparece a janela com o Login. Demo testada no IE com plugin já instalado.
Aula 4 Login
LOGIN
Agora já sabemos criar um Servidor e um Cliente (que vai ter o jogo própriamente dito). Como fazer o Cliente se comunicar com o Servidor?
Uma das maneiras (usadas principalmente para transporte de strings) são as Remote Procedure Call, que são funções que criamos. Vamos ver um exemlo para tudo ficar mais claro. Queremos que, depois de feita a conexão, o jogador tecle seu nome num campo e esse nome vá até o Servidor. O Servidor vai fazer alguma coisa com esse string (na "vida real" geralmente consulta um banco de dados para ver se o jogador é cadastrado) e "responde" para esse jogador (e só para ele).
No nosso exercício o Servidor vai apenas acrescentar a palavra "logado!" ao nome e responder.
Vamos ver primeiro o script (que estará no GO "Administracao" da "scene" Cliente). Esse script é uma modificação do visto na aula anterior.
IMPORTANTE: Vamos chamar esse script de: Login. Vamos ver a razão disso na próxima aula.
No final desse script, temos uma RPC chamada EcoCL, que vai ser chamada pelo Servidor, quando da resposta. Para tudo isso ficar claro, vejamos o script que vai na "scene" do Servidor (no seu GO "Administração"). É também uma modificação do que vimos na aula anterior (na realidade só tem um adendo):
O "info.sender" tem justamente o IP address do jogador que "chamou".
MUITO IMPORTANTE !!! : Na "scene" Cliente, tem que ter um script (no "Administracao") que contém cópia das RPCs (no caso, só uma) contactadas no Servidor. E, na "scene" Servidor, tem que ter um script (no "Administracao") que contém cópia das RPCs (no caso, só uma) contactadas no Cliente.
Para você brincar, colocamos aqui as duas aplicações, com dois clientes. Faça testes disparando o Servidor e depois um ou outro Cliente. Teste também a situação de o Servidor "cair" no meio dum jogo: Os Clientes logados devem "cair" também.
NOTA:Na realidade, a demo aqui não é perfeita pois o Servidor não está startado quando a página é carregada. Se o Servidor estiver startado (caso "normal"), quando o Cliente é carregado, ele se conecta sem precisar se apertar nenhum botão e já aparece a janela com o Login. Demo testada no IE com plugin já instalado.
Agora já sabemos criar um Servidor e um Cliente (que vai ter o jogo própriamente dito). Como fazer o Cliente se comunicar com o Servidor?
Uma das maneiras (usadas principalmente para transporte de strings) são as Remote Procedure Call, que são funções que criamos. Vamos ver um exemlo para tudo ficar mais claro. Queremos que, depois de feita a conexão, o jogador tecle seu nome num campo e esse nome vá até o Servidor. O Servidor vai fazer alguma coisa com esse string (na "vida real" geralmente consulta um banco de dados para ver se o jogador é cadastrado) e "responde" para esse jogador (e só para ele).
No nosso exercício o Servidor vai apenas acrescentar a palavra "logado!" ao nome e responder.
Vamos ver primeiro o script (que estará no GO "Administracao" da "scene" Cliente). Esse script é uma modificação do visto na aula anterior.
IMPORTANTE: Vamos chamar esse script de: Login. Vamos ver a razão disso na próxima aula.
var logado = 0;
var msg = "o<=Nome";
var nome = "";
function Start(){
Network.Connect("127.0.0.1",25000);
}
function OnGUI(){
if(Network.peerType == Network.peerType.Disconnected){
msg = "o<=Nome";
if(GUI.Button(new Rect(10,35,100,30),"Conectar")){
Network.Connect("127.0.0.1",25000);
logado = 0;
}
}
if(Network.peerType != Network.peerType.Disconnected && logado == 0){
msg = GUI.TextField(new Rect(10,10,300,20),msg);
if(GUI.Button(new Rect(10,35,100,30),"Login")){
nome=msg;
networkView.RPC ("EcoSV", RPCMode.Server, msg);
logado = 1;
}
}
if(Network.peerType != Network.peerType.Disconnected && logado == 1){
msg = GUI.TextField(new Rect(10,10,300,20),msg);
if(GUI.Button(new Rect(10,35,100,30),"Sair")){
Network.Disconnect();
msg = "o<=Nome";
logado = 0;
}
}
}
@RPC
function EcoCL (recebido : String)
{
msg = recebido ;
}
Diferentemente do script da aula anterior, agora o jogador tecla, seu nome quando aparece o botão "Login" e o aperta. Nessa hora é executada a linha:networkView.RPC ("EcoSV", RPCMode.Server, msg);
em que, é chamada uma função chamada EcoSV que está no Servidor. Essa função vai receber o valor do parâmetro msg. Essa operação de comunicação é do tipo RPCMode.Server, o que significa que existe um contato só entre esse jogador e o servidor. Em outros tipos de comunicação (que vamos ver mais adiante) pode ser requerido, por exemplo, um contato entre um jogador e todos os outros (caso de chat). Existem outros tipos.No final desse script, temos uma RPC chamada EcoCL, que vai ser chamada pelo Servidor, quando da resposta. Para tudo isso ficar claro, vejamos o script que vai na "scene" do Servidor (no seu GO "Administração"). É também uma modificação do que vimos na aula anterior (na realidade só tem um adendo):
var msg = "Clique para startar";
function OnGUI(){
msg = GUI.TextField(new Rect(10,10,300,20),msg);
if(Network.peerType == Network.peerType.Disconnected){
if(GUI.Button(new Rect(10,35,100,30),"Startar")){
Network.InitializeServer(10,25000,false);
}
}
if(Network.peerType != Network.peerType.Disconnected){
msg= "Servidor OK!";
if(GUI.Button(new Rect(10,35,100,30),"Desligar")){
Network.Disconnect();
msg= "Clique para startar";
}
}
}
@RPC
function EcoSV (recebidoS : String, info : NetworkMessageInfo){
var msgS= recebidoS + " logado!";
networkView.RPC("EcoCL",info.sender,msgS);
}
Reparem como a "mágica" funciona: o script no Cliente, chama a EcoSV que está no Servidor e, esta, tem a linha:networkView.RPC("EcoCL",info.sender,msgS);
que vai chamar, em resposta, a EcoCL que está no Cliente (visto acima), passando o parâmetromsgS.O "info.sender" tem justamente o IP address do jogador que "chamou".
MUITO IMPORTANTE !!! : Na "scene" Cliente, tem que ter um script (no "Administracao") que contém cópia das RPCs (no caso, só uma) contactadas no Servidor. E, na "scene" Servidor, tem que ter um script (no "Administracao") que contém cópia das RPCs (no caso, só uma) contactadas no Cliente.
Para você brincar, colocamos aqui as duas aplicações, com dois clientes. Faça testes disparando o Servidor e depois um ou outro Cliente. Teste também a situação de o Servidor "cair" no meio dum jogo: Os Clientes logados devem "cair" também.
NOTA:Na realidade, a demo aqui não é perfeita pois o Servidor não está startado quando a página é carregada. Se o Servidor estiver startado (caso "normal"), quando o Cliente é carregado, ele se conecta sem precisar se apertar nenhum botão e já aparece a janela com o Login. Demo testada no IE com plugin já instalado.
Aula 3 Server e Cliente
SERVIDOR E CLIENTE MÍNIMOS
Vamos apresentar, nessa aula, os scripts de um Servidor e um Cliente, os mais simples possíveis (não vai dar para jogar nada...). Isso é importante para que você entenda os fundamentos.
A Classe mais usada será a Network.
Uma coisa importante para aprender é que a Unity criou um recurso chamado NetworkView, que ajuda a propagação de informações (posição de um avatar, por exemplo) pelos membros da rede de jogadores de um dado game. Esse recurso funciona junto com dois outros: as "funções RPC" (Remote Procedure Call) e o Network.Instanciate.
Como sempre em nosso curso, a idéia é
que você aprenda fazendo exercícios. Vamos lá...
Primeiro vamos criar um servidor.
Abra um novo projeto e uma scene que pode salver com o nome que quiser. O Servidor e o Cliente serão criados nesse projeto mas serão duas "scenes" diferentes.
Na divisória Jogo-Hierarchy, criamos um GameObject vazio que chamamos de "Administracao" (assim mesmo, sem cedilha ou til).
Selecionando Component | Miscellaneous, na Barra Superior, coloque um NetworkView nesse GO.
IMPORTANTE: Para que seu Servidor possa funcionar, mesmo que sua aplicação servidora não esteja "em foco", você deve sempre, quando criar o projeto de uma aplicação multiplayer, selecionar na Barra Superior: Edit | Project Settings | Player e ticar em "Run in Background". Muitos erros vão ocorrer porque você vai se esquecer disso !!!"
Outra coisa: passe o "Display Resolution Dialog" para "Disabled". Se o jogador puder e mudar a qualidade da resolução do jogo isso causará problemas com a velocidade de movimentação dos objetos.
Dentro da "Administracao" você deve colocar o script:
Você já aprendeu sobre OnGUI . Donde as novidades começam com
Já vimos como criar um jogo numa web-page. Aqui é semelhante:
1 - Salve a "scene como, por exemplo, Servidor1.unity.
2 - Selecione File | Build&Run na Barra Superior. Vai se abrir uma janela.
Para você brincar, colocamos aqui as duas aplicações. Faça testes disparando o Servidor e depois o Cliente. Teste também a situação de o Servidor "cair" no meio dum jogo: O Cliente deve "cair" também.
NOTA: Na realidade, a demo aqui não é perfeita pois o Servidor não está startado quando a página é carregada. Se o Servidor estiver startado (caso "normal"), quando o Cliente é carregado, ele se conecta sem precisar se apertar nenhum botão.Demo testada no IE com plugin já instalado.
Vamos apresentar, nessa aula, os scripts de um Servidor e um Cliente, os mais simples possíveis (não vai dar para jogar nada...). Isso é importante para que você entenda os fundamentos.
A Classe mais usada será a Network.
Uma coisa importante para aprender é que a Unity criou um recurso chamado NetworkView, que ajuda a propagação de informações (posição de um avatar, por exemplo) pelos membros da rede de jogadores de um dado game. Esse recurso funciona junto com dois outros: as "funções RPC" (Remote Procedure Call) e o Network.Instanciate.
Como sempre em nosso curso, a idéia é
que você aprenda fazendo exercícios. Vamos lá...
Primeiro vamos criar um servidor.
Abra um novo projeto e uma scene que pode salver com o nome que quiser. O Servidor e o Cliente serão criados nesse projeto mas serão duas "scenes" diferentes.
Na divisória Jogo-Hierarchy, criamos um GameObject vazio que chamamos de "Administracao" (assim mesmo, sem cedilha ou til).
Selecionando Component | Miscellaneous, na Barra Superior, coloque um NetworkView nesse GO.
IMPORTANTE: Para que seu Servidor possa funcionar, mesmo que sua aplicação servidora não esteja "em foco", você deve sempre, quando criar o projeto de uma aplicação multiplayer, selecionar na Barra Superior: Edit | Project Settings | Player e ticar em "Run in Background". Muitos erros vão ocorrer porque você vai se esquecer disso !!!"
Outra coisa: passe o "Display Resolution Dialog" para "Disabled". Se o jogador puder e mudar a qualidade da resolução do jogo isso causará problemas com a velocidade de movimentação dos objetos.
var msg = "Clique para startar";
function OnGUI(){
msg = GUI.TextField(new Rect(10,10,300,20),msg);
if(Network.peerType == Network.peerType.Disconnected){
if(GUI.Button(new Rect(10,35,100,30),"Startar")){
Network.InitializeServer(10,25000,false);
}
}
if(Network.peerType != Network.peerType.Disconnected){
msg= "Servidor OK!";
if(GUI.Button(new Rect(10,35,100,30),"Desligar")){
Network.Disconnect();
msg= "Clique para startar";
}
}
}
Interessante notar que, no script, não aparece o endereço de sua máquina. Ele é pego automáticamente quando o script é disparado.Você já aprendeu sobre OnGUI . Donde as novidades começam com
Network.peerType == Network.peerType.Disconnected
onde testamos se o servidor está desligado.
ComNetwork.InitializeServer(10,25000,false);
inicializamos o dito cujo. No primeiro parâmetro você coloca a quantidade máxima de jogadores que seu jogo poderá ter concomitantemente. Se seu servidor-hardware é um computador médio e sua linha tem uns 2 Mbps de velocidade nominal (donde uns 1 Mbps de velocidade real de download e uns 300 Kbps para upload) ele suporta uns 10 jogadores sem apresentar falhas ("lag"). O segundo parâmetro é a "porta" que deverá ser aberta, como já vimos em aula anterior. Esqueça o terceiro parâmetro.
Se tudo acontecer OK, seu Servidor "entra no ar" e poderá ser desligado comNetwork.Disconnect();A "scene" com nosso Servidor deve ser salva e vamos criar um executável O Servidor vai trabalhar no computador do dono do game e não vai ser uma web-page.
Já vimos como criar um jogo numa web-page. Aqui é semelhante:
1 - Salve a "scene como, por exemplo, Servidor1.unity.
2 - Selecione File | Build&Run na Barra Superior. Vai se abrir uma janela.
3 - Adicione a "scene" corrente, selecione como Plataform o PC e clique "Build and Run". vai se abrir a janela normal do Windows para salvamento de arquivos (no caso teremos umServidor1.EXE e uma pasta Servidor1_Data).
Vamos então para a criação do Cliente. Abrimos uma outra "scene" também com um GameObject com o nome "Administracao" (com seu NetworkView), colocamos nele o script do Cliente (mínimo):var msg = "Sem conexao";
function Start(){
Network.Connect("127.0.0.1",25000);
}
function OnGUI(){
msg = GUI.TextField(new Rect(10,10,300,20),msg);
if(Network.peerType == Network.peerType.Disconnected){
msg = "Sem conexao";
if(GUI.Button(new Rect(10,35,100,30),"Conectar")){
Network.Connect("127.0.0.1",25000);
}
}
if(Network.peerType != Network.peerType.Disconnected ){
msg = "Conectado";
if(GUI.Button(new Rect(10,35,100,30),"Sair")){
Network.Disconnect();
msg = "Sem conexao";
}
}
}
Na linhaNetwork.Connect("127.0.0.1",25000);
aparece o "IP address" (pode ser um nome, se estiver usando o DynDNS, como explicado em lição anterior) de sua máquina. Aqui, usamos "127.0.0.1" que é um "IP address" usado para testes (chamado "loopback") que representa seu computador visto por ele mesmo. Isso quer dizer que, se você executar com sucesso a demo dessa lição (abaixo) isso não significa que sua "porta" 25000 está aberta, pois a comunicação Cliente-Servidor aqui não passa pelo "firewall".
DICA: Você pode testar se seu computador está OK para ser um Servidor, colocando a aplicação Servidor nele, como executável, e a aplicação Cliente, com SEU "IP address", numa web-page e depois ir numa LAN House e tentar acessar essa web-page, assim como conectar o Cliente.Para você brincar, colocamos aqui as duas aplicações. Faça testes disparando o Servidor e depois o Cliente. Teste também a situação de o Servidor "cair" no meio dum jogo: O Cliente deve "cair" também.
NOTA: Na realidade, a demo aqui não é perfeita pois o Servidor não está startado quando a página é carregada. Se o Servidor estiver startado (caso "normal"), quando o Cliente é carregado, ele se conecta sem precisar se apertar nenhum botão.Demo testada no IE com plugin já instalado.
Aula 2 Abrindo a Porta
ABRINDO A PORTA
Se você é daqueles caras "espertos", metidos a entender de computador, é provável que tenha comprado umas cópias piratas de softwares de firewall e antivirus. Os da Symantec e da McAfee são os mais comuns.
Esses softwares transformam seu computador numa verdadeira fortaleza de guerra, em que nada entra mas, em compensação, nada também sai. E isso vai prejudicar a implantação de seu Servidor multiplayer, pois ele precisa se comunicar com as máquinas dos outros jogadores de seu game, através da "porta" padrão do Unity que é a 25000.
Um computador pode ter até 65.000 "portas". Essas "portas" são de software e não têm nada a ver com as tais "portas USB" ou seriais ou paralelas, que são portas físicas. Elas servem justamente para controlar o que sai ou entra de seu computador, quando conectado numa rede interna (LAN) ou na internet.
Nossa recomendação então, se você tem desses softwares instalados, e não sabe como abrir "portas" com eles, é que desinstale tudo e passe a usar APENAS o firewall da Microsoft, que já vem instalado no Windows. Para antivirus, recomendamos instalar o AVG Free que não vai interferir seu Servidor Unity.
Para liberar a porta 25000, abra o "Painel de controle" (a partir de "Iniciar" | "Configurações") e clique em "Firewall do Windows". Esse firewall deve sempre estar ativado.
Abra a divisória: "Exceções" e clique em "Adicionar Porta".
Essa operação de "abrir a porta" é a que dá mais problemas na instalação de Servidor para games multiplayer. Porque, como dissemos, a maioria dos computadores tem toda uma "tralha" de esquemas de segurança que são instalados sem ninguém entender direito como trabalhar com eles.
NOTA: Claro que dá para trabalhar com o Unity e outra porta que não seja a 25000. Mas, cuidado; pois você precisará abrir a nova porta e verificar, em programas prontos "aproveitados", se a porta padrão 25000 não foi usada e modificar.
Às vezes, se você esquece de abrir a porta, o Windows lhe manda um aviso como o da figura abaixo. Mas, às vezes, não...
Se você é daqueles caras "espertos", metidos a entender de computador, é provável que tenha comprado umas cópias piratas de softwares de firewall e antivirus. Os da Symantec e da McAfee são os mais comuns.
Esses softwares transformam seu computador numa verdadeira fortaleza de guerra, em que nada entra mas, em compensação, nada também sai. E isso vai prejudicar a implantação de seu Servidor multiplayer, pois ele precisa se comunicar com as máquinas dos outros jogadores de seu game, através da "porta" padrão do Unity que é a 25000.
Um computador pode ter até 65.000 "portas". Essas "portas" são de software e não têm nada a ver com as tais "portas USB" ou seriais ou paralelas, que são portas físicas. Elas servem justamente para controlar o que sai ou entra de seu computador, quando conectado numa rede interna (LAN) ou na internet.
Nossa recomendação então, se você tem desses softwares instalados, e não sabe como abrir "portas" com eles, é que desinstale tudo e passe a usar APENAS o firewall da Microsoft, que já vem instalado no Windows. Para antivirus, recomendamos instalar o AVG Free que não vai interferir seu Servidor Unity.
Para liberar a porta 25000, abra o "Painel de controle" (a partir de "Iniciar" | "Configurações") e clique em "Firewall do Windows". Esse firewall deve sempre estar ativado.
Abra a divisória: "Exceções" e clique em "Adicionar Porta".
Na nova janela defina a porta 25000:
NOTA: Claro que dá para trabalhar com o Unity e outra porta que não seja a 25000. Mas, cuidado; pois você precisará abrir a nova porta e verificar, em programas prontos "aproveitados", se a porta padrão 25000 não foi usada e modificar.
Às vezes, se você esquece de abrir a porta, o Windows lhe manda um aviso como o da figura abaixo. Mas, às vezes, não...
Aula 1 Qual é seu endereco
QUAL É SEU ENDEREÇO ?
Nesse nosso curso, nas próximas aulas, vamos tratar da programação de jogos multiplayer. E de um conceito revolucionários chamado: "metaverso". O que é um metaverso?
Já imaginou se você pudesse criar, com total liberdade, usando softwares como o Blender ou Maya etc., um avatar para entrar em um jogo multiplayer criado por outra pessoa? Seria , por exemplo, você criar um cachorro com asas para ser seu avatar no World of Warcraft.
Esse recurso propiciaria também que, jogadores que não fossem bons modeladores, pudessem comprar avatares de produtores independentes.
Pois o Unity nos dá a possibilidade de criar jogos com essa capacidade.
Vamos lá então.
Para sua aplicação-Browser se conectar ao Servidor do Google e abrir a página inicial dele, você tem que indicar o endereço, que é: www.google.com.
Para você colocar um game multiplayer "no ar", você vai ter que colocar "no ar" um Servidor-hardware (que pode ser seu próprio computador), com um Servidor-software feito para esse jogo. O jogo será uma aplicação Cliente (como o Browser é) que vai se conectar através de um endereço. Mas, qual é o endereço de seu computador?
Um endereço de Servidor pode ser uma série de palavras separadas por pontos (como vimos para o do Google) ou pode ser uma série de números separados por pontos. Para saber o endereçode seu computador nesse instante você tem que abrir uma "janela DOS" ou "Prompt de comando" clicando em "Iniciar", depois "Executar" e, disparando o programa "cmd.exe", como visto na figura:
Aberta aquela janela preta, escreva: ipconfig e dê Enter. Será mostrado o endereço IP que é o endereço dessa sua máquina que servirá para endereço do Servidor. Você vai ver qualquer coisa assim:
Se você tiver um roteador WiFi em casa, verá qualquer coisa assim:
Se seu computador está no primeiro caso, ele tem um "endereço IP" que vamos chamar de "endereço net". Mas, se seu computador tem um endereço IP como no segundo caso (começando geralmente por "192" ou "10") você tem um "endereço de rede". Se você está numa rede WiFi, poderá fazer alterações no seu roteador para que seu computador possa ser um Servidor de game. Vamos ensinar como se faz isso. Mas, se sua rede foi criada pelo seu "provedor de internet" (Virtua etc.), você não poderá (por contrato) mexer no roteador, donde terá que entrar em contato com seu provedor para ver o que dá para fazer...
Vamos falar do caso mais simples: você tem um "endereço net".
Você pode ter uma conexão à Internet em que seu "IP" é fixo, será sempre os mesmos números. Mas essas conexões são mais caras (no Speed é 167,90 reais por mês com 4Mbps para download e 600 Kbps para upload). Então, seu endereço provavelmente muda a cada vez que você desliga e liga seu computador. (Você pode testar isso desligando e religando sua máquina agora).
Como para seus amigos entrarem no seu game precisam saber o seu IP, ficaria muito complicado ter sempre que comunicar a todos, toda vez que você desligar e ligar sua máquina, o novo endereço. Mas nós vamos lhe ensinar um truque para resolver isso.
Uma empresa chamada DynDNS presta grátis o seguinte serviço:
Nesse nosso curso, nas próximas aulas, vamos tratar da programação de jogos multiplayer. E de um conceito revolucionários chamado: "metaverso". O que é um metaverso?
Já imaginou se você pudesse criar, com total liberdade, usando softwares como o Blender ou Maya etc., um avatar para entrar em um jogo multiplayer criado por outra pessoa? Seria , por exemplo, você criar um cachorro com asas para ser seu avatar no World of Warcraft.
Esse recurso propiciaria também que, jogadores que não fossem bons modeladores, pudessem comprar avatares de produtores independentes.
Pois o Unity nos dá a possibilidade de criar jogos com essa capacidade.
Vamos lá então.
Para sua aplicação-Browser se conectar ao Servidor do Google e abrir a página inicial dele, você tem que indicar o endereço, que é: www.google.com.
Para você colocar um game multiplayer "no ar", você vai ter que colocar "no ar" um Servidor-hardware (que pode ser seu próprio computador), com um Servidor-software feito para esse jogo. O jogo será uma aplicação Cliente (como o Browser é) que vai se conectar através de um endereço. Mas, qual é o endereço de seu computador?
Um endereço de Servidor pode ser uma série de palavras separadas por pontos (como vimos para o do Google) ou pode ser uma série de números separados por pontos. Para saber o endereçode seu computador nesse instante você tem que abrir uma "janela DOS" ou "Prompt de comando" clicando em "Iniciar", depois "Executar" e, disparando o programa "cmd.exe", como visto na figura:
Aberta aquela janela preta, escreva: ipconfig e dê Enter. Será mostrado o endereço IP que é o endereço dessa sua máquina que servirá para endereço do Servidor. Você vai ver qualquer coisa assim:
Se você tiver um roteador WiFi em casa, verá qualquer coisa assim:
Se seu computador está no primeiro caso, ele tem um "endereço IP" que vamos chamar de "endereço net". Mas, se seu computador tem um endereço IP como no segundo caso (começando geralmente por "192" ou "10") você tem um "endereço de rede". Se você está numa rede WiFi, poderá fazer alterações no seu roteador para que seu computador possa ser um Servidor de game. Vamos ensinar como se faz isso. Mas, se sua rede foi criada pelo seu "provedor de internet" (Virtua etc.), você não poderá (por contrato) mexer no roteador, donde terá que entrar em contato com seu provedor para ver o que dá para fazer...
Vamos falar do caso mais simples: você tem um "endereço net".
Você pode ter uma conexão à Internet em que seu "IP" é fixo, será sempre os mesmos números. Mas essas conexões são mais caras (no Speed é 167,90 reais por mês com 4Mbps para download e 600 Kbps para upload). Então, seu endereço provavelmente muda a cada vez que você desliga e liga seu computador. (Você pode testar isso desligando e religando sua máquina agora).
Como para seus amigos entrarem no seu game precisam saber o seu IP, ficaria muito complicado ter sempre que comunicar a todos, toda vez que você desligar e ligar sua máquina, o novo endereço. Mas nós vamos lhe ensinar um truque para resolver isso.
Uma empresa chamada DynDNS presta grátis o seguinte serviço:
- você define para sua máquina um "nome" que se compõe de palavras separadas por pontos. Por exemplo, nossa máquina tem o nome: doamerico.ath.cx
- você usa um software gratuito deles (que pode ser baixado no link ) e que, toda vez que você desligar e religar sua máquina possibilita atualizar a correspondência entre aquele seu "nome" com os novos números de seu IP.
Assim, seus amigos, e mesmo você, poderão sempre usar o tal nome como seu endereço. E ele é fixo!
Não fique pensando que a DynDNS está fazendo alguma caridade. Esse sistema gratuito deles tem várias limitações. As mais importantes para nós são:
Agora, se você está numa rede WiFi, a coisa fica um pouco mais complicada.
Primeiro você tem que desconectar o cabo do roteador WiFi e conectar direto num computador para saber qual o "endereço net" que "chega" no roteador. Esse endereço você vai usar no DynDNS.
Depois, porque cada roteador tem um "aplicativo administrador" diferente, você vai ter que ler o manual do seu para descobrir como fazer o que é chamado de "Port Range Fowarding". Isso significa que será estabelecido uma espécie de canal que ligará os dados que chegam, no "endereço net" para a o "endereço de rede".
No caso do roteador Linksys modelo WRT54GC, muito comum no Brasil, o "aplicativo administrador" aparece quando entramos com o endereço http://192.168.1.1 num browser (IE, por exemplo).
Primeiro se coloca o nome da aplicação ("unity"), num quadro à esquerda. Colocar o número da Porta HTTP (vamos usar nos exemplos desse curso o 25000) como Start e End Port. Setar "TCP" e "UDP" e "Enabled". O "endereço de rede" deve ser colocado no quadro, como visto na figura. Finalmente se clica "Save Settings".
Como dissemos, cada marca/modelo de roteador vai ter um "aplicativo administrador" diferente, mas tudo deve ser muito parecido com o que mostramos para o Linksys modelo WRT54GC. Consulte o manual de seu roteador...
Em tempo: não estamos recomendando a compra de nenhuma marca ou modelo de roteador. Não temos nenhum conexão comercial com a Linksys. Compre aquele que você achar melhor para seu caso.
Não fique pensando que a DynDNS está fazendo alguma caridade. Esse sistema gratuito deles tem várias limitações. As mais importantes para nós são:
- você tem que atualizar seu IP pelo menos uma vez a cada 28 dias.
- Existe um limite de 648000 consultas para redirecionamento por mês.
Agora, se você está numa rede WiFi, a coisa fica um pouco mais complicada.
Primeiro você tem que desconectar o cabo do roteador WiFi e conectar direto num computador para saber qual o "endereço net" que "chega" no roteador. Esse endereço você vai usar no DynDNS.
Depois, porque cada roteador tem um "aplicativo administrador" diferente, você vai ter que ler o manual do seu para descobrir como fazer o que é chamado de "Port Range Fowarding". Isso significa que será estabelecido uma espécie de canal que ligará os dados que chegam, no "endereço net" para a o "endereço de rede".
No caso do roteador Linksys modelo WRT54GC, muito comum no Brasil, o "aplicativo administrador" aparece quando entramos com o endereço http://192.168.1.1 num browser (IE, por exemplo).
A definição de "Port Range Fowarding" fica na parte: "Applications & Games".
Primeiro se coloca o nome da aplicação ("unity"), num quadro à esquerda. Colocar o número da Porta HTTP (vamos usar nos exemplos desse curso o 25000) como Start e End Port. Setar "TCP" e "UDP" e "Enabled". O "endereço de rede" deve ser colocado no quadro, como visto na figura. Finalmente se clica "Save Settings".
Como dissemos, cada marca/modelo de roteador vai ter um "aplicativo administrador" diferente, mas tudo deve ser muito parecido com o que mostramos para o Linksys modelo WRT54GC. Consulte o manual de seu roteador...
Em tempo: não estamos recomendando a compra de nenhuma marca ou modelo de roteador. Não temos nenhum conexão comercial com a Linksys. Compre aquele que você achar melhor para seu caso.
Assinar:
Comentários (Atom)




































