PDA

Просмотр полной версии : Python - интерфейсы



volod
27.01.2010, 14:37
Доброго всем.
Потратил сегодня три часа на разбор кода, правку и тестирование. И решил поделиться накопанным. Начинающим разработчикам возможно облегчит жизнь.

Чего мы делаем (Цель задачи) - сделать возможность отображать в игре и нормально работать с большим количеством институтов, чем предусмотрено оригинальной игрой.
Задача, возможно, весьма специфическая, но на её примере можно рассмотреть общий принцип редактирования интерфейсов на питоне.

Для справки: Есть более простое решение, использованное в Fall from Heaven (изменены размеры и шрифты панелей, за счёт чего освобождено дополнительное место для новых категорий институтов).

В моём случае мне нужно было впихнуть в экран 10 категорий институтов, чего никак не получалось добиться простым изменением размеров (только при 6-ом шрифте и совсем узеньких панелях, но тогда экран становится совсем нечитабельным). Я решил разделить категории на несколько экранов и сделать возможность перехода между ними.

Итак, поехали.

Копируем файлик CvCivicsScreen.py из каталога Assets/Python/Screens оригинальной игры в такой же каталог внутри своего мода. Файлы этого каталога задают прорисовку различных игровых экранов. Конкретно в этом файле реализуется экран смены институтов власти.

Открываем файлик (можно какой-нибудь спецефической средой разработки, я пользовался обычным блокнотом) и находим там строчки с описанием класса:
class CvCivicsScreen:
....

Здесь задаются всевозможные параметры будущего окна и внутренние переменные, необходимые для его прорисовки. Пока просто поправим размеры панелей так, что бы они соответствовали нашим запросам (мне пришлось несколько раз загрузить игру, чтобы подобрать нужные значения).
Например, я планировал изображать одновременно пять категорий. И выставил следующие значения:
self.HEADINGS_WIDTH = 190 (ширина панели одного института)
self.HEADINGS_SPACING = 7 (расстояние между панелями)
self.TEXT_MARGIN = 12 (размер шрифта)
Остальные параметры я оставил без изменения.

Далее добавим два определителя (будущие кнопки для перехода)
self.NEXT_NAME = "CivicsNext"
self.PREV_NAME = "CivicsPrev"

и их координаты:
self.X_NEXT = 300
self.Y_NEXT = 726
self.X_PREV = 150
self.Y_PREV = 726

Так же нам понадобятся две внутренние переменные (для чего, покажу далее):
self.SCREEN_NUMBER = 0 (номер экрана, отображаемого в данный момент)
self.CHANGE_SCREEN_NUMBER = 0 (флаг, отмечающий, что было переключение экрана)

И свяжем наши кнопки с функциями, которые напишем позже (добавим два определителя в блок):
self.CivicsScreenInputMap = {
self.BUTTON_NAME : self.CivicsButton,
self.TEXT_NAME : self.CivicsButton,
self.EXIT_NAME : self.Revolution,
self.NEXT_NAME : self.Next,
self.PREV_NAME : self.Previous,
self.CANCEL_NAME : self.Cancel,
}

С определителями всё, переходим непосредственно к коду.
Сначала сделаем так, чтобы на экране рисовалось только нужное нам количество категорий.
Находим функцию
def drawAllButtons(self):

В её начало пихаем строчки:
cnt = 5*(self.SCREEN_NUMBER+1)
if (cnt > gc.getNumCivicOptionInfos()): cnt = gc.getNumCivicOptionInfos()

Эти строки создают переменную cnt, в которой лежит индекс категории институтов, которым мы закончим прорисовку.

Меняем строку:
for i in range(gc.getNumCivicOptionInfos()):
на
for i in range(5*self.SCREEN_NUMBER,cnt):

То есть, мы запустили цикл по ограниченному установленными нами индексами количеству категорий.

Теперь изменим координаты прорисовки панели с очередной категорией. Фактически нам нужно менять только X-координату.
Вместо
fX = self.HEADINGS_SPACING + (self.HEADINGS_WIDTH + self.HEADINGS_SPACING) * i
пишем
fX = self.HEADINGS_SPACING + (self.HEADINGS_WIDTH + self.HEADINGS_SPACING) * (i - 5 * self.SCREEN_NUMBER)

Вот и всё, теперь панели с категориями будут прорисовываться аккурат по пять штук в ряд в зависимости от номера экрана.

Теперь добавим тоже самое в прорисовку панелей с описаниями текущего института. Делаем те же операции в функции
def drawAllHelpText(self):

Но здесь нужно изменить ещё кое-что. Поскольку панели описания и текст в них рисуются отдельно, нужно в функции
def drawHelpText(self, iCivicOption):
так же изменить строку
fX = self.HEADINGS_SPACING + (self.HEADINGS_WIDTH + self.HEADINGS_SPACING) * iCivicOption
на
fX = self.HEADINGS_SPACING + (self.HEADINGS_WIDTH + self.HEADINGS_SPACING) * (iCivicOption - 5 * self.SCREEN_NUMBER)

С коррекцией прорисовки закончили, теперь перейдём к переключению экранов.
В основной функции
def interfaceScreen (self):
в самом начале функции заменяем блок
if screen.isActive(): return
на
if (screen.isActive() and (self.CHANGE_SCREEN_NUMBER == 0)): return

то есть, выходим из функции при условии, что экран не только уже был открыт, но и не было перехода между экранами. Ведь именно вызовом этой функции мы дальше будем перерисовывать экран при переходе.

добавляем монтирование кнопок перехода на панель (вставляем перед или за блоком, монтирующим кнопку отмены)
if(self.SCREEN_NUMBER * 5 < gc.getNumCivicOptionInfos() - 5):
screen.setText(self.NEXT_NAME, "Background", u"<font=4>" + localText.getText("TXT_KEY_SCREEN_NEXT", ( )).upper() + u"</font>", CvUtil.FONT_RIGHT_JUSTIFY, self.X_NEXT, self.Y_NEXT, self.Z_TEXT, FontTypes.TITLE_FONT, WidgetTypes.WIDGET_GENERAL, 1, 0)

if(self.SCREEN_NUMBER > 0):
screen.setText(self.PREV_NAME, "Background", u"<font=4>" + localText.getText("TXT_KEY_SCREEN_PREV", ()).upper() + u"</font>", CvUtil.FONT_CENTER_JUSTIFY, self.X_PREV, self.Y_PREV, self.Z_TEXT, FontTypes.TITLE_FONT, WidgetTypes.WIDGET_GENERAL, 1, 0)

То есть, рисуем кнопки в заданные им координаты и проверяем условия: для продвижения экрана, что экран не последний, для возврата, что экран не первый.
Не забываем дать описатели ключам TXT_KEY_SCREEN_NEXT (Далее) и TXT_KEY_SCREEN_PREV (Назад) в текстовых xml-ках мода, для внятного отображения названия кнопок.

Строчку
self.setActivePlayer(gc.getGame().getActivePlayer())
теперь нужно выполнять только при условии
if (self.CHANGE_SCREEN_NUMBER == 0):
self.setActivePlayer(gc.getGame().getActivePlayer())

То есть вызывать эту функцию мы будем только, если экран открыт первый раз. В этой функции производится начальная инициализация выбора игрока. И поскольку мы хотим, что бы при переключении экранов у нас сохранялся выбор на предыдущем и можно было одновременно сменить несколько институтов, то нам не нужно вызывать эту функцию.

И, наконец, сбрасываем флаг переключения экранов:
self.CHANGE_SCREEN_NUMBER = 0

Собственно, здесь всё.
Теперь опишем функции переключения экранов (Вперёд/Назад)

def Next(self, inputClass):
screen = self.getScreen()
self.SCREEN_NUMBER = self.SCREEN_NUMBER + 1
self.CHANGE_SCREEN_NUMBER = 1
self.interfaceScreen()
return 0

def Previous(self, inputClass):
screen = self.getScreen()
self.SCREEN_NUMBER = self.SCREEN_NUMBER - 1
self.CHANGE_SCREEN_NUMBER = 1
self.interfaceScreen()
return 0

Первая увеличивает, вторая уменьшает номер экрана. После чего выставляется флаг переключения и вызывается перерисовка экрана.

Всё, сохраняем наш файлик, запускаем, проверяем :)
Теперь можно описать любое количество категорий институтов власти в XML и свободно использовать их в игре.

Аналогично можно переделать под свои нужды и любой экран или другой элемент интерфейса.

С уважением, Волод.

NeverMind
27.01.2010, 16:34
Волод, отличное описание! Спасибо. :yes:

Как раз не хватает людей, которые могут объяснить разные моменты моддинга Python-SDK для начинающих и продолжающих. Если будет возможность и желание, пиши еще.

Павел I
27.01.2010, 16:45
Спасибо за статью.
Интересно будет почитать.

Ура! NeverMind вернулся!

shkuder
27.01.2010, 17:49
Интересная тема :applau2: .

ПС <div class='quotetop'>Цитата</div>
NeverMind[/b]
:nerves: Мне страшно очень. :nerves:

Павел I
27.01.2010, 19:57
С чего это?
Невер добрый!

shkuder
27.01.2010, 19:59
Знаю я... И как банит больно знаю. :nerves:

kabjans
28.01.2010, 10:54
Большое спасибо за статью. Очень познавательно и полезно.

А на каком моде лучше посмотреть как новый интерфейс работает?

volod
28.01.2010, 16:44
<div class='quotetop'>Цитата(kabjans * 28.1.2010, 9:52) 323418</div>

А на каком моде лучше посмотреть как новый интерфейс работает?
[/b]

Можно подложить в Fall from Heaven. Я брал их файлик и менял его. Там ещё парочка изменений в шрифтах была. У них там 7 или 8 институтов, как раз подойдёт.

С уважением, Волод.

Хальк Юсдаль
28.01.2010, 16:58
Спасибо за статью. Очень полезная тема. С питоном то как раз наибольшие проблемы и возникают.

kabjans
28.01.2010, 17:34
<div class='quotetop'>Цитата(Волод * 28.1.2010, 16:42) 323429</div>

<div class='quotetop'>Цитата(kabjans * 28.1.2010, 9:52) 323418

А на каком моде лучше посмотреть как новый интерфейс работает?
[/b]

Можно подложить в Fall from Heaven. Я брал их файлик и менял его. Там ещё парочка изменений в шрифтах была. У них там 7 или 8 институтов, как раз подойдёт.

С уважением, Волод.
[/b][/quote]
Вообще-то я не любитель "чертовщинки", но уж больно интересно посмотреть сделанные изменения. Качаю FallfromHeaven2041d.exe....

Triver
28.01.2010, 18:10
Эта темка мне пригодится возможно. :applau2:

kabjans
28.01.2010, 20:44
<div class='quotetop'>Цитата(Волод * 28.1.2010, 16:42) 323429</div>

<div class='quotetop'>Цитата(kabjans * 28.1.2010, 9:52) 323418

А на каком моде лучше посмотреть как новый интерфейс работает?
[/b]

Можно подложить в Fall from Heaven. Я брал их файлик и менял его. Там ещё парочка изменений в шрифтах была. У них там 7 или 8 институтов, как раз подойдёт.

С уважением, Волод.
[/b][/quote]
Привет, Волод!

Скачал и установил Fall from Heaven.
Смотрю как выглядит CvCivics экран с оригинальном CvCivicsScreen.py.
Затем меняю оригинальный CvCivicsScreen.py из мода на модифицированный тобой.
Запускаю Fall from Heaven с новым CvCivicsScreen.py.
То же самое и даже не в профиль... :shock:

Не мог бы сделать и выложить в первом сообщении этой темы снимки того как у тебя выглядит CvCivics экран с
1. оригинальном CvCivicsScreen.py,
2. с измененным CvCivicsScreen.py (оба "CivicsPrev" и "CivicsNext").

Мод при этом может быть любым. Интерес представляет только CvCivics экран.

Заранее большое спасибо.

volod
28.01.2010, 21:01
<div class='quotetop'>Цитата</div>
Запускаю Fall from Heaven с новым CvCivicsScreen.py.
То же самое и даже не в профиль... :shock: [/b]

Там кнопочки "Next" и "Prev" переключают экраны :)

1.jpg
[attachmentid=6164]
и 2.jpg
[attachmentid=6165]
- снимки экранов FfH с моим CvCivicsScreen.py,
а в 3.jpg - оригинальный.
[attachmentid=6166]

Естественно в моём моде названия кнопкам внятные даны, а тут я не стал xml-ки править.

С уважением, Волод.

kabjans
28.01.2010, 21:10
Спасибо, теперь вижу.

А почему не сделать просто с помощью "прокрутки", то есть так, как сделано на экране технологий?

И еще вопрос. Ты, кстати, не в курсе, где там эта "прокрутка" прописана. Ищу и не могу найти.

Извини, что слишком много вопросов.

Хальк Юсдаль
28.01.2010, 21:17
А вообще во многих модах используется альтернативный экран цивиков. Мне стандартный больше нравиться за компактность, но многие используют именно альтернативный.
http://forums.civfanatics.com/downloads.ph...le&id=13457 (http://forums.civfanatics.com/downloads.php?do=file&id=13457)
http://s001.radikal.ru/i196/1001/f8/ee101255fb80t.jpg (http://radikal.ru/F/s001.radikal.ru/i196/1001/f8/ee101255fb80.jpg.html)

volod
28.01.2010, 21:24
<div class='quotetop'>Цитата(kabjans * 28.1.2010, 20:08) 323469</div>

Спасибо, теперь вижу.

А почему не сделать просто с помощью "прокрутки", то есть так, как сделано на экране технологий?

И еще вопрос. Ты, кстати, не в курсе, где там эта "прокрутка" прописана. Ищу и не могу найти.

Извини, что слишком много вопросов.
[/b]

Сам сперва думал про прокрутку, но её рисовать сложнее, там события мыши надо учитывать и кучу условий проверять. А времени мало (
Так проще и быстрее :)

А прокрутка есть в экране технологий, теччузер или течсплэш посмотри файлы в том же каталоге. Одно из них - он.

С уважением, Волод.

NeseryozniyVET
28.01.2010, 23:10
<div class='quotetop'>Цитата(kabjans * 28.1.2010, 19:08) 323469</div>
А почему не сделать просто с помощью "прокрутки", то есть так, как сделано на экране технологий?

И еще вопрос. Ты, кстати, не в курсе, где там эта "прокрутка" прописана. Ищу и не могу найти.[/b]Прокрутка делается так:
screen.addScrollPanel( "Уникальное имя", u"", X, Y, Длинна, Высота, PanelStyles.PANEL_STYLE_EXTERNAL )

Все элементы потом помещаются на эту панель.Например
Заместь
screen.setText( "Уникальное имя", "Background", u"Текст", CvUtil.FONT_RIGHT_JUSTIFY, X, Y, -0.3, FontTypes.SMALL_FONT, WidgetTypes.WIDGET_GENERAL, -1, -1 )
Будет
screen.setTextAt( "Уникальное имя", "Имя скролинговой панели", u"Текст", CvUtil.FONT_RIGHT_JUSTIFY, X, Y, -0.3, FontTypes.SMALL_FONT, WidgetTypes.WIDGET_GENERAL, -1, -1 )

kabjans
29.01.2010, 10:57
Спасибо, NeseryozniyVET, за "наводку". Когда доберусь до компа с игрой, то попробую поиграть с прокруткой.