Готовый скрипт: 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 = {} --Список перемещающиеся объектов в данный |
В инициализации мы делаем следующие вещи:
- Вычислим статические переменные
- Создание башни
- Создание текста показывающегося игрокам
- Начать перемещающийся процесс блоков
- Появление игроков
Мы имеем 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, |
И то же самое для камней, но тогда "действительно" случайно вращаемый:
-- Число положений камней в матрице 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 ), |
После создания мы помещаем статический блок (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) |
Наверху башни мы поместили сюрприз. Когда игрок поднимает это (1), мы делаем уведомление, что тот игрок достиг вершины (2) и разрушаем сюрприз. (3)
addEventHandler( "onPickupHit", root, "onPickupHit") function onPickupHit ( player ) --Отметим 1 if (getPickupType ( source ) == 2) then outputChatBox( "* " .. getClientName ( player ) |
Когда игрок присоединяется, мы должны добавить этого игрока к показу текста, чтобы позволить игроку видеть показ текста (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) |
Эта функция копирует таблицы.
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 |
На этом всё, следите за дальнейшими обновлениями на нашем сайте.