Как сделать?
…
Добрый день. У меня такой вопрос: я сделал в своей игре предмет радио. Оно работает через локацию счётчик - когда трек заканчивается, то должен начинаться следующий автоматически. Между песнями встречаются короткие вставки с ведущим. Часть кода, чтобы показать как это сделано:
if radio=1:
if isplay(”Sound\Radio\Music_beat_Darkdreams.mp3”)=0:
radio=2
play “Sound\Radio\Radio_1.mp3”
end
elseif radio=2:
if isplay(”Sound\Radio\Radio_1.mp3”)=0:
radio=3
play “Sound\Radio\Music_trans_Resonate.mp3”
end
…
elseif radio=42:
if isplay(”Sound\Radio\Nialm_Burn.mp3”)=0:
radio=1
play “Sound\Radio\Music_beat_Darkdreams.mp3”
end
end
И оно в целом работает. Вставки с ведущим короткие и после них сразу начинают играть треки с музыкой (как и задумано). Но после музыки долгая пауза, прежде чем начинается следующая аудиозапись (музыка, или ведущий) (в конце музыкальных треков нет молчания, музыка в них играет до самой последней секунды). Обращение к счётчику я указал и settimer 5, и 1, и 500, и просто убирал. Возможно я не знаю какого-то нюанса в QSP, или подобную задумку нужно реализовывать по другому, пожалуйста подскажите.
А в начале радио треков нет пауз?
Byte:
А в начале радио треков нет пауз?
Ни в начале, ни в конце нет. Тут точно проблема не в треках. У меня есть опция в выпадающем меню радио “Переключить”. Всё что она делает это “CLOSE ALL”. Стоит её нажать, как следующий трек сразу же начинает играть. Сложилось впечатление, что QSP просто считает что трек продолжает играть, даже когда тот остановился.
Я проверю, возможно это какая-то ошибка в звуковой подсистеме.
Воспроизвести не получилось (пробовал несколько раз с OGG/Vorbis, MP3 и MIDI) - у меня isplay быстро возвращает правильный результат. А можно прислать какой-то простой пример с ошибкой (с файлами + тестовым файлом игры)? Можно в дискорде, можно в телеграме, можно здесь.
GrimLight,
но ведь легко проверить. Заметь трек, с которым воспроизводится такое молчание, возьми пару треков до него, пару после, и проверяй какие воспроизводятся, используя окно доп.описания:
count += 1
if count = 1000: count = 0
clr
pl 'Контроль: <<count>>'
pl 'darkdreams: '+ $str(isplay("Sound\Radio\Music_beat_Darkdreams.mp3"))
pl 'radio 1: '+ $str(isplay("Sound\Radio\Radio_1.mp3"))
pl 'resonate: '+ $str(isplay("Sound\Radio\Music_trans_Resonate.mp3"))
Ну и, надо всегда помнить, что counter не всегда срабатывает чётко в означенное время. Это может вызывать некоторые глюки в воспроизведении аудио.
https://wiki.qsp.org/help:realtime <– тут не совсем корректно описано, как это работает, позже поправлю. Но в целом смысл думаю ясен. Локация-счётчик может не попасть в заданные интервалы, и таким образом при воспроизведении музыки будут паузы.
Если код выполняется не очень долго (нужно постараться, чтобы при разумном подходе что-то долго работало), то задержки выполнения кода не должны особо влиять.
Я использовал плеер 5.7, скачал последний 5.9.3, в нем все работает (моя вина). Но спасибо, всем! Простите, не заметил что форум ушёл на следующую страницу и только сейчас увидел ваши ответы (отвык от форумов).
Подскажите, пожалуйста
Правильно ли я понимаю, что я не могу сделать итерацию не по всему массиву, а по ячейке массива. То есть “многомерные” массивы по сути не совсем многомерные, это те же линейные массивы, только с кортежами в качестве индекса.
Например, я создаю массив
LOCAL Q_INDEX = 0
$QUESTS_TEXT[Q_INDEX] = "Иди туда, не знаю куда и принеси то, не знаю что"
LOCAL STEP_INDEX = 0
$QUESTS_STEPS[Q_INDEX, STEP_INDEX, "todo"] = "Идти туда, не знаю куда"
QUESTS_STEPS[Q_INDEX, STEP_INDEX, "done"] = 1
STEP_INDEX += 1
$QUESTS_STEPS[Q_INDEX, STEP_INDEX, "todo"] = "Принести то, не знаю что"
QUESTS_STEPS[Q_INDEX, STEP_INDEX, "done"] = 0
Я в таком случае не могу узнать сколько в QUESTS_STEPS[QUEST_INDEX] хранится элементов, и соответственно проитерироваться? Мне нужно хранить условно еще один массив для квестов, где для каждого квеста помнить сколько у него есть шагов, типа QUESTS_STEPS_COUNT[QUEST_INDEX] = 2. И тогда брать эту переменную и с помощью нее итерироваться?
Да, верно. Можно итерироваться по всему массиву (обойти вообще все элементы) или хранить число элементов в каком-то “измерении” отдельно.
Для упрощения работы можно создать специальные служебные локации и вызывать через @/@@, но это будет работать медленнее.
Альтернативный вариант (на мой взгляд он лучше) - хранить элементы измерений, по которым нужно итерироваться, в разных массивах.
Всем привет, может для ветеранов вопрос глупый, но объясните пожалуйста.
Допустим, есть описание локации. Есть действие “осмотреться”, которое в описание выводит пару строк о том, что происходит вокруг через *PL. Так вот, объясните пожалуйста, как сделать так, чтобы описание которое выдается после этого действия выводилось после основного текста, а не перед ним?
Gvozd229, привет, можно пример кода, или подробней описать? Просто любой текст выводится после основного текста по умолчанию.
Gvozd229, а, что ты подразумеваешь под “основной текст”?
Все операторы идут друг за другом, так что любой следующий вывод следует за предыдущим в порядке появления в коде. Поэтому смотри порядок операторов.
Действия через ACt выводятся в отдельном окне (окно действий), и как-то комбинировать их с основным окном может только пользователь. Но можно действия оформить как ссылки внутри текста - ну и тогда располагать их как угодно относительно текстовых блоков. Пример - ‘<a href=“EXEC:любойисполняемыйкод”>НАЗВАНИЕ ДЕЙСТВИЯ</a>’
mkir:
Действия через ACt выводятся в отдельном окне (окно действий), и как-то комбинировать их с основным окном может только пользователь.
Имярек немного за другое говорит. Любое Действие может выводить дополнительный текст и этот текст будет продолжением уже выведенного. У камрада отчего-то текст при выполнении Действия выводится перед основным текстом страницы (на сколько я понял из объяснений). Могу предположить, что код выглядит примерно так:
Act 'Новая строка': *P "Балаболка"
*P "Абракадабра и кадабра абра"
Я давно отказался от “Прямого” вывода текста в КуСПе. Я сначала полностью формирую строку и только потом вывожу. Если мне надо что-то убрать или добавить, то сначала “строка” будет переформатирована и только потом выведена. Что и как выводить передаю самому себе в виде аргумента. Это избавляет от огромного числа “киноляов”. Иногда строку формирую вообще динамически, вплоть до применяемых операторов и операндов. Перед каждым формированием и выводом ставлю Действие “Спасение”, чтобы при возникновении ошибки можно было вернуться в игру, а не “зависнуть в чистом поле”.
Примерно так - простейшее формирование (статическое) нужной строки:
[b]# Кузница[/b]
SHOWSTAT Off
Act 'Спасение': GT 'Домой' & !Создание Действия возврата на основную локацию
$FullStr=Func($CurrentLocation) & !Получаем строку вывода (Приводить не буду, идет простой перебор в цикле и вывод по очереди формирования в зависимости от нужной локации
$FullStr & !Вывод полученной строки
If $CurrentLocation='Снаряжение':
Act 'Собрать инвентарь': Gs 'Get_Ammo_BlackSmith' & Gt 'Кузница' & !Выполняем действие (идет случайный подбор инвентаря) и возвращаемся на локацию
Act 'Продавать | Улучшать' : $CurrentLocation='Снаряжение_Героя' & $CurrentAmmo='' & Gt 'Кузница' & !Выполняем действие (переходим к выбору снаряжения у ГГ) и возвращаемся на локацию
Act 'Назад ': КПокупке=Off & Gt 'Домой'
End
If $CurrentLocation='Снаряжение_Героя':
Act 'Покупать' : $CurrentLocation='Снаряжение' & КПокупке=On & $CurrentAmmo='' & Gt 'Кузница' & !Выполняем действие и возвращаемся на локацию
End
If $CurrentLocation='Апгрейд_Снаряжения':
Act 'Покупать' : $CurrentLocation='Снаряжение_Кузни' & $CurrentAmmo='' & Gt 'Кузница' & !Выполняем действие и возвращаемся на локацию
Act 'Назад' : $CurrentLocation='Снаряжение_Героя' & Gt 'Кузница'
End
Delact 'Спасение' & !Удаление Действия (Код локации отработал правильно или не вызвал критической ошибки)
[b]--- Кузница ---[/b]
Пример динамического формирования выводимого:
!Локация Создания персонажа
!SHOWACTS On & !Включаем окно Действий
Local $ResStr
Local $RaceStr
Local $NameLeft, $NameRight, $NameInput
Local $GenderLeft, $GenderRight
Local $RaceLeft, $RaceRight, $RaceReset
Local $PhotoLeft, $PhotoRight, $PhotoReset
Local $РостLeft, $РостRight
*Clr & !Чистим поле
CLA & !Удаляем Действия
If $Args[0]='First': & !Формирование при "первом посещении" локации
CopyArr 'Player','NPC'
CopyArr 'Tempo','NPC'
!@CopyRacePreset('Tempo','Player') & !Копируем нужные предустановки
GoPresets=On
!@Случайный_Пресонаж(On, On, On)
Player['Раса']=Rand(0,6)
Player['НомерФото']=Rand(RaceSize[Player['Раса']])
@CopyRacePreset('Player',$Race[Player['Раса']]+'_0')
@CopyRacePreset('Player',$Race[Player['Раса']]+'_'+Player['НомерФото'])
SHOWACTS On & !Открыть окно Действий
PercSelected=Off & !Результат выбора перков.
End
! Динамическое формирование нужных операторов.
$NameLeft="If Player[''НомерИмя'']<=0:
Player[''НомерИмя'']=ArrSize(''$''+$Race[Player[''Раса'']]+''_Имя'')-1
Else
Player[''НомерИмя'']-=1
End
$Player[''Имя'']=ArrItem(''$''+$Race[Player[''Раса'']]+''_Имя'',Player[''НомерИмя''])"
$NameRight="If Player[''НомерИмя'']>=ArrSize(''$''+$Race[Player[''Раса'']]+''_Имя'')-1:
Player[''НомерИмя'']=0
Else
Player[''НомерИмя'']+=1
End
$Player[''Имя'']=ArrItem(''$''+$Race[Player[''Раса'']]+''_Имя'',Player[''НомерИмя''])"
$NameInput="$RaceStr=Input(''Введите имя персонажа:'')
$RaceStr=$Replace($RaceStr, '' '')
If $RaceStr<>'''' and $RaceStr<>$Player[''Имя'']:
$Player[''Имя'']=$RaceStr
Player[''НомерИмя'']=-1
End"
$GenderLeft="If Player[''Гендер'']<=0 : Player[''Гендер'']=1 Else Player[''Гендер'']-=1"
$GenderRight="If Player[''Гендер'']>=1 : Player[''Гендер'']=0 Else Player[''Гендер'']+=1"
$RaceLeft="If Player[''Раса'']<=0 : Player[''Раса'']=6 Else Player[''Раса'']-=1"
$RaceRight="If Player[''Раса'']>=6:Player[''Раса'']=0 Else Player[''Раса'']+=1"
$RaceReset="If Player[''НомерФото'']>RaceSize[Player[''Раса'']]:Player[''НомерФото'']=1
@CopyRacePreset(''Player'',$Race[Player[''Раса'']]+''_0'')
If GoPresets=On : @CopyRacePreset(''Player'',$Race[Player[''Раса'']]+''_''+Player[''НомерФото''])
If Player[''НомерИмя'']>-1 :
If Player[''НомерИмя'']>=ArrSize(''$''+$Race[Player[''Раса'']]+''_Имя'') : Player[''НомерИмя'']=ArrSize(''$''+$Race[Player[''Раса'']]+''_Имя'')-1
$Player[''Имя'']=ArrItem(''$''+$Race[Player[''Раса'']]+''_Имя'',Player[''НомерИмя''])
End"
$PhotoLeft="If Player[''НомерФото'']<=1:Player[''НомерФото'']=RaceSize[Player[''Раса'']] Else Player[''НомерФото'']-=1"
$PhotoRight="If Player[''НомерФото'']>=RaceSize[Player[''Раса'']]:Player[''НомерФото'']=1 Else Player[''НомерФото'']+=1"
$PhotoReset="If GoPresets=On : @CopyRacePreset(''Player'',$Race[Player[''Раса'']]+''_''+Player[''НомерФото''])"
! Формирование "строки" вывода
$ResStr=@Заголовок('Создание персонажа')
$ResStr+='<center><table width=1250 <<$AlignLeft>> border=0 cellspacing=0 cellpadding=0>'
$ResStr+='<tr>'
$ResStr+='<td width=400 <<$AlignLeft>>>'
$ResStr+='<table width=300 <<$AlignLeft>> border=0 cellspacing=0 cellpadding=0>'
$ResStr+='<tr>' & !Строка имени
$ResStr+='<td width=60 <<$AlignCLeft>>>'
$ResStr+='Имя:'
$ResStr+='</td>'
$ResStr+='<td width=24 <<$AlignCLeft>>>'
$ResStr+='<a href="exec: Dynamic(''<<$NameLeft>>'') & Gs(''Создание_Персонажа'')"><img src=".\pic\GLeft.png" height=24></a>'
$ResStr+='</td>'
$ResStr+='<td width=252 <<$AlignCenter>>>'
$ResStr+='<a href="exec: Dynamic(''<<$NameInput>>'') & Gs(''Создание_Персонажа'')" >'
If Player['НомерИмя']=-1 and $Player['Имя']='???' :
$ResStr+='Введите имя</a>'
Else
$ResStr+='<<$Player["Имя"]>></a>'
End
$ResStr+='</td>'
$ResStr+='<td width=24 <<$AlignCRight>>>'
$ResStr+='<a href="exec: Dynamic(''<<$NameRight>>'') & Gs(''Создание_Персонажа'')"><img src=".\pic\GRight.png" height=24></a>'
$ResStr+='</td>'
$ResStr+='</tr>'
$ResStr+='<tr>' & !Строка Расы
$ResStr+='<td width=60 <<$AlignCLeft>>>'
$ResStr+='Раса:'
$ResStr+='</td>'
$ResStr+='<td width=24 <<$AlignCLeft>>>'
$ResStr+='<a href="exec: Dynamic(''<<$RaceLeft>>'') & Dynamic(''<<$RaceReset>>'') & Gs(''Создание_Персонажа'')"><img src=".\pic\GLeft.png" height=24></a>'
$ResStr+='</td>'
$ResStr+='<td width=252 <<$AlignCenter>>>'
$ResStr+='<<$RaceName[Player[''Раса'']]>>'
$ResStr+='</td>'
$ResStr+='<td width=24 <<$AlignCRight>>>'
$ResStr+='<a href="exec: Dynamic(''<<$RaceRight>>'') & Dynamic(''<<$RaceReset>>'') & Gs(''Создание_Персонажа'')"><img src=".\pic\GRight.png" height=24></a>'
$ResStr+='</td>'
$ResStr+='</tr>'
$ResStr+='<tr>' & !Строка Пол
$ResStr+='<td width=60 <<$AlignCLeft>>>'
$ResStr+='Пол:'
$ResStr+='</td>'
$ResStr+='<td width=24 <<$AlignCLeft>>>'
$ResStr+='<a href="exec: Dynamic(''<<$GenderLeft>>'') & Gs(''Создание_Персонажа'')"><img src=".\pic\GLeft.png" height=24></a>'
$ResStr+='</td>'
$ResStr+='<td width=252 <<$AlignCenter>>>'
$ResStr+=$Гендер[Player['Гендер']]
$ResStr+='</td>'
$ResStr+='<td width=24 <<$AlignCRight>>>'
$ResStr+='<a href="exec: Dynamic(''<<$GenderRight>>'') & Gs(''Создание_Персонажа'')"><img src=".\pic\GRight.png" height=24></a>'
$ResStr+='</td>'
$ResStr+='</tr>'
$ResStr+='<tr>' & !Пустая строка
$ResStr+='<td>'
!$ResStr+='<br>'
$ResStr+='</td>'
$ResStr+='</tr>'
....
$ResStr+='Навык метательного оружия: <b><<Player[''НавыкНож'']+Бонус[''НавыкНож'']>></b><br><br>'
...
$ResStr+='</td>'
$ResStr+='<td width=350 <<$AlignCenter>>>' & !Вывод картинки
$ResStr+='<table width=350 <<$AlignLeft>> border=0 cellspacing=0 cellpadding=0>'
$ResStr+='<tr>'
$ResStr+='<td width=350 <<$AlignCTop>>>'
$ResStr+='<img src="<<@GetMidlPicture(Player[''Раса''],Player[''НомерФото''])>>" height=400>'
$ResStr+='</td>'
$ResStr+='</tr>'
$ResStr+='</table>'
$ResStr+='<table width=200 <<$AlignCenter>> border=0 cellspacing=0 cellpadding=0>'
$ResStr+='<tr>'
$ResStr+='<td width=24 <<$AlignCLeft>>>'
$ResStr+='<a href="exec: Dynamic(''<<$PhotoLeft>>'') & Dynamic(''<<$PhotoReset>>'') & @Создание_Персонажа"><img src=".\pic\GLeft.png" height=24></a>'
$ResStr+='</td>'
$ResStr+='<td width=148 <<$AlignCenter>>>'
$ResStr+='Выбор вида'
$ResStr+='</td>'
$ResStr+='<td width=24 <<$AlignCRight>>>'
$ResStr+='<a href="exec: Dynamic(''<<$PhotoRight>>'') & Dynamic(''<<$PhotoReset>>'') & @Создание_Персонажа"><img src=".\pic\GRight.png" height=24></a>'
$ResStr+='</td>'
$ResStr+='</tr>'
$ResStr+='</table>'
$ResStr+='</td>'
$ResStr+='</tr>'
$ResStr+='</table></center>'
$ResStr & !Вывод полученной строки
Act 'Создать случайного персонажа': @Случайный_Пресонаж(GoPresets, On, On) & @SetBonus & @Создание_Персонажа
If PercSelected<>On : Act 'Перейти к выбору перков': Gt 'Выбор_Перков' Else Act 'Изменить выбор перков': Gt 'Выбор_Перков'
If $Player['Имя']<>'' and $Player['Имя']<>'???' and PercSelected=On and Бонус[BonusCount+1]<>0 and Бонус[BonusCount+2]<>0 and Бонус[BonusCount+3]<>0 :
Act @Цвет('Принять выбор и играть',ЗЕЛ,'b'): @Персонаж_Создан & Gt 'Письмо'
Else
Act @Цвет('Принять выбор и играть',СЕР):
Local $MsgStr=''
If $Player['Имя']='' or $Player['Имя']='???' : $MsgStr+='Не задано имя Пресонажа<br>'
If PercSelected<>On : $MsgStr+='Не выбраны перки<br>'
If Бонус[BonusCount+1]=0 or Бонус[BonusCount+2]=0 or Бонус[BonusCount+3]=0 : $MsgStr+='Не выбраны cтартовые бонусы'
Msg($MsgStr)
End
End
Выглядит примерно так:
При нажатии на любую ссылку происходит изменение значения и возврат на локацию с полным переформированием строки вывода… и так по кругу, пока не отработает Дейстивие “Принять и Играть”
