W tej części poradnika pt. „Tworzenie gry przeglądarkowej” dodamy możliwość kupowania, zakładania i zdejmowania różnych przedmiotów. Zaczynajmy 🙂
Na początku przejdźmy do bazy danych i stwórzmy tabelę o nazwie items, która będzie przechowywała wszystkie przedmioty.
Tabela składa się z sześciu kolumn. Są to:
- id – unikalny identyfikator przedmiotu
- uid – identyfikator właściciela przedmiotu
- name – nazwa przedmiotu
- defense – ilość obrony dodawanej przez przedmiot
- attack – ilość ataku dodawanego przez przedmiot
- is_equipped – przyjmuje wartość 0 dla przedmiotu aktualnie nie używanego lub 1 dla używanego
Tabela jest już gotowa. Możemy teraz przejść do klasy ModuleLoader i dodać nową metodę – loadItemsShop, która wyświetli przedmioty, które będą do kupienia w sklepie.
Pod zamykającą klamrą } metody load dodaj następujący kod:
static public function loadItemsShop($item, $cena) {
echo '
<div class="item">
<div class="col-xs-1 col-sm-2 col-md-3 col-lg-3">
</div>
<div class="col-xs-5 col-sm-4 col-md-3 col-lg-3">
<img src="images/sklep_'.$item.'.png" class="img-responsive">
</div>
<div class="col-xs-5 col-sm-4 col-md-3 col-lg-3">
<button class="sklep_'.$item.'">Kup <i>'.$item.' ('.$cena.')</i></button>
</div>
<div class="col-xs-1 col-sm-2 col-md-3 col-lg-3">
</div>
</div>
';
}
Ta metoda przyjmuje w parametrach nazwę i cenę przedmiotu. Następnie wyświetla przedmiot w oparciu o te parametry. Wykorzystajmy od razu tą metodę w tej samej klasie i uzupełnijmy case sklep.
case 'sklep':
echo '
<section class="content sklep" id="u_'.$_SESSION['uid'].'">
<div class="container">
<h2>Sklep:</h2>
<div class="row">';
ModuleLoader::loadItemsShop('miecz', 75);
ModuleLoader::loadItemsShop('tarcza', 50);
echo '</div>
</div>
</section>
';
break;
Korzystamy tutaj z wcześniej napisanej metody, aby wyświetlić przedmioty – miecz i tarczę.
Przejdźmy teraz do pliku style.css i dodajmy kilka nowych reguł:
.item {
height: 100px;
border: 1px #ccc solid;
margin-bottom: 30px;
margin-top: 10px;
}
.item img {
float: right;
margin-right: 20px;
}
.item button {
width: 70%;
height: 50px;
border-radius: 5px;
text-align: center;
border: none;
background: rgba(153,0,51,1);
color: #fff;
font-size: 18px;
float: left;
margin-top: 25px;
}
Skoro mamy już strukturę HTML i CSS to możemy przejść do napisania kodu PHP, który obsłuży kupowanie przedmiotów. Przejdźmy do klasy GameManager i dodajmy metodę o nazwie buyItem, która obsłuży kupowanie przedmiotów. Zamykającym znacznikiem } metody checkWorkStatus dodajmy następujący kod:
public function buyItem($UID, $NAME, $PRICE, $DEFENSE, $ATTACK) {
$select = DatabaseManager::selectBySQL("SELECT * FROM stats WHERE id={$UID} AND gold>{$PRICE}"); //sprawdzenie czy użytkownik ma wystarczająco złota
if($select) { //ma wystarczająco
foreach($select as $arr) {
$stats = $arr;
}
$update_gold = $stats['gold'] - $PRICE; //obliczenie złota po kupieniu przedmiotu
DatabaseManager::updateTable("stats", Array('gold' => ''.$update_gold.''), Array('id' => ''.$UID.'')); //odjęcie złota z konta gracza
$res = DatabaseManager::insertInto("items", Array('uid' => ''.$UID.'',
'name' => ''.$NAME.'',
'defense' => ''.$DEFENSE.'',
'attack' => ''.$ATTACK.'',
'is_equipped' => '0'
)); //dodanie przedmiotu do tabeli items
if($res) {
return true;
}
else {
return false;
}
} //brakuje złota
else {
return false;
exit;
}
}
Cała metoda jest dosyć prosta. Dodałem kilka komentarzy, aby wszystko było bardziej zrozumiałe.
Przejdźmy teraz do pliku wlasny.js i dodajmy kod, który wyśle żądanie:
zmienna3 = $('.sklep').attr('id'); //pobranie id
function buyItem(UID, NAME, PRICE, DEFENSE, ATTACK){
$('.sklep_' + NAME).on('click', function() {
var element = $(this);
var posting = $.post( 'buyItem/', { user: UID, name: NAME, price: PRICE, defense: DEFENSE, attack: ATTACK } ); //wysłanie żądania
posting.done(function( data ) { //po zakończeniu żądania
if(data != false){ //kupiono przedmiot
$.smkAlert({text: 'Kupiono przedmiot.', type:'success'}); //wyświetlenie komunikatu o powodzeniu
}
else {
$.smkAlert({text: 'Nie masz wystarczająco złota.', type:'danger'}); //wyświetlenie komunikatu o niepowodzeniu
}
});
});
}
buyItem(zmienna3, 'miecz', 75, 0, 10);
buyItem(zmienna3, 'tarcza', 50, 5, 0);
Żądanie zostaje przesłane do pliku buyItem.library.php. Utwórzmy go teraz wewnątrz folderu LIBRARY.
Plik buyItem.library.php:
<?php
if(isset($_POST['user']) && isset($_POST['name']) && isset($_POST['price']) && isset($_POST['defense']) && isset($_POST['attack'])) {
$um = new GameManager;
$id = ltrim($_POST['user'], 'u_');
$res = $um->buyItem($id, $_POST['name'], $_POST['price'], $_POST['defense'], $_POST['attack']);
if($res) {
echo "success";
exit;
} else {
return 0;
}
} else {
return false;
}
?>
Pamiętajmy jeszcze o dodaniu kolejnego case wewnątrz klasy MainPage:
case 'buyItem':
require_once $this->active_page.".library.php";
break;
Gracz ma już możliwość kupowania przedmiotu 🙂
Powinniśmy teraz pomyśleć nad miejscem gdzie gracz będzie mógł przejrzeć zdobyte przedmioty i z nich korzystać. Moglibyśmy np. dodać nową stronę o nazwie Ekwipunek i tam wyświetlić przedmioty gracza. Możesz tak zrobić. Ja po prostu zrobię to na stronie ze statystykami.
Przejdźmy do klasy ModuleLoader i dodajmy kolejną metodę, która wyświetli listę posiadanych przedmiotów. Zaraz pod wcześniej napisaną metodą, dodaj kolejną:
static public function loadItemsEquipment($item, $defense, $attack, $is_equipped, $item_id) {
echo '
<div class="item">
<div class="col-xs-1 col-sm-2 col-md-3 col-lg-3">
</div>
<div class="col-xs-5 col-sm-4 col-md-3 col-lg-3">
<img src="images/sklep_'.$item.'.png" class="img-responsive">
</div>
<div class="col-xs-5 col-sm-4 col-md-3 col-lg-3">';
if($is_equipped == 0) {
echo '<button name="'.$item_id.'" class="equip_'.$item.'">Załóż <i>'.$item.' ('.$attack.' AT, '.$defense.' OB)</i></button>';
}
else {
echo '<button name="'.$item_id.'" class="takeoff_'.$item.'">Zdejmij <i>'.$item.' ('.$attack.'AT, '.$defense.'OB)</i></button>';
}
echo '</div>
<div class="col-xs-1 col-sm-2 col-md-3 col-lg-3">
</div>
</div>
';
}
Metoda loadItemsEquipment różni się trochę od loadItemsShop. Posiada ona parametry, które ułatwią wyświetlenia informacji o przedmiocie. Użyjmy jej teraz wewnątrz case statystyki:
case 'statystyki':
$select = DatabaseManager::selectBySQL("SELECT * FROM stats WHERE id={$_SESSION['uid']}");
foreach($select as $arr) {
$stats = $arr;
}
echo '
<section class="content statystyki">
<div class="container">
<h2>Statystyki:</h2>
<div class="row">
<ul class="ul" id="u_'.$_SESSION['uid'].'">
<li><img src="images/punkty.png">Punkty: <span>'.$stats['points'].'</span></li>
<li><img src="images/serce.png">Życie: <span>'.$stats['hp'].'</span> <button class="add" name="hp" type="button"><img src="images/dodaj.png"></button></li>
<li><img src="images/miecz.png">Atak: <span>'.$stats['attack'].'</span> <button class="add" name="attack" type="button"><img src="images/dodaj.png"></button></li>
<li><img src="images/tarcza.png">Obrona: <span>'.$stats['defense'].'</span> <button class="add" name="defense" type="button"><img src="images/dodaj.png"></button></li>
<li><img src="images/zloto.png">Złoto: <span id="zloto">'.$stats['gold'].'</span> </li>
</ul>
<div id="result"></div>
</div>
<div class="row">
<h2>Ekwipunek:</h2>';
$select2 = DatabaseManager::selectBySQL("SELECT * FROM items WHERE uid={$_SESSION['uid']}");
if($select2) {
foreach($select2 as $item) {
ModuleLoader::loadItemsEquipment($item['name'], $item['defense'], $item['attack'], $item['is_equipped'], $item['id']);
}
}
else {
echo '<h3>Nie masz żadnych przedmiotów.</h3>';
}
echo '</div>
</div>
</section>
';
break;
Został dodany tylko jeden div o klasie row. Wewnątrz niego korzystamy z napisanej wcześniej metody i wyświetlamy posiadane przez gracza przedmioty.
Wróćmy teraz do klasy GameManager i dodajmy dwie nowe metody, odpowiadające za ubieranie i ściąganie ekwipunku.
public function equipItem($UID, $ITEM_ID, $NAME) {
$select = DatabaseManager::selectBySQL("SELECT * FROM items WHERE is_equipped=1 AND name='".$NAME."' AND uid={$UID}"); //sprawdzenie czy przedmiot tego typu nie jest już założony
if(!$select) { //można założyć
$res = DatabaseManager::updateTable("items", Array('is_equipped' => '1'), Array('id' => ''.$ITEM_ID.'')); //założenie przedmiotu
if($res) {
return true;
}
else {
return false;
}
}
else {
return false;
exit;
}
}
public function takeOffItem($UID, $ITEM_ID, $NAME) {
$select = DatabaseManager::selectBySQL("SELECT * FROM items WHERE is_equipped=1 AND name='".$NAME."' AND uid={$UID}"); //sprawdzenie czy przedmiot jest założony
if($select) { //można zdjąć
$res = DatabaseManager::updateTable("items", Array('is_equipped' => '0'), Array('id' => ''.$ITEM_ID.'')); //zdjęcie przedmiotu
if($res) {
return true;
}
else {
return false;
}
}
else {
return false;
exit;
}
}
Całość została opisana komentarzami. Pierwsza metoda sprawdza czy nie jest już ubrany podobny przedmiot (bo przecież nie chcemy aby gracz mógł ubrać kilka mieczy). Druga metoda odpowiada za ściągnięcie przedmiotu.
Dodajmy teraz w pliku wlasny.js instrukcje odpowiedzialne za wysłanie żądania założenia/zdjęcia przedmiotu:
function manageItem(UID, NAME, ACTION){
$('.' + ACTION + '_' + NAME).on('click', function() {
var element = $(this);
var ITEM_ID = element.attr('name');
var posting = $.post( 'ekwipunek/', { user: UID, name: NAME, action: ACTION, id: ITEM_ID } ); //wysłanie żądania z parametrami
posting.done(function( data ) { //po zakończeniu żądania
if(data != false){ //powodzenie
location.reload();
}
else {
$.smkAlert({text: 'Nie możesz tego teraz zrobić.', type:'danger'}); //wyświetlenie komunikatu o niepowodzeniu
}
});
});
}
manageItem(zmienna, 'miecz', 'equip');
manageItem(zmienna, 'tarcza', 'equip');
manageItem(zmienna, 'miecz', 'takeoff');
manageItem(zmienna, 'tarcza', 'takeoff');
Funkcja manageItem realizuje jednocześnie zakładanie i zdejmowanie przedmiotów. Utwórzmy teraz plik ekwipunek.library.php, w którym obsłużymy wysłane z poziomu Javascriptu żądanie.
Plik ekwipunek.library.php:
<?php
if(isset($_POST['user']) && isset($_POST['name']) && isset($_POST['action']) && isset($_POST['id'])) {
$um = new GameManager;
$id = ltrim($_POST['user'], 'u_');
if($_POST['action'] == 'equip') {
$res = $um->equipItem($id, $_POST['id'], $_POST['name']);
}
elseif($_POST['action'] == 'takeoff') {
$res = $um->takeOffItem($id, $_POST['id'], $_POST['name']);
}
if($res) {
echo "success";
exit;
} else {
return 0;
}
} else {
return false;
}
?>
W zależności od parametru ACTION z funkcji manageItem odwołujemy się do odpowiednich metod. Dodajmy jeszcze kolejny case w klasie MainPage:
case 'ekwipunek':
require_once $this->active_page.".library.php";
break;
I to wszystko. Gracz może już kupować, zakładać i zdejmować przedmioty.
Przykład możesz zobaczyć tutaj.
Paczkę możesz pobrać tutaj.