Strona główna » Aplikacje » Gry » Samotnik - kod źródłowy
 

Samotnik - kod źródłowy

· Gra · Kod źródłowy ·

Wstęp

Do wykonania gry Samotnik został wykorzystany język skryptowy JavaScript. Wszystko co jest na stronie to mieszanka kodu HTML, CSS oraz SVG. Użycie grafiki wektorowej pozwala na uzyskanie dobrej jakości niezależnie od urządzenia, a ponadto bardzo łatwo pozwala zmienić styl pola.

Implementacja

Przygotowanie planszy

Plansza oraz pole wiadomości to zaledwie trzy obiekty DIV. Wszystko pola oraz związane z nimi interakcje zostaną załadowane przez kod JavaScript:

  1. <div style="margin:4px"><div id="gboard"></div><div id="gstatus"></div></div>

Po załadowaniu strony wywoływana jest funkcja newGame(). Odpowiada ona za przygotowane planszy dla gracza oraz zresetowania odpowiednich zmiennych. Funkcja korzysta z zadeklarowanych globalnych zmiennych ids, elements;

  1. function newGame(){
  2.  var board = document.getElementById("gboard");
  3.  var s = "";
  4.  for(var x = 2; x < 5; x++){
  5.   for(var y = 0; y < 2; y++){
  6.    s += getElement(y, x);
  7.   }
  8.  }
  9.  for(var x = 0; x < 7; x++){
  10.   for(var y = 2; y < 5; y++){
  11.    s += getElement(y, x);
  12.   }
  13.  }
  14.  for(var x = 2; x < 5; x++){
  15.   for(var y = 5; y < 7; y++){
  16.    s += getElement(y, x);
  17.   }
  18.  }
  19.  board.innerHTML = s.replace('el3x3" class="fcirc', 'el3x3" class="fbl');
  20.  showMsg("Oczekiwanie na rozpoczęcie rozgrywki");
  21.  elements = 32;
  22.  ids = "";
  23. }

(2.) Znalezienie obiektu gdzie jest wyświetlana plansza. (3.) Dane dotyczące obiektów pionków będą tymczasowo przechowane w zmiennej s. Dodanie wszystkich naraz spowoduje, że przeglądarka nie będzie odświeżać strony po dodaniu każdego obiektu. (4. - 18.) Dodanie wszystkich pól na planszy poprzez funkcję getElement(). Dalej pozostaje tylko (19.) ustalić środkowe pole na puste i dodać obiekty na plansze, a potem (20.) pokazać komunikat dla gracza, (21.) ustalić liczbę elementów na 32 (będzie to potrzebne do określenia zwycięstwa) oraz wyczyszczenie zmiennej ids, która przechowuje id wybranej kulki.

Dodawanie obiektów odbywa się poprzez dodanie obiektu SVG. Jego pozycja jest absolutna przez co na podstawie jego współrzędnych jest ustalana jego pozycja. Co więcej każde pole otrzymuje swój id. Jest to zlepek "el", pozycji Y, "x" oraz pozycji X. Dzięki temu zawsze na podstawie nazwy obiektu można ustalić jego oryginalne położenie na planszy.

  1. function getElement(posy, posx){
  2.  return '<svg class="fel" style="top:' + (4 + posy*60) + 'px;left:' + (4 + posx*60) + 'px" xmlns="http://www.w3.org/2000/svg" width="60" height="60" viewBox="0 0 27.999195 27.999199">
  3.   <g transform="translate(-60.286 -52.648)">
  4.    <circle id="el'+posx+"x"+posy+'" class="fcirc" onclick="el_click(this)" cx="74.286" cy="66.648" r="10.954" fill="#c77037" stroke="#9f5a2b" stroke-width="2.091" stroke-linecap="round" stroke-linejoin="bevel"/>
  5.   </g>
  6.  </svg>';
  7. }

(1.) Każdy element SVG jest klasy fel. Jest to klasa, która ustala sposób ustawiania obiektu na planszy oraz jego rozmiary. (3.) Do kółka, który przedstawia pole zostało dodane zdarzenie na kliknięcie. Ponadto klasa obiektu CIRCLE będzie określała czy pole jest puste, albo wybrane.

Z kolei pokazywanie wiadomości sprowadza się do jednej linijki, która ustala zawartość obiektu gstatus:

  1. function showMsg (msg) {
  2.  document.getElementById("gstatus").innerHTML = msg;
  3. }

Rozgrywka

Wszelkie czynności związane z grą zależą tylko i wyłącznie od tego co kliknie gracz, dlatego wszystkie warunki i zmiany są wprowadzane w funkcji el_click(). Funkcja ta jest wywoływana po kliknięci w kółko / pole i jedynym przekazywanym argumentem jest obiekt, który został kliknięty:

  1. function el_click(el){
  2.  if(el.className.baseVal == "fcirc"){
  3.   if(ids!="")
  4.    ids.className.baseVal="fcirc";
  5.   ids = el;
  6.   ids.className.baseVal="fsel";
  7.   showMsg("Wybrano pionek");
  8.  } else if (el.className.baseVal == "fbl" && ids != "") {
  9.   var posr = document.getElementById(getPosBetween(ids.id, el.id));
  10.   if(checkDist(ids.id, el.id) && posr.className.baseVal == "fcirc"){
  11.    ids.className.baseVal="fbl";
  12.    el.className.baseVal="fcirc";
  13.    posr.className.baseVal="fbl";
  14.    ids = "";
  15.    showMsg("Wykonano ruch");
  16.    elements--;
  17.   } else {
  18.    showMsg("Nieprawidłowy ruch!");
  19.   }
  20.  } else if (el.className.baseVal == "fbl" && ids == ""){
  21.   showMsg("Nie można wybrać pustego pola!");
  22.  }
  23.  if(elements == 1){
  24.   showMsg("Zagadka rozwiązana!");
  25.  }
  26. }

Stan pola określony jest po jego klasie CSS. Domyślnym stylem jest fcirc. (2.) Jeśli obiekt ma taka klasę to znaczy, że gracz wybrał kulkę. Wtedy (3.) jeśli została wybrana inna kulka to (4.) jej styl powraca do fcirc. (5.) Do zmiennej ids zostaje przypisany nowy element, a (6.) jego styl jest zmieniany na fsel - pole została wybrane przez użytkownika. Na koniec zostaje (7.) pokazany odpowiedni komunikat.

(8.) Kolejny rozpatrywany przypadek jest wtedy, gdy zostało wybrane puste pole i jest już wybrany pionek. Wtedy (9.) program szuka pola pomiędzy pustym polem, a wybranym polem z kulką. (10.) Warunkiem przesunięcia jest sprawdzenie odległości oraz, że pole pomiędzy zawiera kulkę. Jeśli oba warunki są spełnione to (11.) pole z wybraną kulką jest ustalane na puste, (12.) wybrane puste pole otrzymuje kulkę, a (13.) pole środkowe między poprzednimi dwoma zostaje puste. (14.) Należy też usunąć id wybranego pola i (15.) zmniejszyć liczbę elementów o 1. (16.) Jednak jeśli warunki nie zostały spełnione do przesunięcia obiektu to (17.) wystarczy pokazać odpowiedni komunikat.

(19.) Dla wygody użytkownika warto jeszcze rozpatrzeć przypadek, gdy użytkownik próbuje wybrać puste pole, aby wybrać kulkę. Wtedy (20.) wystarczy pokazać komunikat, że nie można wybrać pustego pola. (22.) Po ruchu jeśli liczba elementów wyniesie 1 to gracz rozwiązał zagadkę i (23.) pokazany zostaje odpowiedni komunikat.

Warunki

Użyte wcześniej funkcje getPosBetween() oraz getPosBetween() korzystając z funkcji getPos(), która na postawie identyfikatora obiektu zwraca jego pozycję w postaci listy dwuelementowej:

  1. function getPos (str){
  2.  return str.replace("el", "").split("x");
  3. }

Wtedy sprawdzenie czy między wybraną kulką, a wybranym pustym polem jest odległość 2 wystarczy (2. - 3.) wyliczyć ich pozycję i (4.) sprawdzić czy odległość wynosi 2 w pionie lub poziomie.

  1. function checkDist (str1, str2){
  2.  var pos1 = getPos(str1);
  3.  var pos2 = getPos(str2);
  4.  return ((Math.abs(pos1[0] - pos2[0]) == 2 && pos1[1] == pos2[1]) || (Math.abs(pos1[1] - pos2[1]) == 2 && pos1[0] == pos2[0]))
  5. }

Z kolei funkcja getPosBetween() w trzeciej linijce uśredni pozycje X i Y, aby zdobyć identyfikator obiektu pomiędzy wybranymi polami. Jeśli pola zostały nieprawidłowo wybrane to identyfikator nie wskazuje żadnego pola, ale w takim przypadku nie jest sprawdzany stan tego pola przez co program nie zwróci błędu:

  1. function getPosBetween (str1, str2){
  2.  var pos1 = getPos(str1);
  3.  var pos2 = getPos(str2);
  4.  return "el" + ((parseInt(pos1[0]) + parseInt(pos2[0])) / 2) + "x" + ((parseInt(pos1[1]) + parseInt(pos2[1])) / 2);
  5. }

Styl

Mając napisany kod źródłowy można przejść do wyjaśnienia kodu CSS:

  1. .fel{position:absolute;height:60px;width:60px}
  2. .fbl{fill:gray}
  3. .fbl:hover{stroke:black}
  4. .fcirc:hover{stroke:blue}
  5. .fsel{stroke:yellow}
  6. #gstatus{max-width:420px;min-width:248px;text-align:center;border:4px solid #552200;margin: 0 auto}
  7. #gboard{position:relative;background:#552200;width:428px;height:428px;margin: 0 auto}

(1.) Styl elementu. Ustawienia niezależne od stanu pola. (2.) Styl pustego pola oraz po jego (3.) wskazaniu. (4.) Styl elementu po najechaniu niewybranego pola z kulką. (5.) Styl wybranego pola. (6.) Styl wyświetlania komunikatów do planszy oraz (7.) samej planszy.