Главная » Статьи » Деццкий сад

Урок 8. Да будет жизнь 2. Мобы.
"- Нет-нет-нет! – воскликнул Альберт. – Не хочу ни на что намекать хозяин, но в этом восклицании должно быть больше жизни. Смех должен быть заразительным! Это… Это нужно произносить так, словно ты писаешь чистым бренди, а ходишь по-большому рождественским пудингом, прошу прощения за мой клатский."
(с) Терри Пратчетт, "Санта-Хрякус"

Мы тоже постараемся добавить "больше жизни" в нашу игру. 


Подготовка.
    Для начала надо упорядочить работу с нашими персонажами. В самом деле, не создавать же под каждого нового персонажа новую переменную, а потом ещё и разгребать этот бардак. Давайте создадим отдельный класс, который будет отвечать за хранение всех наших персонажей. Я его обозвал CharactersList и поместил в модуль character.py. Вспоминаем прошлый урок и идём смотреть изменения в восьмом уроке http://code.google.com/p/panda-rpg-tutorial/source/list. CharactersList содержит список list, в котором будут храниться все наши персонажи и несколько методов для облегчения работы со списком:
    getNewId - вот за что я люблю питон - три строчки на то, на что в другом языке ушла бы дюжина. Мы генерируем новый список из существующих id персонажей, получаем максимальный id и, увеличив его на 1, возвращаем в качестве результата. Т.е. мы получаем ID для нового персонажа. Если список ещё пустой, то первый ID будет равен 0.
    newCharacter - генерируем id, создаём нового персонажа, заносим его в список и возвращаем указатель на созданного персонажа.
    update - проходим по списку персонажей и обновляем их.
    Так же я внёс несколько изменений в класс character. Первое связано с тем, что появилась необходимость вызывать метод update класса character вручную из CharactersList. Для этого я присвоил дефолтное значение Null передаваемой переменной task и сделал проверку - если task не Null, значит метод был вызван диспетчером задач и нужно ему вернуть task.cont. Второе - исправление небольшого бага, который я допустил в обработке переключения анимаций - может случиться такая ситуация, что интервал animInterval не успеет завершить свою работу по переключению к тому времени как потребуется снова переключить анимацию. В этом случае могут возникнуть разные неприятные эффекты типа подвисания анимации. Поэтому прежде чем запустить новый интервал переключения необходимо принудительно финализировать текущий - animInterval.finish(). Ну и заодно я вынес процедуру переключения в отдельный метод switchAnimTo. И третье изменение - я добавил свойство aistate, являющееся экземпляром нового класса AIState. Оно будет служить для хранения обработчиком ИИ своих данных - например разных таймеров, диалогов, поведенческих коэффициентов и пр. На данный момент в AIState нам потребуется только работа с таймерами, которую я и реализовал в том же character.py.
    Можно было бы сделать отдельный класс для персонажей, контролируемых ИИ, что логично, однако в дальнейшем это может вызвать затруднения, если, например нам потребуется чтобы нашего персонажа взял под контроль ИИ - допустим у нас несколько персонажей и мы переключаемся между ними, либо потребуется скриптовая сцена, либо на персонажа наложили заклинание паники и мы потеряли над ним контроль, да мало-ли что ещё в голову взбредёт smile

Реализация.
     Вероятно, вы уже обратили внимание на то что Mercurial сообщил "Add /modules/aicontroller.py" - да под ИИ я выделил отдельный файл aicontroller.py, и создал в нём класс AIController. При создании экземпляра ему передаётся ссылка на наш список персонажей, с которым ему предстоит работать. Основной метод нашего класса - снова update - "обновление" - основа игры smile . Метод может вызываться как вручную так и из диспетчера задач, по тому же принципу, как я переделывал character. Данный метод будет вызываться не каждый раз, а через определённый интервал для экономии ресурсов, т.к. обрабатывать ИИ нам достаточно пару раз в секунду, поэтому мы будем возвращать не task.cont, а task.again и добавление этой задачи будет отличаться, о чём расскажу в конце.
    На текущий момент поведение нашего ИИ очень простое и заключается в рандомном блуждании туда-сюда, пусть данное поведение у нас будет под индексом 1. Для этого мы проходим по списку персонажей и смотрим у кого из них выставлен aitype = 1, после чего проеряем его состояние - нам нужно чтобы он стоял и список вэйпойнтов у него был пустым. Хорошо - нашли такого персонажа, теперь вспомним про таймеры, о которых я упомянул в описании AIState - чтобы поведение было немного более естественным, мы будем с помощью таймера заставлять ждать персонажа, прежде чем ИИ назначит ему новую точку пути. Т.е. если персонаж стоит и ждёт - уменьшаем таймер пока он не станет <= 0, после этого генерируем случайную новую точку пути для персонажа и заново выставляем таймер.

Завершающие штрихи.
    В завершение соберём проделанную работу в кучу с помощью main.py и globals.py. В globals.py создадим экземпляры классов CharactersList и AIController, а так же изменим создание персонажа игрока - теперь он будет создаваться через CharactersList. Изменим процедуры, добавляемые в менеджер задач - раньше у нас обрабатывалась процедура update одного персонажа - заменим её на update созданного CharactersList, затем добавим процедуру обработки ИИ - обратите внимание - эта процедура добавлена с помощью doMethodLater, что позволяет выполнять её не каждый проход, а через заданные промежутки времени, в нашем случае 0.5 сек. В main.py мы в цикле создадим трёх мобов, и назанчим им aitype = 1, в результате чего контроллер ИИ получит над ними управление.

Категория: Деццкий сад | Добавил: ninth (31.10.2010)
Просмотров: 8736 | Рейтинг: 2.9/8
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Онлайн всего: 2
Гостей: 2
Пользователей: 0