Уроки по созданию браузерной игры (ККИ)
| |
Assasin | Дата: Понедельник, 31 Декабря 2012, 22:53 | Сообщение # 1 |
web-coder
Сейчас нет на сайте
| Глава 4. «Доказать кто тут лучший» - сражения Итак, сражения. Самое интересное в играх. В нашем случае сражения будут смотреться так. Игрок нажимает кнопку «Напасть». Скрипт ищет соперника и происходит бой по алгоритму: - Удар напавшего первой картой по первой карте защитника - Удар защитника первой картой по первой карте напавшего И т.д. пока все 5 карт не ударят, либо если карт меньше, то алгоритм пойдет по новой, пока не будет сделано 5 ударов с каждой стороны игроков. После расчета кто кого и как отпинал, записывается лог, на который тут же переадресовывает игрока что бы он мог насладится победой, либо унывать от поражения. Весь процесс от нажатия на кнопку «Напасть» и до переадресации в лог занимает доли секунды. Так что игроку долго ждать не придется. Бой будет состоять с двух файлов. Модуль боя, в котором отображается либо кнопка «Напасть», либо лог боя, если такой существует. И класс боя, в котором непосредственно будет происходить вся механика боя. Приступим к модулю, откройте файл module/battle.php и запишите следующее. Код <?php $User = mysql_fetch_array($db->q("SELECT * FROM `user` WHERE `id`='".$_SESSION['user_id']."'"));
if (!empty($_POST['rush'])) { # Нападение if ($User['life'] == 0) { # Если мало жизней, нельзя нападать echo "<div style='text-align: center;color: red;'>У вас мало жизней</div>"; } elseif ($User['position'] == '0|0|0|0|0') { # Если не выставлены карты для боя, нельзя нападать echo "<div style='text-align: center;color: red;'>Выставьте карты для сражения</div>"; } else { # Поиск игроков у которых выставлены карты для боя $user = array(); $find = $db->q("SELECT `id` FROM `user` WHERE `position`<>'0|0|0|0|0' AND `id`<>'".$_SESSION['user_id']."'"); while($r = mysql_fetch_array($find)) { $user[] = $r['id']; } $rnd = mt_rand(1,sizeof($user)); $id = $user[$rnd-1]; # Игрок найден, запоминается его id $player = mysql_fetch_array($db->q("SELECT * FROM `user` WHERE `id`='".$id."'")); include("inc/battle.php"); # Подключениет класс боя $battle = new battle; $battle->rush($User,$player,$db); # Инициализируется функция боя } }
$log = false; # Указывает что лог не найден if (!empty($_GET['id'])) { # Просматривает лог боя # Фильтрация данных $id = preg_replace("/[^0-9]/","",$_GET['id']); if ($id == '') go2page("game.php"); # Получение характеристик игроков на основе выбранного боя $sql = $db->q("SELECT `battle`.*,`user`.`login`,`user`.`id` FROM `battle`,`user` WHERE `battle`.`id`='".$id."' AND (`battle`.`p1`=`user`.`id` OR `battle`.`p2`=`user`.`id`)"); if (mysql_num_rows($sql) >= 1) { $i=0; while($row = mysql_fetch_array($sql)) { $p[$i] = $row; $i++; } $log = true; } } if (!$log) { # Если не просматривается лог, выводится кнопка "Напасть" ?> <form method="post"> <input type="submit" value="Напасть" name="rush"> </form> <?php } else { # Просмотр лога боя echo "<div style='text-align:center;'><b>".$p[0]['login']."</b> VS <b>".$p[1]['login']."</b> (".$p[0]['time'].")</div>"; echo "<table><tr>"; $p1 = json_decode($p[0]['p1_map']); # Список карт первого игрока $p2 = json_decode($p[0]['p2_map']); # Список карт второго игрока $_p = $p1; # Выводится список карт первого игрока for ($i=0;$i<5;$i++) { echo "<td style='padding:4px;'> <table style='width:140px;display:block;border:1px solid black;'> <tr> <td style='text-align:center;width:140px;' colspan='2'><b>".$_p[$i]->name."</b></td> </tr> <tr> <td>Уровень</td> <td>".$_p[$i]->lvl."</td> </tr> <tr> <td>Атака</td> <td>".$_p[$i]->att."</td> </tr> <tr> <td>Ловкость</td> <td>".$_p[$i]->abi."</td> </tr> <tr> <td>Мастерство</td> <td>".$_p[$i]->skill."</td> </tr> </table> </td>"; if ($i == 4 && $_p == $p1) { # Если список карт первого игрока выведены и просматриваются карты первого игрока, то переключает на вывод списка карт второго игрока $i = -1; $_p = $p2; echo "</tr><tr><td colspan='5' align='center'><h2>VS</h2></td></tr><tr>"; } } echo "</tr>"; # Вывод лога боя $sql = $db->q("SELECT * FROM `battle_log` WHERE `battle_id`='".$id."'"); while($log = mysql_fetch_array($sql)) { echo "<tr><td colspan='5' align='center'>".$log['desc']."</td></tr>"; } # Проверка на победителя if ($p[0]['win'] == 0) { echo "<tr><td colspan='5' align='center'>Ничья</td></tr>"; } else { echo "<tr><td colspan='5' align='center'>Победитель <b>".($p[0]['id'] == $p[0]['win'] ? $p[0]['login'] : $p[1]['login'])."</b></td></tr>"; $loot = json_decode($p[0]['desc']); # Если выиграны монеты, отображает их количество и слово "монеты" с правильным окончанием в зависимости от количества монет. Пример: 1 монетУ, 2 монетЫ, 5 монет if ($loot->money > 0) { if (substr($loot->money,-1) == 1) $m = 'у'; if (substr($loot->money,-1) > 1 && substr($loot->money,-1) < 5) $m = 'ы'; if ($loot->money > 9 && $loot->money < 20) $m = ''; echo "<tr><td colspan='5' align='center'>Выиграл <b>".$loot->money."</b> монет".$m."</td></tr>"; } } echo "</table>"; } ?>
Таблица battle - id – уникальный идентификатор - p1 – id нападающего - p2 – id защищающегося - win – кто выиграл (0 – ничья, любая цифра – id выигравшего) - desc – приз победителя - time – время начала сражения - p1_map – список карт нападавшего - p2_map – список карт защищающегося Таблица battle_log - id – уникальный идентификатор - battle_id – id боя - desc – предложение лога Таблица word - id – уникальный идентификатор - type – тип фразы (1 – простой удар, 2 – промах, 3 – критический удар) - desc – фраза для лога, пример: - {name1} зарядил в лоб {name2} ({damage})
- {name2} уклонился от атаки
- {name1} удачно использовал прием ({damage})
Слова {name1} заменится на имя атакующего, {name2} на имя защищающегося, {damage} на количество урона
Модуль боя есть. Осталось логику боя прописать. Для этого откройте файл inc/battle.php и запишите: Код <?php /* * Класс боя * */
class battle {
private $W_krit = array(); # Список слов для критического удара private $W_att = array(); # Список слов для простого удара private $W_miss = array(); # Список слов для промаха # Инициализируется бой # $p1:Array - характеристики нападающего (Н) # $p2:Array - характеристики защищающегося (З) # $db:Class - класс БД public function rush($p1,$p2,$db) { $db->q("INSERT INTO `battle` (`p1`,`p2`,`time`) VALUES ('".$p1['id']."','".$p2['id']."','".date('Y-m-d H:i:s')."')"); # Созадется запись боя $battle_id = mysql_insert_id(); # Запоминается id боя $map1 = explode("|",$p1['position']); # Список карт Н $map2 = explode("|",$p2['position']); # Список карт З # Создание списка слов для лога $sql_word = $db->q("SELECT * FROM `word`"); while($word = mysql_fetch_array($sql_word)) { if ($word['type'] == 1) { $this->W_att[] = $word['desc']; } elseif ($word['type'] == 2) { $this->W_miss[] = $word['desc']; } elseif ($word['type'] == 3) { $this->W_krit[] = $word['desc']; } } $j=0; # Текущая карта Н $k=0; # Текущая карта З $_map1 = array(); # Характеристики карт Н $_map2 = array(); # Характеристики карт З $ids1 = array(); # Список карт Н $ids2 = array(); # Список карт З $log1 = array(); # Список характеристик карт Н для вывода в лог $log2 = array(); # Список характеристик карт З для вывода в лог # Запоминается расположение карт игроков for ($i=0;$i<5;$i++) { $n_map1 = $map1[$j]; if ($n_map1 == 0) { # Если в текцщем слоте Н нет карты, то записывается первая карта $n_map1 = $map1[0]; $j=0; } $n_map2 = $map2[$k]; if ($n_map2 == 0) { # Если в текцщем слоте З нет карты, то записывается первая карта $n_map2 = $map2[0]; $k=0; } # Получение характеристик карты. Если характеристики карты были уже получены, то считывается с переменной if (!isset($ids1[$n_map1])) { $sql = $db->q("SELECT `user_map`.`att`,`user_map`.`abi`,`user_map`.`skill`,`user_map`.`lvl`,`user_map`.`exp`,`user_map`.`id`,`map`.`name`,`map`.`lvl_exp`,`map`.`c har` FROM `user_map`,`map` WHERE `user_map`.`map_id`=`map`.`id` AND `user_map`.`id`='".$n_map1."'"); $_map1[] = mysql_fetch_array($sql); } else { $_map1[] = $_map1[$j]; } # Получение характеристик карты. Если характеристики карты были уже получены, то считывается с переменной if (!isset($ids2[$n_map2])) { $sql = $db->q("SELECT `user_map`.`att`,`user_map`.`abi`,`user_map`.`skill`,`user_map`.`lvl`,`user_map`.`exp`,`user_map`.`id`,`map`.`name`,`map`.`lvl_exp`,`map`.`c har` FROM `user_map`,`map` WHERE `user_map`.`map_id`=`map`.`id` AND `user_map`.`id`='".$n_map2."'"); $_map2[] = mysql_fetch_array($sql); } else { $_map2[] = $_map2[$k]; } # Запись характеристик карт для лога $log1[] = array( 'name'=>$_map1[$j]['name'], 'att'=>$_map1[$j]['att'], 'abi'=>$_map1[$j]['abi'], 'skill'=>$_map1[$j]['skill'], 'lvl'=>$_map1[$j]['lvl'] ); $log2[] = array( 'name'=>$_map2[$k]['name'], 'att'=>$_map2[$k]['att'], 'abi'=>$_map2[$k]['abi'], 'skill'=>$_map2[$k]['skill'], 'lvl'=>$_map2[$k]['lvl'] ); # Записывает характеристики карты, что бы не проверять каждый раз одну и ту же карту в БД, будут браться характеристики с этой переменной $ids1[$n_map1] = $_map1[$j]; $ids2[$n_map2] = $_map2[$k]; $j++; $k++; } $life1 = $p1['life']; # Жизненная энергия Н $life2 = $p2['life']; # Жизненная энергия З $data = array(); # Выигрышь победителя $all_damage1 = 0; # Всего урона Н $all_damage2 = 0; # Всего урона З $win = -1; # Определяет кто победитель # Запускается бой на 5 ходов for ($i=0;$i<5;$i++) { if (!isset($ids1[$_map1[$i]['id']]['k'])) $ids1[$_map1[$i]['id']]['k'] = 0; # Количество урона, который нанесла карта Н за все ходы if (!isset($ids2[$_map2[$i]['id']]['k'])) $ids2[$_map2[$i]['id']]['k'] = 0; # Количество урона, который нанесла карта З за все ходы $damage1 = $this->damage($_map1[$i],$_map2[$i]); # Урон в текущем ходе Н $damage2 = $this->damage($_map2[$i],$_map1[$i]); # Урон в текущем ходе З # Создается запись в лог $db->q("INSERT INTO `battle_log` (`battle_id`,`desc`) VALUES ('".$battle_id."','".$damage1['txt']." - ".$damage2['txt']."')"); $life1 -= $damage2['damage']; # Уменьшается жизненная энергия Н $life2 -= $damage1['damage']; # Уменьшается жизненная энергия З $ids1[$_map1[$i]['id']]['k'] += $damage1['damage']; # Увеличивается количество урона, нанесенного картой Н $ids2[$_map2[$i]['id']]['k'] += $damage2['damage']; # Увеличивается количество урона, нанесенного картой З $all_damage1 += $damage1['damage']; # Увеличивается количество общего урона Н $all_damage2 += $damage2['damage']; # Увеличивается количество общего урона З # Если жизненная энергия обои игроков закончилась или какого то одного из них, а ходы еще остались, то записывается победитель и его приз if ($life1 <= 0 && $life2 <= 0) { $win = 0; $desc = ''; break; } elseif ($life1 <= 0) { $win = $p2['id']; $data['money'] = mt_rand(0,$all_damage2); $desc = json_encode($data); break; } elseif ($life2 <= 0) { $win = $p1['id']; $data['money'] = mt_rand(0,$all_damage1); $desc = json_encode($data); break; } } # Если прошло 5 ходов, а жизненная энергия игроков еще не закончилась, то в зависимости от нанесенного урона выбирается победитель и получает свой приз if ($win == -1) { if ($all_damage1 == $all_damage2) { $win = 0; $desc = ''; } elseif ($all_damage1 < $all_damage2) { $win = $p2['id']; $data['money'] = mt_rand(0,$all_damage2); $desc = json_encode($data); } elseif ($all_damage2 < $all_damage1) { $win = $p1['id']; $data['money'] = mt_rand(0,$all_damage1); $desc = json_encode($data); } } # Запись карт игроков в лог, так же их фильтрация $_p1_map = json_encode($log1); $_p2_map = json_encode($log2); $_p1_map = str_replace("\\","\\\\",$_p1_map); $_p1_map = str_replace("'","\\'",$_p1_map); $_p2_map = str_replace("\\","\\\\",$_p2_map); $_p2_map = str_replace("'","\\'",$_p2_map); $db->q("UPDATE `battle` SET `win`='".$win."', `desc`='".$desc."',`p1_map`='".$_p1_map."',`p2_map`='".$_p2_map."' WHERE `id`='".$battle_id."'"); if ($win != 0) $db->q("UPDATE `user` SET `money`=`money`+'".$data['money']."' WHERE `id`='".$win."'"); # Если есть победитель, увеличивается его количество монет $char_list = array('att','abi','skill'); # Список характеристик для карт # Список карт Н foreach($ids1 as $id => $val) { $exp = $val['exp']+$val['k']; # Расчитывается количество опыта для карты $lvl = $val['lvl']; # Уровень карты $char = array($val['att'],$val['abi'],$val['skill']); # Характеристики карты $plvl = $val['lvl']-1; # Позиция уровня $extra_sql = ''; if ($lvl == 5) continue; # Если уровень карты 5 (максимальный), то переходим к следующей $_exp = explode("|",$val['lvl_exp']); # Количество опыта для поднятия уровня $_char = explode("|",$val['char']); # Процент увеличения для каждой характеристики отдельно для всех уровней if ($_exp[$plvl] <= $exp) { # Если текущий опыт больше опыта для текущего уровня, то увеличивается уровень $lvl++; $exp -= $_exp[$plvl]; # Указывается реальный опыт на текущем уровне $__char = explode(":",$_char[$plvl]); # Процент увеличения для каждой характеристики отдельно для текущего уровня карты # Случайным образом увеличивается характеристика, либо не увеличивается, как повезет <img src="http://s12.ucoz.net/sm/1/smile.gif" border="0" align="absmiddle" alt="smile" /> for ($i=0;$i<3;$i++) { $rnd = mt_rand(1,100); if ($rnd >= $__char[$i]) { $extra_sql = ",`".$char_list[$i]."`=`".$char_list[$i]."`+'".mt_rand(1,5)."'"; break; } } } $db->q("UPDATE `user_map` SET `exp`='".$exp."', `lvl`='".$lvl."' ".$extra_sql." WHERE `id`='".$id."'"); # Обновление информации о карте } # Отправляется уведомление о бое $db->q("INSERT INTO `post` (`p1`,`p2`,`read`,`theme`,`text`,`time`) VALUES ('".$p1['id']."','0','1','Вы участвовали в сражении','<a href=\'?a=battle&id=".$battle_id."\'>Просмотреть лог боя</a>','".date('Y-m-d H:i:s')."'), ('".$p2['id']."','0','1','Вы участвовали в сражении','<a href=\'?a=battle&id=".$battle_id."\'>Просмотреть лог боя</a>','".date('Y-m-d H:i:s')."')"); # Список карт З foreach($ids2 as $id => $val) { $exp = $val['exp']+$val['k']; # Расчитывается количество опыта для карты $lvl = $val['lvl']; # Уровень карты $char = array($val['att'],$val['abi'],$val['skill']); # Характеристики карты $plvl = $val['lvl']-1; # Позиция уровня $extra_sql = ''; if ($lvl == 5) continue; # Если уровень карты 5 (максимальный), то переходим к следующей $_exp = explode("|",$val['lvl_exp']); # Количество опыта для поднятия уровня $_char = explode("|",$val['char']); # Процент увеличения для каждой характеристики отдельно для всех уровней if ($_exp[$plvl] <= $exp) { # Если текущий опыт больше опыта для текущего уровня, то увеличивается уровень $lvl++; $exp -= $_exp[$plvl]; # Указывается реальный опыт на текущем уровне $__char = explode(":",$_char[$plvl]); # Процент увеличения для каждой характеристики отдельно для текущего уровня карты # Случайным образом увеличивается характеристика, либо не увеличивается, как повезет <img src="http://s12.ucoz.net/sm/1/smile.gif" border="0" align="absmiddle" alt="smile" /> for ($i=0;$i<3;$i++) { $rnd = mt_rand(1,100); if ($rnd >= $__char[$i]) { $extra_sql = ",`".$char_list[$i]."`=`".$char_list[$i]."`+'".mt_rand(1,5)."'"; break; } } } $db->q("UPDATE `user_map` SET `exp`='".$exp."', `lvl`='".$lvl."' ".$extra_sql." WHERE `id`='".$id."'"); # Обновление информации о карте } # Переадресация на лог боя go2page("game.php?a=battle&id=".$battle_id); } # Расчет урона # $m1:Array - характеристики атакующей карты # $m2:Array - характеристики защищающейся карты private function damage($m1,$m2) { $ret = array('damage'=>0,'txt'=>''); # Данные, которые будут возвращаться текущей функцией $is_miss = round($m1['att']/(mt_rand($m1['att'],($m1['att']+($m2['abi']*2))))); # Расчитывает возможность промаха if ($is_miss == 1) { # Если промаха нет, то расчитывает урон $is_krit = round(round(mt_rand(0,10)/10)*$m1['skill']/($m1['skill']+$m2['abi'])); # Расчитывает критический удар if ($is_krit == 1) { # Если удар критический, то увеличивается урон $m1['att'] = round(($m1['att']*150)/100); } $_damage = round($m1['att']*(mt_rand(75,150)/100)); # Общий урон $_block = round($m2['abi']*(mt_rand(5,10)/10)); # Защита защищающегося $ret['damage'] = $_damage-$_block; # Окончательный урон } if ($ret['damage']<0) $ret['damage'] = 0; # Что бы не было минусового урона # Указывает какие слова для лога использовать if ($is_krit == 0) { $word = $this->W_att; } elseif ($is_krit == 1) { $word = $this->W_krit; } if ($ret['damage'] == 0) { $word = $this->W_miss; } # Получает случайную фразу из списка фраз $sizeof = sizeof($word)-1; $arr_word_rand = mt_rand(0,$sizeof); $ret['txt'] = $word[$arr_word_rand]; if ($ret['txt'] == "") { $ret['txt'] = $word[0]; } # Преобразовывает зарезервированые слова в нужные $ret['txt'] = str_replace('{name1}','<b>'.$m1['name'].'</b>',$ret['txt']); $ret['txt'] = str_replace('{name2}','<b>'.$m2['name'].'</b>',$ret['txt']); $ret['txt'] = str_replace('{damage}','<b>'.$ret['damage'].'</b>',$ret['txt']); # Возвращает данные return $ret; } }
?> В этом файле прописана логика боя. Он прокомментирован, но если что то не ясно, пишите в теме. Логика довольно проста. По очереди карты нападающего атакуют карты защищающегося, те в ответ отбиваются. Если у одного игрока 1 карта, а у другого несколько, то эта 1 карта отбивается от всех. Но бывает что одна карта раскачана так, что может нескольких побить спокойно. Всего есть 5 ходов. Т.е. с каждой стороны игроков должно быть по 5 ударов. После окончания этих ходов, либо у игрока(игроков) закончилась жизненная энергия происходит подсчет урона. По наибольшему урону, либо тот кто выжил тот и выигрывает. Каждой карте дается опыт равный урону, который нанесла эта карта. При повышении уровня, у карты случайным образом увеличивается определенная характеристика, либо не увеличивается, как повезет. После всех этих манипуляций игрок сможет увидеть лог боя. В следующей главе я расскажу как уведомить игрока, о том что на него напали, либо о покупке лота с аукциона, либо просто пообщаться с другими игроками.
При копировании материала ссылка на источник обязательна!
|
|
| |
Tima9900 | Дата: Понедельник, 21 Июля 2014, 20:05 | Сообщение # 2 |
был не раз
Сейчас нет на сайте
| после нажатия на кнопку напасть http://s1.uploadpics.ru/images/xkeWM-L3Zl.jpg
|
|
| |
Assasin | Дата: Понедельник, 21 Июля 2014, 20:12 | Сообщение # 3 |
web-coder
Сейчас нет на сайте
| Вероятно у нападающего нет карт для боя или не выставлены карты для боя.
|
|
| |
Tima9900 | Дата: Понедельник, 21 Июля 2014, 20:15 | Сообщение # 4 |
был не раз
Сейчас нет на сайте
| карты есть
|
|
| |
Assasin | Дата: Понедельник, 21 Июля 2014, 20:23 | Сообщение # 5 |
web-coder
Сейчас нет на сайте
| Можно скрин с пункта меню "Список карт"?
|
|
| |
Tima9900 | Дата: Понедельник, 21 Июля 2014, 20:33 | Сообщение # 6 |
был не раз
Сейчас нет на сайте
| http://s1.uploadpics.ru/images/lyZfw8Lhbl.jpg
|
|
| |
Assasin | Дата: Понедельник, 21 Июля 2014, 20:51 | Сообщение # 7 |
web-coder
Сейчас нет на сайте
| Еще при нажатии на "Напасть", mysql запросы отображаются? Если да, то нужно и их глянуть.
|
|
| |
Tima9900 | Дата: Понедельник, 21 Июля 2014, 21:42 | Сообщение # 8 |
был не раз
Сейчас нет на сайте
| после нажатия на кнопку напасть на той же странице (game.php?a=battle) отображается http://s1.uploadpics.ru/images/xkeWM-L3Zl.jpg , а потом идет переадресация на лог боя http://s1.uploadpics.ru/images/lJlLPePnbg.jpg
|
|
| |
Assasin | Дата: Понедельник, 21 Июля 2014, 22:08 | Сообщение # 9 |
web-coder
Сейчас нет на сайте
| Видимо какой то недочет. Можно мне в личку дамп базы?
|
|
| |
playerro | Дата: Пятница, 29 Января 2016, 19:39 | Сообщение # 10 |
уже был
Сейчас нет на сайте
| Assasin, та же проблема, как ее исправить?
|
|
| |
eldalomeo | Дата: Пятница, 19 Февраля 2016, 11:49 | Сообщение # 11 |
уже был
Сейчас нет на сайте
| playerro, убери пробел
|
|
| |
DonMoscow | Дата: Пятница, 15 Июля 2016, 21:18 | Сообщение # 12 |
уже был
Сейчас нет на сайте
| После нажатия на кнопку напасть вылетает такая ерунда http://prntscr.com/btclcy и она продолжает добавляться пока не остановишь. Как решить проблему может кто сталкивался?
|
|
| |
kogtehvost | Дата: Среда, 04 Января 2017, 03:08 | Сообщение # 13 |
уже был
Сейчас нет на сайте
| Assasin, Аналогичная проблема! При нажатии на "Напасть" лог боя бесконечно разрастается, пока не остановишь выполнение страницы или пока браузер не крашнется. Помогите, плиз!
|
|
| |
ДьявоL | Дата: Пятница, 14 Июля 2017, 22:44 | Сообщение # 14 |
уже был
Сейчас нет на сайте
| Как решить то данную проблему с кнопкой напасть?Подскажите.
|
|
| |
|