Ir para conteúdo

A Linguagem Lua E Suas Aplicações Em Jogos


SkyLigh

Posts Recomendados

Iae galera do ekz como antes eu tinha trago um ttópico da origem .lua agora trago sobre como utilizala e com sua origem também

 

 

ALinguagemLuaesuasAplicacoesemJogos Waldemar Celes, Luiz Henrique de Figueiredo, Roberto Ierusalimschy

Umapesquisarealizadaemsetembrode2003pelagamedev.net—umimportantesite paraprogramadores de jogos — revelou que a grande maioria dos jogos (72%) e desenvolvida com o auxılio de uma linguagem de script.

Embora as linguagens de script nao sejam definidas muito precisamente, elas apresentam um conjunto de caracterısticas comuns tıpicas. Em geral, as linguagens de script sao linguagens interpretadas, temtipagemdinamicaegerenciaautomaticadememoria, efornecemfacilidadespara construcaodeestruturasdedadosdinamicasemanipulacaodecadeiasdecaracteres. Tipicamente, essas linguagens funcionam acopladas a programas hospedeiros implementados em linguagens compiladas tradicionais como C e C++. Uma outra caracterıstica importante de linguagens de script e que elas devem ser seguras, nao sendo possıvel acessar servicos nao autorizados do programa hospedeiro. A combinacao dessas caracterısticas resulta numa excelente ferramenta para o desenvolvimento de jogos.

Acoplar uma linguagem de script em um jogo traz varios benefıcios. A linguagem de script pode ser usada para efetivamente implementar o script do jogo, para definir objetos e seus comportamentos, para gerenciar os algoritmos de inteligencia artificial e controlar os personagens, e ainda para tratar os eventos de entrada e descrever a interface com o usuario. Uma linguagem de script tambem desempenha um papel importante nas etapas de prototipacao, teste, depuracao e analise deadequacaodojogo. Aescolhadeumalinguagemdescript simplespermiteaindaquesejadadoa roteiristas e artistas acesso programavel ao jogo, a fim de que eles que possam experimentar novas ideias e variacoes. Esses profissionais conduzem a maior parte do desenvolvimento real do jogo mas nao sao em geral programadores profissionais e nao estao familiarizados com tecnicas sofisticadas de programacao.

AmesmapesquisamencionadaacimarevelouqueLua eatualmentealinguagemdescript mais utilizada no desenvolvimento de jogos (20% dos jogos sao desenvolvidos com Lua, enquanto somente 7% usam Python, a segunda linguagem de script mais citada na pesquisa). De fato, devido aoseupequenotamanho,bomdesempenho,portabilidadeefacilidadedeintegracao,Luatemsido amplamente utilizada na industria de jogos. Empresas com LucasArts, BioWare, Microsoft, Relic Entertainment, Absolute Studios e Monkeystone Games desenvolvem jogos usando Lua.

Lua eumalinguagemdescript extensıvel, projetadaparaoferecermeta-mecanismosquepossibilitam a construcao de mecanismos mais especıficos. Com isso, e facil adequar Lua as necessidades da aplicacao, sem comprometer as suas caracterısticas basicas, mantidas desde a sua criacao, tais como portabilidade, pequeno tamanho e simplicidade. Em particular, os programadores dos jogos podem fornecer abstracoes adequadas para roteiristas e artistas, simplificando as tarefas desses.

Neste tutorial, discutiremos o uso da linguagem Lua no desenvolvimento de jogos. Vamos apresentar os principais mecanismos de programacao oferecidos pela linguagem e a interface para a integracao com programas hospedeiros escrito em C ou C++. Discutiremos ainda como estes mecanismos podem ser usados para a construcao de jogos mais flexıveis, que fornecem acesso programavel aos servicos implementados pelo programa hospedeiro.

 

 

2 Linguagensdeextensao

 

Vamos classificar as linguagens de extensao ou de script segundo a sua complexidade:

• Linguagens de configuracao servem para selecionar preferencias e sao tipicamente uma lista de valores associados a variaveis. Um exemplo tıpico sao os arquivos .ini do Windows.

• Linguagensdemacros servemparaautomacaodetarefasesaotipicamenteumalistadeacoes primitivas, com muito pouco ou nenhum controle de fluxo. Um exemplo tıpico sao os arquivos de automacao de conexoes internet via modem.

• Linguagens embutidas permitem acesso programavel aos servicos da aplicacao, com fluxo de controle completo e funcoes definidas pelo usuario a partir de primitivas exportadas pela aplicacao. Essas linguagens sao linguagens completas, muitas vezes variantes simplificadas de linguagens tradicionais como Lisp ou C.

Independente da complexidade da linguagem, a adocao de uma linguagem de extensao e uma tecnica poderosa de desenvolvimento de software, pois permite que muitos aspectos da aplicacao sejam controlados externamente, a partir de arquivos textos facilmente editados pelo programador ou pelo usuario, sem necessidade de recompilar a aplicacao. Isso torna o desenvolvimento mais agil, pois permite que partes importantes da aplicacao sejam desenvolvidas por outros membros da equipe que nao sao programadores profissionais (no caso de jogos, animadores e artistas).

Alem disso, a adocao de uma mesma linguagem para varias tarefas na aplicacao permite um aumento importante de produtividade global, pois nao e necessario definir, documentar e manter varios formatos diferentes. Para o usuario da aplicacao, isso se traduz no re-aproveitamento automatico (e inconsciente) dos conceitos aprendidos para realizar as varias tarefas, encorajando a exploracao.

 

 

3 AlinguagemLua

 

AlinguagemLua eumalinguagemdeprogramacaopoderosaeleve,projetadaparaestenderaplicacoes. Isso quer dizer que ela foi projetada para ser acoplada a programas maiores que precisem ler e executar programas escritos pelos usuarios. Na classificacao da Secao 2, Lua e uma linguagem embutida, com sintaxe semelhante a de Pascal mas com construcoes modernas, como funcoes anonimas, inspiradas no paradigma funcional, e poderosos construtores de dados. Isso faz com que Lua seja uma linguagem de grande expressao com uma sintaxe familiar.

 

 

3.1 Historia

 

Lua foi projetada e implementada no Tecgraf, o Grupo de Computacao Grafica da PUC-Rio. A primeira versao de Lua (1.0) e de julho de 1993. A primeira versao publica (1.1) e de julho de 1994. A versao atual e a 5.0.2, lancada em marco de 2004 para corrigir pequenas falhas na versao 5.0, de abril de 2003. A versao 5.1 esta em desenvolvimento no momento. Este texto trata da versao oficial atual (5.0.2).

A motivacao para a criacao de Lua no Tecgraf foi a necessidade crescente das suas aplicacoes serem configuraveis externamente pelos usuarios. Isso quer dizer que diversos aspectos essenciais das aplicacoes podem ser modificados sem recompilar a aplicacao. Desde o inıcio, nas aplicacoes criadas no Tecgraf, esse tipo de configuracao era muito mais do que simplesmente poder escolher a cor da janela ou o tipo de fonte de texto: era necessario poder tomar decisoes em tempo de execucao que somente os usuarios sabiam quais eram. Sendo assim, era necessario fornecer algum tipo de programacao para os usuarios finais. Um outro tipo de configuracao era a descricao de complexos relatorios e analises feitas pela Petrobras por encomenda ao Tecgraf. Mais uma vez, essa descricao nao podia estar congelada dentro da aplicacao pois cada usuario tinha uma necessidade diferente e que mudava a cada tarefa. O Tecgraf tinha portanto (e ainda tem) forte demanda para aplicacoes que fossem configuraveis externamente, tanto descrevendo que decisoes deveriam ser tomadas quanto descrevendo quais dados seriam usados e como eles seriam usados.

Apos projetar e usar com sucesso duas pequenas linguagens especıficas para cada uma dessas tarefas, o Tecgraf decidiu investir na criacao de uma linguagem unica que pudesse atender a todas as necessidades de configuracao das suas aplicacoes. Assim nasceu Lua: uma linguagem procedural simples com poderosas construcoes para descricao de dados. Desde entao Lua tem sido usada em inumeros projetos no Tecgraf.

A versao seguinte de Lua (2.1) foi lancada em fevereiro de 1995 e trouxe maior poder de expressao, introduzindo a nocao de semantica extensıvel: passou a ser possıvel programar o que fazer em casos excepcionais, como quando um campo nao existe numa tabela. Ter uma semantica extensıvel e desde entao uma caracterıstica marcante de Lua.

A versao 2.1 tambem foi a primeira a ser completamente livre; as versoes anteriores eram livres somente para aplicacoes academicas. Aliada a portabilidade e a eficiencia da implementacao, a falta de restricoes de uso foi um dos fatores importantes na adocao de Lua em inumeros projetos nomundotodo.

A primeira notıcia que tivemos do uso de Lua em jogos foi em 1997 quando a LucasArts adotou

Lua como a sua linguagem de script no lugar de SCUMM no jogo “Grim Fandango”. A adocao de Lua nesse jogo foi uma consequencia direta da publicacao de um artigo de divulgacao sobre Lua na revista Dr. Dobb’s Journal, em junho de 1996. Desde entao, Lua tem sido cada vez mais usada em jogos, uma area longe das areas que motivaram a sua criacao!

Atualmente, Lua tem uma comunidade ativa de programadores. A lista de discussao tem mais de 750 assinantes do mundo todo. Alem do site oficial de Lua (lua.org), ha tambem um ativo site mantido por usuarios (lua-users.org), uma sala de bate-papo, um web forum e um repositorio (luaforge.net).

Lua e uma linguagem de extensao projetada para dar suporte a programacao procedural, oferecendo facilidades para descricao de dados. No contexto da programacao de jogos, isso significa que Lua possibilita combinar a descricao de objetos e a programacao de seus comportamentos num mesmo contexto. Lua e uma biblioteca implementada em C, podendo ser compilada em qualquer plataforma que tenha um compilador C padrao. Lua tambem pode ser compilada sem alteracoes como uma biblioteca C++. No que se segue, toda referencia a C deve ser entendida como uma referencia a C++ tambem. Em alguns poucos lugares trataremos exclusivamente de C++.

Por ser uma linguagem de extensao, Lua trabalha acoplada a uma aplicacao hospedeira (host).

Essa aplicacao pode criar e ler valores armazenados em Lua, executar funcoes de Lua e registrar funcoes C no ambiente de Lua. As funcoes C registradas em Lua, por sua vez, podem ser invocadas de programas Lua. Dessa forma, podemos conciliar as facilidades de uma linguagem de script oferecidas porLua com a eficiencia daslinguagens C e C++. Adistribuicao dalinguagem Lua inclui um programa hospedeiro, lua.c, que pode ser usado para executar scripts Lua interativamente ou em batch. Neste tutorial, no entanto, focaremos no uso de Lua acoplada a programas de jogos.

Para que uma aplicacao tenha acesso a Lua, precisamos abrir a biblioteca conforme sera discutido na Secao 3.9. Ao final, a aplicacao deve fechar a biblioteca. Apos a abertura da biblioteca, a aplicacao pode usar os recursos oferecidos por Lua, como por exemplo, executar scripts Lua e acessardadosarmazenadosemLua. Antesdedetalharmoscomoissopodeserfeitodentrodocodigoda aplicacao, temos que aprender como escrever scripts em Lua. Programas ou scripts Lua sao armazenados em arquivos (usualmente com extensao .lua) ou em strings da aplicacao. Um arquivo ou string com codigo Lua caracteriza o que chamamos de chunk, que e simplesmente uma sequencia de comandos Lua. Daremos a seguir uma breve introducao as principais caracterısticas da linguagem Lua.

 

3.3 Variaveis e tipos

 

Em Lua, as variaveis nao tem tipos associados a elas: os tipos estao associados aos valores armazenadosnasvariaveis. Dessaforma,umamesmavariavelpodenummomentoarmazenarumvalorde um tipo e depois passar a armazenar o valor de outro tipo (naturalmente, a variavel deixa de armazenar o valor inicial). O trecho de codigo abaixo ilustra o uso de variaveis armazenando diferentes valores:

(Note a forma dos comentarios em Lua: comecam com -- e vao ate o final da linha.)

O fato de o tipo estar associado ao valor, e nao a variavel, da grande flexibilidade a linguagem. Podemos, por exemplo, criar conjuntos de valores heterogeneos naturalmente, pois o poliformismo e intrınseco a linguagem. Por outro lado, a verificacao de tipo so pode ser feita em tempo de execucao. Assim, se tentarmos somar duas variaveis cujos valores nao sao numericos, um erro sera reportado, mas somente quando a soma for executada. Como pretendemos, ao acoplar Lua ao jogo, exportar servicos da aplicacao, devemos prever um tratamento adequado desses erros de execucao. Um usuario de um jogo pode codificar uma configuracao invalida e isso deve ser tratado de maneira adequada, sem necessariamente abortar o jogo.

Em Lua, variaveis globais nao precisam ser declaradas. Quando escrevemos a = 3, a variavel a e, por default, uma variavel global. Se desejarmos que uma variavel tenha escopo local (a um bloco ou chunk), devemos declara-la previamente usando a palavra local. Por exemplo:

Os valores em Lua podem ser de oito tipos:

• nil: o valor nil indica ausencia de valor. Variaveis nao inicializadas contem o valor nil. O valor nil tambem e interpretado como falso numa expressao booleana.

• boolean: valor booleano, podendo ser falso (false) ou verdadeiro (true);

• number: valor numerico. Lua nao diferencia valor inteiro de valor real; so existe um tipo para representar numeros;

• string: valor cadeia de caracteres. Uma constante string pode ser delimitada por aspas duplas ("..."), aspas simples (’...’), ou duplo colchetes ([[...]]).

• table: vetor associativo (a ser detalhado na Secao 3.6);

• function: funcao escrita em Lua ou escrita em C e registrada em Lua;

• userdata: dado do host, representado por um ponteiro void*;

• thread: linha de execucao, que sera apresentado na Secao 3.8, quando descrevermos o uso de co-rotinas em Lua.

 

 

3.4 Operadores e controladores de fluxo

dados por: and (e), or (ou), not (negacao). Existe ainda o operador para concatenacao de strings.

A linguagem Lua oferece os operadores comumente encontrados em linguagens de programacao. Os operadores aritmeticos sao os usuais: + (adicao), - (subtracao), * (multiplicacao), / (divisao), (exponenciacao) e - unario (negacao). Os operadores relacionais resultam num valor booleano e incluem: < (menor que), > (maior que), <= (menor ou igual que), >= (maior ou igual que), == (igualdade), ~= (diferenca). Os operadores logicos servem para combinar valores booleanos e sao Os operadores logicos and e or sao uteis tambem na avaliacao de expressoes. Esses operadores combinam duas expressoes e fazem a avaliacao da segunda expressao apenas quando necessario. Alem disso, o resultado de um and ou or e ultimo valor usado na sua avaliacao. Dessa forma, e valido e muito util usar construcoes como as seguintes:

x = v or w y = a and b or c Na primeira atribuicao acima, x passa a armazenar o valor de v, se esse for diferente de falso (false ou nil); caso contrario, passa a armazenar o valor de w. A segunda atribuicao, que deve ser lida como (a and b) or c, e equivalente a expressao y = a ? b : c em C, desde que b nao resulte em falso.

trucoes para tomada de decisao sao as variantes usuais de if then ... else:

A linguagem Lua oferece os controladores de fluxo comuns as linguagens procedurais. As cons-

if expr then if expr then if expr1 then end else elseif expr2 then end else ... end

Asconstrucoesparaexecucaoiterativapodemteroseutestenoinıcio(while)ounofim(repeat): while expr do repeat end until expr

Lua oferece ainda a construcao de lacos com for. O for numerico tem a seguinte forma: for var = expr_inicial, expr_final, expr_incremento do ... end

Nessa construcao, a variavel var e automatica e local ao laco, isto e, nao precisa ser explicitamente declarada e so existe dentro do laco. As expressoes inicial, final e de incremento sao avaliadas uma unica vez, antes do inıcio da execucao do bloco de comandos do laco. A expressao de incremento, se omitida, vale 1. Um laco de for pode ainda aparecer na sua forma generica, que permite a construcao de diversostiposdeiteradoresespecializados. Otrechodecodigoabaixo,porexemplo,usaumforgenerico para ler e imprimir cada linha do arquivo de entrada corrente, usando funcoes pre-definidas na biblioteca de entrada e saıda (uma discussao de como se constroi iteradores foge do escopo desse tutorial).

for line in io.lines() do io.write(line,"\n") end A execucao de lacos while, repeat e for pode ser interrompida usando o comando break.

Funcoes em Lua sao valores de primeira classe. Isso significa que, como qualquer outro valor, uma funcao pode ser criada, armazenada em uma variavel (local ou global) ou campo de tabela e passada adiante como parametro ou valor de retorno de uma outra funcao. Uma funcao pode receber zero ou mais valores. A lista de parametros e especificada da maneira usual: entre os parenteses que seguem o nome da funcao. Como exemplo simples (tradicional, mas util somente para fins didaticos), consideremos a definicao da funcao recursiva abaixo para o calculo do fatorial de um numero inteiro: function fat (n) if n==0 then return 1 else return n*fat(n-1) end end

As funcoes em Lua nao tem nome; elas sao sempre anonimas. O codigo acima e apenas uma maneira conveniente de definir uma funcao e atribuı-la a uma variavel global, e e equivalente a

fat = function (n) end -- func~ao anonima atribuıda a variavel fat Para testar essa funcao, podemos usar a funcao print da biblioteca padrao de Lua que imprime um valor na tela (nesse caso, 120):

res,escrevendoreturn expr1, expr2, Issoevitaemgrandeparteanecessidadedepassagem

Lua permite atribuicoes multiplas. E valido, por exemplo, escrever x,y = y,x, que troca os valores de x e y sem a necessidade de usar uma variavel temporaria, da mesma forma que e valido escrever a,b = 1,2. Ainda de forma analoga, e valido escrever a,b = f() — os valores retornados por f serao atribuıdos as variaveis a e b. (Sim, Lua permite que uma funcao retorne multiplos valode parametros por referencia; em Lua todos os parametros sao passados por valor.) Se o numero de variaveis numa atribuicao multipla for maior que o numero de valores resultantes a direita do sinal de igualdade, as variaveis excedentes recebem o valor nil. Se o numero de valores for maior, os valores excedentes sao descartados. Esse mesmo ajuste ocorre ao se chamar funcoes: argumentos ausentes recebem o valor nil; argumentos extras sao ignorados (exceto quando a funcao aceita um numero variavel de argumentos).

Funcoes podem ser criadas localmente dentro de outras funcoes, e depois retornadas ou armazenadas em uma tabela. Uma funcao pode ainda acessar variaveis locais do escopo acima. Considere por exemplo o trecho de codigo abaixo: function counter () local i = 0 return function () i = i+1 return i end end local c = counter() print(c()) print(c())

A variavel c armazena uma instancia da funcao anonima criada (e retornada) em counter. Essa funcao usa a variavel local i declarada em counter. Assim, cada vez que executamos a funcao armazenada em c, recebemos o valor da variavel i incrementado de uma unidade. Se fizermos um paralelo com C, a variavel da funcao counter funciona como uma variavel estatica para a funcao c. Se executarmos a funcao counter novamente, teremos como retorno uma outra funcao que, se chamada, retornara da primeira vez o valor 1, depois 2, e assim por diante. Essa segunda funcao e diferentedaprimeira: emboraambasfacamamesmacoisa,elasofazemdemaneiraindependente. Eimportanteobservarqueafuncaoanonima e unicaeseucodigo egeradouma unicavez. Afuncao counter retorna o que chamamos de closure, que guarda uma referencia para a funcao anonima e uma lista com os valores das variaveis do escopo superior usadas, entre outras coisas. A existencia de closures com escopo lexico (acesso a variaveis do escopo superior) permite que Lua seja usada como linguagem funcional, o que da grande flexibilidade de programacao. Por fim, considere o trecho de codigo abaixo: Todo chunk representa o corpo de uma funcao anonima que e retornada quando o chunk e carregado. No exemplo acima, atribui-se tres variaveis globais (a, f e g) e declara-se uma variavel local b. FazendoumaanalogiacomprogramacaoemC,temosqueavariavelbfuncionacomoumavariavel estatica do modulo. Na verdade, em Lua, b e uma variavel local da funcao anonima caracterizada pelo chunk, acessada de dentro da funcao que foi armazenada na variavel global g.

 

 

 

3.6 Tabelas e objetos

 

O tipo table representa um vetor associativo, implementado internamente com o uso de uma eficientecombinacaodearray ehash(tabeladedispersao). Astabelassaoa unicaformadeestruturacao de dados em Lua. Todas as estruturas de dados comumente encontradas em programacao (tais como vetores, listas, filas, conjuntos e hash) podem ser eficientemente (e facilmente) implementadascomousodetabelas. UmatabelaemLua ecriadapelaexpressao{ }. Seumavariavelarmazena um valor do tipo tabela, essa variavel pode ser indexada por qualquer outro valor (exceto nil ). O valor armazenado em cada ındice da tabela tambem pode ser de qualquer tipo (incluindo nil ). O valor associado a um ındice da tabela nao inicializado tem o valor nil. O trecho de codigo abaixo ilustra a criacao de uma tabela e a atribuicao de alguns campos:

local t = {} -- cria nova tabela t[1] = 4 -- armazena 4 no ındice 1 t[2] = "alo" -- armazena "alo" no ındice 2 t["alo"] = 5 -- armazena 5 no ındice "alo" t[t[2]] = 0 -- armazena 0 no ındice "alo" (sobrescrevendo)

Lua oferece uma sintaxe simplificada quando oındice e uma string simples (desde que a string nao seja uma palavra reservada na sintaxe de Lua). Assim, a atribuicao acima t["alo"] = 5 pode ser escrita simplesmente por t.alo = 5. Lua permite ainda que campos da tabela sejam inicializados na criacao. Dessa forma, as tres primeiras linhas do codigo acima podem ser substituıdas por:

local t = {4,"alo"; alo=5}

A biblioteca padrao de Lua oferece duas funcoes que permitem iterar sobre os elementos armazenados na tabela. A funcao ipairs itera sobre todos osındices numericos armazenados na tabela. Assim,

for i,v in ipairs(t) do end

itera sobre os pares (1,t[1]), (2,t[2]), , ate que o primeiro ındice com valor associado igual a

nil seja encontrado.

A funcao pairs permite iterar sobre todos os pares armazenados na tabela, independente do tipo associado a chave:

for k,v in pairs(t) do end

Nesse caso, a ordem em que os pares k,v sao reportados e indefinida.

Como ındices (chaves) e valores de uma tabela podem ser valores quaisquer, podemos naturalmente usar tabelas como ındices e valores. Com isso, podemos ter tabelas aninhadas (inclusive com ciclos). Considere a tabela abaixo, que especifica os parametros para a criacao de uma janela de dialogo numa aplicacao grafica. Observe que funcoes podem tambem ser armazenadas em tabelas.

{label="Load",action=function () end},

{label="Save",action=function () end},

Lua permite ainda a especificacao de um “construtor” na criacao da tabela. Consideremos, por exemplo, a especificacao de um ponto em 3D, dado pelas suas coordenadas. Em Lua, podemos escrever:

local p = Point{x=3.0,y=1.3,z=3.2}

O codigo acima e equivalente a local p = Point({x=3.0,y=1.3,z=3.2}) isto e, uma tabela e criada e chama-se a funcao Point passando a nova tabela como parametro. Essa funcao pode ser o construtor do objeto sendo criado. Por exemplo, podemos usar a funcao para validar e inicializar campos do objeto.

function Point (self) self.x = tonumber(self.x) or 0.0 self.x = tonumber(self.y) or 0.0 self.x = tonumber(self.z) or 0.0 return self end

Assim, se na criacao do objeto nao forem especificados valores das coordenadas (ou se forem especificados valores nao numericos), a funcao inicializa esses valores com zero.

Lua oferece ainda um eficiente mecanismo para estendermos a sua semantica atraves do uso de eventos. Esse mecanismo permite, por exemplo, adotarmos uma programacao orientada a objetos. Para estender a semantica de um objeto (tabela), devemos associar a ele uma outra tabela, chamada de metatable. Na metatable, podemos programar a acao que deve ser tomada quando ocorre um determinado evento. Por exemplo, a operacao de soma nao e especificada para tabelas; no entanto, podemos fazer com que dois objetos do nosso tipo Point acima possam ser somados, gerando um terceiro novo objeto do tipo Point. Para isso, devemos primeiro criar uma metatable com o comportamento da operacao de soma definido:

local Point_metatable = { __add = function (p1,p2) return Point(p1.x+p2.x,p1.y+p2.y,p1.z+p2.z} end }

Devemos reescrever o construtor de Point para definir a metatable de cada objeto criado:

function Point (self) self.x = tonumber(self.x) or 0.0 self.x = tonumber(self.y) or 0.0 self.x = tonumber(self.z) or 0.0 setmetatable(self,Point_metatable) return self end

Assim, definimos um objeto Point e podemos usa-lo de maneira transparente:

local p = Point{x=3.0,y=1.3,z=3.2} local q = Point{x=4.2,y=1.0} local r = p+q -- r.x=7.2, r.y=2.3, r.z=3.2

Alemdeadd,podemos(re-)definirocomportamentoquandodaocorrenciadosseguinteseventosdeoperacaoaritmetica: sub (subtracao),mul(multiplicacao),div (divisao),pow (exponeciacao), unm (negacao), concat (concatenacao), eq (igualdade), lt (menor que), le (menor ou igual que).

Basta criar o campo adequado na metatable. (O nome do campo e o nome do evento precedido de _.)

Existem ainda dois eventos especiais cujos comportamentos podem ser programados: index, gerado quando tentamos acessar um ındice nao existente na tabela, e newindex, gerado quando tentamos atribuir um valor a um ındice ainda nao existente na tabela. Esses eventos podem ser usados para programar diferentes comportamentos. Por exemplo, podemos usar o evento index para delegar a uma outra tabela a busca do valor associado aoındice. Dessa forma, podemos programar nosso proprio mecanismo de heranca. Se o objeto nao tem o campo, retornamos o campo associado a sua “classe”:

local Point_methods = {

Print = function (self) print(self.x, self.y, self.z) end, ... }

Na metatable, associamos a tabela acima ao campo __index:

local Point_metatable = { __index = Point_methods,

__add = function (p1,p2) return Point(p1.x+p2.x,p1.y+p2.y,p1.z+p2.z} end }

Podemos entao acessar o “metodo” Print de nosso tipo:

local p = Point{x=3.0,y=1.3,z=3.2} local q = Point{x=4.2,y=1.0} local r = p+q r.Print®

Para facilitar o uso e dar clareza ao codigo, a ultima linha do codigo acima pode ser escrita r:Print(), como se espera de uma chamada de metodo em C++ ou Java. Em Lua, a chamada de funcao da forma t:meth(...) e equivalente a t.meth(t,...).

Seadelegacaonaofordireta,podemosatribuiraocampo__indexdametatable umafuncaoque deveserexecutadaquandooeventoocorrer. Istonosdaflexibilidadepara,porexemplo,buscarmos o valor do campo num objeto em C!

 

 

3.7 Biblioteca padrao

 

A distribuicao oficial de Lua inclui um conjunto de bibliotecas que implementam diversas funcoes importantes para a construcao de programas. Com excecao das funcoes que pertencem ao que chamamos de biblioteca basica, as funcoes de cada biblioteca sao agrupadas em tabelas. Assim, a tabela string agrupa as funcoes para manipulacao de strings, a tabela table agrupa as funcoes para manipulacao de tabelas e assim por diante. Listamos abaixo as bibliotecas padrao incluıdas na distribuicao. O manual de referencia contem uma descricao detalhada das funcoes oferecidas.

Alemdabibliotecabasica,queoferecefuncoesbasicasparaaprogramacaoemLua(comoprint, setmetatable, pairs, que usamos acima), a distribuicao inclui as seguintes bibliotecas:

• string: oferece funcoes para manipulacao de strings. Destacamos o poderoso mecanismo de casamento de padroes (pattern matching) oferecido atraves das funcoes string.find, que permite buscar a ocorrencia de um padrao numa string, e string.gsub, que permite substituirmos ocorrencia de um padrao por uma sequencia de caracteres dentro de uma string.

• table: oferece funcoes para manipulacao de tabelas, tais como funcoes para inserir um novo elemento (associado a umındice numerico) na tabela (table.insert), remover um elemento databela(table.remove)eordenaroselementosarmazenadosemıncidesnumericosdeuma tabela (table.sort).

• math: oferecefuncoessemelhantes asfuncoesoferecidaspelabibliotecamatematicadeC,tais como math.sqrt, math.sin, math.log, etc.

• io: oferece funcoes para operacoes de entrada e saıda, tais como abertura (io.open), fechamento de arquivos (io.close), leitura (io.read) e escrita (io.write). A biblioteca de io trabalha com o conceito de objeto. Um arquivo aberto e um objeto ao qual temos associado metodos. Assim, apos o comando f = io.open("entrada.txt","r"), a variavel f contem um objeto do tipo arquivo. De posse do objeto, podemos usar funcoes (io.read(f,...)) ou metodos (f:read(...)) para manipularmos o arquivo.

• os: oferece funcoes relacionadas ao sistema operacional, tambem analogas as funcoes oferecidas pela biblioteca C, tais como os.clock, os.date, os.execute (analoga a system de C).

• debug: oferece funcoes para depuracao de codigos Lua. As funcoes oferecidas permitem, por exemplo, consultar o estado corrente da pilha de execucao de Lua e os valores de variaveis locais em todos os nıveis da pilha. Essa biblioteca oferece ainda mecanismos para cadastrar acoes a serem tomadas a cada execucao de uma linha de codigo, a cada chamada de funcao, etc., viabilizandoaconstrucaodeinterfacesdedepuracao. Assim, emvezdeoferecerumaferramenta de depuracao, Lua oferece mecanismos para que tais ferramentas sejam facilmente construıdas, direcionadas para o domınio da aplicacao em questao.

Lua oferece ainda a biblioteca de co-rotinas, que discutiremos na proxima secao, dada a sua especial importancia para a programacao de jogos.

 

 

3.8 Co-rotinas

 

Co-rotinas sao um poderoso mecanismo de programacao para jogos. Uma co-rotina e semelhante a um thread num sistema de multithreading, no sentido de que temos uma linha de execucao com seu proprio ambiente local (pilha de execucao) compartilhando o ambiente global com outras corotinas. A grande diferenca entre uma co-rotina e uma funcao e que a execucao de uma co-rotina pode ser suspensa e retomada posteriormente (no ponto em que foi suspensa). A diferenca entre co-rotinas e threads e que, conceitualmente, diferentes threads executam simulataneamente, enquanto que num sistema com co-rotinas, apenas uma co-rotina executa por vez.

As funcoes que manipulam co-rotinas estao agrupadas na tabela coroutine. Criamos uma corotina passando uma funcao (em geral, anomina) para a funcao de criacao, que retorna um valor do tipo thread:

local c = coroutine.create(function () end)

print(type©) --> "thread"

Uma co-rotina pode estar em tres diferentes estados: suspensa, executando e inativa. Imediatamente apos a sua criacao, uma co-rotina esta no estado “suspensa”. Para executar uma co-rotina, invocamos a funcao coroutine.resume. A execucao de uma co-rotina comeca pela execucao da funcao passada como parametro na sua criacao. Dentro do codigo da co-rotina, podemos suspender sua execucao invocando a funcao coroutine.yield. Ao executar essa funcao, o controle volta paraocodigoquetinhadadocoroutine.resumenaco-rotina,restaurandotodooambientelocal. A co-rotina pode voltar a ser executada com uma outra chamada de coroutine.resume, e a execucao e retomada logo apos o ultimo comando coroutine.yield executado. Do ponto de vista da corotina, uma chamada a coroutine.yield retorna quando a execucao da co-rotina e retomada (via coroutine.resume). Luaofereceummecanismosimpleseversatilparatrocadedados(mensagens) entre co-rotinas. Os argumentos de uma chamada a coroutine.yield sao passados como valores deretornodachamadaacoroutine.resume. Simetricamente,osargumentosdecoroutine.resume sao passados como valores de retorno da funcao coroutine.yield.

Co-rotinassaomuito uteisquandoqueremosimplementarumprocedimentodemaneiraincremental. Em jogos, onde temos um tempo limitado para executarmos nossas simulacoes, podemos implementar as simulacoes de forma incremental, executando os passos que sao possıveis entre quadros da animacao. Para ilustrar, vamos considerar um exemplo hipotetico: um jogo tem que fazerasimulacaodocomportamentodediversospersonagens. Paranaofavorecerumpersonagem em relacao aos outros, podemos pensar em implementar a simulacao de forma incremental, criando co-rotinas e suspendendo sua execucao apos um passo da simulacao. Podemos prever entao uma funcao que gerencia a execucao das diversas simulacoes, executando cada uma passo a passo. Note que o uso de co-rotinas aqui e muito apropriado, pois cada simulacao pode ser retomada a qualquer instante — a linguagem garante a restauracao do seu ambiente local.

Comecamos pela programacao da simulacao de cada personagem (ou grupo de personagens) encapsulada por co-rotina. Agrupamos as co-rotinas numa tabela e passamos essa tabela para um gerenciador das simulacoes. O gerenciador chama uma co-rotina por vez. Conforme ilustrado abaixo, o gerenciador pode, por sua vez, ser uma co-rotina gerenciada por um controle externo.

coroutine.create(function () end), -- simulac~ao 1

coroutine.create(function () end), -- simulac~ao 2

coroutine.create(function () end), -- simulac~ao 3

function manager () while true do for i,v in pairs(simulators) do coroutine.resume(v) end coroutine.yield() -- repassa para controlador externo end end

 

 

3.9 Interface com C

 

Como Lua e uma linguagem para estender aplicacoes, ela nao tem somente uma sintaxe e uma semantica: ela tem tambem uma API para comunicacao com a aplicacao. Essa API esta descrita em lua.h e e formada por aproximadamente 80 funcoes C. (Nao se assuste com esse numero! A API e razoavelmente simples.)

O primeiro conceito na API e o estado Lua: a execucao de um programa Lua e a comunicacao deCcomLuasedaoatravesdeumestadoLua, quecontemtodasasvariaveiseseusvalorescorrentes. A aplicacao pode criar mais de um estado Lua. Eles sao todos completamente independentes uns dos outros. Por isso, cada funcao da API recebe como primeiro parametro o estado Lua sobre o qual ela deve operar. A unica excecao a essa regra e a funcao lua_open, que cria um estado novo.

Um estado Lua existe ate que ele seja fechado, com lua_close. Nesse momento, toda a memoria usada pelo estado e liberada, e suas variaveis e valores desaparecem.

O principal mecanismo de comunicacao entre Lua e C e uma pilha virtual. Nela, C poe valores a serem usados por Lua e vice-versa. A pilha pode armazenar valores Lua de qualquer tipo (nil, booleano, numero, string, tabela, funcao, userdata e thread). Ha portanto funcoes da API para por na pilha valores de cada um desses tipos. Ha tambem funcoes da API para consultar o tipo de um valorqueestanapilhaeparaconverte-loparaumvalorC,quandoissofazsentido. (Naofazsentido converter uma tabela Lua para C porque C nao tem tabelas. Mas faz sentido converter um numero ou string para C.)

Como Lua tem coleta automatica de lixo, e necessario estar atento para nao usar valores obtidos deumapilhainativa. Oerromaiscomum eguardarumstring LuaemCcomosimplesmenteoponteiro que Lua retorna via lua_tostring: quando a pilha ficar invalida, esse ponteiro pode nao mais apontar para o string correspondente (nem para nenhum outro string ou qualquer area valida). A pilha fica invalida quando a funcao C retorna ou quando o estado e fechado.

 

 

4 UsodeLuaemjogos

 

Nesta secao, discutiremos o uso de Lua em jogos, desde um nıvel mais simples ate um nıvel sofisticado.

 

 

4.1 Luacomolinguagemdeconfiguracao

 

Como discutimos na Secao 2, no nıvel mais simples uma linguagem de configuracao e uma maneira de associar valores a variaveis. Nao ha controle de fluxo nem funcoes definidas pelo usuario, somente uma sequencia de atribuicoes. Um exemplo tıpico e:

-- comecar no meio do jogo, usando Mickey... LEVEL = 13 HERO = "Mickey"

Mesmo uma linguagem simples como essa ja da uma grande flexibilidade a aplicacao, pois permite ao usuario controlar a aplicacao externamente, bastando editar um arquivo texto.

VejamoscomousarLuanessasituacaodopontodevistadoprogramadordaaplicacao. Estamos portanto agora falando de codigo C. (Do ponto de vista do usuario da aplicacao, para usar a linguagemdeconfiguracaobastaleradocumentacaodaaplicacaoparasaberquevariaveisexistem,quais os seus possıveis valores e o que eles significam para a aplicacao. O usuario nem precisa saber que esta escrevendo na verdade um programa Lua.)

A primeira coisa e carregar essa configuracao de dentro da aplicacao. Antes disso, e preciso inicializar Lua, criando um estado, que vai existir ate ser fechado:

#include "lua.h" #include "lauxlib.h" ... lua_State *L=lua_open(); ... lua_close(L);

UmavezcriadoumestadoLua,podemoscarregarumarquivodeconfiguracao,digamosinit.lua:

luaL_loadfile(L,"init.lua"); lua_pcall(L,0,0,0);

Notequeacargadaconfiguracao efeitaemdoispassos: leituracomluaL_loadfileeexecucaocom lua_pcall. Isso permite o tratamento separado de erros de sintaxe e erros de execucao. Entretanto, o codigo acima nao trata erros. Na pratica, usa-se o codigo abaixo ou algo parecido:

if (luaL_loadfile(L,"init.lua") || lua_pcall(L,0,0,0)) error(lua_tostring(L,-1)); onde error e uma funcao que trata erro. A mensagem de erro vinda de Lua esta no topo da pilha e portanto e obtida com lua_tostring(L,-1).

Assumindo que nao houve erros na carga da configuracao, a execucao de init.lua criou no estado L as variaveis com seus valores dados em init.lua. E hora portanto da aplicacao usar esses valores. Note que os valores estao em Lua, mas ainda nao em C; e necessario le-los de Lua para C. Tipicamente, a aplicacao esta interessada nos valores de algumas variaveis especıficas, como LEVEL no exemplo inicial. Podemos ler o valor de LEVEL com lua_getglobal(L,"LEVEL");

IssoleovalordavariavelLEVELdeLuaedeixaessevalornapilha,que eomecanismodecomunicacao entre Lua e C e vice-versa. Basta agora copiar essa valor para uma variavel C:

level=lua_tonumber(L,-1); assumindoclaroquelevelestejadeclaradacorretamenteemC.Notequenaohanenhumarelacao entreavariavelCeavariavelLua. Nesseexemplo,elasnemtemomesmonome,somenteumnome parecido. Mas mesmo que tivessem o mesmo nome, seriam variaveis em mundos separados, sem nenhuma relacao automatica entre elas. (E possıvel programar uma tal relacao automatica entre os mundos C e Lua usando mecanismos avancados de Lua.) A mesma coisa se aplica para HERO, exceto que agora queremos um string:

lua_getglobal(L,"HERO"); hero=lua_tostring(L,-1);

E isso e tudo. A aplicacao nao precisa mais de Lua e pode agora fazer o que ela tem que fazer, usando os valores de level e hero fornecidos pelo usuario. Um codigo completo seria entao algo como:

#include "lua.h" #include "lauxlib.h" static int level=0; const char* hero="Minnie"; ... int main(void) { lua_State *L=lua_open(); luaL_loadfile(L,"init.lua"); lua_pcall(L,0,0,0); lua_getglobal(L,"LEVEL"); level=lua_tonumber(L,-1); lua_getglobal(L,"HERO"); hero=lua_tostring(L,-1); play(level,hero); lua_close(L); return 0; }

Note que nao podemos fechar o estado Lua antes de chamar play, pois play usa hero, que e um string obtido de Lua. Para poder fechar o estado Lua antes de chamar play, seria necessario duplicar o valor de hero antes.

Mais uma vez, o codigo acima nao trata erros. Isso e feito somente para simplificar a exposicao.

Na pratica, o tratamento de erros e obrigatorio (como em toda aplicacao de qualidade), principalmente quando se carrega arquivos escritos por usuarios: nao se pode exigir que os usuarios nao cometam enganos! (A aplicacao tambem precisa se proteger contra usuarios mal intencionados...)

O uso de Lua nessa situacao simples pode parecer um exagero. E codigo demais para ler dois valores fornecidos pelo usuario. Seria bem mais simples le-los da linha de comando ou mesmo de um arquivo, mas sem a necessidade de nomes de variaveis. Na pratica, sao necessarios muito maisdoquesomentedoisvalores. Dequalquermodo,notecomousarumalinguagemtemgrandes vantagens: comentarios, linhas em branco, indentacao, aspas e espacos dentro de aspas sao todos tratadosautomaticamenteefuncionamdamaneiracomoousuarioesperainconscientementeque eles funcionem. Fazer isso manualmente na aplicacao seria sim uma grande complicacao!

Esse nıvel simples de configuracao tambem permite coisas mais complicadas, como definir variaveis em funcao de outras:

GREET = "Bom dia " HERO .. "! Como vai"

-- comecar no meio do jogo, usando Mickey... LEVEL = 13 HERO = "Mickey" SCORE = 1.2 * LEVEL

Embora o arquivo continue sendo uma lista de atribuicoes de valores a variaveis, e possıvel usar expressoes do lado direito das atribuicoes. Entender e executar expressoes e uma das tarefas principais de uma linguagem de programacao. Note aqui a vantagem de termos uma linguagem embutida completa!

O usuario pode nao saber que e possıvel fazer isso, mas assim que ele souber ou descobrir, vai provavelmente usar atribuicoes complicadas sem ter que pensar muito na sua forma, pois a sintaxe das expressoes em Lua e a mesma da maioria das linguagens (com a possıvel excecao do operador de combinacao de strings).

 

 

4.2 Luacomolinguagemdeextensao

 

O uso de Lua como linguagem de configuracao mostrado na secao anterior ainda e muito simples. Lua oferece facilidades para estruturacao de dados que podemos explorar quando descrevemos os objetosdeumjogo. Parailustraradiscussao,vamosconsiderarqueprecisamosdescreverdiferentes armasquepodemserusadaspornossospersonagens. Paracadaarma,devemosinformarseu“fator de agressividade”, “alcance de ataque” e “precisao”. O conjunto de armas pode ser agrupado numa tabela, onde os elementos especificam as caracterısticas de cada arma:

Com os dados estruturados, e facil estender o jogo, incluindo, por exemplo, um novo tipo de arma. Dessaforma,a“precisao”deumaespada eobtidaconsultandoovalordeweapons.sword.accuracy. De C, assumindo que weapons e uma variavel global de Lua, esse valor seria obtido pelo seguinte trecho de codigo:

double accuracy; lua_getglobal(L,’weapons’); /* push weapons on stack */ lua_pushstring(L,’sword’); /* push string ’sword’ */ lua_gettable(L,-2); /* get weapons.sword */ lua_pushstring(L,’accuracy’); /* push string ’accuracy’ */ lua_gettable(L,-2); /* get weapons.sword.accuracy */ accuracy = lua_tonumber(L,-1); /* convert value to C */ lua_pop(L,2); /* restore Lua stack */

Conforme mencionado na secao anterior, e fundamental que tenhamos verificacao de erros.

A verificacao de erros em C seria tediosa. Fica bem mais simples escrever codigo Lua que faca a verificacao de erros nos scripts escritos pelos usuarios (roteiristas, artistas, programadores, ou os proprios usuarios finais dos jogos). Uma maneira simples de fazer a verificacao de erro e incluir construtores de tabelas. No exemplo acima, podemos incluir o construtor Weapon para cada arma descrita:

O construtor Weapon pode entao verificar erros e preencher valores defaults:

funciton Weapon (self) if not self.aggression then self.aggression = 0.5 -- default aggression value elseif self.aggression < 0.0 or self.aggression > 1.0 then

ReportError("Invalid aggression value") ... return self end

Podemos ir mais longe, por exemplo, especificando o comportamento dos personagens. Em Lua, como funcoes sao tratadas como valores de primeira classe, esses comportamentos e acoes podem ser facilmente integrados na descricao de tabelas. Como exemplo, vamos imaginar o momento em que o personagem encontra uma nova arma. As caracterısticas da arma encontrada podem enriquecer o dialogo:

weapons = { knife = Weapon{ aggression = 0.3, attackrange = 0.5, accuracy = 1.0, getit = function (person) if person:HasEnoughWeapon() then person:Speak("N~ao preciso dessa faca") return false else person:Speak("Essa faca me sera muito util") return true end end, }, ... }

 

 

4.3 Luacomolinguagemdecontrole

 

Nesse terceiro nıvel de utilizacao da linguagem Lua em jogos, invertemos os papeis: Lua passa a ser o controlador do jogo, o cliente, e o codigo C funciona apenas como servidor, implementando de forma eficiente os servicos demandados por Lua. Nesse caso, ganhamos uma grande flexibilidade com o uso de uma linguagem de script. Os programadores C ficam responsaveis por implementar algoritmos eficientes e os “programadores” Lua ficam responsaveis por criar o roteiro, a historia, o comportamento dos personagens, etc. Dessa forma, em C codificamos as engines do jogo (estruturacao e rendering de cenas, simulacao fısica, algoritmos de inteligencia artificial, gerenciamento de sons, etc.) e, em Lua, escrevemos o script, decidindo que arma usar, que som tocar, que algortimo de inteligencia artificial usar, etc. Essa e uma divisao natural para o desenvolvimento dos jogos. A vantagem de se usar uma linguagem como Lua e que os profissionais envolvidos com a programacao do roteiro nao sao, em geral, profissionais com experiencia em programacao. No entanto, aprender a programar um ambiente Lua onde os erros sao automaticamente verificados e muito simples. Alem disso, como nao ha necessidade de compilacao da aplicacao — que pode ser demorada — o desenvolvimento do jogo fica muito mais rapido.

Para que de Lua tenhamos acesso aos servicos oferecidos por C temos que exportar as funcionalidades de C para Lua. Isso pode ser feito utilizando a API de Lua diretamente ou atraves de ferramentas que fazem o mapeamento de forma automatica. No site de Lua, encontram-se disponıveis algumas dessas ferramentas.

A disponibilizacao dos servicos implementados em C para “programadores” Lua pode ser feita em duas etapas: mapeamento direto das funcoes e classes, e codigo de interface em Lua.

Naprimeiraetapa,usandoaAPIouumaferramentademapeamento,obtemosumcodigoCque exporta as funcoes e metodos para Lua. Em geral, isso e feito escrevendo-se funcoes C que, usando a API de Lua, recebem os parametros de Lua, chamam as funcoes e metodos de C e mapeiam os valores retornados para Lua.

Na segunda etapa, podemos encapsular as chamadas das funcoes e metodos de C atraves de construtores e funcoes escritos em Lua, elevando o nıvel de abstracao para acesso aos servicos das engines. Dessa forma, fazemos com que a programacao em Lua seja feita de forma simples, facilitando o acesso programavel a artistas, roteiristas, etc.

Paraexemplificar, vamosconsideraraimplementacaoemC++ daclasse‘CPerson’queestrutura as caracterısticas de uma personagem do jogo. A cada personagem associamos uma serie de atributos: nome, energia inicial, listas das armas que sabe manusear, etc. Em C++, esses atributos sao definidos atraves de chamadas de metodos. Podemos tambem prever a implementacao de acoes simples como andar, correr, pular, atacar. A interface da classe em C++ poderia ser dada entao por:

class CPerson { ... public:

CPerson (char* model_file); void SetName (char* name); void SetEnergy (double value); AddSkill (Weapon* w); double GetEnergy ();

Com o uso de uma ferramenta (ou fazendo o mapeamento diretamente via API), podemos ter acessosaessesmetodosemLua. Noentanto,naoqueremosqueoroteiristadojogotenhaquefazer chamadasdemetodosdeC++. Oquantopossıvel,devemosdarpreferenciasainterfacesdescritivas, como ja vinhamos fazendo nas secoes anteriores. Um roteirista poderia, por exemplo, instanciar um novo personagem de forma descritiva:

Hero = Person { name = "Tarzan", model = "models/tarzan.mdl", energy = 1.0, skills = {knife, axe} }

O construtor, previamente codificado em Lua, seria responsavel por instanciar o objeto em C++ e definir seus atributos iniciais (alem de fazer verificacao de erros, que sera omitida aqui):

function Person (self) local cobj = CPerson:new(self.model) -- create instance cobj:SetName(self.name) cobj:SetEnergy(self.energy) for i,v = ipairs(self.skills) do cobj:AddSkill(v) end return cobj end

Numa segunda etapa, o roteirista pode programar as acoes associadas ao personagem:

... if Hero:GetEnergy() > 0.5 then

Hero:Attack() else

Hero:Run() end ...

A linguagem Lua tem sido amplamente utilizada no desenvolvimento de jogos. A Lucasarts, por exemplo,usouaversao3.1deLuaparadesenvolverostıtulos“GrimFandango”e“ScapefromMonkey Island”. A versao 3.1 de Lua foi por eles modificada para tratar co-rotinas. Hoje, como vimos, suporte para co-rotinas esta presenta na versao

 

 

5.0.

 

Double Fine utilizou Lua em “Psychonauts” para controlar toda a logica do jogo. Basicamente, a engine carrega um mundo estatico e os scripts em Lua tomam o controle, dando vida e interatividade as cenas. Em ”Baldur’s Gate”, Bioware usou Lua para prover uma ferramenta de depuracao em tempo-real. Relic utilizou Lua em “Impossible Creatures” para controlar a IA, as aparencias dos objetos e personagens, para definir as regras do jogo e tambem como ferramenta de depuracao em tempo-real. Em “FarCry”, Crytek tambem utilizou Lua para controlar diversos aspectos do jogo e para permitir a criacao de modificadores atraves da codificacao de scripts Lua.

 

 

Créditos

OsusosdeLuaemjogoslistadosnaconclusaoforamlevantadosporMarcioPereiradeAraujocomo parte do trabalho da disciplina “Linguagem Lua”, ministrada por Roberto Ierusalimschy, oferecida nos programas de graduacao e pos-graduacao do Departamento de Informatica da PUC-Rio.

Skyligh Pela Postagem

Editado por SkyLigh
Link para o comentário
Compartilhar em outros sites

Se for para copiar de outro site,entao nem traga.

 

Crie seu proprio tutorial,olhe os meus de HTML.

 

Note que há varios erros de portugues em seus tutoriais,olhe neste por exemplo.Há muitos erros.

 

Por mim:REPROVADO.

Link para o comentário
Compartilhar em outros sites

Se for para copiar de outro site,entao nem traga.

 

Crie seu proprio tutorial,olhe os meus de HTML.

 

Note que há varios erros de portugues em seus tutoriais,olhe neste por exemplo.Há muitos erros.

 

Por mim:REPROVADO.

 

Sim código copiado os erros de português to sem tempo pra arruma

Link para o comentário
Compartilhar em outros sites

Isso não é um tutorial, é apenas conteúdo copiado discaradamente da internet e dividido em spoilers. Se quer fazer tutoriais, siga exemplos já existentes na seção de Scripting.

Link para o comentário
Compartilhar em outros sites

Visitante
Este tópico está impedido de receber novos posts.
×
×
  • Criar Novo...