Faktoriális
-- factorial function
function fact(n)
if n == 0 then
return 1
else
return n*fact(n-1)
end
end
n=arg[1] or 10 -- for other values, do lua fib.lua XX
n=
tonumber(n)
if n < 0 then
print("Pozitiv szamot kerek!")
else
print(fact(n))
end
Faktoriális (coroutine)
function generatefact (n)
return
coroutine.wrap(function ()
local a, b = 1, 1
while a <= n do
coroutine.yield(b)
a, b = a+1, b*(a+1)
end
end)
end
for i in generatefact(10) do print(i) end
Fibonacci
-- very inefficient fibonacci function
function fib(n)
if n<2 then
return n
else
return fib(n-1)+fib(n-2)
end
end
n=arg[1] or 24 -- for other values, do lua fib.lua XX
n=tonumber(n)
print(fib(n))
Fibonacci (coroutine)
function generatefib (n)
return
coroutine.wrap(function ()
local a,b = 1, 1
while a <= n do
coroutine.yield(a)
a, b = b, a+b
end
end)
end
for i in generatefib(1000) do print(i) end
QSort
-- two implementations of a sort function
-- this is an example only. Lua has now a built-in function "sort"
function qsort(x,l,u,f) -- x: table, l:first index, u:last index, f:function
if l < u then
local m=math.random(u-(l-1))+l-1 -- choose a random pivot in range l..u
x[l],x[m]=x[m],x[l] -- swap pivot to first position
local t=x[l] -- pivot value
m=l
local i=l+1
while i<=u do
if f(x[i],t) then
m=m+1
x[m],x[i]=x[i],x[m] -- swap x[i] and x[m]
end
i=i+1
end
x[l],x[m]=x[m],x[l] -- swap pivot to a valid place
-- x[l+1..m-1] < x[m] <= x[m+1..u]
qsort(x,l,m-1,f)
qsort(x,m+1,u,f)
end
end
function selectionsort(x,n,f) -- move the greater element to the first place, then the second greater to the
local i=1 -- second place, and so on...
while i<=n do
local m,j=i,i+1
while j<=n do
if f(x[j],x[m]) then m=j end -- x[j]>x[m]
j=j+1
end
x[i],x[m]=x[m],x[i] -- swap x[i] and x[m]
i=i+1
end
end
function show(m,x)
io.write(m,"\n\t")
local i=1
while x[i] do
io.write(x[i])
i=i+1
if x[i] then io.write(",") end
end
io.write("\n")
end
function testsorts(x)
local n=1
while x[n] do n=n+1 end; n=n-1 -- count elements
show("original",x)
qsort(x,1,n,function (x,y) return x<y end)
show("after quicksort",x)
selectionsort(x,n,function (x,y) return x>y end)
show("after reverse selection sort",x)
qsort(x,1,n,function (x,y) return x<y end)
show("after quicksort again",x)
end
-- array to be sorted
x={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}
testsorts(x)
Memory manager
/*
** $Id: lmem.c,v 1.70 2005/12/26 13:35:47 roberto Exp $
** Interface to Memory Manager
** See Copyright Notice in lua.h
*/
#include <stddef.h>
#define lmem_c
#define LUA_CORE
#include "lua.h"
#include "ldebug.h"
#include "ldo.h"
#include "lmem.h"
#include "lobject.h"
#include "lstate.h"
/*
** About the realloc function:
** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize);
** (`osize' is the old size, `nsize' is the new size)
**
** Lua ensures that (ptr == NULL) iff (osize == 0).
**
** * frealloc(ud, NULL, 0, x) creates a new block of size `x'
**
** * frealloc(ud, p, x, 0) frees the block `p'
** (in this specific case, frealloc must return NULL).
** particularly, frealloc(ud, NULL, 0, 0) does nothing
** (which is equivalent to free(NULL) in ANSI C)
**
** frealloc returns NULL if it cannot create or reallocate the area
** (any reallocation to an equal or smaller size cannot fail!)
*/
#define MINSIZEARRAY 4
void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems,
int limit, const char *errormsg) {
void *newblock;
int newsize;
if (*size >= limit/2) { /* cannot double it? */
if (*size >= limit) /* cannot grow even a little? */
luaG_runerror(L, errormsg);
newsize = limit; /* still have at least one free place */
}
else {
newsize = (*size)*2;
if (newsize < MINSIZEARRAY)
newsize = MINSIZEARRAY; /* minimum size */
}
newblock = luaM_reallocv(L, block, *size, newsize, size_elems);
*size = newsize; /* update only when everything else is OK */
return newblock;
}
void *luaM_toobig (lua_State *L) {
luaG_runerror(L, "memory allocation error: block too big");
return NULL; /* to avoid warnings */
}
/*
** generic allocation routine.
*/
void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
global_State *g = G(L);
lua_assert((osize == 0) == (block == NULL));
block = (*g->frealloc)(g->ud, block, osize, nsize);
if (block == NULL && nsize > 0)
luaD_throw(L, LUA_ERRMEM);
lua_assert((nsize == 0) == (block == NULL));
g->totalbytes = (g->totalbytes - osize) + nsize;
return block;
}
Rendezés és keresés progress barral
Készítette: Czövek Aurél, 2010.
Fejlesztve és tesztelve a Lua for Windows csomaggal.
Letöltéshez -->
A példaprogram a következő részekből áll:
-
Egy "array" könyvtár a következő függvényekkel:
- Buborékrendezés
- Gyorsrendezés
- Bináris keresés
A gyorsrendezést és a bináris keresést úgy implementáltuk,
hogy együtt tudjanak működni az animáló könyvtárral, de
ne kelljen beléjük megjelenítés-specifikus kódot építeni.
-
Egy "anim" könyvtár, a következő függvényekkel:
- Progress bar kirajzolása
- Függvény futtatása progress barral
A cél, hogy úgy tudjunk futtatni időigényes műveleteket,
hogy közben információt kapunk arról, hol tart a végrehajtás.
-
Tesztadatokat generáló szkript (lua_testgen), amely a következő feladatokat hajtja végre:
- Adott számű véletlenszámot generál.
- Az adatsort egy output fájlba menti.
A szkriptnek opcionálisan megadható első paraméterként az adatsor hossza,
második paraméterként az output fájl neve.
-
A rendezést/keresést bemutató szkript (lua_sorttest), amely a következő feladatokat
hajtja végre:
- Beolvassa a teszt számsort egy input fájlból.
- Gyorsrendezéssel rendezi a számokat.
- A rendezett sorozatban bináris kereséssel megkeresi a 42-es szám
egy előfordulását (ha van).
- A rendezett adatsort egy output fájlba menti.
A szkriptnek opcionálisan megadható első paraméterként az input fájl,
második paraméterként pedig az output fájl neve.
Mindkét szkript felhasználja az animációs könyvtárat, így mindig látható,
éppen hol tart az aktuális művelet.
Forrásfájlok tömörítve: itt.
Bellman-Ford
Az alábbi példaprogram a Bellman-Ford algoritmussal egy legrövidebb utat
határoz meg egy irányítatlan gráfban két csúcs között. A bemeneti fájl nevét
parancssori argumentumként kell megadni a Lua programnak.
Az input fájlt első sora a forrás és cél csúcs sorszámát tartalmazza. A további
sorok az éleket jelölik. Az első két komponens az él két csúcspontjának
sorszámát, a harmadik komponens pedig az adott él költségét jelöli.
3 6
1 2 1
1 3 3
2 3 2
3 4 5
2 5 4
4 5 6
4 7 5
5 6 1
6 7 3
edge_list = {}
---------- Gráf felépítése fájlból ----------
file = io.open(arg[1])
start = file:read("*n")
target = file:read("*n")
while true do
from = file:read("*n")
to = file:read("*n")
cost = file:read("*n")
if from == nil then break end
if edge_list[from] == nil then
edge_list[from] = {}
end
if edge_list[to] == nil then
edge_list[to] = {}
end
table.insert(edge_list[from], {id = to, cost = cost})
table.insert(edge_list[to] , {id = from, cost = cost})
end
file:close()
---------- Bellman-Ford ----------
parent = {}
distance = {}
distance[start] = 0
for k = 1, #edge_list - 1 do
for i = 1, #edge_list do
for j = 1, #edge_list[i] do
neighbour = edge_list[i][j]
if not distance[neighbour.id] or
distance[i] and
distance[i] + neighbour.cost < distance[neighbour.id]
then
if distance[i] then
distance[neighbour.id] = distance[i] + neighbour.cost
parent[neighbour.id] = i
end
end
end
end
end
---------- Eredmény kiírása ----------
for i = 1, #distance do
print("distance[" .. tostring(i) .. "] == " .. tostring(distance[i]))
end
for i = 1, #parent do
print("parent[" .. tostring(i) .. "] == " .. tostring(parent[i]))
end
current = target
while current do
print(current)
current = parent[current]
end
LuaSpline
Készítette: Kustra László Zsolt, 2012.
A program Java környezetbe ágyazott Lua szkriptek futtatását mutatja be egy egyszerű görberajzoló program keretein belül.
Letöltés: futtatható jar, forráskód, bezier.lua, circle.lua, zigzag.lua, interpolator.lua
A linkelt forráskód egy Eclipse projektet tartalmaz, a program futtatásához Java SE 1.6 vagy magasabb verzió javasolt.
A program egy görbét rajzol ki, amit ún. kontrollpontok segítségével manipulálhatunk. (Mint ahogy például a Bézier-görbéknél is.)
A forráskód legérdekesebb része a hu.elte.inf.luaspline.model.CurveGenerator
interfész, ami egy tetszőleges paraméterezett görbét ír le. Ezen interfész két implementációval rendelkezik:
hu.elte.inf.luaspline.model.spline.InterpolatorSpline
, ami egy egyszerű, Java nyelven megírt implementáció. Ez az osztály a felhasználó által felvett kontrollpontokat érintve egy töröttvonalat rajzol ki. Ezt használja a program akkor, ha a felhasználó üresen hagyja a Generator szövegmezőt a főablakban.
hu.elte.inf.luaspline.model.spline.LuaSpline
, ami egy előzetesen beállított Lua szkriptet futtat az interfész implementációjában. Példa szkriptek láthatók .lua kiterjesztéssel a letöltések között.
A program többi része – azaz a görbét kirajzoló kód – nem tud arról, hogy az épp kirajzolt görbét generáló kód Javaban vagy Luában íródott-e. Egyetlen osztály implementációjának változtatásával szabadon megváltoztathatjuk a programunk Lua szkriptelési interfészét, vagy akár le is cserélhetjük azt, hogy a program egy másik szkriptnyelvet használjon. Ennek elérése volt a célunk a program létrehozásakor.
∎
Általános nyelvi lehetőségek
Készítette: Németh Nándor, 2013.
A következő programok a nyelv egyes elemeit mutatják be, kitérve az esetlegesen előforduló hibázási lehetőségekre.
Használt futtatókönyezet: Lua for Windows
tipusok.lua:
Ebben a mintaprogramban bemutatom a nyelv típusait a műveleteikkel. Ez a kód mutatja be a többszörös értékadás lehetőségét is.
lathatosag.lua:
Itt ismerkedhetünk meg az egyes változók láthatóságával.
fuggveny.lua:
Ez a mintaprogram mutatja be a függvény definiálások lehetőségeit, a rekurziót és a speciális paraméterezéseket. Itt láthatunk példát metódusok definiálására.
ciklus.lua:
Ebben a mintaprogramban az 1,2,3,4,5 számok kiíratása során ismerhetjük meg a ciklusok definiálását, illetve a break utasítást.
hibakezeles.lua:
Ebben a rövid programban láthatunk példát a hibák generálására, illetve, a biztonságos függvényhívásokra.
tobbszalusag.lua:
A program bemutatja a többszálúság lehetőségeit a nyelvben.
Letöltés:
forráskódok
Osztály megvalósítás,dinamikus kötés
Készítette: Hack János, 2013.
A program egy egyszerű példa feladaton keresztül mutat be egy osztály implementációt, valamint egy könytárat ami támogatja a dinamikus kötést és virtuális függvényeket.
A programok egy a geometriai alakzatok megvalósításának osztály hierarchiájára épülő primitív feladatot oldanak meg. A feladat pontos leírását lásd a forráskódok elején.
Az egyik megvalósítás egy saját osztály implementációt használ, ami nem támogatja a virtuális függvényeke, a másik egy külső könyvtárat használ, lásd a kódban vagy az Objektum-orientált programozás fejezet Polimorfizmus, Virtuális függvények alfejezetében.
Lua C API Qt használatával
Készítette: Bodnár István, 2013.
A következő program a Lua C API használatát mutatja be Qt környezetben egy egyszerű példán keresztül.
Fejlesztőkörnyezet: QtCreator
script.lua:
Néhány egyszerűbb matematikai függvény implementációja lua-ban, megjelenítéshez.
function2.lua:
Sin, cos, tan, stb. függvények kombinációját tartalmazó lua script.
function3.lua:
Ez a script egy random nevű függvényt tartalmaz, ami egy adott paraméterhez egy véletlen számot add hozzá és ezt adja eredményül.
A program lua scripteket tud betölteni, majd az ezekben található függvényeket meghívva kirajzolja őket a koordinátarendszerben.
A függvények a Run... menüpont választásával jeleníthetőek meg. Itt ügyeljünk a helyes név megadására. Az Open script... menüpont
választásával tölthetőek be a lua script fájlok. A források közt néhány példa lua script fájl is található a teszteléshez.
Letöltés:
LuaWithQt
Lua a Metin2 játékban
Készítette: Horvat Franjo, 2013.
A következő program a Lua felhasználását mutatja be MMORPG-s játékoknál.
A Lua-t, mint programozási nyelvet, többek között a Metin2 MMORPG játékban is használják. A MMORPG (Massively Multiplayer Online Role-Playing Game – nagyon sok szereplős online szerepjáték) Interneten, online játszható szerepjáték. A Metin2, mint az MMORPG-s játékok többsége kitalált fantasy témákon alapul, és a játék célja a játékos karakterének fejlesztése. A játéktér PvE és PvP alapú is egyben. PvE (player vs environment) játéktér azt jelenti, hogy a játékos más játékosokkal együtt az adott terület szörnyei ellen harcolhat.
PvP (player vs player) játéktér jelentése, hogy a játékosok egymás ellen is harcolhatnak.
Felépítés:
A játék felépítésileg áll:
-szerverből :A szerver motorja vagy más néven game file-ja C nyelven iródott, ez felelős az üzenet fogadásért, üzenet feldolgozásért valamit üzenet küldésért.
-kliensből : A kliens áll egy C nyelven írt kliens motor file-ból és Pythonban írt GUI-ból.
-adatbázisból : itt is, mint minden minimális biztonsággal rendelkező rendszernél, csak a szerver módosíthatja az adatokat (a kliens csak szerveren keresztül kommunikál az adatbázissal).
Működés:
Szerver inditás során , a szerver betölt a memóriájába egy konzisztens szerver állapotot. Itt jön be a LUA szerepe. LUA-ban van megírva a játékban szereplő összes küldetés, amelyek segítségével a játék sokkalta jobban játszhatóbb, emberbarátibb. Küldetések alatt ne csak azokra gondoljunk amik a karakter fejlődését segítik, hanem gondoljunk olyanokra is amelyek a szerver karbantarthatóságát segítik elő stb.
LUA a Metin2-ben:
Mint azt tudjuk a LUA nyílt forráskódú ezálltal személyre vagy rendszerre szabhatjuk annak működését, kivehetünk belőle, módosíthatunk benne és hozzáadhatunk új részeket. Itt is ez történt. A LUA egy változata van jelen ami ki lett egészítve különféle függvényekkel. Ilyenek például az adatbázis mezőinek lekérdezésére szolgáló, és az adatbázis mezőinek megváltoztatására szolgáló függvények.
Nézzünk néhány példát ezekre:
pc.gethp() - lekérdezhetjük a felhasználó karakterének életpontjait
pc.get_local_x() - lekérdezhetjük a felhasználó karakterének x koordinátás pozícióját
pc.get_local_y() - lekérdezhetjük a felhasználó karakterének y koordinátás pozícióját
pc.get_account_id() - lekérdezhetjük a felhasználó accountjának azonosítóját
pc.get_name() - lekérdezhetjük a felhasználó karakterének nevét
pc.give_exp(int mennyiseg) - adhatunk fejlődéspontokat, amivel a karakter fejleszthető
pc.give_gold(int mennyiseg) - adhatunk a felhasználónak játék pénzt
pc.give_item(int id) - tárgyat adhatunk a felhasználó karakterének
A példaprogram a játék azon részét valósítja meg, amikor a játékos karakterével teleportálni szeretne.
Letöltés:
LuaMetin2
LuaPaint
Készítette: Pintér Krisztián, 2014.
A LuaPaint segítségével Lua szkriptekkel rajzolhatunk BMP ábrákat.
A Lua szkriptben előszőr az image(szélesség,magasság) függvény segítségével kell inicializálnunk a rajzvásznat, majd a pixel, line és circle függvények segítségével rajzolhatunk.
Példa:
local lp = require "luapaint"
image(400,400)
circle(lp.point(100, 200),50,lp.color(255, 0, 0))
line(lp.point(100, 200), lp.point(200, 300), lp.color(0,0,255))
pixel(lp.point(300,300),lp.color(0,0,0))
A program felépítése
A főprogram a main.c fájlban van, ez futtatja a Lua szkriptet. A rajzolást a C-ben írt GUT könyvtár valósítja meg.
Luában írt adattípusok a rajzoláshoz a luapaint.lua fájlban vannak.
Egy függvény grafikon rajzoló példaprogram a plot_function.lua fájlban van.
Egy egyszerű Logo implementáció a luaturtle.lua fájlban van. LuaTurtle példaprogramok a koch.lua, hilbert_curve.lua, dragon_curve.lua és a sierpinski.lua fájlban találhatóak.
main.c
#include
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "GUT.h"
// Segédfüggvény egészek Lua táblából való kiolvasására
// L - a Lua állapot
// keys - a Lua táblából kiolvasandó mezők nevei
// vals - tömb, ahova a függvény a kiolvasott egészeket írhatja
void load_ints_by_key(lua_State *L, char *keys[], int *vals);
// Beágyazott függvények
// Kép inicializálása, ez az első függvény amit rajzolás előtt meg kell
// hívni a szkriptben
int init_image(lua_State *L);
// Pixel rajzolása
int draw_pixel(lua_State *L;
// Vonal rajzolása
int draw_line(lua_State *L);
// Kör rajzolása
int draw_circle(lua_State *L);
int main(int argc, char *argv[])
{
if(argc < 3)
{
printf("Usage: luapaint < script > < output bmp >");
}
else
{
lua_State* L = luaL_newstate();
luaL_openlibs(L);
// Beágyazandó függvények regisztrálása
lua_register(L, "image" , init_image);
lua_register(L, "pixel" , draw_pixel);
lua_register(L, "line" , draw_line);
lua_register(L, "circle", draw_circle);
if(luaL_dofile(L, argv[1]))
{
int i;
// Hiba esetén a stack kiíratása
for(i = -lua_gettop(L); i < 0 ; ++i)
printf("%s\n", lua_tostring(L, i));
}
// Lemezre írjuk a képet
GUT_output_bmp(argv[2]);
GUT_close();
lua_close(L);
}
return 0;
}
GUT.h
#ifndef _GUT_H_
#define _GUT_H_
#include
#include
#include
// Vászon inicializálása
void GUT_init(int w, int h);
// Inicializáltság lekérdezése
int GUT_is_init();
// Vászon felszabadítása
void GUT_close();
// BMP mentése
void GUT_output_bmp(char * fname);
// Rajzolószín beállítása
void GUT_set_color( int r, int g, int b );
// Pixel rajzolása
void GUT_draw_pixel( int x, int y );
// Vonal rajzolása
void GUT_draw_line( int x0, int y0, int x1, int y1);
// Kör rajzolása
void GUT_draw_circle( int x, int y, int rad );
luapaint.lua
local function color(r,g,b)
return { r = r, g = g, b = b }
end
-- 2D pont/vektor típus
local function point(x,y)
return setmetatable( {
x = x,
y = y,
-- Vektor elforgatása origó körül
rotate = function(self, angle)
local rads = angle * math.pi / 180
return point(self.x * math.cos(rads) - self.y * math.sin(rads),
self.x * math.sin(rads) + self.y * math.cos(rads))
end,
-- Vektor normalizálása
normalized = function(self)
local len = self:length()
return point(self.x / len, self.y / len)
end,
-- Vektor hossza
length = function(self)
return math.sqrt(self.x * self.x + self.y * self.y)
end
}, {
-- Vektorösszeg
__add = function(lhs, rhs)
return point(lhs.x + rhs.x, lhs.y + rhs.y)
end,
-- Szorzás skalárral jobbról
__mul = function(lhs, rhs)
return point(lhs.x * rhs, lhs.y * rhs)
end
})
end
return {
color = color,
point = point
}
plot_function.lua
local lp = require "luapaint"
-- Intervallum típus
function range(low, high)
local l
local h
if low < high then l,h = low,high else l,h = high,low end
return {
low = l,
high = h
}
end
-- Függvényrajzoló függvény
-- paraméterek:
-- fun - R->R függvény, kirajzolandó függvény
-- dest - point, a kirajzolt grafikon bal felső sarka
-- size - point, a kirajzolt grafikon mérete
-- dom - range, a megjelenítendő értéktartomány
-- rng - range, a megjelenítendő értékkészlet
-- draw_axes - bool, kirajzoljuk-e az x és y tengelyeket
function plot_function(fun, dest, size, dom, rng, draw_axes)
local d1 = dest -- bal felső sarok
local d2 = dest + size -- jobb alsó sarok
-- keret kirajzolása
line(d1,lp.point(d1.x,d2.y),lp.color(0,0,0))
line(d1,lp.point(d2.x,d1.y),lp.color(0,0,0))
line(d2,lp.point(d1.x,d2.y),lp.color(0,0,0))
line(d2,lp.point(d2.x,d1.y),lp.color(0,0,0))
-- tengelyek kirajzolása, draw_axes alapértelmezésben true
if draw_axes == nil or draw_axes == true then
local axis_x = (-rng.low)/(rng.high-rng.low)
local axis_y = (-dom.low)/(dom.high-dom.low)
if 0 < axis_x and axis_x < 1 then
line( lp.point(0 , axis_x * size.y) + dest
, lp.point(size.x, axis_x * size.y) + dest
, lp.color(0,0,0))
end
if 0 < axis_y and axis_y < 1 then
line( lp.point(axis_y * size.x, 0 ) + dest
, lp.point(axis_y * size.x, size.y) + dest
, lp.color(0,0,0))
end
end
local height = size.y
local width = size.x
-- függvény kirajzolása, minden pixeloszlopbani kiértékelésével
for i=0,width-1 do
local ii0 = ( i /(width-1))*(dom.high-dom.low)+dom.low
local ii1 = ((i+1)/(width-1))*(dom.high-dom.low)+dom.low
local j0 = 1-(fun(ii0)-rng.low)/(rng.high-rng.low)
local j1 = 1-(fun(ii1)-rng.low)/(rng.high-rng.low)
if j0 < 0 then j0 = 0 elseif j0 > 1 then j0 = 1 end
if j1 < 0 then j1 = 0 elseif j1 > 1 then j1 = 1 end
line( lp.point(i ,j0*height) + dest
, lp.point(i+1,j1*height) + dest
, lp.color(0,0,0))
end
end
luaturtle.lua
local lp = require "luapaint"
-- A teknőc állapotát leíró változók.
local pos = lp.point(0,0) -- hely
local dir = -90 -- szög
local pendn = true -- toll letéve
local penclr = lp.color(0,0,0) -- toll színe
-- Egyszerű setterek
local function pencolor(color)
penclr = color
end
local function penup()
pendn = false
end
local function pendown()
pendn = true
end
-- Forgatás
local function left(angle)
dir = (dir - angle) % 360
end
local function right(angle)
dir = (dir + angle) % 360
end
-- Teknőc áthelyezése rajzolás nélkül
local function moveto(target)
pos = target
end
-- Rajzolás előre
local function forward(distance)
local rads = dir * math.pi / 180
-- Az új koordinátákat átszámoljuk a teknőc polárkoordinátarendszeréből
local newpos = pos + lp.point(math.cos(rads), math.sin(rads)) * distance
if pendn then
line(pos, newpos, penclr)
end
pos = newpos
end
local function backward(distance)
forward(-distance)
end
return {
pencolor = pencolor,
penup = penup,
pendown = pendown,
left = left,
right = right,
moveto = moveto,
forward = forward,
backward = backward
}
koch.lua
local lp = require "luapaint"
local lt = require "luaturtle"
function koch(step, length)
if step == 0 then
lt.forward(length)
else
koch(step - 1, length/3)
lt.left(60)
koch(step - 1, length/3)
lt.right(120)
koch(step - 1, length/3)
lt.left(60)
koch(step - 1, length/3)
end
end
image(800,250)
lt.moveto(lp.point(0,240))
lt.right(90)
koch(5, 800)
Letöltés: LuaPaint
proteaAudio - cross-platform 2D audio library for C++ and Lua
Példaprogramot készítette: Tomcsik Bence Tibor, 2014.
A proteaAudio open-source library-vel egyaránt használhatjuk az RtAudio, alacsony szintű audio input/output API-t vagy a több platformon is használatos SDL multimédia library-t.
A példaprogram bemutatja a legegyszerűbb függvényeket amik segítségével egyszerű dalok lejátszására alkalmas programokat írhatunk.
Figyelem: Halkítsd le a hangerőt a program futtatásakor!!!!
proteaAudio hivatalos oldala
Letöltés: LuaSound
Alapértelmezetten a proteaAudio belső része az RtAudio alacsony szintű valós idejű ki-/bemeneti audio API-t használja, így ezt és néhány belső rendszerszintű lib-et leszámítva nincs más függősége.
További lehetőségként tartalmaz opcionális binding-okat a több platformra is portolható SDL multimédia könyvtárhoz.
Számos profi szolgáltatást nyújt amelyek segítségével akár egy komplett stúdió programot is össze tudnánk állítani. Kezeli továbbá a .wav, .mp3, stb. kiterjesztésű audio fájlokat.
A proteaAudio tartalmaz egy majdnem teljes Lua binding listát, amelyek megfelelnek a C++ API-knak. Alapértelmezetten ezek a Lua binding-ok egy dll-ként vannak fordítva, amely az RtAudio backend-nek felel meg és a következő paranccsal importálható:
require("proAudioRt")
A példaprogramban található pár függvény amelyek működéséről és paramétereiről a hivatalos oldalon és a program kommentjei között is olvashatsz.
Felmerülhet a kérdés, hogy ha szeretnénk egy kotta hangjait leprogramozni hogyan lássunk hozzá?
Ehhez először röviden leírnám, hogy mi is a használandó folyamat amit követtem a példaprogramban:
- Csináltam egy mintát (local sample = sampleSine(440, 0.5, 88200)), amely gyakorlatilag egy hang hullám. Első paramétere a frekvencia, második a hossza (nem a hang időben kitartott hossza), harmadik a minta arány (minősége). Ezt a mintát a lib segítségével (proAudio.sampleFromMemory függvény) átalakítottam egy belső audio formátummá, amit fel tudunk használni egy hang lejátszásához.
- Ezt a mintát amit már belső formátummá alakítottam, már csak meg kell hívni proAudio.soundLoop megfelelő paramétereivel. Ha ezt a függvényt meghívjuk, akkor folyamatosan fogja játszani az adott hangot amit átadtunk neki paraméterként.
- proAudio.sleep(duration) segítségével irányítom, hogy meddig tartson ez a hang, így tudom tartani a zene ritmusát és a szünetek megfelelő ideig való kitartását.
- proAudio.soundStop() függvény segítségével leállíthatom a hangot. Ha nem adunk neki paramétert, akkor az összes hangot leállítja, egyébként azt a hangot állítja le amit megadtunk neki paraméterként. (A proAudio.soundLoop kimenete egy hang, ezt adhatjuk meg neki.)
Azt, hogy a kotta hangjainak mely számok felelnek meg, az csak az implementációnktól függ:
A playNote(sample, pitch, duration) függvény amit én használok a programomban azt jelenti, hogy az adott hang amit létrehoztam azt a pitch paraméter szerint tolom el az alaphangtól és duration paraméter segítségével mondom meg, hogy meddig tartom ki.
Ezt a pitch paramétert úgy használom fel, hogy elosztom 12-vel, mert ennyi félhang van egy oktávon belül. Ez lesz a kitevője a 2 alapú hatványomnak. Ez azért jó, mert így nem csak 1 oktávon belül tudok mozogni. A megkapott érték mondja meg, hogy mennyivel toljuk el az alaphangot. Ha 0-át adunk meg akkor az érték 1 lesz és ez az alaphangnak felel meg. Ha 12-őt, akkor az érték 2 lesz ami 1 oktávval magasabban lévő hangot adja meg.
Innentől kezdve egy dolgunk van hátra:
Mi az általunk létrehozott hang alaphangja?
A példaprogram esetében 440 Hz frekvenciájú hangot hoztam létre. Ennek A az alaphangja ami 0-nak felel meg. A' (egy oktávval magasabban lévő alaphang) 12-nek felel meg.
Egy kicsi zeneelmélet:
Egy oktávban 8 hang:
A-H-C-D-E-F-G-A'
és 13 (13. az alaphang) félhang van:
A-Aisz-H-C-Cisz-D-Disz-E-F-Fisz-G-Gisz-A'
Azért nem 17, mert van két hangpár amik között a távolság csak félhang. Ezek a H-C és az E-F.
Most, hogy tudjuk a hangokat és azt, hogy a függvényünkben a szám félhangonkénti eltolást jelent, könnyen ki tudjuk számolni, hogy milyen paramétereket kell használnunk a megfelelő hangokhoz. Feltéve, hogy tudunk kottát olvasni. A példaprogramban 2 hanggal fentebb eltoltam minden hangot, így az én alaphangomnak nem 0 az értéke, hanem 4. Ezt csak a hangzás miatt csináltam.
Egyszerre akár több hangot is lejátszhatunk, így a többszólamúság sem akadály.
Lua jellegzetességek unit tesztekbe ágyazva
Példaprogramot készítette: Kovács Krisztina Magdolna, 2014.
A program futtatásához Luaunit szükséges.
A példaprogram a Lua olyan jellegzetességeit mutatja be, amelyek a más nyelvek felől érkező programozók számára megtévesztőek, szokatlanok lehetnek. Mindez unit tesztek formájában került implementálásra, így a program futtatása egyúttal bizonysággal is szolgál a hozott példák helyességére, helyes működésére.
Luaunithivatalos oldala
Letöltés: Luaunit Tutorial
Lua Threading bemutatása
Példaprogramot készítette: LepártLevente Béla, 2014.
A csomag 2 példaprogramot tartalmaz. Az első az unschedulled coroutineok használatát szemlélteti, mígy a másik egy schedulled exec szerű viselkedést mutat be.
Bővebb leírás az alábbi lapokon található:
Letöltés: Lua Threading Totorial
Lua Tcp/Ip bemutatása
Példaprogramot készítette: LepártLevente Béla, 2014.
A csomag 2 példaprogramot tartalmaz. Az első az egy egszerű szerver/kliens kommunikációt mutat be, a második azonban egy bonyolultabb messanger-t valósít meg.
Bővebb leírás az alábbi lapon található:
luasocket reference
Letöltés: Lua Tcp/Ip Tutorial
egy Lua WoW addon bemutatása
A World of Warcraft egy igen népszerű MMO-RPG, és a játékhoz készült addonok is különösen közkedveltek, mivel javítják a játékélményt és könnyítik a játszhatóságot. Ebben a fejezetben egy World of Warcraft addont készítünk melyhez alapvető Lua ismeretek szükségesek.
Aki már használt WoW addont, az valószínűleg tisztában van azzal, hogy az addon telepítéshez elegendő annak mappáját bemásolni az /Interface/AddOns könyvtárba, ami a játék könyvtárában található (alapértelmezetten a C:/Program Files (x86)/World of Warcraft elérési úton). Ha az addon stimmel (nem tartalmaz hibákat, megfelel a verziója... stb.), akkor ezzel installáltuk, a játék (újra)indítása után használhatjuk is. Ha megvizsgáljuk az egyes addonokhoz tartozó mappák tartalmát, azt láthatjuk, hogy minden addon (még a Blizzard által szállított gyári addonok is), követ bizonyos szabályokat. Ezek közül is a két legfontosabb, melyet mi is követni fogunk, a következő:
Minden addonnak van egy saját könyvtára, az /Interface/AddOns mappában.
Minden ilyen könyvtárban kell lennie egy .toc file-nak melynek neve meg kell, hogy egyezzen az adott addon könyvtár nevével, és az addonnal kapcsolatos információkat tartalmazza.
Elsőként tehát, készítsünk egy egyszerű Hello World addont, mely egy üdvözlő üzenetet ír ki a képernyőre. Először is, hozzunk létre egy "HelloWorld" nevű könyvtárat az /Interface/AddOns mappában, illetve ebben egy "HelloWorld.toc" (Table Of Contents) file-t.
Az indítása során a játék ezeket a TOC file-okat nyitja meg elsőként, így különösen fontos, hogy mind formailag mind pedig tartalmilag megfelelőek legyenek. A file elejére direktívákat lehet (és kell is) írni, mely olyan információkat tartalmaz, mint például, hogy az addon melyik játék verzióhoz készült, az addon neve, az addon verziója, az addon alkotója, megjegyzések, ...stb. Ezeket két hashmark prefix-szel jelölve sorolhatjuk fel, melyet egy space, az általunk definiálni kívánt property neve, majd egy kettőspont követ, végül pedig az az érték, amivel a property-t szeretnénk feltölteni. A verzióhoz tartozó property-t leszámítva, mely a ##Interface: XXXX direktívát követi, az átlag property nevek igen beszédesek, akár még ki is találhatóak. Esetünkben, a HelloWorld.toc file tartalma tehát az alábbihoz hasonlóan kell, hogy kinézzen:
## Interface: 50001
## Title: Hello World
## Author: John Smith
## Version: 0.1
Megj.: Bővebben a property tag-ekről itt:
TOC format
A játék bármely nem '##' kezdetű sort file-névként kezel, melyet megpróbál az addon betöltése során futtatni/betölteni (például egy karakterrel történő belogolás során). Ezen file-ok betöltése a toc-file-ban történt felsorolásukkal megegyező sorrendben hajtódik végre. Jelen esetben, csak egy egyszerű "Hello World"-öt szeretnénk kiíratni egy Lua script segítségével, így hozzunk is létre mondjuk egy 'main.lua' nevű file-t, mely az addonunkhoz tartozó programkódot tartalmazza majd, illetve soroljuk fel a file-unk nevét a 'HelloWorld.toc' file végén, hogy indításkor az betöltésre kerüljön.
main.lua
Mivel ezzel az addonunk betöltéséhez szükséges TOC file elkészült, egy dolgunk maradt hátra, megírni a Lua scriptet mely megvalósítja az általunk kívánt funkcionalitást. Az addon-készítők számára a World of Warcraft interface-ének köszönhetően szamos custom függvény és table erheto el, hogy ezzel elősegítsék a játék customizálását. Jelen esetben, persze csak egy text outputra van szükségünk, melyet kétféleképpen is elerhetunk: a print függvény hívásával az üzenetünk a chat ablakban jelenik meg, míg a message függvény hívásával egy pop-up ablakban. Itt jegyeznénk meg, hogy a message függvényt a Blizzard deprecated-nek nyilvánította, így rövidesen már nem lesz elérhető. Így tehát használjuk inkább a print metódust. Adjuk hozzá az alábbi sort a 'main.lua' file-lunkhoz:
message('Hello World!')
Ezután indítsuk el a játékot. A karakterválasztás előtt ellenőrizzük, hogy az "Addons" menüpont alatt megjelent-e az addonunk (amennyiben nem, úgy ellenőrizzük a TOC file-lunk tartalmát), majd válasszuk ki karakterünket és logoljunk be. Azt láthatjuk, hogy a chat ablakban megjelent a 'Hello World!' üzenet. Tehát a "Hello World" addonunk működik.
Ez az addon azonban jelenleg nem túl hasznos, hiszen egy konstans textet ír ki minden egyes belogoláskor. Azonban igen könnyen tudjuk hasznossá tenni. Sok WoW játékos számára a guild (klán) egy olyan nem opcionális szociális konvenció, amire azért van szüksége, mert bónuszokat kap érte. Ha egy játékos tagja egy guildnek, akkor több XP-t kap, vásárolhat egyes vendoroknál, ahol egyébként nem tehetné. Viszont a guildben rossz szemmel nézik, ha az ember logint követően nem köszön... Ha a fenti script-tünket az alábbiakkal módosítjuk:
SendChatMessage("Hi all!", "GUILD");
Akkor egy gonddal kevesebb. Egyes szemfüles guildtársaknak persze feltűnhet, hogy mindig ugyanúgy köszönünk. Erre megoldást nyújthat például az alábbi kód:
local greetings = {}
table.insert (greetings, 'Hello!')
table.insert (greetings, 'Hi guys!')
table.insert (greetings, 'Greetings!')
SendChatMessage( (greetings [math.random(1,#greetings)], "GUILD");
Megj.: sajnos a botolás elkerülése céljából egyes Lua funkciók le vannak tiltva így pl. az 'os' module nem elérhető. Ezért hívjuk az os.time() helyett a globál táblában definiált time() függvényt, illetve mivel sajnos a randomseed állítása is le van tiltva, ezt kerüljük meg a ciklussal.
A WoW API azonban ennél jóval kreatívabb addonok készítését is támogatja. Lehetőség van például egyes eventekre való regisztrálásra. Mint amikor a karakterünk egy vendorhoz ér, megtehetjük, hogy az értéktelen low-level itemeket automatikusan eladjuk. Ehhez először is be kell regisztrálni arra az eventre, ami akkor váltódik ki, ha egy vendor ablak nyílik.
Legyen az új addonunk neve JunkSeller, a Lua file neve 'JunkSeller.lua' , a TOC file ugyanígy JunkSeller.toc, illetve legyen egy JunkSeller.xml file-unk is, de erről majd idejében.
A TOC file tartalma legyen a következő:
## Interface: 50400
## Title: JunkSeller
## Notes: Automaticaly sells all gray items and a list of other items when a merchant window openes
## Author: John Smith
JunkSeller.lua
JunkSeller.xml
Az event regisztrációnkat tegyük bele egy egy Init függvénybe. Hogy elkerüljük a lehetséges névütközéseket, init helyett nevezzük a függvényünket junkSellerInit-nek
function junkSellerInit()
junkSellerFrame:RegisterEvent("MERCHANT_SHOW");
end
Az addonunk a későbbiekben minden itemet elad majd, amely nem túl ritka, viszont tegyük fel, hogy vannak olyan ritkább itemek is, melyek a fenti kategóriába nem esnek bele, ám mi meg szeretnénk tőlük válni
Megj.: ez általában akkor fordul elő ha egy játékos egy specifikus item kedvéért tisztít ki egy magánál jóval kisebb szintű dungeont újra és újra, amíg az item nem esik. Ekkor általában a többi itemre nincs szüksége, ezért eladja őket.
Ezután soroljuk fel azokat az itemeket amiktől minden esetben meg szeretnénk válni, ám nem low level-ek.
Tehát a lista legyen mondjuk a következő:
junkSellerList = {}
junkSellerList ['White Turnip'] = 1
junkSellerList ['Fizzy Faire Drink'] = 1
junkSellerList ['Pickled Kodo Foot'] = 1
junkSellerList ['Spinefish'] = 1
Az event handler függvényünknek a következő feladatai vannak: Végig kell iterálnia a táskákon, majd azok slotjain. Meg kell néznie, hogy az adott slotban van-e item és ha igen, akkor adott rarity szint alatt van-e. Ha igen, el kell adnia, ha nem akkor meg kell néznie, hogy rajta van-e az általunk explicit haszontalannak ítélt tárgyak listáján. Ha igen, akkor azt is el kell adnia.
function junkSellerEvent()
local junkSellerBag, junkSellerNSlots, junkSellerSlot, junkSellerLink
local junkSellerItemName, junkSellerItemLink, junkSellerItemRarity
local junkSellerItemLevel, junkSellerItemMinLevel, junkSellerItemType
local junkSellerItemSubType, junkSellerItemStackCount
local junkSellerItemEquipLoc, junkSellerItemTexture, junkSellerItemSellPrice
for junkSellerBag = 0, 4, 1 do
junkSellerNSlots = GetContainerNumSlots(junkSellerBag);
if junkSellerNSlots ~= nil then
for junkSellerSlot = 1, junkSellerNSlots, 1 do
junkSellerLink = GetContainerItemLink(bag,junkSellerSlot);
if junkSellerLink ~= nil then
junkSellerItemName, junkSellerItemLink,
junkSellerItemRarity, junkSellerItemLevel,
junkSellerItemMinLevel, junkSellerItemType,
junkSellerItemSubType, junkSellerItemStackCount,
junkSellerItemEquipLoc, junkSellerItemTexture
junkSellerItemSellPrice = GetItemInfo(junkSellerLink)
-- if this is a very common item the we sell it
if junkSellerItemRarity == 0 then
print (junkSellerItemLink);
UseContainerItem(junkSellerBag,junkSellerSlot);
-- else if this is an item that we have declared that we
-- does not need
elseif junkSellerItemName ~= nil
and junkSellerList [caItemName] ~= nil then
print (junkSellerItemLink);
UseContainerItem(junkSellerBag,junkSellerSlot);
end
end
end
end
end
end
Megj.: a
junkSellerItemName, junkSellerItemLink,
junkSellerItemRarity, junkSellerItemLevel,
junkSellerItemMinLevel, junkSellerItemType,
junkSellerItemSubType, junkSellerItemStackCount,
junkSellerItemEquipLoc, junkSellerItemTexture
junkSellerItemSellPrice = GetItemInfo(junkSellerLink)
helyett használhattuk volna a
junkSellerItemName, junkSellerItemLink,
junkSellerItemRarity, _, _, _, _, _, _, _, _
= GetItemInfo(junkSellerLink)
is, vagy el hagyhattuk volna az alulvonásokat, hiszen (még) nem használtuk fel csak az első 3 információt.
Három megválaszolatlan kérdés maradt hátra:
-
Mi is pontosan az init függvényben található:
junkSellerFrame:RegisterEvent("MERCHANT_SHOW");
-
honnan kéne tudnia a játéknak, hogy melyik függvényt is kell meghívnia az addon betöltésekor
-
illetve hogy mi az xml file tartalma.
Kezdjük az xml file-lal. A WoW lehetőséget nyújt arra hogy az event regisztrációkat xml segítségével tegyük meg, továbbá xml-ben mondjuk meg a játék számára azt is, hogy az addon betöltésekor mely függvény hívódik meg elsőként.
JunkSeller.xml
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\..\FrameXML\UI.xsd">
<Script file="JunkSeller.lua"/>
<Frame name="junkSellerFrame">
<Scripts>
<OnEvent>
junkSellerEvent();
</OnEvent>
<OnLoad>
junkSellerInit();
</OnLoad>
</Scripts>
</Frame>
</Ui>
Ezzel valójában egy csapásra megválaszoltuk mind a három kérdést, hiszen:
junkSellerFrame egy xml-ben deklarált frame.
az xml-ben az tag mondja meg pontosan, hogy mit kell hívni az addon indításakor
valamint az tag regisztrálja a függvényünket mint event handlert.
Irodalom jegyzék:
Feldolgozásra váró további témák:
Letöltés: Lua Wow Addon Totorial
Egyszerű szövegszerkesztő alkalmazás
Készítette: Fülöp László
Egy egyszerű szövegszerkesztő alkalmazás Windows Forms GUI felülettel, ami LuaInterface és CLRPackage könyvtárak segítségével lett Lua alatt megvalósítva.
Forrás: Megjelenítés, Logika