UniCurses на Python 3 под windows
Модераторы: Sanja, Максим Кич
- Cfyz
- Сообщения: 776
- Зарегистрирован: 30 ноя 2006, 10:03
- Откуда: Санкт-Петербург
- Контактная информация:
Re: UniCurses на Python 3 под windows
Насколько я понял, это каноничный вариант замены do-while: Emulate a do-while loop in Python?
Даже если break не хочется, read() дважды это все равно не то. Что-либо дублировать в коде вообще нежелательно, а тем более ввод, который должен обрабатываться. В данном случае получается возможность пропустить нажатие кнопки, ведь первый read() фактически игнорируется. Если он не был TK_ESCAPE, то сразу же следует новый read() и значение первого потеряно. Это может быть критично если аналогичные циклы будут использоваться вложенно в обработке диалогов. На это есть очень простое решение: если нам первое значение key не важно, лишь бы в цикл зайти, то пусть оно просто будет 0 и все, а не read().
Даже если break не хочется, read() дважды это все равно не то. Что-либо дублировать в коде вообще нежелательно, а тем более ввод, который должен обрабатываться. В данном случае получается возможность пропустить нажатие кнопки, ведь первый read() фактически игнорируется. Если он не был TK_ESCAPE, то сразу же следует новый read() и значение первого потеряно. Это может быть критично если аналогичные циклы будут использоваться вложенно в обработке диалогов. На это есть очень простое решение: если нам первое значение key не важно, лишь бы в цикл зайти, то пусть оно просто будет 0 и все, а не read().
Пытается раскуклиться
Re: UniCurses на Python 3 под windows
Согласен, про игнор первого ввода не подумал. Век живи - век учись! С нулем идея по душе пришлась - оставил такой вариант:
Код: Выделить всё
from bearlibterminal import terminal
def main_loop():
key = 0
while key != terminal.TK_ESCAPE:
key = terminal.read()
Re: UniCurses на Python 3 под windows
И еще вопрос: у меня есть карта - массив 20 на 80 и объекты: стены, двери, ловушки, предметы, мобы.
Если с объектами, которые не меняют местоположение: стены, пол, двери и ловшки все норм - я их буду хранить, как элементы массива, то с мобами не могу определиться.
Первый вариант: храню мобов в массиве - очень удобно для передвижения. Например, я хочу пойти на одну клетку влево - проверяю Map[x-1][y].mob - если истина, то там моб и вместо движения атака, если ложь, то моба нет и проверяю проходимость. Но вот для определения очередности хода мне нужно просмотреть всех мобов на карте и найти из них того, у кого самый высокий показатель энергии, т.е. каждый ход каждого существа придется делать поиск по 80*20=1600 ячейкам массива, что не айс.
Второй вариант: я буду хранить мобов отдельным массивом, определение очередности хода пойдет на ура, но при проверке занятости клетки нужно будет проверять не только клетку (вдруг стена), но и весь список мобов, которых может быть много.
Третий вариант - хранить и там и там, а при изменении положения синхронизировать, но тут уже дублирование переменных идет по всем мобам...
Посоветуйте, какому варианту отдать предпочтение? Мне хотя бы общее направление, куда копать, там уже найду
Если с объектами, которые не меняют местоположение: стены, пол, двери и ловшки все норм - я их буду хранить, как элементы массива, то с мобами не могу определиться.
Первый вариант: храню мобов в массиве - очень удобно для передвижения. Например, я хочу пойти на одну клетку влево - проверяю Map[x-1][y].mob - если истина, то там моб и вместо движения атака, если ложь, то моба нет и проверяю проходимость. Но вот для определения очередности хода мне нужно просмотреть всех мобов на карте и найти из них того, у кого самый высокий показатель энергии, т.е. каждый ход каждого существа придется делать поиск по 80*20=1600 ячейкам массива, что не айс.
Второй вариант: я буду хранить мобов отдельным массивом, определение очередности хода пойдет на ура, но при проверке занятости клетки нужно будет проверять не только клетку (вдруг стена), но и весь список мобов, которых может быть много.
Третий вариант - хранить и там и там, а при изменении положения синхронизировать, но тут уже дублирование переменных идет по всем мобам...
Посоветуйте, какому варианту отдать предпочтение? Мне хотя бы общее направление, куда копать, там уже найду
- Jesus05
- Сообщения: 1840
- Зарегистрирован: 02 дек 2009, 07:50
- Откуда: Норильск, сейчас Санкт-петербург.
- Контактная информация:
Re: UniCurses на Python 3 под windows
К примеру можно хранить ссылку\указатель\порядковый номер в карте, а список мобов в отдельном массиве. Конечно это потянет за собой другие проблемы идеального решения наверное и нет.
Или у моба хранить координату где он стоит. или и то и другое (и координату, и на карте ссылку).
Или у моба хранить координату где он стоит. или и то и другое (и координату, и на карте ссылку).
- Максим Кич
- Администратор
- Сообщения: 1642
- Зарегистрирован: 03 дек 2006, 20:17
- Откуда: Витебск, Беларусь
- Контактная информация:
Re: UniCurses на Python 3 под windows
Третий вариант. Я не в курсе за питон, но вообще в переменных обычно содержатся указатели на объект, так что если ты его один раз создал и двум переменным (свойствам, элементам массива) присвоил, то в обоих местах будет ссылка на один и тот же объект в памяти.vapekreng писал(а): Если с объектами, которые не меняют местоположение: стены, пол, двери и ловшки все норм - я их буду хранить, как элементы массива, то с мобами не могу определиться.
<добрый_инквизитор>
Я же, надеюсь, у тебя игровые объекты в виде классов описаны, мой юный друг
</добрый_инквизитор>
Dump the screen? [y/n]
- Cfyz
- Сообщения: 776
- Зарегистрирован: 30 ноя 2006, 10:03
- Откуда: Санкт-Петербург
- Контактная информация:
Re: UniCurses на Python 3 под windows
Определенно третий вариант. Как заметил Максим, дублирования данных не будет -- и в поле mob ячейки, и в массиве мобов ссылки на один и тот же объект (в Python все переменные это ссылки на объект). Но важно избежать дублирования действий по работе с мобом. Нельзя оперировать этими данными на месте в каждом отдельном случае, периодически расставляя в коде конструкции типаДля того, чтобы данные надежно были в согласованном состоянии, нужно просто выделить специально ответственного за это. Например, набор функций или методов add_mob/delete_mob/move_mob/find_next_mob и т. д. и работать только через них. Будет заметно сложнее сломать данные что-то забыв или опечатавшись.
Код: Выделить всё
if some_mob.hp <= 0:
Map[x][y].mob = None
Mobs.remove(some_mob)
Пытается раскуклиться
- Максим Кич
- Администратор
- Сообщения: 1642
- Зарегистрирован: 03 дек 2006, 20:17
- Откуда: Витебск, Беларусь
- Контактная информация:
Re: UniCurses на Python 3 под windows
Строго говоря, это должен быть отдельный класс, который и будет содержать в себе и обслуживать очерёдность ходов, причём, игрок и монстр для него должны быть сущностями одной природы. Ну и, попутно, он же будет размещать персонажей на карте. С картой мобы уже будут взаимодействовать непосредственно — я уже описывал пару раз эту схему.Cfyz писал(а):Например, набор функций или методов add_mob/delete_mob/move_mob/find_next_mob и т. д. и работать только через них. Будет заметно сложнее сломать данные что-то забыв или опечатавшись.
Dump the screen? [y/n]
Re: UniCurses на Python 3 под windows
Послушаю опытных людей и буду бить по третьему варианту. И да, игровые объекты у меня в классах - из-за них в том числе с паскаля и ушел.
Я правильно понимаю, что этот обслуживающий класс, в основном, будет работать с данными других классов (класс мобов, предметов, карты) и осуществлять их взаимодействие?
Классы только месяц назад осваивать начал, так что извините за кучу вопросов. Игрок и моб у меня аналогичные объекты, просто героем можно управлять, а мобами нетCfyz писал(а):Строго говоря, это должен быть отдельный класс, который и будет содержать в себе и обслуживать очерёдность ходов, причём, игрок и монстр для него должны быть сущностями одной природы.
Я правильно понимаю, что этот обслуживающий класс, в основном, будет работать с данными других классов (класс мобов, предметов, карты) и осуществлять их взаимодействие?
- Максим Кич
- Администратор
- Сообщения: 1642
- Зарегистрирован: 03 дек 2006, 20:17
- Откуда: Витебск, Беларусь
- Контактная информация:
Re: UniCurses на Python 3 под windows
Ну, если с Object/Free Pascal, то, вообще говоря, там классы очень хорошо реализованы. Если с Turbo Pascal, то дай попользоваться криогенной капсулой, я тоже хочу залечь лет на 20 )vapekreng писал(а):Послушаю опытных людей и буду бить по третьему варианту. И да, игровые объекты у меня в классах - из-за них в том числе с паскаля и ушел.
Смотря, что вкладывать в слово «взаимодействие». Взаимодействовать классы должны друг с другом, по возможности без посредников. Скажем, вопрос мордобития решают два экземпляра Монстров без постороннего участия. Точно так же вопрос занятия/оставления клетки карты должны решать Монстр и Клетка Карты (клетка — отдельный от карты объект со своими свойствами событиями. Это окупится, честное слово!)vapekreng писал(а):Я правильно понимаю, что этот обслуживающий класс, в основном, будет работать с данными других классов (класс мобов, предметов, карты) и осуществлять их взаимодействие?
В отдельный класс надо собрать вещи, которые экземпляры Монстров не могут делать сами: создавать экземпляр нужного класса по имени/описанию, вызывать событие "ход" в нужной очерёдности, и удалять ссылки из очереди хода. Можно генератор и handler очерёдности хода разнести по двум разным объектам, потому что генератор разрастётся.
В принципе, если все Монстры ходят строго по очереди, можно обойтись списочной структурой. Т.е. карта хранит первого Монстра в списке, а каждый Монстр хранит указатель на того, кто ходит после него — тогда все необходимые операции можно будет делать в конструкторах/деструкторах Монстров. Соответственно Монстр ходит сам и вызывает следующего в списке. Можно даже зациклить список, тогда будет вообще красиво.
Но у такого решения есть два больших минуса:
во-первых, требует некоторой академической подготовки и понимания операций на списках, а во-вторых (что важнее!) в дальнейшем может оказаться тяжело внедрить более сложную систему очерёдности хода (с учётом скорости или инициативы, например).
Dump the screen? [y/n]
Re: UniCurses на Python 3 под windows
Именно с него, капсулу не отдам - самому нужна)))vapekreng писал(а):Если с Turbo Pascal, то дай попользоваться криогенной капсулой, я тоже хочу залечь лет на 20 )
Большое спасибо за развернутый ответ!
Соответственно в классе моб делаю метод attack() и die(). Метод атаки (как и любой другой, который может снизить хп) включает в себя проверку на смерть и в её случае вызывает метод смерти, который чистит очередь хода и клетку карты от моба.vapekreng писал(а):Скажем, вопрос мордобития решают два экземпляра Монстров без постороннего участия.
У меня карта-массив, его элементы-тайтлы (клетки), которые, на данный момент, имеют три атрибута: моб, список предметов и рельефvapekreng писал(а):клетка — отдельный от карты объект со своими свойствами событиями. Это окупится, честное слово!
Систему ходов взял из ADOM - у каждого монстра есть скорость - количество энергии, восстанавливаемое за единицу времени.vapekreng писал(а):Но у такого решения есть два больших минуса:
во-первых, требует некоторой академической подготовки и понимания операций на списках, а во-вторых (что важнее!) в дальнейшем может оказаться тяжело внедрить более сложную систему очерёдности хода (с учётом скорости или инициативы, например).
1. Если есть мобы с энергией выше нуля, то ходит моб с максимальной энергией, его энергия снижается на цену действия.
2. Если у всех мобов энергия ниже 0, то пропуск хода с восстановлением энергии в количестве равном скорости каждому мобу. Переходим к 1
Реализовать думаю следующим образом: просьба поправить, если что не так:
1. При создании моб кидается на клетку карты и в список мобов. Дублирования как мне выше подсказали не будет, в чем убедился и сам тоже:
Скрытый текст: ПОКАЗАТЬ
3. Отрисовка зоны видимости героя перед началом его хода и по завершению хода.
Как считаете, жизнеспособный вариант?
- Cfyz
- Сообщения: 776
- Зарегистрирован: 30 ноя 2006, 10:03
- Откуда: Санкт-Петербург
- Контактная информация:
Re: UniCurses на Python 3 под windows
Edit: кажется, пока я набирал ответ, исходное сообщение потерли =)
Чтобы получить свежую версию библиотеки, надо обновить пакет:
По поводу кода: глаз зацепился за двойное сравнение с TK_ESCAPE в основном цикле (у меня вообще пунктик по поводу повторяющегося кода). Сравнение перед вызовом move_mob() излишне. Escape в этом случае ничем не отличается от любой другой клавиши и будет "проигнорирован" так же как, скажем, TK_A. Советую как минимум сразу выходить из move_mob() если переданный аргумент key не равен ни одному из допустимых значений (if .. elif .. else return). Еще тип аргумента key в move_mob() совсем не str, python сам по себе не проверяет эти подсказки.
Кстати, простой цикл с выходом только по нажатию клавиши и где ввод читается только один раз за итерацию, можно записать еще чуть-чуть компактнее, без переменной снаружи:Суть в том, что прочитанное состояние клавиш доступно до следующего вызова read(), т. е. check(key) фактически означает "была ли нажата клавиша key на момент предыдущего read()".
Но как только придется выходить еще и по закрытию окна или читать события во вложенном цикле, работать не будет ни этот вариант, ни текущий =/.
Так было задумано ранее, должны же читаться события отпускания кнопок, чтобы их можно было отбработать если нужно. В теории, не какая ли разница что игнорировать -- лишнее нажатие какой-нибудь запятой или отпускание клавиши? На деле это оказалось не так удобно. Как минимум получилось, что read() не работает как "нажмите любую клавишу" без дополнительной настройки. Поэтому я в итоге поменял поведение на такое, что по умолчанию считываются только нажатия клавиш, а если надо что-то сверх того (отпускания, мышь), то это легко задействовуется отдельно (cм. какую-никакую, а справку по этому фильтру).vaperkreng писал(а):Немного странно ведет себя команда terminal.read(): она считывает каждое нажатие кнопки дважды - один раз когда нажмешь кнопку и еще раз когда отпустишь. Это так и задумано или я что-то не так делаю?
Чтобы получить свежую версию библиотеки, надо обновить пакет:
Код: Выделить всё
pip3 install -U bearlibterminal
Кстати, простой цикл с выходом только по нажатию клавиши и где ввод читается только один раз за итерацию, можно записать еще чуть-чуть компактнее, без переменной снаружи:
Код: Выделить всё
while not terminal.check(terminal.TK_ESCAPE):
key = terminal.read()
...
Но как только придется выходить еще и по закрытию окна или читать события во вложенном цикле, работать не будет ни этот вариант, ни текущий =/.
Пытается раскуклиться
Re: UniCurses на Python 3 под windows
Дело было вечером, делать было нечего. Свой ответ потер потому, что к моменту его написания в глаза бросилось двойное использование read() в цикле - отсюда пошли проблемы. Так как косяк был мой - не видел причины напрягать людей)))
Либу обновил, справку в закладки добавил. Что тип не str увидел, там же шестнадцатеричное число, верно? Сделал проверку и цикл на нажатие клавиши из списка тех, которые уже назначил хоть на что-то, пока этот список тупо в программе прописал, потом в файл перекину. Чуть позже выложу, что получилось)
Ну и метод карты move_mob()
В данный момент пишу класс параметров персонажа (сила, ловкость и т.д.), на очереди зона видимости, потом нормальный обработчик нажатий клавиши
Либу обновил, справку в закладки добавил. Что тип не str увидел, там же шестнадцатеричное число, верно? Сделал проверку и цикл на нажатие клавиши из списка тех, которые уже назначил хоть на что-то, пока этот список тупо в программе прописал, потом в файл перекину. Чуть позже выложу, что получилось)
Скрытый текст: ПОКАЗАТЬ
Скрытый текст: ПОКАЗАТЬ
Re: UniCurses на Python 3 под windows
И еще вопрос: при зажатии кнопки, например, вправо, моб движется еще некоторое время после того, как её отпустишь. Я так понимаю, очередь ввода накапливается и, так как у меня сейчас на каждый ход отрисовывается вся карта, карта не успевает прорисовываться, верно? Есть ли возможность читать последнее событие в очереди ввода?
Re: UniCurses на Python 3 под windows
Чуть-чуть поменял главный модуль, а то время после первого хода не увеличивалось
Скрытый текст: ПОКАЗАТЬ
Re: UniCurses на Python 3 под windows
Вопрос снят - сделал вывод только видимой области, а не всей карты - полет нормальныйvapekreng писал(а):И еще вопрос: при зажатии кнопки, например, вправо, моб движется еще некоторое время после того, как её отпустишь. Я так понимаю, очередь ввода накапливается и, так как у меня сейчас на каждый ход отрисовывается вся карта, карта не успевает прорисовываться, верно? Есть ли возможность читать последнее событие в очереди ввода?
Кто сейчас на конференции
Сейчас этот форум просматривают: нет зарегистрированных пользователей и 30 гостей