Professional Documents
Culture Documents
como os comandos de laço e repetição disponíveis. Anteriormente, havia dito que não
entraria em detalhes quanto a variáveis e laços condicionais, mas este guia não visa
programadores que estão se adaptando a Second Life, e sim o usuário sem base
nenhuma, eis o motivo de voltar atrás neste guia. Vou explicar primeiramente os laços,
e depois aplicá-los no estudo de algumas funções. Se a explicação não for suficiente
para o entendimento do leitor, por favor, mande-me um email que terei o maior prazer
em ajudar. A melhora deste guia esta em sua ação de apontar erros, solicitar maiores
explicações, e apresentar sugestões.
Tipos de Variáveis.
Integer
Quando você necessitar armazenar um numero inteiro, sem casas decimais, este é o tipo
ideal, pode ser negativo ou positivo, entre -2,147,483,648 e +2,147,483,647. Apenas
atente para o fato de o valor ser inteiro e não ultrapassar o limite. Se for trabalhar com
divisão, prefira o tipo float de antemão, você se palpará de alguma dor de cabeça ou
contratempo. Mesmo que o valor seja inteiro, nunca acrescente um ponto ao numero, o
compilador vai entendê-lo como um float, gerando um erro.
Float
Se necessitar armazenar números com casas decimais, este é o tipo ideal, pode ser
negativo ou positivo, variando de -1.175494351E-38 ate 3.402823466E+38. Algumas
atenções devem ser observadas. A primeira refere-se a um valor float consumir mais
memória que um integer, então só use float se realmente for necessário. Observe
novamente os limites negativos e positivos do valor a ser armazenado. E uma ultima
observação que quebra a cabeça de muita gente, em uma divisão, todos os valores
envolvidos devem ser explicitamente declarados como float, isto consegue-se usando a
seguinte sintaxe em todos os operandos envolvidos: (float)valor ou (float)variável.
Obviamente que se o resultado for atribuído a uma outra variável, necessariamente deve
ser do tipo float. Ao contrario do tipo integer, sempre especifique o valor desejado com
um ponto, como 1.0 ou .5 ou ainda 1. , você se precavi contra anomalias em seu script
Vector
Um vetor é um tipo composto de 3 floats, sua sintaxe é a seguinte: <float,float,float>.
Cada elemento pode ser individualmente acessado e alterado através dos atributos .x .y
.z da variável vetor. Por exemplo:
Vector meu_vetor=<1.0,2.5,.5>
Meu_vetor.x Æ 1.0
Meu_vetor.y Æ 2.5
Meu_vetor.z + 1. Æ 1.5
Vetores suportam as quatro operações matemáticas, divisão, multiplicação, adição e
subtração. Quem gosta de geometria, deve ter notado que x, y e z representam
coordenadas cartesianas, mundo tridimendional, com isso espero que entendam porque
o uso de vetor será uma constante quando analisarmos movimentação e rotação de
objetos, e nossa própria movimentação, em SL.
String
O tipo string armazena texto, números, caracteres, enfim, armazena praticamente
qualquer coisa, com exceção da barra invertida (\) e dentro de um limite demarcado
pela memória de script disponível. Toda informação atribuída a uma string deve estar
entre aspas “”, com exceção de variáveis.
A barra invertida serve para alterar como o compilador ira interpretar o próximo
caractere. Vamos explicar com exemplos:
\n Î Nova linha, ou quebra de linha. Corta o texto em mais de uma linha, no ponto
onde é inserida.
String texto=”Esta é uma linha. \n E esta é uma linha abaixo da primeira”
\t Æ 4 Espaços. Insere 4 espaços entre o texto, ou uma tabulação, no ponto onde é
inserida.
\” Æ Como dito no inicio, um texto atribuído a uma variável deve estar entre aspas, pois
se inserirmos aspas no meio do texto, o compilador vai entender que o texto termina ai,
e vai retornar um erro ou, na melhor hipótese, ignorar o restante. A barra invertida evita
este comportamento, como se dissesse ao compilador, “Ei, esta aspas faz parte do
texto”.
\\ Æ Similar á aspas, se quiser mostrar uma barra invertida no texto, ela terá que vir
precedida de outra barra invertida, para não ser interpretada erroneamente
Se quiser transformar um numero em texto, ou uma variável de outro tipo em texto, a
sintaxe é:
String texto= (string)valor ou (string)variável.
Para concatenar-mos strings, isso é, uni-las, usamos o sinal de mais (+). Por exemplo:
“Valdinei” + “Rossini” = “Valdinei Rossini”
Key
O tipo Key armazena o que chamamos de UUID, que nada mais é do que um
identificador único para qualquer coisa em Second Life, desde objetos, avatares, scripts,
sons, tudo enfim. Na vida real, cada pessoa tem seu próprio e único numero de RG e
CPF, vários objetos também seu numero de serie, que é único. A utilidade deste tipo em
armazenar este identificador é podermos nos referenciar a objetos e avatares em nosso
script. Sem ele, seria bem mais trabalhoso interagir nossos objetos com outros. A UUID
é formada por uma cadeia de números e letras, separadas por um traço. Um exemplo de
UUID seria:
"a822ff2b-ff02-461d-b45d-dcd10a2de0c2".
Logo faremos alguns exercícios de exemplo para fixar legal a ideia de UUID e sua
atribuição a um tipo Key.
List
Lista, esse é um tipo especial, que pode armazenar zero ou mais valores, e cada valor
pode ser de um tipo diferente. Complicado? Nem tanto. Uma lista é delimitada por
Colchetes [], e seus valores são separados um do outro por vírgula, veja um exemplo:
list lista=[ “Valdinei”, 4.5 , 325, "a822ff2b-ff02-461d-b45d-
dcd10a2de0c2" , <4.5,.5,1.> , [“Rossini” , 2 , 4.5] ]
Complicou ainda mais? Observe atentamente, lembre-se que colchetes delimitam a lista,
e a vírgula separa cada elemento, tente descobrir quantos elementos temos em nossa
lista e quais seus tipos.
Você pode acrescentar quantos elementos quiser á lista, porem, quando estiver
escrevendo seu script, não se esqueça que em tempo de compilação, ou seja, quando for
salvar seu script, existe um limite de 72 elementos. Você pode recuperar qualquer
elemento dentro de uma lista especificando seu índice, que é simplesmente a posição
ocupada pelo mesmo, mas isso deixaremos para quando formos estudar as funções
relativas ao tipo lista.
Caso não tenha descoberto quantos elementos possui nossa lista exemplo, veja se
consegue perceber 6 elementos, sendo, na seqüência, dos seguintes tipos:
String , float , integer , key , vector , list . é isso mesmo, nossa lista tem outra lista
dentro.
Rotation e quaternion
Este tipo é usado para armazenar valores relativos a rotação de um objeto. Vou ser bem
sincero, este é o tipo mais complicado que temos, pois temos que aprender conceitos
sobre rotação global e local, temos que ter uma noção mínima de grau e radiano, assim
como de rotação relativa ao objeto raiz, ou principal , etc. Enfim, são muitos conceitos
relacionados para aprofundar-mos sem ter o devido conhecimento sobre os outros tipos
e sem saber utilizar corretamente controles de fluxo. Fica para o próximo guia.
Controle de Fluxo
while
Podemos traduzir while como “enquanto” para nossa explicação. While verifica uma
condição e, caso ela retorne verdadeira, executa o bloco de código, verificando a
condição novamente em seguida. Esse processo se repete ate que o teste da condição
retorne falso. Vamos imaginar um laço while em nossa vida real: “enquanto (não
ganhei) {jogar na megasena}”, “Enquanto (ganhar abaixo R$ 10.000,00) {tentar
promoção}”, e por ultimo, “Enquanto (não saber programar scripts){estudar este guia}.
A sintaxe é a seguinte:
While(condição)
{
//comandos a executar;
}
Este loop é muito usado em situações onde não sabemos quantas vezes teremos que
executar determinado bloco de código, e devemos tomar certo cuidado com ele, visto
que a condição que estipulamos pode não ser alcançada nunca, ocasionando o que
chamamos de loop infinito. Isto pode, dependendo da complexidade dos comando
executados, deixar o script extremamente lento.
Atentem para a finalização de cada comando dentro do bloco de códigos com pont e
virgula, abra e feche todos as chaves abertas e, principalmente, observe que while testa
a condição primeiro, e se depois de verificada como true(verdadeiro) ela executa o
bloco de códigos. Com isso, seu código pode não ser executado nenhuma vez.
do while
Faça enquanto. “Faça {exercícios} enquanto (não saber programar)” A sintaxe de um
do...while é a seguinte:
Do
{
//comandos a executar;
}
While (condição)
Entre os parênteses, temos 3 blocos separados por ; (ponto e virgula), vamos entender
cada um:
1 bloco i = 0;
Este bloco atribui a variável i o valor 0, em outras palavras, esse bloco diz, "Atenção
for, vou começar a contar a partir de zero".
2 bloco i >=10;
Este bloco estabelece a condição necessária para o fim do loop, para iniciantes, esse
bloco diz, "atenção for, enquanto for menor ou igual a dez"
3 bloco i++
Este bloco estabelece como incrementar o contador, algo como, "Hey for, vou contar de
um em um"
Apos verificada a condição, o laço for executa o bloco de códigos, então incrementa o
contador, e faz a verificação da condição novamente.
If...else
Simples e largamente utilizado, dizem popularmente que programar é saber usar if ,
else.
A tradução de if é “se”. É um laço condicional, que avalia uma condição para saber se
faz isso ou aquilo. Na vida real, o laço if seria como: “ Se (estiver com fome) {coma}”
“Se (tem dinheiro e quer uma camisa) {compre}”. Else traduzido quer dizer “senão”,
novamente, na vida real, seria algo assim: “Se (tenho dinheiro) {vou gastar} senão {vou
trabalhar}”, ou “Se (tênis custa menos do qe tenho) {vou comprar a vista} senão {vou
parcelar }. Espero ter conseguido passar a noçã do uso de If...else. A sintaxe é a
seguinte:
If (condição)
{
//código a executar se verdadeiro;
}
Else
{
//código a executar se falso}
}
Esta sintaxe não é inflexível, vejamos quando apenas desejo testar se é verdadeiro:
If (condição)
{
//código a executar se verdadeiro;
}
E se o código a executar á apenas um comando??
If (condição)//comando a executar;
Este if é chamado “inline”, ou “em uma linha”.
Não podemos esquecer também que um if pode estar dentro de outro if, o que nos
confere a habilidade de especificar não apenas dois caminhos, mas sim quantos
caminhos considerarmos que nosso script pode seguir.
If (condição)
{
If (condição)
{
If (condição)
{
//código a executar se verdadeiro;
}
Jump
Este controle de fluxo é de fácil entendimento (jump = pulo em português). Vamos
começar com a vida real. Imagine-se precisando sair agora, você analisa seu estado, se
esta limpo, com uma roupa adequada para o momento, em caso negativo, você vai
pensar e começar a fazer o que é necessário para estar adequado para sua saída de
emergência, okay?? Agora vamos supor que você considere-se adequado para sair
imediatamente, por um acaso você fica pensado em tudo que faria se não estivesse
adequado? Seu cérebro automaticamente pula (jump) toda a informação relativa ao que
não fazer. Em script, podemos fazer algo parecido, analisando uma condição ou
automaticamente ao chegar a certo ponto do script. Para conseguirmos isto, definimos
etiquetas (labels), que são pontos definidos, e então, quando necessário, dizemos ao
script “pule para local1” (jump local1). Os Locais (labels) são definidos colocando @na
frente do nome que escolhermos.
Vamos a um exemplo?
vou comentar resumidamente o que ocorre:
integer a = 5;
jump avance;
@agora;
a = 6;
@avance;
llOwnerSay((string)a);
if(a < 6)jump agora;
return
Retorno, volta, regresso, a tradução de return quase nos é suficiente. Quando incluímos
uma declaração return; em uma função ou evento de nosso script, dizemos ao
compilador que, “quando chegar aqui, pule direto para aquele lugar, esqueça o restante
da função ou evento” .
Observação: jump e return são métodos depreciados de controle de fluxo, é raro casos
em que seu uso realmente se justifica. Na maioria das vezes, seu uso deveria ser
substituído por uma lógica adequada. A principio não se preocupe, quando atingir certo
nível de compreensão e uso dos outros laços, automaticamente deixara de usar jump e
return.
Funções
Como dito na introdução, Second Life disponibiliza, até o momento, mais de 400
funções pré-definidas. Devido a a esta grande quantidade, vamos agrupar funções co-
relacionadas para um melhor aproveitamento.
Este capitulo se apresenta com o intuito de explicar na pratica algumas funções
relacionadas com a comunicação. Veremos as seguintes funções:
• llWhisper
• llSay
• llShout
• llOwnerSay
• llInstantMessage
• llListen
• llLintenControl
• llListenRemove
Veremos também os seguintes eventos:
• listen
Canal de Comunicação
Antes, vamos ver o que é canal de comunicação em SL.
Quando você esta conversando com alguém, todos ao seu redor, em uma determinada
distancia, vêem o que você digitou assim como você também vê o que outras pessoas
relativamente próximas a você estão falando. Isto ocorre porque todos, inclusive você,
estão usando um canal publico para comunicação, esse canal é o de numero 0. Alem
deste, temos outros 2.147.483.647 canais para comunicação. Achou um numero
absurdo? Considere então que os objetos, entre si, podem usar também canais negativos.
Apenas os objetos podem usar canais negativos, não se esqueça disso. Todos os canais,
exceto o 0, são canais privados, o que significa que mensagens transmitidas através
deles não são ouvidas pelas pessoas próximas ou não de você. O uso de canal privado é
intenso entre objetos, quando, por exemplo, você toca em um objeto interruptor, ele
envia uma mensagem para um objeto lâmpada, fazendo a mesma acender.
Você também pode enviar mensagens para objetos, basta para isso que você configure-o
para ouvir em um determinado canal e dizer sua mensagem através do mesmo, isso se
consegue com a barra invertida seguida do canal desejado e a mensagem. Por exemplo,
se você teclar na janela de chat a seguinte linha:
/5 Será que vou ouvir??
Você estará dizendo “Será que vou ouvir??” no canal 5, e como avatares apenas ouvem
no canal 0, você não verá sua mensagem ser mostrada na tela de chat. Experimente.
O objeto também pode estar configurado para ouvir no canal 0, ou em todos, como
veremos adiante.
Chegamos finalmente ás funções.
llOwnerSay(string mensagem);
Quando desejamos que um objeto envie uma mensagem para nos mesmos, sem usar
nenhum canal, evitando uma possível captura, usamos esta função. Ela necessita apenas
da mensagem desejada como parâmetro. A única exigência desta função é que você
esteja na mesma área em que esta o objeto.
Aqui faço uma pausa para explicar mais um conceito em programação de scripts em Sl,
o delay, ou atraso em português.
Delay
Esta é uma indesejável característica de varias das funções que nós estudaremos. Vamos
explicar com a ultima função vista. Esta função possui um delay de 2.0 segundos, isso
quer dizer que, quando nosso script encontrar esta função, vai demorar 2 segundos para
ela ser executada, é como se nosso script dormisse por 2 segundos. Imagine se tivermos
cerca de 20 desta função em nosso script, precisaríamos de 40 segundos para que nosso
script mandasse a ultima mensagem. Certas funções chegam a ter um delay de 20
segundos, o que pode ser absurdo para que nossa intenção se concretize. Vamos supor
que esta desenvolvendo um escudo contra aquelas armas que nos mandam pra longe, e
você resolva mandar uma IM (mensagem instantânea) para o usuário que atirou em
você. Com o delay de 2 segundos, você vai estar muuuito longe quando seu escudo
finalmente resolver funcionar, e você vai quebrar a cabeça imaginando o que tem de
errado com seu script. Jamais ignore o delay de cada função.
Uma maneira de resolver este problema é colocar a função lerdinha em um script
separado, a qual se chama de “child”, e fazer uma chamada a ele. Assim, enquanto o
script child fica travado esperando a função concluir seu trabalho, nosso script principal
continua normalmente, parecendo estar em “tempo real”.
Logo colocarei exemplos de scripts lerdos, que podem ser otimizados separando
convenientemente as funções mais demoradas.
listen(integer canal, string nome, key pessoa, string mensagem) {...}
Vamos ver agora um evento, antes de ver suas funções correlacionadas. O evento listen
é acionado quando o objeto ouve algo, quando captura qualquer mensagem. Então, se
quisermos que nosso objeto responda a mensagens, provenientes de outros objetos ou
pessoas, devemos acionar este evento e codifica-lo para responder a essas mensagens.
Como visto acima, chamamos o evento listen declarando as variáveis que representarão
o canal em que escutara, o nome do objeto, a pessoa de quem ele escutara as
mensagens, e as próprias mensagens. Com estas variáveis vamos codificar, dentro das
chaves, o código necessário.
Preste atenção.
Estamos apenas declarando as variáveis que vamos trabalhar com elas, passar os
valores é trabalho para a seguinte função
llListenRemove(integer numero);
Novamente trabalhamos com o valor de retorno da função llListen. Aqui, ao passar o
numero do filtro á função, ela remove definitivamente o evento listen correspondente a
este filtro.
Pratica
Finalmente chegamos a alguma coisa interessante, confesso que eu não agüentava mais
tanta teoria, mas infelizmente é importantíssima. Caso não tenha entendido algo, não
tenha dado importância a detalhes, observações, sugiro que volte e leia novamente a
parte que você não teve paciência para ler. Apesar de simples, os exemplos que veremos
são para aprendizado, no sentido de saber fazer, e não copiar um script pronto e
modificar o que você achar necessário.
Faremos uso das funções relacionadas ao evento listen, bem como o uso de laços.
Nosso objeto, depois de codificado, vai responder a comandos específicos. Por
enquanto, nada demais, mas acredito que você vai ter uma boa noção das possibilidades,
alem de, muito importante, praticar quase tudo que viu ate agora.
Procure uma área em que possa construir, em pesquisar, procure por “sandbox”.
Crie um novo objeto (quadrado, esfera, tanto faz) e na aba conteúdo, clique em novo
script. Apague o esqueleto que é montado pra você e digite o código da próxima pagina.
Vou comentar resumidamente o que o código faz, se tiver duvida, releia a parte relativa
à que você não entendeu. Se ainda restarem duvidas, estou à inteira disposição para
esclarecimentos via e-mail.
Logo no inicio, temos a declaração de uma variável l (ele, rss) do tipo integer, ela
manipulará um dos filtros do nosso evento listen.
No evento que ocorre ao entrarmos no estado default (state_entry), configuramos nosso
listen para ouvir no canal 127, e aceitar qualquer outro parâmetro (nome, pessoa e
mensagem).
Atribuímos nosso segundo filtro a variável l, e na próxima linha, desativamos este filtro.
A partir de então, trabalhamos apenas no evento listen.
Lembra-se como mandar uma mensagem em algum canal privado?
Caso tenha esquecido, digite /127 e a mensagem em seguida, não se esqueça que tem
um espaço entre o canal especificado e a mensagem.
Vamos tratar as diferentes mensagens com IFs aninhados (um if dentro de outro if). Se
digitarmos “Ativar” no canal 127, nosso evento habilitará a escuta no canal público
(segundo filtro criado). Se digitarmos “Desativar”, ele desativa a escuta no canal
publico.
Se digitarmos “Lerdo”, veremos o significado do delay de uma função, observe a
velocidade com que as mensagens serão exibidas na janela de chat. Aqui também
podemos ver um laço for funcionando.
Já se digitarmos “Rápido”, nosso script executa uma função sem delay, e o texto é
exibido instantaneamente na tela. Aqui temos um laço while. Preste atenção e veja se
consegue entende-lo completamente.
Você deve ter notado que, em cada bloco de códigos if, há um return. Os IFs só
retornam verdadeiro se o canal for o 127, que escolhemos para comunicar-mos com
nosso objeto. Não há necessidade e nem queremos que o script continue respondendo ao
evento se já executou a ação desejada. Eis a função do return, esquecer o resto do
código e sair do evento.
Caso o filtro para o canal publico esteja habilitado, a ultima função é chamada
(llOwnerSay(msg)), e o que nosso objeto captou é retransmitido a nós.
Comunicação e Controle sobre um Objeto
integer l;
default
{
state_entry()
{
llListen(127,"","","");
l=llListen(0,"","","");
llListenControl(l,FALSE);
}
listen(integer canal,string obj,key id,string msg)
{
if (canal==127)
{
if (msg=="Ativar")
{
llListenControl(l,TRUE);
llOwnerSay("Escuntando em todos os Canais");
return;
}
if (msg=="Desativar")
{
llListenControl(l,FALSE);
llOwnerSay("Apenas Escutando Canal 127");
return;
}
if (msg=="Lerdo")
{
integer i;
key id = llGetOwner();
for(i=1;i<=9;i++)
{
llInstantMessage(id,"Mensagem Lerda " + (string)i);
}
return;
}
if (msg=="Rapido")
{
integer i=1;
while(i<10)
{
llOwnerSay(" Mensagem Rapida " +(string)i);
i++;
}
return;
}
}
llOwnerSay(msg);
}
}
Um bom nome para nosso objeto seria “repetidor”, pois é apenas isso que ele faz. Ouve,
quando ativado, no canal publico, e retransmite ao dono. Com exceção de llGetOwner(),
apenas utilizamos funções que aprendemos até agora. Não se esqueça que podemos ter
qualquer função executada através de nosso comando. Então não se desanime caso
tenha achado o exemplo entediante. Se você for novato de tudo, sinta-se orgulhoso por
estar escrevendo seu primeiro script.
Sinta-se livre para alterar os comandos a vontade, apenas não se esqueça que se alterar
“Ativar” para “ligar”, você terá que dizer “ligar” para seu script funcionar.
Atenção:
1. “Case Sensitive” significa “sensível a maiúsculas e minúsculas”. Então, preste
atenção a nomes, funções, e tudo o mais. FALSE é diferente de False.
2. Todas as funções embutidas de SL começam por ll seguida da primeira letra em
maiúscula para cada palavra da função. Por exemplo llInstantMessage.
3. Toda chave aberta deve ser fechada. { e }.
4. Toda comando digitado, deve ser finalizado com ponto-e-virgula.
Vamos agora fazer algo um pouco mais interessante, mas sem fugir do que foi visto até
agora.
Nosso repetidor é legalzinho, mas que tal um objeto transmissor e outro receptor?
A primeira coisa que temos que fazer, é escolher em que canal se comunicarão, o canal
em que nos comunicaremos com eles e o alcance desejado.
Para este exemplo, estou considerando o seguinte:
• A comunicação dono Æ receptor será no canal 127
• A Comunicação receptor Æ dono será via llOwnerSay
• A comunicação receptor Æ transmissor será apenas no canal -254
• A comunicação transmissor Æ receptor será apenas no canal -500
• O alcance inicial entre objetos será de 20 metros.
Feitas as considerações, vamos ao código dos objetos.
Transmissor
integer l;
default
{
state_entry()
{
llListen(-254,"","","");
l=llListen(0,"","","");
llListenControl(l,FALSE);
llOwnerSay("Transmissor Posicionado \n\t\t\t\t\t Aguardando
Inicializacao");
}
listen(integer canal,string nome,key id,string msg)
{
if (canal==-254)
{
if(msg=="Ativar")
{
llListenControl(l,1);
llSay(-500,"Transmissor Ativado");
return;
}
if (msg=="Desativar")
{
llListenControl(l,0);
llSay(-500,"Transmissor Desativado");
return;
}
}
llSay(-500,msg);
}
}
Receptor
default
{
state_entry()
{
llListen(127,"","","");
llListen(-500,"","","");
llOwnerSay("Receptor Posicionado \n\t\t\t\t\t Ouvindo
Canal 127 e -500 \n\t\t\t\t\tTransmitindo no Canal -254");
}
listen(integer canal,string nome,key id, string msg)
{
if(canal==127)
{
if(msg=="Ativar")
{
llSay(-254,msg);
return;
}
if(msg=="Desativar")
{
llSay(-254,msg);
return;
}
}
else
{
llOwnerSay(msg);
}
}
}
Acredito que não seja mais necessário dizer isso, mas vamos lá. Crie um objeto de
qualquer forma, e na aba conteúdo, abra um novo script, apague o esqueleto montado, e
digite o código do objeto receptor. Na aba Geral, de o nome de receptor ao objeto. Crie
um novo objeto, digite o código do transmissor, e de a ele o nome de transmissor.