Драки с монстрами
Итак, для начала создадим два новых демона для атак в level.py:
self.attack_sprites = pygame.sprite.Group() #атакующий спрайт
self.attackable_sprites = pygame.sprite.Group() #атакуемый спрайтДумаю, по названиям понятно, что демоны нужны для обозначения процесса атаки. Дополним метод вызова врагов помимо видимых спрайтов, атакуемыми спрайтами (self.attack_sprites):
Enemy(monster_name, (x, y), [self.visible_sprites, self.attackable_sprites], self.obstacle_sprites)Также, дополним метод create_attack атакующим спрайтом (self.attack_sprites) :
def create_attack(self):
self.current_attack = Weapon(self.player, [self.visible_sprites, self.attack_sprites])Далее пропишем новый метод с логикой атаки игрока:
def player_attack_logic(self):
if self.attack_sprites:
for attack_sprites in self.attack_sprites:
collision_sprites = pygame.sprite.spritecollide(attack_sprites, self.attackable_sprites, False)
if collision_sprites:
for target_sprite in collision_sprites:
target_sprite.kill()Самая интересная строка тут, это строка с методом пайгейма pygame.sprite.spritecollide. Данный метод позволяет удалять спрайт из группы. Первый аргумент функции — спрайты для атаки, второй — группа спрайтов, из которой мы будем удалять спрайт, третий — DoKill. Если у DoKill установлено значение True, все спрайты, которые сталкиваются, будут удалены из группы. Далее, в run-методе пропишем наш метод. Исход:

Немного улучшим метод player_attack_logic:
Мы стали сопоставлять наши спрайты по типам. В моём проекте типов только два (enemy и weapon). Я прописал в файле weapon.py в демоне строку для присваивания ему нового типа:
Далее нам не нужно удалять врага при ударе. Нам нужно прописывать ему урон от нашего оружия. Собственно, теперь нужно в файле enemy.py прописать новый метод — get_damage:
Тут мы прописываем новый метод (get_full_weapon_damage), который должен высчитывать сумму урона от оружия и от силы самого Линка (прямо как в Dark Souls). Пропишем же данный метод в player.py:
Находим и складываем уроны из наших списков. Возможно, тут встанет вопрос: "Зачем так сложно, если у нас только один меч и всё?". Я хотел бы сделать проект так, чтобы вы могли самостоятельно с ним "поиграться". Собственно и цель книги не номинация "Игра года" в The Game Awards, а лишь попытка продемонстрировать работоспособность языка Python как неплохого движка. Ну да вернёмся к коду. Помимо урона, я решил сразу прописать кулдаун оружия и заменил строку:
На строку:
Напишем новый метод в enemy.py на проверку смерти монстра:
Тут я даже не знаю что ещё подсветить в коде :) Не забудьте добавить данный метод в update-метод. Теперь один удар приводит к смерти врага. Таким образом, PyGame считает, что пока оружие соприкасается с врагом (вызывается метод коллизий), удары наносятся один за другим. Как итог — Линк танк, который уничтожает всё на своём пути. Исправим это. Для начала, создадим новых демонов enemy.py:
Тут достаточно прозрачные демоны. Важный момент — флаг уязвимости. Если он поднят — враг может получать урон. Теперь встроим их в get_damage:
Далее необходимо дополнить код cooldown-метода:
Тут, как я говорил ранее, сразу добавляем вариацию флага. У нас было место, где флаг опускается и теперь в cooldown-методе он поднимается по истечению указанного времени неуязвимости. Теперь все враги убиваются весьма приятно. Теперь, нужно добавить отбивание врага на дистанцию, которая указана у каждого врага. Создадим ещё метод:
Осталось вычислить положение в методе get_damage:
Теперь добавим мерцание во время удара, чтобы понять что удар был сделан. В PyGame все сигнатуры (синусоидные функции) лежат в диапазоне от -255 до 255, а позиции удобно брать из синусоид, так как интерпретация в Python будет работать на основе степеней (как и любой калькулятор), а затем будет процесс получения точки на синусоиде. Этот процесс я описывал дольше, чем будет писаться метод отображения пульсации:
Данный метод написан в entity.py. Не забудьте импортировать sin-метод из библиотеки math. Теперь вызовем данный метод при ударе по врагу в методе animate:
Сейчас мы бьём врагов абсолютно верно и можем отследить когда монстры атакуют нас (в терминал приходит сообщение "attack"). Осталось сделать метод, который делает урон Линку. Пропишем его в level.py:
Дополним в create_map в строку вызова монстров нанесение урона Линку:
Добавим в Enemy-класс параметр (damage_player) и пропишем нового демона — self.damage_player = damage_player. Теперь вместо простого вывода сообщения "attack" выполним вызов нашего метода:
Добавим параметры таймеров в демонов нашего player-класса:
Они аналогичны демонам в enemy.py. Далее традиционно пропишем смену флага в наш кулдаун-метод:
Теперь пропишем наше мерцание. Тут всё также, как и ранее. Прописывать будем в animate-методе:
Теперь нам нужно восстанавливать энергию (повторим механику из Dark Souls). Для этого создадим метод energy_recover:
Далее пропишем, что при ударе у нас теряется 10 очков стамины, а если её не хватает — атака не проходит:
Последнее, что я хотел бы сделать — добавить экспу за убийство врага в level.py:
Добавим этот же метод для create_map в Enemy. Далее повторим всё, что делали ранее с damage_player.
Файлы данного шага тут. Приступим к последнему шагу — музыке.
Last updated