Strange Wood

Закрытые или заброшенные проекты, не состоявшие в Клубе, но имевшие ветку на форуме.

Модератор: Jolly Roger

Dmiry
Сообщения: 168
Зарегистрирован: 14 июн 2007, 10:32

Strange Wood

Сообщение Dmiry » 15 июн 2007, 10:41

Продукт: StrangeWood
Статус: проект
Описание: ролевая игра
Аналоги: Angband, Nethack, ADOM

Используемые паттерны: не знаю

Общая структура программы:
Для отображения на экране используется класс Painter, содержащий всю функциональность по выводу изображения на экран. Все остальные классы при необходимости отображить себя на экране обращаются к классу Painter.
Вопрос: надо ли вынести задачу отображения на экране в отдельный класс? Точнее, надо оформлЯть в виде отдельной команды необходимость перерисовать себя на экране.
Например, после создания карты надо ее показать на экране.
Что должно быть сделано: или карта обращается к паинтеру с вызовом DrawMap, или посылает команду PaintMap медиатору, который пересылает ее паинтеру. Тогда паинтер должен знать про все классы в программе. Или паинтер должен отслеживать состояние всех объектов и при необходимости обновить состояние объекта на экране выполняет перерисовку только требуемых объектов.

30/03/07
17:45
Пришел к следующей архитектуре
Есть Паинтер, который содержит набор методов вида DrawXXX, где XXX - соответствующий объект.
Соответственно, все объекты знают про паинтер и при необходимости себя нарисовать (вызывается их метод Draw) вызывают Painter.DrawXXX(self), то есть передают паинтеру указатель на самого себя.

При инициализации паинтер загружает из ИНИ файла все настройки экранного представления, т.е. расположение и размер карты, панели атрибутов, панели сообщений и т.д. При завершении - сохраняет.

Следующий вопрос: как организовать взаимодействие персонажа (любого) и карты.
Пока есть тока такой вариант: персонаж при попытке выполнить действие (например, перемещение) обращается к карте с соответствующим запросом. Карта обрабатывает запрос и возвращает результат. На основе этого персонаж либо делает что надо, либо возвращает отказ от действия.
Вариант: у персонажа есть метод IsCanMoveTo, который получает координаты клетки куда хочет пойти и возвращает результат, можно ли туда пройти данному персонажу. Если можно, то вызывается метод MoveTo (или MoveRel).
Первая заповедь фотолюбителя: Проявил себя - закрепи!

Dmiry
Сообщения: 168
Зарегистрирован: 14 июн 2007, 10:32

Сообщение Dmiry » 15 июн 2007, 10:42

10/04/07
17:07
Сейчас перемещение персонажа по карте происходит неправильно.
В частности, иногда идет на непроходимые клетки, иногда - не идет на проходимые.
Подозреваю, что это связано с некорректной работой функции проверки клетки на проходимость.
Поменял: некоторые числовые значения на константы (в частности, добавил проверку при определении глифа по его ИД при несуществовании искомого глифа возвращалось значение -1. Теперь GlyphNotFound). Также добавлена проверка на возвращаемое значение, и если оно равно GlyphNotFound - отрисовка не выполняется.
Добавлена возможность вести лог работы. Теперь в любой функции можно написать ToLog, и переданная строка запишется в лог-файл с временем.
Первая заповедь фотолюбителя: Проявил себя - закрепи!

Dmiry
Сообщения: 168
Зарегистрирован: 14 июн 2007, 10:32

Сообщение Dmiry » 15 июн 2007, 10:43

13/04/07
Пока некорректно работает покрутка карты. Думаю, как лучше это сделать.
Точнее, перемещение героя по карте происходит корректно до тех пор, пока не потребуется карту прокрутить. В этот момент программа вылетает с ошибкой Access Violation в функции GetCellType.
Надо проверять алгоритм определения необходимости прокрутки.
Похоже, нашел. Прокрутка выполняется классом TPersonage при приближении к краю карты на расстояние менее ScrollDistance. Там не делается проверка на допустимость прокрутки - например, если подошли к краю карты. Как вариант - прокручивать постоянно, чтобы персонаж всегда был в центре. Сейчас так и сделаю. Для этого придется реализовать каким-то образом безразмерную карту - чтобы вне зависимости от размеров карты персонаж всегда был в центре. Прямая аналогия - URW. Для этого придется довольно сильно переработать класс карты.
Из карты убрал параметры Left и Top - теперь это прерогатива паинтера. С другой стороны, получается, что в паинтере собрано довольно много весьма разнородных действий. Хотя по логике все они относятся только и исключительно к выводу на экран.
Первая заповедь фотолюбителя: Проявил себя - закрепи!

Dmiry
Сообщения: 168
Зарегистрирован: 14 июн 2007, 10:32

Сообщение Dmiry » 15 июн 2007, 10:44

17/04/07
Сейчас проверил - не работает проверка выхода за пределы карты. Надо включить такую проверку: если шаг приводит к выходу за пределы карты - шаг не делается. Вопрос: включить это в метод IsWalkableCell или воспользоваться методом CheckBounds? Сейчас сделаю в CheckBounds, чтобы потом можно было перейти к большой карте с прокруткой и переходом из области в область.
Все, проверка на выход за границы есть.
Следующие шаги:
1) добавляем прокрутку карты;
2) добавляем монстров;
3) добавляем инвентарь и оснащение героя;
4) добавляем предметы на карте, их подбор и бросание;
Прокрутка проиходит в тот момент, когда герой ближе ScrollDistance к границам карты на экране. Эта проверка выполняется в паинтере при отрисовке карты. Сделаю отдельный метод CheckScroll. То, что писал 13/04/07 - делать не буду (про постоянное центрирование героя). Сделаю вместо этого в герое открытое для чтения свойство CurrentMap. Собственно, оно уже есть. Все равно не нравится подход. Вариант: при перемещении герой (именно герой, никто больше) вызывает Painter.ValidateScroll(Map,Hero);
Первая заповедь фотолюбителя: Проявил себя - закрепи!

Аватара пользователя
Sanja
Администратор
Сообщения: 786
Зарегистрирован: 24 ноя 2006, 12:25
Откуда: Новосибирск
Контактная информация:

Сообщение Sanja » 15 июн 2007, 11:09

Отлично, прям себя вспоминаю. Те же ошибки :) Например это:
Точнее, перемещение героя по карте происходит корректно до тех пор, пока не потребуется карту прокрутить. В этот момент программа вылетает с ошибкой Access Violation в функции GetCellType.
Налицо ошибка при попытке получить данные о ячейке, лежащей вне пределов карты (массива). В общем, если эта проблема для тебя актуальна, могу выложить реализацию алгоритма правильной прокрутки. На том движке что у тебя есть сейчас (перемещение и вывод карты) его можно вполне легко протестировать.

Аватара пользователя
Maelstrom
Мастер
Сообщения: 2062
Зарегистрирован: 26 ноя 2006, 14:19
Откуда: г. Усть-Кирдык
Контактная информация:

Сообщение Maelstrom » 15 июн 2007, 11:17

То, что писал 13/04/07 - делать не буду (про постоянное центрирование героя).
А зря...
Сейчас проверил - не работает проверка выхода за пределы карты. Надо включить такую проверку: если шаг приводит к выходу за пределы карты - шаг не делается.
Легче просто обнести каждую карту стеной. Много нервов сэкономит.

P.S. А я вот себя не вспоминаю. У меня были огромные запарки с функциями прямой, круга и лося. А вот с передвижением и скроллом - нифига :)
Айв кнгенгах Йог-Сотот

Dmiry
Сообщения: 168
Зарегистрирован: 14 июн 2007, 10:32

Сообщение Dmiry » 15 июн 2007, 11:55

Это уже не актуально. Задачу решил. Просто это только часть дневника. Сейчас выложу остальное.
Первая заповедь фотолюбителя: Проявил себя - закрепи!

Dmiry
Сообщения: 168
Зарегистрирован: 14 июн 2007, 10:32

Сообщение Dmiry » 15 июн 2007, 11:56

26/04/07
Димыч советует сразу делать тесты для всех классов. В этом случае набор тестов автоматически определяет интерфейс класса, и его функциональность - то есть, что именно класс делает.
Пока я до таких высот не добрался.

04/05/07
Создал копию проекта, добавил туда компоненты для автоматизированного тестирования.
Сейчас первоочередная задача - сделать нормальную прокрутку карты. Затык в том, что вызов метода прокрутки реализуется при перемещении персонажа. Так как прокрутка выполняется только при перемещении героя, а не других персонажей, то сейчас проверка на прокрутку находится в методе SetPosition. Нюанс в том, что этот метод объявлен как виртуальный. И похоже, у меня вызывается метод базового класса вместо метода потомка.
Не понимаю этот геморрой с виртуальными методами. Сейчас в классе TPersonage объявляется property с методами Get/SetPosition. При этом SetPosition объявлен как виртуальный, и в классе-потомке THero он переопределяется. Но все равно при присваивании "Position := ..." вызывается базовый метод SetPosition вместо метода потомка, хотя объявлен как virtual. Варианты решения: 1) переопределить свойство Position в потомке; 2) отказаться от виртуальных методов; 3) отказаться от наследования TPersonage - THero (сделать их отдельными независимыми классами).
Первая заповедь фотолюбителя: Проявил себя - закрепи!

Dmiry
Сообщения: 168
Зарегистрирован: 14 июн 2007, 10:32

Сообщение Dmiry » 15 июн 2007, 11:56

08/05/07
Кажется, разобрался, почему не работает прокрутка. Точнее, сделал, только частично. Не полностью был реализован метод ValidateScroll. В частности, проверка условия на близость к границе была сделана только для левой и верхней границы. Вынес проверку расположения героя близко к границе в отдельный метод Painter.IsHeroNearBorder, где и делаю все проверки.
В данный момент прокрутка карты происходит, но герой после прокрутки оказывается в неправильном месте на экране. Соответственно карта становится неизвестной.
Начал делать предметы. Пока только название отдельного предмета с использованием категории предмета и его материала. Операцию изменения материала буду делать аналогично тому как это сделано в IVAN. То есть свитками или другой магией. Обозвать "трансмутацией" :-).
По поводу хранения предметов: все предметы буду хранить в списке, на каждой ячейке карты - указатель на первый элемент в списке. Каждый элемент списка содержит указатель на следующий и предыдущий элементы.
Первая заповедь фотолюбителя: Проявил себя - закрепи!

Dmiry
Сообщения: 168
Зарегистрирован: 14 июн 2007, 10:32

Сообщение Dmiry » 15 июн 2007, 11:57

22/05/07
Прокрутка карты по-прежнему работает неправильно.
Сделал генератор подземелья (на Паскале). Интегрирую в игру. Не интегрируется. Выдает Access Violation. Исправил. Сейчас подземелье вроде отрисовывается, но герой оказывается в толще камня. Алгоритм требует серьезной доработки. Чего хочу добиться в первую очередь - нормальной отрисовки карты подземелья. Следующий шаг - прокрутка.
Подземелье рисуется правильно. Надо включить список комнат в свойства класса Map. Тогда размещение героя в подземелье будет без проблем.
Следующий шаг - загрузка и сохранение карты(?).
Продолжаю размышлять на тему "надо ли разделять классы персонажа и героя".
Первая заповедь фотолюбителя: Проявил себя - закрепи!

Dmiry
Сообщения: 168
Зарегистрирован: 14 июн 2007, 10:32

Сообщение Dmiry » 15 июн 2007, 11:57

29/05/07
Есть мысль разделить класс карты-вилдернесса и карты-подземелья. Тогда можно без проблем разделить нагрузку по генерации карты - вынести в разные конструкторы. С другой стороны это может затруднить обработку разных ситуаций. Сначала сделаю нормальную прокрутку в вилдернессе, потом уже остальное.
Все, прокрутка карты сделана корректно. Затык был в неправильной отрисовке персонажа в паинтере. При рисовании использовались абсолютные координаты героя на карте вместо относительно верхнего левого угла карты.
Следующий шаг - делаю предметы.
Первая заповедь фотолюбителя: Проявил себя - закрепи!

Dmiry
Сообщения: 168
Зарегистрирован: 14 июн 2007, 10:32

Сообщение Dmiry » 15 июн 2007, 11:58

04/06/07
Начинаю делать описание предмета. Сразу делаю чтение всех предметов из файла. Тогда достаточно сделать описание предмета в файле и парсер для чтения из этого файла. Первый вариант формата файла выглядит следующим образом:
ITEM ItemName
<attribute>=<value>
END
Комментарии - через символ #, так как точка с запятой может использоваться в описании параметров. Все символы после # и до конца строки считаются комментарием.
Сейчас озадачился. У меня фактически нет четкого плана - что же именно я хочу получить в итоге? Или это будет аналог URW, или что-то футуристическое на тему колонизации далекой планеты. Основная идея - возможность изготовить любой предмет, какой только потребуется. Естественно, для изготовления этого предмета понадобится сырье и инструменты, плюс еще возможно чертежи. Все инструменты также изготавливаются по соответствующим чертежам и из соответствующих материалов. Сейчас еще идея - любой предмет подвержен износу. При каждом использовании предмета его износ увеличивается. Высокий износ инструмента или предмета приводит к увеличению шанса неправильно выполнить действие, для которого предназначен предмет. Если это инструмент - изготавливаемая деталь оказывается испорченной. Если просто предмет - шанс не выполнить или выполнить неправильно действие. Еще есть шанс, что предмет разрушится полностью.
Первая заповедь фотолюбителя: Проявил себя - закрепи!

Dmiry
Сообщения: 168
Зарегистрирован: 14 июн 2007, 10:32

Сообщение Dmiry » 15 июн 2007, 11:58

06/06/07
Начал писать парсер для считывания предметов из файла. Наткнулся на следующимй затык: прежде чем писать парсер, надо хоть немного определиться со структурой предмета и закодировать ее. В общих чертах парсер уже нарисовался. Осталось определиться с предметом.
Точно буду делать различные материалы.
Первая заповедь фотолюбителя: Проявил себя - закрепи!

Dmiry
Сообщения: 168
Зарегистрирован: 14 июн 2007, 10:32

Сообщение Dmiry » 15 июн 2007, 11:59

12/06/07
Попробую сейчас написать несколько примеров изготовления предметов. Если сразу планируется подобная цель, то будет использоваться такая технология: для каждого предмета нужно как минимум 1 материал и как минимум 1 инструмент. Исключение составляют начальные предметы, которые могут быть сделаны без инструментов. Или как вариант - в качестве инструментов могут выступать материалы. То есть любой предмет может быть как инструментом, так и материалом.
Примеры изготовления некоторых предметов:
Меч - чугун(М)+молот(И)+наковальня(И)+уголь(М)+печь(И)
Наковальня - чугун(М)+уголь(М)+глина(М)+печь(И)
Чугун - уголь(М)+руда(М)+печь(И)+глина(М)
Если делать таким способом, то придется различать инструменты, которые можно поднять и которые нельзя поднять. Для этого можно просто делать проверку веса или ввести флаг "MOVABLE". То есть включить в качестве одного из условий использование стационарных устройств - назовем их станками. Тогда любой предмет можно сделать с использованием соответствующих материалов, инструментов и станков.
Тогда сразу вопрос в терминах игромеханики - требование находиться рядом со станком для изготовления какого-либо предмета. При этом можно допустить, что инструменты и материалы могут находиться не только в инвентаре, но и рядом, на соседних клетках. Станок первоначально можно описывать как клетку карты. До сих пор колеблюсь - надо ли все изменения на карте делать как реальные изменения клетки карты или как просто изменение находящихся на клетке предметов. Пока склоняюсь к изменению клетки карты. Для изготовления предмета можно также включить требование находиться вместе с предметами и материалами в некоторой области - аналогично тому, как сделано в URW - при постройке дома бревна должны быть на территории, отведенной для дома.
Только что посмотрел - получается, что для изготовления любого металлического предмета по приведенной выше технологии надо обязательно иметь некий минимум инструментов или станков. С другой стороны, можно сделать так, чтобы самые простые станки и инструменты можно было сделать почти без ничего. Например, печь можно сложить из кирпича, который обжигается опять же в печи, а можно из природного камня, который можно найти просто так.
Описание производственных цепочек делаю сейчас в файле PROD.TXT. Хотя была мысль поместить это вместе с описанием предметов. Пока не буду заморачиваться чертежами.
Первая заповедь фотолюбителя: Проявил себя - закрепи!

Dmiry
Сообщения: 168
Зарегистрирован: 14 июн 2007, 10:32

Сообщение Dmiry » 15 июн 2007, 11:59

13/06/07
Решил убрать из описания предмета поле "Категория". Пока непонятно, как его задавать, как обрабатывать ситуацию, когда один предмет может выступать в разных категориях. Например, нож может быть как оружием, так и инструментом. Камень - оружие и исходный материал.

Сделаю в предметах все флагами. Например, тип повреждения при использовании предмета в качестве оружия. Сейчас первоочередная задача - добиться, чтобы все описания предметов загружались в память. Причем задача разделяется на две: загрузить в память описание всех предметов, и выбирать из этого списка необходимые предметы.

Другая задача - вообще реализовать загрузку и сохранение игры. Сначала сохранение, затем загрузка. Карту сохранять буду в текстовый файл, каждый символ соответствут тайлу карты. Похоже на механизм URW. Написал сохранение карты и базовых параметров героя в текстовый файл. Карта сохраняется в виде прямоугольного массива. Параметры героя - аналогично INI-файлам. Следующий вопрос - как лучше считывать эти разделы. Точнее, как определить, что в одном разделе находится карта, а в другом - информация о герое.

Пока можно оставить фиксированно. Кончился один раздел - начался следующий. Тогда усложняется загрузка. Как вариант - сначала при сохранении получаем список строк от соответствующего класса, затем в файл пишем заголовок, размер раздела и содержимое списка строк. При загрузке - считываем заголовок раздела, определяем его наименование и размер. Считываем в список строк число строк по размеру раздела и этот список подаем соответствующему классу на загрузку. При таком подходе загрузчик не интересует внутренняя структура каждого раздела, и ее можно изменять независимо от структуры других разделов.
Первая заповедь фотолюбителя: Проявил себя - закрепи!

Ответить

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость