Всем привет. Разрабатываю браузерную игру на PHP.
Есть bash скрипт, который запускает определенный PHP-скрипт каждую секунду.
Изначально скрипт был написан так, что регенирирует здоровье игроков:
- Получаем игроков, у которых кого не полное здоровье, добавляем нужное количество, записываем в БД.
Но даже с 50+ активных игроков это занимает немало времени. Ко всему этому мне теперь нужно добавить, чтоб игрок имел баффы (эффект кровотения как пример, который например каждую секунду отнимает опр. кол-во здоровья). На MYSQL это всё очень будет затрано по времени.
Дальше я пришёл к тому, что при старте боя начал записывать копию данных игрока из БД в Redis, и уже скрипт обрабатывал данные из Redis, что в теории должно быть быстрее, но мне все равно не хватает скорости, т.к. теперь каждую секунду в скрипте мне приходится: получать всех игроков, все баффы и т.п. И потом под каждый бафф в цикле уменьшать\увеличивать здоровье игроков. При 50+ активных игроков это занимает больше 0.15 сек времени.
Есть ли способ как-то уменьшить время выполнения? Или может какие-нибудь другие технологии
Есть ли способ как-то уменьшить время выполнения? Или может какие-нибудь другие технологии
Ну если ты разработчик игры - то ты должен уметь находить узкое место в коде. Только указать его не так как ты указал на словах. А привести фрагмент кода. Готов спорить что у тебя там стоит $conn->query("UPDATE ....")
Вот. Технологий много. От регулировки MySQL engine до полного отказа от MySQL и перехода на NoSQL.
А потом - отказ от PHP и переход на что-то другое.
Написать игру на компилируемом языке. Запускать и она будет постоянно работать в памяти, обсчитывать всё в рилтайме. Изредка будет сохранять данные в БД, что бы можно было восстановить некоторое предыдущее состояние при крахе.
Ну может вам редисе или в мускуле держать не 50 записей, а одну агрегированную аля сражение, в котором будут в json лежать ид игроков и их бафы дебафы.
Ну да, перепишем все на компилируемом языке и прям сразу все будет работать в десятки раз быстрее. Ага, конечно, особенно когда проблема с записью/чтением из бд.
Отсюда вопрос, Whos, а зачем постоянно это все писать/читать из бд?
Другие технологии, их есть у нас. Называется - просто не делай этого вообще.
Игрок получил повреждения - записываешь в базу, и все, ничего не регенерируешь.
Когда произойдет какое-то новое взаимодействие с игроком - получил новый урон, обновил страницу, или какая там у вас игровая логика, тогда уже, при помощи формулы "прошедшее_время * скорость_регена = сколько_здоровья_оргененило".
С баффами все немножко сложнее, но смысл тот-же - считайте формулой, и в тот момент когда данные нужны, а не в фоновом процессе неведомо зачем.
Если и сделать так, то к примеру взять 50 игроков, которые между собой наносят урон каждую секунду, то возможна ситуация, когда два или более игрока получат одинаковое значение "прошедшего времени" и вместе зарегенят здоровье тому, кого бьют (уже сталкивался с подобным). Да и с баффами та же ситуация может проскочить.
Stalker_RED , Вы, похоже, не игрок. Есть эффекты, действующие в единицу времени - "Damage over Time" и "Heal over Time". Если на игроке "дот", то игрок через N интервалов должен умереть, даже если его никто не бьёт. Если "хот" - то весьма вероятна ситуация, когда при получении очередного урона игрок выживет ( а без "хота" умер бы).
Ну и до кучи, игроки хотят видеть своё состояние оперативно. Так что подход "обсчитывайте данные, когда они нужны", тут не катит, данные нужны на каждом "тике".
Михаил Ливач, я никогда не играл в вашу игру и не знаю какие механики у вас реализованы.
Применяете оба эффекта, можете хоть график построить, и если значение хп опускается до нуля - пичалька.
В школе производные проходили? Тот случай, где школьная математика позволяет не считать тики в реалтайме.
Михаил Ливач, моей первой MMO были фришарды UO в 2002 году, наигрался уже, спасибо. В том числе в три ММО браузерки играл (не считая тех, что на один вечер).
Даже если бы не играл - все равно дергать php ежесекундно через баш(?) это какая-то трешанина.
Оптимальный, в плане производительности вариант - считать эти данные когда они нужны, а не в фоне.
Если очень надо в фоне - можно написать демона, который не будет выгружаться и загружаться каждую секунду заново, а будет просто работать, потребляя намного меньше ресурсов.