Четверг, 18 Апреля 2024, 04:49

Приветствую Вас Гость

Меню сайта
Категории каталога
Создание игр [355]
Статьи об общих понятиях связанных с созданием игр.
Программирование [82]
Гайды по программированию на разных ЯП.
Движки и Гейммейкеры [145]
Статьи о программах для создания игр, уроки и описания.
Софт [43]
Различные программы, в том числе в помощь игроделам.
2D-графика [14]
Уроки по рисованию, растр, пиксель-арт, создание спрайтов и пр.
3D-графика [16]
Уроки по моделированию, ландшафт, модели, текстурирование и пр.
Моддинг игр [5]
Модификация компьютерных игр, создание дополнений, перевод, хакинг.
Игры [161]
Статьи об играх, в том числе и сделанных на гейммейкерах.
Разное [129]
Статьи, которые не вошли в определённые разделы.
Наш опрос
Сколько вы уже создали своих игр?
Всего ответов: 16612
Главная » Статьи » Программирование

Lua. Туториал для начинающих. Часть 4
Продолжение прошлой статьи. Поехали.
--=========================

§14. Таблицы.

Таблицы в целом — самый важный тип данны в Lua.

-------------------------------

§14.1. Массивы.

Первое, что рассмотрим, — массивы. Массивы — это таблицы с числовой индексацией. Массив начинается с его названия, потом ставится равно и в фигурных скобках значения.
Каждый элемент массива пишется в кавычках и разделяется запятой.

Синтаксис:

Код
... = {...};


Самый простой массив выглядит так:

Код
m = {};


«Заполнять» массивы можно так:

Код
m = {"one","two","three",};


После последнего элемента запятая не обязательна.

А можно и так:

Код
m[1] = "one";  
m[2] = "two";  
m[3] = "three";


Индексация массивов — это следующий параграф.

-------------------------------

§14.1.1. Индексация массивов.

Индексация массивов в Lua начинается не с нуля, как в некоторых других языках (в том же C), а с единицы.

Вот эта запись:

Код
m = {"one","two","three",};


Полностью эквивалентна этой:

Код
m = {[1] = "one",[2] = "two",[3] = "three",};


Подобная индексация нежелательна:

Код
m = {[1] = "one",[3] = "three",};


Почему? Это следующий параграф.

Но если надо, можно так:

Код
m = {[1] = "one",[2] = nil,[3] = "three",};


-------------------------------

§14.1.2. Определение длины массива.

Оператор длины массива возвращает наибольший индекс элементов массива. В более старых версиях Lua этим оператором служит функция table.getn(), в более новых же можно использовать есть оператор «#»,
функцию же можно по-прежнему использовать.

Вот простой пример:

Код
m = {[1] = "one",[2] = "two",[3] = "three",};  
print(#m);  
print(table.getn(m));


Чтобы не было проблем с версиями Lua, дальше уже будет писаться только table.getn().

Здесь напечатается 3, поскольку в массиве три элемента.

А что напечатается здесь?:

Код
m = {[1] = "one",[3] = "three",};  
print(table.getn(m));


А напечатается здесь 1, поскольку индекс два равен nil.

А тут вовсе напечатается 0:

Код
m = {[2] = "two",[3] = "three",};  
print(table.getn(m));


Поскольку индекс один равен nil.

Тут тоже 0:

Код
m = {1 = "one",2 = "two", 3 = "three",};  
print(table.getn(m));


Потому что тут вообще ошибка вылезет.

В общем, чтобы оператор длины работал корректно, нужно указывать все индексы правильно, или не указывать вообще, — Lua это сам сделает.

-------------------------------

§14.1.3. Обращение к элементам массива.

Обращение к элементам массива происходит так:

Код
m = {"one","two","three",};  

if m[1] then  
  print(m[1]); -- "one"  
end  
if m[2] then  
  print(m[2]); -- "two"  
end  
if m[3] then  
  print(m[3]); -- "three"  
end


Пишется название массива, затем в квадратных скобках указывается его индекс.

-------------------------------

§14.1.4. Цикл обхода всех элементов массива.

Вот, собственно, один из двух циклов, упомянутый в §10.5.

Для обхода всех элементов массива используется расширенный арифметический цикл for вместе с переменной ipairs.

Синтаксис:

Код
for ...,... in ipairs(...) do  
  ...  
end


То, что перед запятой, — индекс массива, а после — его значение (для примера ниже значение первого индекса — "one").

Пример:

Код
m = {"one","two","three",};  
for i,v in ipairs(m) do  
  print(i.." is "..v);  
end


Как и в случае с арифметическим циклом, две эти переменные являются локальными и могут принимать любые другие значения:

Код
for h,z in ipairs(m) do  
  ...  
end


Иногда в получении индекса либо значения нет необходимости, в таком случае, переменная заменяется на подчёркивание:

Код
for _,v in ipairs(m) do  
  ...  
end


-------------------------------

§14.1.4.1. Обход элементов массива иными способами.

Для обхода все элементов можно и не пользоваться ipairs и for .. in, а просто воспользоваться арифметическим for и оператором длины:

Код
for i=1,table.getn(m) do  
  ...  
end


В качестве индекса используется, как понятно, переменная i.

Только стоит учесть, что при использовании этого варианта получение значения массива будет недоступным.

А вот может случиться такая ситуация, что нескольким (но не всем) элементам массива необходимо будет присвоить одно и то же значение. Можно, конечно, воспользоваться примитивными методами, типа:

Код
m[5] = nil;  
m[6] = nil;


И так далее. Но намного быстрее воспользоваться арифметическим for:

Код
for i=5,10 do  
  m[i] = nil;  
end


Для всех элементов можно по стандарту:

for i,_ in ipairs(m) do
m[i] = nil;
end

Тут уже кому как.

-------------------------------

§14.1.5. Массивы внутри массивов.

Если есть необходимость в этом, внутри пары фигурных скобок создаётся ещё одна пара (просто фигурные скобки, без названия), и туда как обычно записываются элементы нового массива.

Пример:

Код
m = {{"one","half",},"two","three",};


Обращение к элементам массива, который внутри другого массива, происходит так: сначала в квадратных скобках пишется индекс внешнего массива, в котором расположен внутренний, затем уже так же индекс элемента внутреннего массива:

Код
print(m[1][1]); -- "one"  
print(m[1][2]); -- "half"


Обход такого массива выглядит так:

Код
for i,_ in ipairs(m) do  
  m[1][i] = nil  
end


Код
print(m[1][1]); -- nil  
print(m[1][2]); -- nil


Так можно создавать огромное количество массивов, каждый из которых будет внутри предыдущего:

Код
m = {{{{{nil}}}}};  

print(m[1][1][1][1][1]); -- nil


-------------------------------

§14.2. Таблицы.

Таблицы — это набор пар «ключ — значение». Конструкция такая же, как и у массивов.

Вот пример:

Код
t = {  
  one = 1,  
  two = 2,  
  three = 3,  
};


В отличии от массивов элементы таблицы таблицы индексируются переменными. А значением может быть абсолютно любой тип данных Lua, да и вообще всё что угодно:

Код
t = {  
  color = "black",  
  number = 1.2,  
  param = true,  
};


Как уже было сказано выше, значением таблиц могут быть и числа, и булевые значения (true, false), и функции, и строки, и таблицы, и массивы, и даже nil.
Для отделения типов данных друг от друга будет удобно использовать точку с запятой вместо обычной запятой:

Код
t = {  
  number1 = 1,  
  number2 = 2;  
  str = "string";  
  t2 = {  
  n = 4;  
  n1 = true;  
  };  
  m = {"one","two","three",};  
  jj = false,  
  gg = true;  
  wtf = nil;  
};


-------------------------------

§14.2.1. Обращение к элементам таблицы.

Почти всегда обращение выглядит так:

Код
l = {  
  one = 1,  
  two = 2,  
  three = 3,  
};  
print(l.one); -- 1  
print(l.two); -- 2  
print(l.three); -- 3


Когда в таблице таблица, обращение происходит так:

Код
t = {  
  t1 = {  
  one = 1,  
  two = 2,  
  three = 3,  
  },  
};  
print(t.t1.one); -- 1


Когда в таблице массив, обращаться можно так:

Код
t = {  
  t1 = {"one","two","three",},  
};  
print(t.t1[1]); -- "one"


Ну и понятно, что если в таблице есть массив, внутри которого массив, обращаться можно так:

Код
t = {  
  t1 = {{"one","half",},"two","three",},  
};  
print(t.t1[1][2]); -- "half"


Для таблиц понятия «длина» как такового нет, так что использовать соответствующего оператора для таблиц нельзя.

-------------------------------

§14.2.2. Цикл обхода элементов таблицы.

Что это — обьяснять не надо. Для обхода элементов таблицы используется pairs, вместо ipairs. И обычно вместо переменной i (index) используется k (key) (но можно, естественно, писать свои названия).

Синтаксис:

Код
for k,v in pairs(...) do  
  ...  
end


Пример:

Есть таблица со списком оружия и его уроном в процентах. Надо присвоить всему оружия нулевой урон:

Код
Weapons = {  
  Knife = 20,  
  Pistol = 40,  
  ShotGun = 80,  
  AssaultRifle = 85,  
  SniperRifle = 95,  
  MiniGun = 100,  
  RocketLauncher = 110,  
};  

for k,_ in pairs(Weapons) do  
  local w = Weapons;  
  w[k] = 0;  
end


-------------------------------

§14.2.3. Функции в таблицах.

Сразу создать функцию в таблице, похоже нельзя. Но если такое необходимо, это можно сделать следующим образом:

Код
tab = {};

function tab:func(a,b)
  print(a+b);
end

tab:func(2,2); -- 4


-------------------------------

§14.3. Функции для работы с таблицами.

Все они начинаются с «table.» (от англ. «table» — ‘таблица’). Вот все они:

table.concat(table [, sep [, i [, j]]]):

Задан массив, в котором все элементы — строки или числа, возвращает table[i]..sep..table[i+1] ··· sep..table[j]. Значение по умолчанию для sep — пустая строка, значение по умолчанию для i — 1, а для j — длина таблицы.
Если i больше j, функция возвращает пустую строку.

table.insert(table, [pos,] value):

Вставляет элемент value в позицию pos в table, сдвигая вверх остальные элементы. Значение по умолчанию для pos равно n+1, где n — длина таблицы, т. о., вызов table.insert(t,x) добавляет x в конец таблицы t.
Только для массивов.

Пример:

Код
m = {"one","two","three",};  
table.insert(m,"four");

print(m[4]); -- four


table.maxn(table):

То же, что и table.getn и #.

table.remove(table [, pos]):

Удаляет из table элемент в позиции pos, сдвигая вниз остальные элементы, если это необходимо. Возвращает значение удаленного элемента. Значение по умолчанию для pos — n, где n — длина таблицы, т. о.,
вызов table.remove(t) удаляет последний элементы таблицы t. (Примечание: использование insert-remove со значениями по умолчанию позволяет работать с таблицей как со стандартным LIFO – стеком) Только для массивов.

Пример:

Код
m = {"one","two","three","four"};  
table.remove(m);  

print(m[4]); -- nil


table.sort(table [, comp]):

Сортирует элементы таблицы в заданном порядке внутри таблицы, начиная с table[1] и заканчивая table[n], где n — длина таблицы. Если параметр comp задан, то он должен быть функцией,
которая для двух получаемых параметров возвращает true, если первый из них меньше второго (т. о., not comp(a[i+1],a[i]) будет верно для любого i давать true после окончания сортировки).
Если comp не задан, то вместо него будет использован стандартынй оператор Lua «<».

Алгоритм сортировки не стабилен; в том смысле, что равные элементы могут быть переставлены в процессе сортировки.

Также ещё существуют такие полезные функции для массивов:

next():

Возвращает следующей индекс массива после указанного и соответствующее ему значение.

Пример:

Код
m = {"one","two","three","four","five"};

print(next(m)); -- 1 one  
print(next(m,1)); -- 2 two  
print(next(m,table.getn(m))); -- nil


unpack():

Возвращает либо все значения массива, либо от одного индекса и до другого.

Пример:

Код
m = {"one","two","three","four","five"};  

print(unpack(m)); -- one two three four five  
print(unpack(m,2,3)); -- two three  
print(unpack(m,1,4)); -- one two three four


rawget():

Возвращает значение указанного индекса массива.

Пример:

Код
m = {"one","two","three","four","five"};

print(rawget(m,3)); -- three  
print(rawget(m,table.getn(m))); -- five


Вместо этого можно просто написать так:

Код
print(m[3]); -- three  
print(table.getn(m)); -- five


rawset():

Присваивает указанному индексу массива новое указанное значение.

Код
m = {"one","two","three","four","five"};

rawset(m,1,"oneone");  

print(m[1]); -- oneone


Вместо этого можно просто написать так:

Код
m[1] = "oneone"  

print(m[1]); -- oneone

--=========================
§15. Функции ввода-вывода.

Все эти функции начинаются с «io.» (сокр. от англ. «input-output» — ‘ввод-вывод’). Главное применение — изменение внутреннего содержания файла непросредственно из Lua-скрипта.
Вот четыре функции, которые понадобятся для этого:

io.open():

Открывает файл по указанному пути в указанном режиме. Режимов всего три:
«r» — режим чтения. Данный режим используется как режим по умолчанию. То есть, если не указать режим, файл откроется в данном режиме;
«w» — режим записи. Вся имеющаяся ранее информация стирается;
«a» — режим дозаписи в конец файла. Вся имеющаяся ранее информация сохраняется.
Путь в свою очередь пишется в кавычках; название файла обязательно должно иметь расширение. Если в указанной директории не существует такого файла, он будет создан.

file:write():

Записывает в указанный файл указанные значения. Ими должны быть только строки, числа и управляющие последовательности. file — переменная, открывающая файл (ниже всё станет понятно).

file:flush():

Сохраняет сделанные изменения в указанном файле.

io.close():

Закрывает указанный файл.

Пример:

Нужно дописать в конец файла script.lua, расположенного в папке data, несколько строк:

Код
-- окрываем наш файл в режиме дозаписи в конец файла  
local f = io.open("data/script.lua","a");  

-- создаём массив из строк, которые необходимо добавить в конец нашего файла  
local ns = {  
"string1",  
"string2",  
"string3",  
"string4",  
"string5",  
};  

-- сначала записываем первую строку, чтобы между ней и записями в файле была отступлена пустая строка  
f:write("\n".."\n"..ns[1].."\n");  
-- затем записываем остальные строки кроме последней (её, как и первую, нужно отформатировать отдельно)  
for i=2,(table.getn(ns))-1 do  
  f:write(ns[i].."\n");  
end  
-- ну и записываем последнюю строку  
f:write(ns[table.getn(ns)]);  

-- сохраняем сделанные изменения  
f:flush();  

-- закрываем наш файл  
io.close(f);


После открытия файла в конце будет следующее:

Код
[прочие строки, уже имеющиеся в файле]  

string1  
string2  
string3  
string4  
string5


-------------------------------

§15.1. Ещё несколько полезных функций.

io.lines():

Открывает указанный файл в режиме чтения, считывает из него все имеющиеся в нём в строке и возвращает каждую отдельно.

Пример:

Код
local f = io.open("data/script.lua");

for line in io.lines(f) do
  print(tostring(line));
end


После конца цикла эта функция автоматический закрывает файл.

file:lines():

То же, что и io.lines, но не закрывает файл file после окончания цикла.

file:seek():

Получает и выставляет в файле позицию, заданную первым аргументом, им может быть:

"set" — начало файла;
"cur" — текущая позиция;
"end" — конец файла.

Вторым аргументом (число) можно приплюсовать к первому дополнительное количество строк, которое нужно отсчитать от выбранной позиции.

Пример:

Код
f:seek("set",0); -- позиция выставлена в самое начало файла
f:seek("set",1); -- позиция выставлена во второй строке от начала файла вниз

--=========================
§16. Функции операционной системы.

Все эти функции начинаются с «os.» (сокр. от англ. «operation system» — ‘операционная система’) Вот некоторые из них:

os.clock():

Возвращает примерное количество времени (в секундах), которое программа выполнялась на CPU.

os.date():

Возвращает дату, отформатированную в соответствии с заданным форматом.
Если аргумент time передается функции, то должно быть отформатировано «время» (os.time). В противном случае, параметр date используется для форматирования текущего времени.
Если параметр format начинается с «!», то время форматируется в соответствии с универсальным глобальным временем (по Гринвичу). После этого опционального символа, если format равен «*t», то date возвращает таблицу
со следующими полями: year (год, четыре цифры), month (месяц, 1—12), day (день, 1—31), hour (час, 0—23), min (минуты, 0—59), sec (секунды, 0—61), wday (день недели, воскресенью соответствует 1 и так адлее), yday (день года),
и isdst (флаг дневного времени суток, тип boolean).
Если format не равен «*t», то функция date возвращает дату в виде строки, отформатированной в соответствии с правилами функции C strftime.
При вызове без аргументов возвращают дату, во время которой была вызвана данная функция, в соответствии с установленными датой и временем оперционной системы, в следующем формате: MM/DD/YYYY HH:MM:SS.

os.difftime():

Возвращает время, прошедшее от первого аргумента до второго, в секундах. На самом деле функция просто возвращает значение первого аргумента минус значение второго аргумента.

Пример:

Код
print(os.difftime(50,10)); -- 40
print(os.difftime(10,50)); -- -40


os.remove():

Удаляет указанную пупку или файл из указанной директории. Если удаляется папка, она должна быть пустой. Если функция не может произвести удаление, она возвращает nil и сообщение об ошибке.

Пример:

Код
os.remove("data/script.lua"); -- файл удалён
os.remove("data"); -- папка, если она пустая, удалена


os.rename():

Переименовывает указанную папку или файл (первый аргумент) в новое имя (второй аргумент). Если функция не может произвести переименовывание, она возвращает nil и сообщение об ошибке.

Пример:

Код
os.remove("data/script.lua","data/script1.lua"); -- файл переименован в script1.lua
os.remove("data","data1"); -- папка переименована в data1


os.tmpname():

Возвращает строку с именем файла, который может быть использован в качестве временного файла. Файл должен быть явно открыт до использования и явно удален, если больше не будет нужен.
--=========================
Автор статьи: TranZit.
Для написания статьи были использованы и изменены материалы с Lua.ru.
Категория: Программирование | Добавил: TranZIt (27 Июня 2016)
Просмотров: 26249 | Рейтинг: 4.2/24 |
Теги: туториал, для новичков, уроки, язык программирования, программирование, кратко и понятно, Скриптование, основы, с подробными примерами, LUA
Дополнительные опции:
Также если вы считаете, что данный материал мог быть интересен и полезен кому-то из ваших друзей, то вы бы могли посоветовать его, отправив сообщение на e-mail друга:

Игровые объявления и предложения:
Если вас заинтересовал материал «Lua. Туториал для начинающих. Часть 4», и вы бы хотели прочесть что-то на эту же тему, то вы можете воспользоваться списком схожих материалов ниже. Данный список сформирован автоматически по тематическим меткам раздела. Предлагаются такие схожие материалы: Если вы ведёте свой блог, микроблог, либо участвуете в какой-то популярной социальной сети, то вы можете быстро поделиться данной заметкой со своими друзьями и посетителями.

Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Поиск по сайту
10 случ. движков
  • MegaZeux
  • RGM
  • Asphyre Sphinx
  • Ardor3D
  • Lavgine
  • BuildBox
  • TURBU
  • Arcade Game Studio
  • AppGameKit
  • Yogurt3D
  • Друзья сайта
    Игровой форум GFAQ.ru Перевод консольных игр
    Все права сохранены. GcUp.ru © 2008-2024 Рейтинг