Komentarze

# 10 naprawdę denerwujących rzeczy
  1. Faktycznie osoby w heli są wysoko denerwujące. Dorwie się taki jeden do maszyny i jest dosłownie w niebo wzięty bo może ...

Zadaniem wszystkich graczy jest wspinanie się wszelkimi sposobami coraz wyżej, aż na szczyt wieży zrobionej… Z bel siana! Ta wieża o rozmiarach 4×4x50 nie jest w cale jednym obiektem, lecz wypełnionym w 31.25% stosem siana. Pozwala graczom na wspinanie się na poszczególne bele. żeby było trudniej, przesuwają się one w losowym kierunku. Losowe jest też to, która z nich się poruszy na danym ‘poziomie’ wieży. Tym samym zrzuci nieuważnego gracza i najczęściej poważnie zrani lub zabije. Im wyżej znajduje się gracz tym szybciej bele zmieniają swoją pozycję. Przy ziemi poruszają się co 4 sekundy.Na szczycie czas ten wynosi tylko 2 sekundy. Wyobraź sobie, że skaczesz w górę aby złapać się następnej beli, gdy ta nagle ucieka ci spod rąk. Frustrujące? Aby umilić zabawę w kilku miejscach umieszczone są skały, które spadają rozrzucając wszystko wokół, gdy tylko ktoś ich dotknie.
Żeby zrozumieć ideę całej zabawy, proponuję najpierw zobaczyć dołączony materiał filmowy.

Video footage: scriptvideo4.wmv – Windows Media Video (640×480, 25fps)

Complete script: script4.lua

Zmienne lokalne

local options = {

x = 4,

y = 4,

z = 49, — +1

b = 245,

r = 4}

Definiujemy szerokość ‘x’ , długość ‘y’, wysokość ‘z’, wszystkich beli oraz, ‘b’, skały i ‘r’ utrzymujące konstrukcję w postaci wieży. Zmienna ‘z’ ma +1 dlatego, że na górze musi zostać miejsce na belę, która nigdy się nie porusza oraz pickup, którego inni na pewno nie polubią.

Dodatkowo potrzeba nam:

– Nic niżej nie zmieniaj!

local matrix = {} –Matryca 3D przechowująca wszystkie pozycje beli

local objects = {} –Lista obiektów

local moving = {} –Lista tych obiektów, które są w ruchu (Nie chcemy przesuwać już będących w ruchu beli)

local leveltop = {} –Lista najwyższych poziomów wieży, które osiągnął każdy gracz

local textDisplay –Tutaj przechowujemy textDisplay

local textItem –…a tu textItem

local xy_speed –Liczba milisekund, o które będzie zwiększana wartość przyspieszenia beli w poziomie na każdym etapie

local z_speed – Liczba milisekund, o które będzie zwiększana wartość przyspieszenia beli im wyżej w górę

local root = getRootElement() – Element główny

local barrier_x –Bariera zapobiegająca ucieczce (współrzędna x)

local barrier_yBariera zapobiegająca ucieczce (współrzędna y)

local barrier_rBariera zapobiegająca ucieczce (promień)

Inicjalizacja skryptu

Na samym początku musimy:

- Przeliczyć I ustalić zmienne

- Stworzyć wieżę

- Wyświetlić tekst na ekranach graczy (tabelka wyników)

- Rozpocząć ruch beli

- Wprowadzić samych graczy

Wartości statyczne

Mamy takich 5. Mógłbyś pomyśleć: Po co przeliczać stałe, ustalone na początku wartości? Umożliwimy zmianę kształtu, liczby i ilości skał. Dlatego za każdym razem musimy sprawdzać jak skrypt jest ustawiony.

–Liczymy prędkość

xy_speed = 2000 / (options.z + 1)z_speed = 1500 / (options.z + 1)
Jak napisano powyżej, im bliżej jesteś szczytu wieży, tym szybciej poruszają się same bele. ‘Normalny’ odstęp między ruchem beli to 4 sekundy w poziomie i 3 w pionie. Różnica między poziomem, a pionem jest ustalona na jedną sekundę, ponieważ wymiary jednej beli siana to dokładnie 4×4x3 jednostek. Na szczycie bele poruszają się dwa razy szybciej. Aby przeliczyć czas, który będzie dodawany na każdym poziomie musimy podzielić połowę normalnego (2000ms dla poziomu i 1500 ms dla pionu) Przez liczbę samych poziomów (czyli options.z + 1).

Dodatkowo musimy policzyć także kilka rzeczy związanych z barierą wokół wieży:
–Liczymy, gdzie jest środek wieży oraz promień bariery

barrier_x = (options.x + 1) * -2

barrier_y = (options.y + 1) * -2x = options.x * 2 + 4y = options.y * 2 + 4

barrier_r = math.sqrt(x*x+y*y)
Tutaj muszę napisać, że w poziomie 0 minus 3000 jednostek. Wszystkie te koordynaty są ujemne. Dzieje się tak dlatego, że wieża stanie w środku mapy (dalej od absolutnego środka 0.0.0).

Tworzenie wieży.

Jak już zauważyliście, użyliśmy matrycy 3D aby przechowywać informacje o wieży. Język Lua właściwie nie pozwala na tworzenie matrycy, więc właściwie będzie to zwykła tabela ze wszystkimi koordynatami.
–Czyścimy matrycę

for x = 1,

options.x do –dla każdego X

matrix[x] = {} –znajdujemy odpowiedni Y

for y = 1,

options.y do –A dla każdego Y

matrix[x][y] = {} — Z

for z = 1,

options.z do –Dla każdego Z

matrix[x][y][z] = 0 –wpisujemy 0

end

end

end
Samo umieszczenie beli siana jest proste: Dla każdej z nich, pobierz losową (1) nie zajętą pozycję (2) w matrycy, zaznacz ją jako zajętą (3) i stwórz obiekt, którego pozycja odwołuje się do obliczonej. (4)

Aby bele się wyróżniały obracamy losowo każdą o 90 stopni w poziomie i 180 w pionie (4)
–Umieszczamy liczbę bel w matrycy

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
To samo robimy ze skałami, tylko one NAPRAWDĘ są obracane pod dowolnym kątem:
–Umieszczamy liczbę skał w matrycy

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
Po całym procesie tworzymy jeszcze jedną belę (1) na górze oraz niespodziankę (2):

–bela i niespodzianka

createObject ( 3374, barrier_x, barrier_y, options.z * 3 + 3 ) –(1)

createPickup ( barrier_x, barrier_y, options.z * 3 + 6, 2, 38, 500 ) –(2)

Tekst

Jak zapewne widziałeś na filmiku pokazowym, po lewej stronie ekranu znajdowała się lista wszystkich graczy oraz ich pozycja wraz z najwyżej osięgniętym poziomem. Dodatkowo pokazywany jest współczynnik życia. Wszystko jest jednym blokiem tekstu. Możesz dzięki tej funkcji wyświetlać tekst wszędzie na ekranie. Nie chcę się zagłębiać w szczegóły jej działania, ale sprowadza się ono do:

1. Stworzenia przechowalni dla tekstu. ‘textCreateDisplay ()’

2. Stworzenia tego, co będzie przechowywać ‘textCreateTextItem ( tekst, x, y, priorytet, czerwony, zielony, niebieski kolor, rozmiar)’

3. Dodajemy wspomniane obiekty do ‘textDisplayAddText ( display, item )’

4. Dodajemy graczy do ‘textDisplayAddObserver ( display, player )’ – będą mogli zobaczyć tekst

5. Tutaj też policzymy najwyższy poziom osiśgnięty przez wszystkich, na początku niech będzie to 0.

–Ustawiamy textdisplay

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

Zobaczyliście także, że całe info jest uaktualniane co sekundę. Wszystko dzięki zastosowaniu licznika, który wykonuje tę funkcję co 1000ms:

setTimer ( ‘level’, 1000, 0 )

Niech bele zaczną się poruszać!

Znowu posłużymy się licznikiem, który będzie wykonywał główną funkcję ruchu co 100ms.

setTimer ( ‘move’, 100, 0 )

Główna funkcja

Sercem całego skryptu jest funkcja ruchu. Najpierw pobieramy z matrycy numer dowolnej beli, między 1, a ich liczbę. (1). Jeżeli bela się nie porusza (2) poruszamy obiektem (3) w losowy sposób (4). Teraz wykonujemy tymczasową kopię matrycy (5), zapisujemy pozycję wszystkich graczy (6) obliczamy obecną pozycję beli (7). Jeżeli ruch jest możliwy, (nie blokuje go żaden obiekt) (8), zaznaczamy w matrycy belę jaką „poruszającą się” (9). Teraz nadajemy jej odpowiednią prędkość używając wcześniej ustalonych zmiennych (10). Jeżeli ruch został zakończony, również musimy wszystko zapisać (11). Potem liczymy nową pozycję (12). Aby zabezpieczyć się przed przenikaniem jednaj bali przez drugą, oznaczamy nową pozycję jako zajętą (13). Ewentualnie poruszamy belę (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

Uaktualnienie tabeli wyników

Funkcja jest wywoływana co sekundę i uaktualnia wyświetlany tekst o aktualną wysokość, najwyższą, na której znajdował się gracz oraz jego poziom zdrowia. Na górze pokazujemy liczbę poziomów wieży (1), następnie dla każdego gracza (2) liczymy jego obecny poziom (3). Ponieważ funkcja jest wywoływana co sekundę, możemy dodać tu też barierę. Jeżeli gracz znajdzie się poza wyznaczonym obrębem pokazywana jest wiadomość I gracz ginie (4). (Liczba 700 jest częścią pakietu, który jest wysyłany do serwera, gdy gracz ginie oraz użyta tu, aby zapisać obliczenia). Jeżeli stracił życie, zapisujemy go jako kogoś, kto znajduje się na niepoprawnym poziomie wieży ‘-’. (5). Jeżeli żyje – pokazujemy obecny poziom (6). Pozostaje jeszcze edycja tekstu na ekranie. (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

Reszta funkcji

Na samej górze umieszczamy niespodziankę. Kiedy gracz ją zdobędzie (1) zaznaczamy, że osięgnął szczyt (2) i ją niszczymy. (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
Jeżli do gry dołączy nowy gracz, dodajemy jego nick do listy I wyświetlamy go w naszej tabeli wyników (1). Musimy także zapisać jego najwyższy zdobyty poziom jako 0. (2)

addEventHandler( ‘onPlayerJoin’, root, ‘onPlayerJoin’)

function onPlayerJoin ( )

leveltop[source] = 0 – 1

textDisplayAddObserver ( textDisplay, source ) — 2

end
Potrzeba nam jeszcze funkcji, która obsłuży moment zakończenia ruchu beli (1) oraz oznaczenia jej jako nieruchomej. (2)
function done ( id, x, y, z )

moving[id] = 0 — 1

matrix[x][y][z] = 0 – 2

end
Inną potrzebną funkcją jest taka, która oznaczy pozycję beli w matrycy jako zajętą odnosząc się do pozycji graczy. Dla każdego gracza (1), obliczana jest pozycja (2), która zostaje sprawdzona (3) oraz oznaczona jako zajęta (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 = 1) and (y = 1) and (z <= options.z) then — 3

src[x][y][z] = 2 – 4

end

end

end
Ostatnią funkcją, której nam potrzeba, to kopiarka tabeli.

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