Вот и пришла пора выполнить свое обещание, данное когда-то. Итак, в этом сообщении я опишу работу 5ой демки к скриптовому модулю, что выкладывал на всеобщее обозрение. Так как я близок к теме создания игровых программ, то и здесь я не смог удержаться, чтобы не показать простой способ использования скриптов для построения диалогов, что может быть применимо в компьютерных играх и интерактивных системах. С одной стороны - скрипты как нельзя лучше подходят для этой задачи, как минимум по трем причинам:
С другой стороны, приближение демок к реальным примерам использования, должно только положительно сказываться на их восприятии. Ну кому интересно смотреть демки с квадратом, двигающимся по окружности? В общем, сегодня будем "лепить" маленький диалог на скриптах... Не знаю как для остальных, а для меня уже этих трех вышеупомянутых факторов достаточно для того, чтобы перенести диалоговую часть игры в скрипты! |
Итак, что нам нужно?
Уметь задавать вопрос и предлагать несколько вариантов ответа на него.
Всегда, прежде чем программировать диалоги, цепочку их последовательности рисуют на бумаге. Так проще, ведь держать в голове десяток вопросов и их взаимосвязи довольно трудная задача, да и в дальнейшем проследить правильность выполнения программы намного проще, когда все наглядно перед глазами.
Предлагаю схему вопросов, которые задаются в демке:
А вот и скрин демки, на котором можно увидеть способ выбора ответа - это обычный RadioGroup с кнопкой "Answer it!!!", которая передаст выбранное значение в скрипт:
А теперь приступим к реализации...
Зарегистрируем для скриптов две функции:
Set_QuestionText('Итак, ты уже изучил Lua?'); и Add_Answer(2, 'Конечно!');
Первая - задает вопрос, устанавливает текст вопроса, очищает список ответов.
Вторая - добавляет новый ответ в список, задает текст ответа и индекс вопроса, на который перейдет диалог при выборе этого ответа. В данном примере при выборе ответа "Конечно!" диалог перейдет на вопрос с индексом 2.
Теперь посмотрим, что происходит на стороне хост-программы.
При вызове Set_QuestionText() как я и говорил происходит очищение списка ответов и задание строки-вопроса:
Function Set_QuestionText(aLua_VM: Plua_State): integer; cdecl; begin frmMain.ClearAnswers; frmMain.lblQuestion.Caption := Lua_ToString(aLua_VM, 1); end;
При вызове Add_Answer()
а) добавляется новый индекс ответа в массив fAnswersID[],
б) добавляется элемент в RadioGroup
код парсинга:
Function Add_Answer(aLua_VM: Plua_State): integer; cdecl; begin frmMain.fAnswersID[frmMain.rgAnswers.Items.Count] := Round(Lua_ToNumber(aLua_VM, 1)); frmMain.rgAnswers.Items.Add(Lua_ToString(aLua_VM, 2)); frmMain.rgAnswers.ItemIndex := 0; result := 0; end;
Остается один вопрос - каким образом передать выбранное значение номера ответа и, следовательно, следующего вопроса в скрипт? До сих пор мы ни разу не воспользовались вторым параметром, передаваемом в
TScriptManager.DoScript(const aFunctionName: String; aArguments: Array of lua_Number; const aWriteError: boolean = true)
Для чего этот параметр нужен? Ответ прост - массив Single-значений, поданных в качестве второго аргумента пересылаются как параметры в скриптовую функцию.
Например, мы можем написать в хост-программе:
ScriptManager.DoScript('MyScript', [MyArgument]);
и теперь описание скриптовой функции может иметь уже входной параметр:
function MyScript(MyArgument) ... end;
Я уже говорил, что подается целый массив параметров? Ну так вот, допустима и такая запись, когда мы через запятую формируем массив из нескольких параметров:
ScriptManager.DoScript('MyScript', [Argument1, Argument2, Argument3]);
Тогда описание скриптовой функции изменилось бы на такое:
function MyScript(Argument1, Argument2, Argument3) ... end;
Здесь стоит уточнить один момент. Дело в том, что я, конечно, немного урезал функционал скриптов, разрешив передачу только Single-параметров. Но лично у меня не возникало необходимости в передаче аргументов других типов (строковых, например). Дело в том, что в Delphi мне показался самым красивым и простым способом передачи параметров - через массив. А вот хранение нетипизированных переменных в массиве в мире Delphi запрещено. Можно использовать тип Varinat, но он слишком медленный, чтобы применять его здесь. Именно поэтому я остановился на Single. Вот так, с этим вроде все.
Ну вот, по поводу Single-параметров вроде отговорился, теперь можно двигаться дальше.
Итак, в демке мы вызываем скриптовую функцию:
fScriptManager.DoScript('main', [fQuestIndex], false);
ну и приведу сам скрипт, ибо исходники мало кто качает, наверно:
function main(QuestIndex) if QuestIndex == 1 then Set_QuestionText('Итак, ты уже изучил Lua?'); Add_Answer(2, 'Конечно!'); Add_Answer(3, 'Не-а'); Add_Answer(4, 'Вообще ничего не ясно.'); elseif QuestIndex == 2 then Set_QuestionText('Молодец! Надеюсь, эти демо тебе помогли...'); Add_Answer(5, 'Да, всё круто!'); Add_Answer(4, 'Ерунда всё это'); elseif QuestIndex == 3 then Set_QuestionText('Жаль, недеюсь, всё еще получится.'); Add_Answer(4, 'Я тоже надеюсь'); Add_Answer(5, 'Да я не переживаю, и без Lua справлюсь'); elseif QuestIndex == 4 then Set_QuestionText('Перечитай всё заново - может станет яснее?'); Add_Answer(1, 'Ок, попробую'); elseif QuestIndex == 5 then Set_QuestionText('Я рад, удачи!'); Add_Answer(1, 'Ага, и тебе...'); end; end;
Все новое разобрали, почти обо всем рассказано. Теперь стало ясно, как обработать нажатие кнопки "Answer it!!!", мы просто считываем выставленный ответ и выполняем скрипт:
procedure TfrmMain.btnAnswerClick(Sender: TObject); begin fQuestIndex := fAnswersID[rgAnswers.ItemIndex]; DoScript; end;
Вот и все... Качаем, компилируем, отвечаем на вопросы программы, разговариваем по заскриптованныму диалогу.
Ура! Я дописал это чтиво :)
p.s. Кстати, а кто-нибудь заметил, что пропущена Демо-4? Я уже отвечал, что на самом деле я ее даже начал делать, но не придумалось ничего интересного, что можно было бы продемонстрировать. Вроде все обыденно-безынтересно. Так что, если будут замечательные идеи по поводу темы для 4ой программы - с радостью постараюсь реализовать и выложить.
Хорошие примеры.
ОтветитьУдалитьА вот нумеровать шкуру неубитого медведа чревато :)
благодарю!
ОтветитьУдалитьпо поводу нумерации - мне было проще сначала создать папки, проекты для демо, а потом уже по наличию времени каждую из них наполнять кодом, функционалом... как силы иссякли - решил выложить!))
согласен, получилось чуднО, отдам этот первый блин комам;))
Прошу прощения, но указанный в записке файл(http://lampogolovii.fileave.com/Demos/Demos_v1.rar)
ОтветитьУдалитьуже недоступен.
Каким образом можно ознакомиться с его содержимым?
боюсь, что теперь мне будет трудно найти демку...
Удалитьсервис fileave накрылся, теперь все демки, которые я хранил там, канули в лету...
если найду на диске бэкап - обязательно выложу!