Комментарии 8
У Вас очень здорово получилось, прочитал с удовольствием. Ваш немного иной логический подход мне понравился, дал пищу для размышлений, а конкретнее адаптировать его под Python. Raku, конечно, мне в диковину, но вы всегда давали понятные комментарии.
И даже записали видео с демонстрацией! Одним словом, вы проделали большую работу, спасибо. В начале своей статьи оставил упоминание вашей работы.
P.S. По поводу "побега от хардкодинга". Я согласен, что хардкодинг (особенно такой изящный, как здесь) более уместен при разработке игры, однако я создал под себя такую систему, чтобы можно было ограничиться эффектами по умолчанию. Фактически, это результат лени. Когда придёт вдохновение под какую-то особую поверхность (например, проклятое облако нефти снижает боевой дух и шанс походить), то я пропишу под нее логику отдельно.
Спасибо большое за ваш комментарий и за упоминание в вашей статье. Я рад, что Raku не стал слишком высоким барьером для понимания, я немного боялся, что он будет слишком отталкивать.
По хардкодингу: что думаете о проблеме "невозможных состояний"? То есть, если какая-то комбинация из субстанция/агрегатное не будет существовать в игре. Похоже, что нужно будет при создании или изменении везде ставить проверки на то, что набор свойств позволителен. Например для electrify
у вас такое условие:
self.base_surface == BaseSurface.NEUTRAL and self.aggregate_state != AggStates.VAPOR) or self.aggregate_state == AggStates.SOLID
Наверное нужно будет что-то придумать, если система будет расширяться. Какое-нибудь пост-условие, что конечный объект всегда валидный.
Спасибо большое за ваш комментарий и за упоминание в вашей статье. Я рад, что Raku не стал слишком высоким барьером для понимания, я немного боялся, что он будет слишком отталкивать.
По хардкодингу: что думаете о проблеме "невозможных состояний"? То есть, если какая-то комбинация из субстанция/агрегатное не будет существовать в игре. Похоже, что нужно будет при создании или изменении везде ставить проверки на то, что набор свойств позволителен. Например для electrify
у вас такое условие:
self.base_surface == BaseSurface.NEUTRAL and self.aggregate_state != AggStates.VAPOR) or self.aggregate_state == AggStates.SOLID
Наверное нужно будет что-то придумать, если система будет расширяться. Какое-нибудь пост-условие, что конечный объект всегда валидный.
Очень интересно, насколько глубоко простирается взаимодействие элементов?
Можно ли смешать яд и воду, чтобы получить отравленную воду, потом огнем испарить её и получить ядовитое облако и в конце ветром сдуть облако на клетку с противником?
Как только говорят про взаимодействие элементов, сразу вспоминается Магика с её целебными булыжниками.
Отвечая на вопрос, как глубока эта система, я думаю, что речь будет идти о возможности воплотить перечисленные вами механики, используя концепты из этой статьи. И отдельный вопрос, насколько будет легко адаптировать текущую имплементацию для этих механик. Я попробую ответить по порядку сначала про концепты, а затем про имплементацию.
Смешать яд и воду, чтобы получить отравленную воду. Это работает в текущей концепции так: к поверхности "вода" применяется элемент "яд", и вода из обычной воды WaterSurface
становится отравленной водой, или просто ядом PoisonSurface
. В текущей имплементации это уже есть, правда сделано с особенностью Divinity, что там высчитывается вероятность, будет ли замещение воды ядом.
Испарить огнем для получения отравленного облака. Работает аналогично, к поверхности PoisonSurface
применяется элемент FireElement
и мы испаряем эту поверхность, превращая в ядовитое облако PoisonCloud
. В текущей имплементации, следуя канону Divinity, когда огонь соединяется с ядом, то образуется взрыв. Но это можно легко поменять, сейчас эта логика находится в этом мульти методе:
class PoisonSurface is Surface does Solution is export {
# ...
multi method apply (FireElement) { [StateChange.empty, ExplosionEnvironmentEffect.new] }
}
В мульти-методе выше при столкновении ядовитой лужи с огнем происходят две вещи: убираем все поверхности и облака с клетки, и мы вызываем эффект взрыва.
Сдуть облако на клетку с противником. Это интересная механика, она не ограничивается просто клеткой, на которую оказывают воздействие, поэтому в текущем концепте это будет еще один эффект окружающей среды. Выглядеть это будет примерно следующим образом:
class PoisonCloud is Cloud is export {
multi method apply (AirElement $e) {
[StateChange.empty,
MoveEnvironmentEffect.new(
source => $e.source-cell,
cell => StateChange.cloud(PoisonCloud.new))]
}
# ...
}
Мы очищаем текущую клетку и вызываем эффект окружающей среды, чтобы произвелась механика "сдвига" облака. Мы передаем туда source
, клетку-источник нашего элемента, чтобы рассчитать траекторию, куда должно сместиться облако. На данный момент в имплементации не хватает клетки-источника у элемнтов — элементы не знают, кто и откуда их применил. Скорее всего эту информацию все равно можно будет использовать, поэтому ее нужно будет добавить. Как мне кажется, это будет правка достаточно большого количества кода, но не потребует редизайна имеющейся системы, просто добавить данные.
***
Мне на ум еще приходит игра, в которую я играл в детстве и сейчас не могу найти. Это был дарк фентези сеттинг, там была книга заклинаний, где тоже можно было комбинировать разные школы. Почему-то на ум приходит название "Blood Magick", но увы, я не могу ничего найти. Помню, что там была темная церква, в которой проводили месу, и рядом с ней было какое-то существо, похожее на голума из Властелина колец.
Статья интересная, но пожалуйста не сочетайте новый материал (механики) с еще одним новым материалом (язык). Дело конечно ваше, но среднему читателю (к которому отношусь и я) приходится обращать дополнительное внимание на синтаксис и задумываться в лишний раз «А правильно ли я все понял». Хотя прекрасно понимаю это ощущение, когда находишь для себя новый, мало кому известный язык. Когда-то для меня таковым стал Rust. А в остальном - спасибо за статью, очень интересно.
Механика окружающей среды в фентезийном мире