Катсцена с субтитрами на Ren'Py

Катсцена с субтитрами на Ren'Py

Содержание

  1. Предисловие
  2. Подготовка проекта
  3. Лейблы
  4. Экран
  5. Функции
  6. Нюансы:
    1. Использование музыки вместо видео
    2. Выход в главное меню
    3. Текстовые теги
  7. Полный код
  8. Видео-туториал

1. Предисловие

Всем привет! Я начинаю свою небольшую рубрику «wiwts что-то выдумал». Буду писать в ней туториалы по некоторым плюшкам, которые написал для себя или кому-то в помощь. Сегодня затронем простые субтитры. То, как они могут выглядеть, можете посмотреть здесь:

В качестве подопытного кролика видео-титры из новеллы "Ошибки Первого Рода". К слову, я уже пытался в эту новеллу (т.к. в её разработке я участвовал) внедрить субтитры, но вышло из рук вон плохо. В статье представлена допиленная версия.

И заранее скажу, что меня не волнует, если кто-то где-то когда-то уже такую штуку делал. Я захотел сделать это сам и своим методом — я сделал. Адекватную критику принимаю.

Спасибо за понимание и приятного прочтения!
(P.S. хочу записать видео-туториал по субтитрам в ближайшее время).


2. Подготовка проекта

Прежде всего нам надо обозначить нашу видео-катсцену и сами субтитры.
Тут всё просто: обозначаем видео через Movie, а субтитры — словарём.

Указываем свой канал, я назвал его subtitled_cutscene, вы называйте как хотите, но учтите, что он ещё пригодится дальше по коду.
size=(config.screen_width, config.screen_height) — видео будет тем же разрешением, что и разрешение новеллы.

  1. image song_video = Movie(play='your_video.webm', loop=False, channel='subtitled_cutscene',
  2. size=(config.screen_width, config.screen_height))

Субтитры пишем по такому принципу:

  1. Создаём словарь {}
  2. В ключ пишем время в секундах, когда начинается нужная нам строка {«1»: }
  3. В значение пишем саму строку {«1»: «Строка»}

 Если хотите в будущем переводить субтитры на другие языки, то оборачивайте строки в такую конструкцию: _(«Строка»).

  1. define cutscene_song_lyrics = {
  2. '1': _('Расстрел во тьме дурного сна'),
  3. '4': _('Кладёт плашмя'),
  4. '5': _('И, прячась, в венах ждёт'),
  5. '8': _(''),
  6. '10': _('Война летит в лицо'),
  7. '12.5': _('Болит и всё про всё'),
  8. '15': _('Скулит, а совесть жрёт')}
  9.  
  10. default cutscene_seen_text = [] # Список с просмотренными строками субтитров

Далее можно задать стиль для субтитров, чтобы определить, как и где будут показаны строки. Тут чисто вкусовщина.

  1. style cutscene_text_style:
  2. xmaximum 1840
  3. ymaximum 60
  4. xalign .5
  5. yalign .99
  6. color 'dddddd'
  7. size 22

3. Лейблы

Для перехода к лейблу катсцены используем старый добрый jump.

  1. label start:
  2. jump cutscene_start

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

  1. label cutscene_start:
  2. # Прячем менюшку снизу
  3. $ quick_menu = False
  4. # Черный фон, чтобы не было возможных просветов между краями экрана и видео
  5. scene black
  6. # Показываем заданное ранее видео
  7. show image 'song_video'
  8. # Показываем экран через python, чтобы передать аргумент, который обозначает продолжительность видео
  9. $ renpy.show_screen('cutscene_screen', 18)
  10. pause

Лейбл, в который мы попадём по окончании субтитров.

  1. label cutscene_end:
  2. # Возвращаем менюшку
  3. $ quick_menu = True
  4. 'КОНЕЦ КАТСЦЕНЫ'

4. Экран

Экран нам нужен, чтобы не давать пропустить катсцену и показывать строки субтитров.

  1. screen cutscene_screen(dur):
  2. # Запрещаем скипать катсцену через ctrl и tab
  3. $ config.allow_skipping = False
  4. # Не даём прокликать катсцену
  5. key "dismiss" action NullAction()
  6. # При выходе в игровое меню останавливаем видео и показываем экран 'save'
  7. key "game_menu" action [PauseAudio('subtitled_cutscene', True), ShowMenu('save')]
  8. # Каждую сотую долю секунду проверяем, если видео на паузе, то запускаем его обратно, если нет, то выполняем функцию (см. далее)
  9. timer .01 repeat True action If(renpy.music.get_pause('subtitled_cutscene'),
  10. PauseAudio('subtitled_cutscene', False),
  11. Function(cutscene_update_text, renpy.music.get_pos('subtitled_cutscene'), dur, cutscene_song_lyrics))

5. Функции

Теперь самое главное.
То, что порождает наши субтитры.

Создаём функцию для обновления текста в соответствии с временем видео.

pos — тип float, получаем нашу позицию на временной шкале видео через renpy.music.get_pos('subtitled_cutscene')

lyrics — тип dict, это наш cutscene_song_lyrics
dur — продолжительность катсцены, задавать в int или float

slow_cps=25  — Указываем свой cps
style='cutscene_text_style') — Указываем наш стиль для строк.

  1. init python:
  2. def cutscene_update_text(pos:float, dur:float, lyrics:dict):
  3. # Берём переменную с просмотренными строками
  4. global cutscene_seen_text
  5. # Первые секунды Ren'Py на renpy.music.get_pos() возвращает None, поэтому необходимо это условие
  6. if pos == None:
  7. return
  8. # Если катсцена закончилась
  9. if pos >= dur:
  10. renpy.music.stop('subtitled_cutscene')
  11. # Обнуляем катсцену, функцию эту опишу ниже
  12. reset_cutscene()
  13. config.allow_skipping = True
  14. renpy.hide_screen('cutscene_screen')
  15. renpy.jump('cutscene_end')
  16. # Запускаем перебор словаря с субтитрами
  17. for t in lyrics:
  18. # Проверяем, видели ли мы текст на этом времени, и какую строку показывать в зависимости от времени
  19. if t not in cutscene_seen_text and pos >= float(t):
  20. # Добавляем время строки в увиденный текст
  21. cutscene_seen_text.append(t)
  22. # Показываем строку через show text
  23. renpy.show('cutscene_subtitles_text', what=Text(lyrics[t], slow_cps=25, style='cutscene_text_style'))
  24. return
  25. return

Создаём функцию для сброса катсцены. Она понадобится для того, чтобы по окончанию или прерыванию катсцены она смогла снова исправно запуститься без перезапуска.

  1. def reset_cutscene():
  2. global cutscene_seen_text
  3. cutscene_seen_text = []
  4. renpy.hide('cutscene_subtitles_text')

6. Нюансы

Подробнее о них будет в видео-туториале.

1. Использование музыки вместо видео
Если вас интересует использование аудио, вместо видео, то необходимо поменять show image на play music
В renpy.music.stop() поменять канал на music, в таймере так же с get_pause, get_pos, PauseAudio

2. Выход в главное меню
Чтобы катсцена не продолжила играть в уши при выходе в главное меню и при повторном запуске снова воспроизвелась, надо её остановить и «сбросить». Для этого добавим ниже приведённую строку.
В screens.rpy, screen main_menu()

  1. $ renpy.music.stop('subtitled_cutscene'); reset_cutscene()

3. Текстовые теги
В субтитрах можно указывать все ренпаевские теги. Все они будут работать, за исключением {w}, {nw}.
Если кому-то интересно, сработает ли с kinetic-tags
Да, сработает. Проверял.


7. Полный код

Если возникнут вопросы или какие-то проблемы, то пишите в комментарии к статье или в личные сообщения ВК https://vk.com/da_wiwts. Советую написать сюда в комментарии, чтобы в случае чего было удобно всю информацию по этой теме хранить в одном месте.

  1. image song_video = Movie(play='your_video.webm', loop=False, channel='subtitled_cutscene',
  2. size=(config.screen_width, config.screen_height))
  3.  
  4. define cutscene_song_lyrics = {
  5. '1': _('Расстрел во тьме дурного сна'),
  6. '4': _('Кладёт плашмя'),
  7. '5': _('И, прячась, в венах ждёт'),
  8. '8': '',
  9. '10': _('Война летит в лицо'),
  10. '12.5': _('Болит и всё про всё'),
  11. '15': _('Скулит, а совесть жрёт')}
  12.  
  13. default cutscene_seen_text = [] # Список с просмотренными строками субтитров
  14.  
  15. style cutscene_text_style:
  16. xmaximum 1840
  17. ymaximum 60
  18. xalign .5
  19. yalign .99
  20. color 'dddddd'
  21. size 22
  22.  
  23. init python:
  24. def reset_cutscene():
  25. global cutscene_seen_text
  26. cutscene_seen_text = []
  27. renpy.hide('cutscene_subtitles_text')
  28.  
  29. def cutscene_update_text(pos:float, dur:float, lyrics:dict):
  30. # Берём переменную с просмотренными строками
  31. global cutscene_seen_text
  32. # Первые секунды Ren'Py на renpy.music.get_pos() возвращает None, поэтому необходимо это условие
  33. if pos == None:
  34. return
  35. # Если катсцена закончилась
  36. if pos >= dur:
  37. renpy.music.stop('subtitled_cutscene')
  38. # Обнуляем катсцену, функцию эту опишу ниже
  39. reset_cutscene()
  40. config.allow_skipping = True
  41. renpy.hide_screen('cutscene_screen')
  42. renpy.jump('cutscene_end')
  43. # Запускаем перебор словаря с субтитрами
  44. for t in lyrics:
  45. # Проверяем, видели ли мы текст на этом времени, и какую строку показывать в зависимости от времени
  46. if t not in cutscene_seen_text and pos >= float(t):
  47. # Добавляем время строки в увиденный текст
  48. cutscene_seen_text.append(t)
  49. # Показываем строку через show text
  50. renpy.show('cutscene_subtitles_text', what=Text(lyrics[t], slow_cps=25, style='cutscene_text_style'))
  51. return
  52. return
  53.  
  54. screen cutscene_screen(dur):
  55. # Запрещаем скипать катсцену через ctrl и tab
  56. $ config.allow_skipping = False
  57. # Не даём прокликать катсцену
  58. key "dismiss" action NullAction()
  59. # При выходе в игровое меню останавливаем видео и показываем экран 'save'
  60. key "game_menu" action [PauseAudio('subtitled_cutscene', True), ShowMenu('save')]
  61. # Каждую сотую долю секунду проверяем, если видео на паузе, то запускаем его обратно, если нет, то выполняем функцию (см. далее)
  62. timer .01 repeat True action If(renpy.music.get_pause('subtitled_cutscene'),
  63. PauseAudio('subtitled_cutscene', False),
  64. Function(cutscene_update_text, renpy.music.get_pos('subtitled_cutscene'), dur, cutscene_song_lyrics))
  65.  
  66. label cutscene_start:
  67. # Прячем менюшку снизу
  68. $ quick_menu = False
  69. # Черный фон, чтобы не было возможных просветов между краями экрана и видео
  70. scene black
  71. # Показываем заданное ранее видео
  72. show image 'song_video'
  73. # Показываем экран через python, чтобы передать аргумент, который обозначает продолжительность видео
  74. $ renpy.show_screen('cutscene_screen', 18)
  75. pause
  76.  
  77. label cutscene_end:
  78. # Возвращаем менюшку
  79. $ quick_menu = True
  80. 'КОНЕЦ КАТСЦЕНЫ'

8. Видео-туториал

---{-={ЗАПОЛНИТЕЛЬ}=-}---

Автор добавления

15:50
2.06K
Загрузка...
wiwts
wiwts #

26.01.2025: Замечен баг с тем, что текст не воспроизводится при повторном прохождении. Внесены правки в код и в статью с целью решения бага.

Ответы 0
Согласен0Против

Нет ответов

Пользуясь данным сайтом, вы соглашаетесь с тем, что мы используем cookie