W ramach naszej witryny stosujemy pliki cookies zgodnie z Polityką Cookie. Zasady przechowywania lub dostępu plików cookie możesz zmienić w swojej przeglądarce.
X

mywebcases
.com



Blog

Geekowy blog o łamigłówkach, JavaScript i wszystkim, co ciekawe.

Przykład 2: Tunnel Rocket the GAME!

Cheat Champ - Cheat -
napisał Jakub Caban

Łezka w oku się zakręciła, gdy odkopywałem stare moje foldery pamiętające niemal początek kariery. Znalazłem tam jednakże grę, która będzie idealnym przykładem na dzisiaj.

Pamięta ona czasy, gdy powiedzenie "CANVAS!" było uważane za wizjonerstwo, a zwolenników Flash'a było więcej, niż dzisiaj fanów Justina Biebera. Próbowałem wtedy udowodnić, że szybko i łatwo można stworzyć grę, która nie ma Flasha i jest grywalna. Choć szata graficzna pozostawia wiele do życzenia i oczywiście można znacznie urozmaicić tą pozycję, to i tak grało się przyjemnie, gdy szef nie patrzył. Dzisiaj sam jestem szefem i daję Wam narzędzie do denerwowania Waszych szefów.

Przed nami dzisiaj - Tunnel Rocket the GAME!

Tunnel Rocket the GAME!
Tunnel Rocket the GAME!

O co chodzi w tej grze? Otóż po kliknięciu "LEĆ" pojawi się rakieta w "tunelu", którym jest nic innego jak szesnaście prostokątów udających perspektywę. Zadaniem gracza jest sterować rakietą (za pomocą strzałek na klawiaturze), aby nie wlecieć w ścianę.

Gra jest stara i ze względów czysto sentymentalnych nie zmieniałem w jej silniku więcej, niż było trzeba. Toteż na wszelką krytykę odnośnie jej działania odpowiadam z góry: "Acha" i żyję dalej. Każdy bowiem kiedyś się uczył i nie powinien się tego wstydzić.

To po co to?

Ostatnio próbowaliśmy oszukać system przez wysłanie fałszywego wyniku na serwer. Czasem jednak zdarzy się, że musimy oszukać system na innym poziomie - na poziomie samej gry. I choć Tunnel Rocket nie posiada wyników wysyłanych na serwer, to można wyobrazić sobie sytuację, w której serwer decyduje o ułożeniu ścian i odczytuje historię naszego lotu, by sprawdzić, czy na pewno osiągnęliśmy dany wynik. W takim wypadku możemy grać ręcznie, albo...

...napisać automat grający za nas!

Tak - właśnie to dzisiaj spróbujemy zrobić na tym prostym przykładzie. Jak próbowałem ręcznie grać na większej planszy (czyli znacznie łatwiej), to osiągałem coś w granicach ~45s. Na podanej dzisiaj wersji kilka sekund to już niezły wynik... Przy czym te sekundy to nie są sekundy, tylko tak na prawdę ta gra liczy, że 20 klatek to zawsze sekunda nie ważne ile zajęło jej ogarnięcie ich. Ewidentnie warto poprawić ten wynik, ale po co się męczyć grając ręcznie?

Zaczynajmy!

Jak zawsze najpierw musimy poznać przeciwnika, którym w tym wypadku jest po prostu skrypt JavaScript. Analogicznie do ostatnich poczynań - wchodząc w zakładkę Script (dla nowych czytelników - tutaj wyjaśnienie) i wyszukując "game_start" znajdziemy się w pliku fly.js.

Warto spróbować przeanalizować działanie gry. Nie będę tego robił w całości, zwrócę uwagę jedynie na kilka faktów:

Dla referencji przyjrzyjmy się bliżej funkcji timeoutFunct:

function timeoutFunct(){
 Time += 5;
 document.getElementById('Time').innerHTML = 'Time: '+(Time/100);
 MakeStep();
 DrawAll();
 Top += mUp;
 Left += mSide;
 DrawPlayer();
 if(Top < rects[0][1] || Left < rects[0][0] || Top+8 > rects[0][3] || Left+8 > rects[0][2]){
 document.onkeydown = '';
 document.onkeyup = '';
 alert("You loose
Your Time: "+(Time/100)+"s");
 }else
 setTimeout(function(){timeoutFunct()}, 50);
}

Szybka analiza - najpierw funkcja ta zwiększa czas o 5 (jednostka - centysekundy) i go wyświetla. Potem MakeStep i DrawAll, które odpowiadają za aktualizację i narysowanie ścian. Następnie przesuwana jest rakieta, DrawPlayer rysuje rakietę i w końcu sprawdzenie, czy rakieta nie wleciała w ścianę.

Podmiana funkcji

Jeśli chcemy zachować pełną funkcjonalność gry, najlepiej będzie jak nie zmienimy funkcji timeoutFunct - wtedy zawsze będziemy mieć pewność, że nasza gra będzie odczytana jako poprawna. Chcemy jednak w jakiś sposób sterować zachowaniem gry. Zwykle wystarczy przed przeliczeniem każdej klatki wykonać własne działania. W tym celu dokonamy podmiany funkcji.

Trik ten polega na zamienieniu funkcji timeoutFunct na własną funkcję, która między innymi wywoła oryginalną wersję timeoutFunct. W tym celu wykorzystamy fakt, iż w JavaScript każda funkcja jest również obiektem i możemy go przypisać do innej zmiennej. W ten sposób:

var last = timeoutFunct;
timeoutFunct = function(){
 console.log("Jestem fajny!");
 last();
}

będzie przy każdym wywołaniu timeoutFunct najpierw wywoływać nasz kod (w tym wypadku wypluwać do konsoli narcystyczne "Jestem fajny!"), po czym wykona oryginalną funkcję, która teraz jest przechowana w obiekcie last.

Niech marionetka zatańczy!

Najbardziej nas niewątpliwie interesuje możliwość sterowania rakietą bez konieczności dotykania klawiatury. W tym celu zamiast console.log("Jestem fajny!") będziemy umieszczać kod do poruszania rakietą.

Jako że timeoutFunct odpowiada za przesuwanie rakiety za pomocą zmiennych mUp i mLeft wystarczy, że przypiszemy do nich jedną z możliwych wartości, a rakieta usłucha naszych rozkazów.

Pozostaje obmyślenie strategii i wdrożenie jej do gry. Pierwszym pomysłem jest wysyłanie rakiety zawsze w kierunku środka aktualnego prostokąta ściany. Środek ten możemy łatwo obliczyć z tablicy rects:

var l = (rects[0][0]+rects[0][2])/2;
var t = (rects[0][1]+rects[0][3])/2;

Aby środek rakiety leciał w tym kierunku musimy skierować samą rakietę w kierunku punktu (l-4, t-4), czyli określić do zmiennych mSide i mUp kierunki lotu. W tym celu wystarczy porównać wartości z aktualną pozycją rakiety, czyli (Left, Top). Cały kod realizujący to założenie przedstawia się następująco:

var last = timeoutFunct;
timeoutFunct = function(){
 var l = (rects[0][0]+rects[0][2])/2-4;
 var t = (rects[0][1]+rects[0][3])/2-4;
 if(Left != l) mSide = l>Left ? 1 : -1;
 else mSide = 0;
 if(Top != t) mUp = t>Top ? 1 : -1;
 else mTop = 0;
 last();
}

Kod ten wystarczy skopiować do konsoli Firebug i wykonać jeszcze przed uruchomieniem gry. Po wykonaniu klikamy "LEĆ" i podziwiamy lot rakiety...

Rozbiła się!

Po chwili przekonamy się, iż takie podejście jednak powoduje rozbicie się rakiety. Co jest w sumie logiczne! Przesuwamy w końcu rakietę w kierunku środka aktualnego prostokąta, ale porównywać będziemy ze ścianami kolejnego, jako że za chwilę wywołuje się przesunięcie w tunelu.

Dlatego już samodzielnie zachęcam do zabawy tym kodem i poprawienie go celem lepiej latającej rakiety. Pierwszym pomysłem jest wzięcie środka drugiego zamiast pierwszego elementu ścian. Może ktoś się pokusi nawet o jeszcze ciekawsze algorytmy określania kierunku. Do dzieła!

Cheat
Oszukiwanie internetowych aplikacji konkursowych w najczystszym wydaniu. Dzięki wiedzy Tymoteusza możecie się dowiedzieć jak wygrać tak, aby nikt nie miał Wam nic do zarzucenia.

Podobne artykuły:

Skomentuj: