Монстры
Для начала, я прописал референсы для монстры. Они хранятся в папке graphic/monsters
. Также я добавил звуки ударов и закинул их в папку audio/attack
Далее, в setting.py прописаны их входные данные:
Пробежимся по параметрам:
health
— здоровье монстраexp
— сколько очков за смерть монстраdamage
— какой урон он нанесёт героюattack_type
— тип атакиattack_sound
— звук удараspeed
— скорость зверькаresistance
— на сколько монстр отлетит после нашего удараattack_radius
— радиус, с которого монстр опасен и может ударитьnotice_radius
— радиус зрения монстра
Далее, создадим новый файл сущностей (entity.py
) и добавим туда супер демона с наследованием групп:
Скопируем методы move
и collision
из player.py
. Теперь удаляем из player.py
эти методы и будем ссылаться в классе не на pygame.sprite.Sprite
, а на Entity
(не забывайте импортировать файл). Эти небольшие танцы с бубном нужны для того, чтобы не переписывать каждый раз правила движений для нашего героя и монстров. Все они — одинаковые сущности. Также я перенёс демонов скорости анимации, фрейма и определения вектора скорости. Когда всё сделаете, перепроверьте, что всё работает.
Затем, наконец, создадим файл enemy.py
:
Перейдём к настройке уровня. Для начала, сделаем так, чтобы наш герой спаунился там, где надо (зелёный квадрат на карте). Для этого, нам нужно импортировать новый csv-файл из уже созданной карты 'entities': import_csv_layout('../map/map_Spawn.csv')
. И пропишем в методе creat_map
новый объект:
Результат вас удивит:
Герои Хайрула размножились. Проблема в том, что я прорисовывал карту разными наборами элементов. Не повторяйте моих ошибок и давайте всё исправлять. Дело в том, что номер тайла автоматически рассчитывается программой Tiles, а я указал, разные тайлы и номера задублировались, так как у меня был отдельный файл Bebs.png для спауна врагов и Link_and_block.png для Линка и блоков-стен. Теперь я объединил два набора тайлов и присвоил линку номер 16. Результат:
Линк на своём законном месте. Давайте заспаумим врагов, добавив лишь один else:
Монстры отобразились, но теперь нужно отобразить их верно. Работаем с файлом enemy.py
:
Тут мы делаем всё ровно также, как и ранее, но если в файле level.py
мы внесём имя любого монстра, то получим картинку монстра на карте:
Осталось только перебрать монстров по их номерам тайлов на карте:
Теперь, добавим аргумент obstacle_sprites
в нашу конструкцию, чтобы монстры могли взаимодействовать с Линком. Далее, создадим update-метод для файла enemy.py
:
Далее, нужно прописать несколько статусов для наших плохишей. Добавим их в демонов данного файла:
Тут мы ссылаемся на файл settings.py и перехватываем все параметры монстров оттуда. Теперь наша задача прописать метод определения дистанции до объекта. Я думал, что эта задача непроста, так как координаты объекта рассчитываются с верхнего левого угла, у них есть свои векторы (скорости), да ещё и нужна нормализация для предотвращения "диагонального чита" (как это было у Линка). Собственно весь метод:
Я искренне не ожидал, что это так просто. По сути, все сложные методы вычисления Евклидовой величины по поиску дистанции мы переложили на функцию magnitude()
, а с читерской функцией normalize()
вы уже знакомы. И зачем я учил математику? Далее, пропишем метод определения статуса монстра по отношению к Линку:
Тут мы отсекаем изнутри во вне "окружности" зрения (близко — атака, средняя дистанция — преследование, далеко — idle), но чтобы оно заработало, нам нужно обновлять данные в файле level.py
:
Тут самая интересная строка — строка прорисовывания спрайтов для врага. Тут можно как в анекдоте: "Потерялся атрибут? Ничего страшного! Всегда есть метод hasattr
". Далее, в run-методе пропишем отрисовку спрайтов врага:
Теперь мы сможем замкнуть врага на игрока, а игрока на уровень. Для этого пропишем новый метод в enemy.py
:
Теперь, у нас есть способ получения методов, но мы с ними не взаимодействуем. Исправим это новым методом:
В этом методе всё так же, как было ранее, но не забудьте закинуть его вызов в enemy_update
-функцию командой self.actions(player)
. Тетерь пропишем анимацию. Она полностью аналогична анимации Линка:
Также, добавьте animate в update-функцию. Теперь можно получить ачивку: "Собрал всех чушпанов с района":
Но есть проблема. Они атакуют несчастного Линка толпой без остановки. Это нужно исправить, а значит время нового метода и нового кулдауна. Сначала я добавил нового демона self.can_attack = True
. Это флаг, который будет указывать на то, что монстр может пнуть Линка. Соответственно, нужно подправить условие атаки и помимо дистанции, указать данный флаг. Если вы добавили флаг на True
, то обязательно сразу нужно прописать ситуацию, когда он будет опускаться (положение False
). Запишем этот пункт в методе анимации:
Немного объясню происходящее. Анимация атаки не должна прерывать анимацию перехода и если мы завершили весь цикл из переходов от картинки к картинке, то только тогда можно менять флаг на опущенное состояние. Простыми словами, все враги могут ударить нас только 1 раз, так как флаг не поднимается обратно. Поднимать тот самый флаг мы будем по кулдауну через паузу. То есть, я добавлю два демона, которые будут обозначать время атаки и кулдаун после атаки:
Теперь пропишем сам метод кулдауна по вычислению разницы текущего времени и времени задержки:
Тут самое главное, не забыть про место старта времени, то есть про установку времени на момент атаки:
После этого, не забудьте закинуть метод в update-метод. Результат:
Last updated