|
GTA.ru > Сервер > Cкриптинг в MTA: DeathMath > Четвёртое руководство
Четвёртое руководство по скриптингу в Multi Theft Auto: DeathMatch
Готовый скрипт: script4.lua

Чтобы объяснить это руководство, сначала вы должны посмотреть видео, чтобы лучше понимать понятие Сена:
Обучающее видео: scriptvideo4.wmv - Windows Media Video (640x480, 25fps, 18,4mb)
Что такое сено?
Сено - это карта, в которой цель состоит в том, чтобы полностью подняться на вершину объёмной башни, пройдя весь путь по... блокам сена. Это 4x4x50 башня не твердая, однако, заполнена для 31.25 %, позволяющее игрокам подняться между остановкой блоков сена. Блоки перемещаются в разнообразном порядке (когда возможно), чтобы препятствовать восхождению игрокам, передвигать их или помочь игрокам со следующим скачком. Для фактора напряжения, каждый блок перемещается в высоту быстрее, чем вы добираетесь. Таким образом, блок, находящийся на земле занимает 4 секунды, чтобы переместиться, в то время как наверху занимает только 2 секунды. Это довольно обидно, когда Вы прыгаете, и блок переезжает прежде, чем Вы приземляетесь на него. Для забавного фактора мы добавили камни, которые остаются на месте, пока их не тронешь. Тогда он разрушает каждый блок сена внизу и забирающий (по большей части) Вас и других вниз к смерти.
Локальные переменные
local options = {
x = 4,
y = 4,
z = 49, -- +1
b = 245,
r = 4
} |
Опции определяют ширину 'x', длина 'y', высота 'z', блоки, 'b', камни 'r', который используется для башни. 'z' имеет +1, потому что наверху мы делаем блок, который никогда не перемещается, плюс хороший пикап с другими не передвигаются.
Кроме этого, мы имеем:
-- Ничего не трогайте ниже!
local matrix = {} -- Трехмерная матрица, содержащая информацию по позиции блоков
local objects = {} --Список объектов
local moving = {} --Список перемещающиеся объектов в данный (Мы не хотим перемещать уже перемещающиеся объекты)
local leveltop = {} -- Список самого высокого уровня находящегося от каждого игрока
local textDisplay -- Контейнер для textDisplay
local textItem -- Контейнер для textItem
local xy_speed -- Число мс блоков перемещающихся быстрее горизонтально с каждым уровнем
local z_speed -- Число мс блоков перемещающихся быстрее вертикально с каждым уровнем
local root = getRootElement() -- Главный элемент
local barrier_x -- Антибезудержный барьер положения x
local barrier_y -- Антибезудержный барьер положения y
local barrier_r -- Антибезудержный барьер радиуса |
Инициализация
В инициализации мы делаем следующие вещи:
- Вычислим статические переменные
- Создание башни
- Создание текста показывающегося игрокам
- Начать перемещающийся процесс блоков
- Появление игроков
Статистические переменные
Мы имеем 5 статических переменных, чтобы вычислить, Вы могли подумать: почему вычисление статических переменных? Хорошо мы обеспечиваем опции в местных переменных, чтобы изменить форму, плотность и число камней.
--Вычисление скорости
xy_speed = 2000 / (options.z + 1)
z_speed = 1500 / (options.z + 1) |
Как я и сказал, чем выше Вы добираетесь, тем быстрее перемещаются блоки. 'Нормальное' движущееся время 1 блока равняется 4 секундам по x/y-оси и 3 секундам по оси Z. Различие между x/y осью и осью Z, потому что измерения блоков сена - точно 4x4x3 единицам. Наверху перемещающееся время - половина 'нормального' времени. Чтобы вычислять время сокращения на уровень, мы делим половину 'нормального' времени (2000мс для x/y оси и 1500мс для оси Z) по числу уровней (options.z + 1).
Кроме этого, мы имеем некоторые переменные, чтобы вычислить для антибезудержного барьера:
-- Вычислите центр башни и радиус барьера
barrier_x = (options.x + 1) * -2
barrier_y = (options.y + 1) * -2
x = options.x * 2 + 4
y = options.y * 2 + 4
barrier_r = math.sqrt(x*x+y*y) |
Здесь я должен сделать примечание, мы помещаем башню в x/y диапазон оси 0 до минус 3000. Все координаты x/y отрицательны. Это потому что мы помещаем башню рядом с фермой в середине карты, которая имеет координату 0,0.
Создание башни
Как вы могли увидеть в местных переменных, мы используем трехмерную матрицу для башни. Lua не знает точно матричный тип, таким образом мы фактически работаем с таблицей (Ось X) таблиц (Ось Y), которые содержат таблицу (Ось Z) переменных. Логично, правда?
--Очищение матрицы
for x = 1,options.x do --Для каждого X
matrix[x] = {} --Инициализация таблицы Y
for y = 1,options.y do --Для каждого Y
matrix[x][y] = {} -- Инициализация таблицы Z
for z = 1,options.z do --Для каждого Z
matrix[x][y][z] = 0 -- Заполнить 0
end
end
end |
Размещение блоков сена легкоё: Для каждого, выберите случайное (1) не взятое положение (2) в матрице, отметьте, как это взято (3) и создайте объект на позиции относительно того положения. (4)
Чтобы заставить блоки сена выглядеть 'отличающимися' друг от друга, мы вращаем в разном порядке блоки сена в шагах 90 градусов по x/y-оси и 180 градусам по оси Z. (4)
-- Число положений блоков сена в матрице
local x,y,z
for count = 1,options.b do
repeat
x = randInt ( 1, options.x ) --Отметить 1
y = randInt ( 1, options.y )
z = randInt ( 1, options.z )
until (matrix[x][y][z] == 0) -- Отметить 2
matrix[x][y][z] = 1 --Отметить 3
objects[count] = createObject ( 3374, x * -4, y * -4, z * 3, randInt ( 0, 3 ) * 90, randInt ( 0, 1 ) * 180 , randInt ( 0, 1 ) * 180 ) -- Отметить 4
end |
И то же самое для камней, но тогда "действительно" случайно вращаемый:
-- Число положений камней в матрице
for count = 1,options.r do
repeat
x = randInt ( 1, options.x ) -- Отметить 1
y = randInt ( 1, options.y )
z = randInt ( 1, options.z )
until (matrix[x][y][z] == 0) -- Отметить 2
matrix[x][y][z] = 1 -- Отметить 3
createObject ( 1305, x * -4, y * -4, z * 3, randInt ( 0, 359 ), randInt ( 0, 359 ), randInt ( 0, 359 ) ) -- Отметить 4
end |
После создания мы помещаем статический блок (1) на вершину плюс сюрприз (2):
-- Место главного блока сена + сюрприз
createObject ( 3374, barrier_x, barrier_y, options.z * 3 + 3 ) --Отметить 1
createPickup ( barrier_x, barrier_y, options.z * 3 + 6, 2, 38, 500 ) --Отметить 2 |
Создание показа текста
Как вы можете увидеть в видео в левой стороне был список имен всех игроков с текущим там уровнем, самый высокий достигнутый уровень и оставленное здоровье. Это сделано через показ текста. С показом текста Вы можете добавить текстовые сообщения в любой часте пользовательского экрана. Я не хочу сейчас углубляться в создании этого прямо сейчас, но в основном сводится к этому:
1. Создать контейнер пункта. 'textCreateDisplay ()'
2. Создайте пункты 'textCreateTextItem 'textCreateTextItem ( text, x, y, priority, red, green, blue, alpha, scale)'
3. Добавить пункты к контейнеру пункта ''textDisplayAddText ( display, item )'
4. Добавить игроков к контейнеру пункта, таким образом они будут видеть все пункты на их экране 'textDisplayAddObserver ( display, player )'
Это также, где мы инициализируем самый высокий достигнутый уровень игрока, который является 0 (5).
--Настройка показа текста
textDisplay = textCreateDisplay () --Отметить 1
textItem = textCreateTextItem ( "", 0.08, 0.20, 2, 255, 255, 255, 255, 1) --Отметить 2
textDisplayAddText ( textDisplay, textItem ) --Отметим 3
local players = getElementsByType( "player" )
for k,v in players do
leveltop[v] = 0 --Отметить 5
textDisplayAddObserver ( textDisplay, v ) --Отметить 4
end |
Как вы можете увидеть, это обновляется каждую секунду показывая, что это сделано устанавливая таймер на инициализации, чтобы вызывать функцию каждую секунду:
setTimer ( "level", 1000, 0 ) |
Начало перемещения блоков
Начало перемещения блока - снова таймер, который вызывает функцию каждые 100мс.
setTimer ( "move", 100, 0 ) |
Функция перемещения блоков
'Ядро' (core) сена. Сначала мы выбираем случайное число, которое назначаем блоку, между 1 и числом блоков (1). Если этот блок, не перемещается (2) мы получаем объект (3) и выбираем случайное передвижение (4). Затем мы делаем временную копию матрицы (5), заполняем во всех положениях игрока (6), и вычисляем положение объекта в матрице (7). Если выбранное движение возможно, (это не перемещается из матрицы и свободно (8), мы отмечаем блок как перемещаемый (9)). Затем это вычисляет скорость движения с использованием переменных "время сокращения на уровень" (reduction-time-per-level) (10). Если блок перемещается, мы хотим сделать некоторые настройки (11). После этого мы вычисляем новое положение блока (12). Чтобы предотвращать передвижение блоков друг в друга, мы отмечаем следующее местоположение блока в матрице как взятый (13). В конечном счете, мы перемещаем непосредственно блок (14).
function move ()
local rand
repeat
rand = randInt ( 1, options.b ) --Отметим 1
until (moving[rand] ~= 1) --Отметим 2
local object = objects[ rand ] --Отметим 3
local move = randInt ( 0, 5 ) --Отметим 4
local x,y,z
local x2,y2,z2 = getElementPosition ( object )
local free = {}
copyTable(matrix,free) --Отметим 5
getFree(free) --Отметим 6
x = x2 / -4 --Отметим 7
y = y2 / -4
z = z2 / 3
if (move == 0) and (x ~= 1) and (free[x-1][y][z] == 0) then --Отметим 8
moving[rand] = 1 --Отметим 9
local s = 4000 - xy_speed * z --Отметим 10
setTimer ("done", s, 1, rand, x, y, z) --Отметим 11
x = x - 1 --Отметим 12
matrix[x][y][z] = 1 --Отметим 13
moveObject ( object, s, x2 + 4, y2, z2, 0, 0, 0 ) --Отметим 14
elseif (move == 1) and (x ~= options.x) and (free[x+1][y][z] == 0) then
moving[rand] = 1
local s = 4000 - xy_speed * z
setTimer ("done", s, 1, rand, x, y, z)
x = x + 1
matrix[x][y][z] = 1
moveObject ( object, s, x2 - 4, y2, z2, 0, 0, 0 )
elseif (move == 2) and (y ~= 1) and (free[x][y-1][z] == 0) then
moving[rand] = 1
local s = 4000 - xy_speed * z
setTimer ("done", s, 1, rand, x, y, z)
y = y - 1
matrix[x][y][z] = 1
moveObject ( object, s, x2, y2 + 4, z2, 0, 0, 0 )
elseif (move == 3) and (y ~= options.y) and (free[x][y+1][z] == 0) then
moving[rand] = 1
local s = 4000 - xy_speed * z
setTimer ("done", s, 1, rand, x, y, z)
y = y + 1
matrix[x][y][z] = 1
moveObject ( object, s, x2, y2 - 4, z2, 0, 0, 0 )
elseif (move == 4) and (z ~= 1) and (free[x][y][z-1] == 0) then
moving[rand] = 1
local s = 3000 - z_speed * z
setTimer ("done", s, 1, rand, x, y, z)
z = z - 1
matrix[x][y][z] = 1
moveObject ( object, s, x2, y2, z2 - 3, 0, 0, 0 )
elseif (move == 5) and (z ~= options.z) and (free[x][y][z+1] == 0) then
moving[rand] = 1
local s = 3000 - z_speed * z
setTimer ("done", s, 1, rand, x, y, z)
z = z + 1
matrix[x][y][z] = 1
moveObject ( object, s, x2, y2, z2 + 3, 0, 0, 0 )
end
end |
Обновление показа текста
Эта функция вызывается каждую секунду и обновляет показ текста с уровнем игрока в данный момент, оставшегося числа уровней и здоровье. Наверху показа текста мы сообщаем о числе уровней в башне (1), после которого мы повторяем через каждого игрока (2) и вычисляем текущий этаж (3). Поскольку эту систему вызывают каждую секунду, мы можем также сделать здесь проверку преграды. Если игрок заденет преграду, ему покажется сообщение и убьёт игрока (4). (Номер 700 в этом коде - часть координации, которую игрок получает, когда он умер и используется здесь, чтобы сохранить некоторые расчёты), Если он мертв, внесите в список его как являющийся на недействительном уровне '-'. (5). Если он живой показывать текущий уровень (6). Редактируйте пункт показа текста, и мы готовы. (7)
function level()
local x,y,z
local level
local string = options.z + 1 .. " levels:\n" --Отметим 1
local players = getElementsByType( "player" )
for k,v in players do --Отметим 2
x,y,z = getElementPosition( v )
level = math.floor(z / 3 - 0.5) --Отметим 3
if (getDistanceBetweenPoints2D(barrier_x,barrier_y,x,y) > barrier_r) and (isPlayerDead ( v ) == false) and (z ~= 700) then --Отметим (4)
outputChatBox( "* Killed: Don't walk away.", v, 255, 100, 100 )
killPlayer(v)
end
if (z == 700) then --Отметим 5
string = string .. getClientName ( v ) .. " (-/" .. leveltop[v] .. ") 0%\n"
else --Отметим 6
if (level > leveltop[v]) then
leveltop[v] = level
end
string = string .. getClientName ( v ) .. " (" .. level .. "/" .. leveltop[v] .. ") " .. math.floor(getPlayerHealth(v)) .. "%\n"
end
end
textItemSetText ( textItem , string ) --Отметим 7
end |
Другие функции
Наверху башни мы поместили сюрприз. Когда игрок поднимает это (1), мы делаем уведомление, что тот игрок достиг вершины (2) и разрушаем сюрприз. (3)
addEventHandler( "onPickupHit", root, "onPickupHit")
function onPickupHit ( player ) --Отметим 1
if (getPickupType ( source ) == 2) then
outputChatBox( "* " .. getClientName ( player ) .. " made it to the top!", root, 255, 100, 100 ) --Отметим 2
destroyElement( source ) --Отметим 3
end
end |
Когда игрок присоединяется, мы должны добавить этого игрока к показу текста, чтобы позволить игроку видеть показ текста (1). Также мы должны инициализировать его самый высокий достигнутый уровень, который является 0. (2)
addEventHandler( "onPlayerJoin", root, "onPlayerJoin")
function onPlayerJoin ( )
leveltop[source] = 0 --Отметим 1
textDisplayAddObserver ( textDisplay, source ) --Отметим 2
end |
Когда блок перемещается, свободное предыдущее место (1) и пометить блок как не-перемещающийся. (2)
function done ( id, x, y, z )
moving[id] = 0 --Отметим 1
matrix[x][y][z] = 0 --Отметим 2
end |
Эта функция отмечает позиции в матрице как взято согласно местоположениям игрока. Это повторяется через каждого игрока (1), вычисляет его позицию (2), выполняет граничную проверку (3) и помечает в матрице как взято (4)
function getFree ( src )
local x,y,z
local players = getElementsByType( "player" )
for k,v in players do --Отметим 1
x,y,z = getElementPosition( v )
x = math.floor(x / -4 + 0.5) --Отметим 2
y = math.floor(y / -4 + 0.5)
z = math.floor(z / 3 + 0.5)
if (x >= 1) and (x <options>= 1) and (y <options>= 1) and (z <= options.z) then --Отметим 3
src[x][y][z] = 2 --Отметим 4
end
end
end |
Эта функция копирует таблицы.
function copyTable ( src, des )
for k,v in pairs(src) do
if (type(v) == "table") then
des[k] = {}
copyTable(src[k],des[k])
else
des[k] = v
end
end
end |
На этом всё, следите за дальнейшими обновлениями на нашем сайте.
|
|