Краткие сведения о Microsoft Agent
Продолжаем разрабатывать методологию мультимедиа на примере интеграции Visual Basic с очень популярной и перспективной технологией Microsoft Agent. Microsoft Agent – это беспрецедентная программная мультимедийная технология для более естественных путей связи человека и компьютера через создание новых диалоговых интерфейсов. Это набор программных услуг, которые дают возможность разработчикам включать интерактивные анимированные персонажи в их приложения и веб-страницы. Эти персонажи могут говорить при помощи программы (средства, механизма, инструмента, преобразователя) для перевода текста в речь (a text-to-speech engine - TTS), воспроизводить аудио и даже принимать разговорные речевые команды через механизм распознавания речи(speech recognition engine). Microsoft Agent дает возможность разработчикам расширить интерфейс пользователя за пределы распространенных сегодня взаимодействий мыши и клавиатуры. Технология Microsoft Agent может быть применима в следующих областях:
имеется огромное число ролей, которые разработчик в качестве режиссера может создать для персонажей Microsoft Agent и применить в своих программах;
при помощи этих персонажей главный компьютер провайдера может приветствовать новых пользователей и снабдить их показом времени, сообщением о том, что компьютер включен, приложение выполнено или веб-узел просмотрен;
дружественная обучающая программа с такими персонажами могла бы помогать человеку в поэтапном освоении нового материала;
персонаж мог бы представить уведомление или предупреждение, что новая электронная почта прибыла, и затем предложить ее прочитать;
такой помощник мог бы выполнить поиск информации в Интернете, а затем прочитать найденную информацию вслух.
Технология Microsoft Agent предназначена прежде всего для разработчиков, использующих языки или среды, которые поддерживают компонентную объектную модель (Component Object Model – COM) или интерфейсы управления Microsoft ActiveX. Они включают, например, Microsoft Visual Studio (Visual C#, Visual Basic, Visual FoxPro), Microsoft Office (Visual Basic for Applications), Microsoft Internet Explorer (Visual Basic Scripting Edition or Microsoft Jscript), Microsoft Windows Script Host (ActiveX Scripting Language).
Глава 47. Методика управления мультипликационными персонажами
Листинг 47.1.Объявление членов интерфейса и глобальных переменных.
//Объявляем персонаж Джина (Genie) и путь к его файлу:
static AgentObjects.IAgentCtlCharacterEx myGenie;
static String DATAPATH_1 = "Genie.acs";
//Объявляем персонаж Мага (Merlin) и путь к его файлу:
static AgentObjects.IAgentCtlCharacterEx myMerlin;
static String DATAPATH_2 = "Merlin.acs";
//Объявляем персонаж Попугая (Peedy) и путь к его файлу:
static AgentObjects.IAgentCtlCharacterEx myPeedy;
static String DATAPATH_3 = "Peedy.acs";
//Объявляем персонаж Робота (Robby) и путь к его файлу:
static AgentObjects.IAgentCtlCharacterEx myRobby;
static String DATAPATH_4 = "Robby.acs";
//Объявляем член интерфейса Agent:
private AgentObjects.Agent myAgentController;
//Глобальная переменная для любого текста персонажа:
static String mySpeech;
А в шаблон (метода Form1_Load) записываем наш код (согласно постановке задачи для всех персонажей), и метод Form1_Load принимает такой вид.
Листинг 47.2.Загрузка персонажей в элементы управления.
private void Form1_Load(object sender, EventArgs e)
{
//Загружаем персонаж в элемент управления axAgent1:
axAgent1.Characters.Load("Genie", DATAPATH_1);
myGenie = axAgent1.Characters.Character("Genie");
//Чтобы он выполнял голосовые команды на англ. яз.:
myGenie.LanguageID = 0x409;
//Записываем текст речи персонажа в окно TextBox:
textBox1.Text = "Здравствуйте. Меня зовут Джин.";
//Загружаем персонаж в элемент управления axAgent2:
axAgent2.Characters.Load("Merlin", DATAPATH_2);
myMerlin = axAgent2.Characters.Character("Merlin");
//Чтобы он выполнял голосовые команды на англ. яз.:
myMerlin.LanguageID = 0x409;
//Записываем текст речи персонажа в окно TextBox:
textBox2.Text = "Здравствуйте. Меня зовут Маг.";
//Загружаем персонаж в элемент управления axAgent3:
axAgent3.Characters.Load("Peedy", DATAPATH_3);
myPeedy = axAgent3.Characters.Character("Peedy");
//Чтобы он выполнял голосовые команды на англ. яз.:
myPeedy.LanguageID = 0x409;
//Записываем текст речи персонажа в окно TextBox:
textBox3.Text = "Здравствуйте. Меня зовут Попугай.";
//Загружаем персонаж в элемент управления axAgent4:
axAgent4.Characters.Load("Robby", DATAPATH_4);
myRobby = axAgent4.Characters.Character("Robby");
//Чтобы он выполнял голосовые команды на англ. яз.:
myRobby.LanguageID = 0x409;
//Записываем текст речи персонажа в окно TextBox:
textBox4.Text = "Здравствуйте. Меня зовут Робот.";
//Для всех четырех персонажей добавляем
//нашу голосовую команду, как пользователей,
//например, команду "MoveToMouse" -
//переместиться на место курсора мыши:
mySpeech = "MoveToMouse";
myGenie.Commands.Add(
mySpeech, mySpeech, mySpeech, true, true);
myMerlin.Commands.Add(
mySpeech, mySpeech, mySpeech, true, true);
myPeedy.Commands.Add(
mySpeech, mySpeech, mySpeech, true, true);
myRobby.Commands.Add(
mySpeech, mySpeech, mySpeech, true, true);
//Задаем, например, Джину выполнение еще команды,
//для примера, голосовой команды "Merlin":
mySpeech = "Merlin";
myGenie.Commands.Add(
mySpeech, mySpeech, mySpeech, true, true);
//Задаем, например, Магу выполнение еще команды,
//для примера, голосовой команды "Peedy":
mySpeech = "Peedy";
myMerlin.Commands.Add(
mySpeech, mySpeech, mySpeech, true, true);
//Задаем, например, Попугаю выполнение еще команды,
//для примера, голосовой команды "Robby":
mySpeech = "Robby";
myPeedy.Commands.Add(
mySpeech, mySpeech, mySpeech, true, true);
//Задаем, например, Роботу выполнение еще команды,
//для примера, голосовой команды "Genie":
mySpeech = "Genie";
myRobby.Commands.Add(
mySpeech, mySpeech, mySpeech, true, true);
}
Чтобы записать нашу часть кода для показа на экране монитора первого персонажа Genie (Джин) при помощи первой кнопки “Показать Джина” на Form1 (рис. 47.5), дважды щелкаем эту кнопку в режиме редактирования (или в панели Properties выбираем заголовок button1 и на вкладке Events дважды щелкаем по имени события Click). Появляется файл Form1.h с шаблоном (метода button1_Click), который после записи нашего кода (согласно постановке задачи для первого персонажа) принимает следующий вид.
Листинг 47.3. Метод для кнопки “Показать Джина”.
//Объявляем общую для персонажей объектную переменную:
Object myObject = null;
private void button1_Click(object sender, EventArgs e)
{
//От начала координат в вехнем левом углу Form1
//задаем координаты "x,y" места расположения персонажа:
myGenie.MoveTo(
Convert.ToInt16(this.Location.X + 400),
Convert.ToInt16(this.Location.Y - 130), 1000);
//Показать персонаж в заданном месте:
myGenie.Show(0);
//Чтобы персонаж произносил речь через динамики,
//задаем ему следующие свойства:
myAgentController = new AgentObjects.Agent();
myAgentController.Connected = true;
myAgentController.Characters.Load(
"genie", "genie.acs");
myGenie =
myAgentController.Characters.Character("genie");
//Персонаж произносит текст из окна TextBox
//и показывает этот текст в виде подсказки:
myGenie.Speak(textBox1.Text, myObject);
}
Отметим, что в этом коде и далее число 1000 означает время (в миллисекундах) выполнения персонажем нашей команды в коде; это время, естественно, мы можем изменять.
Чтобы удалить персонаж с экрана монитора при помощи второй кнопки “Скрыть Джина ” на Form1 (рис. 47.5), дважды щелкаем эту кнопку в режиме редактирования. Появляется файл Form1.h с шаблоном (метода button2_Click), который после записи нашего кода принимает такой вид.
Листинг 47.4. Метод для кнопки “Скрыть Джина”.
private void button2_Click(object sender, EventArgs e)
{
//Скрыть персонаж:
myGenie.Hide(0);
}
Аналогично, чтобы записать нашу часть кода для показа на экране монитора второго персонажа Merlin (Маг) при помощи кнопки “Показать Мага” на Form1 (рис. 47.5), дважды щелкаем эту кнопку в режиме редактирования. Появляется файл Form1.h с шаблоном (функции button3_Click), который после записи нашего кода принимает следующий вид.
Листинг 47.5.Метод для кнопки “Показать Мага”.
private void button3_Click(object sender, EventArgs e)
{
//От начала координат в вехнем левом углу Form1
//задаем координаты "x,y" места расположения персонажа:
myMerlin.MoveTo(
Convert.ToInt16(this.Location.X + 400),
Convert.ToInt16(this.Location.Y - 130), 1000);
//Показать персонаж в заданном месте:
myMerlin.Show(0);
//Чтобы персонаж произносил речь через динамики,
//задаем ему следующие свойства:
myAgentController = new AgentObjects.Agent();
myAgentController.Connected = true;
myAgentController.Characters.Load(
"merlin", "merlin.acs");
myMerlin =
myAgentController.Characters.Character("merlin");
//Персонаж произносит текст из окна TextBox
//и показывает этот текст в виде подсказки:
myMerlin.Speak(textBox2.Text, myObject);
}
Чтобы удалить персонаж с экрана монитора при помощи кнопки “Скрыть Мага” на Form1 (рис. 47.5), дважды щелкаем эту кнопку в режиме редактирования. Появляется файл Form1.h с шаблоном (функции button4_Click), который после записи нашего кода принимает такой вид.
Листинг 47.6.Метод для кнопки “Скрыть Мага”.
private void button4_Click(object sender, EventArgs e)
{
//Скрыть персонаж:
myMerlin.Hide(0);
}
Аналогично, чтобы записать нашу часть кода для показа на экране монитора третьего персонажа Peedy (Попугай) при помощи кнопки “Показать Попугая” на Form1 (рис. 47.5), дважды щелкаем эту кнопку в режиме редактирования. Появляется файл Form1.h с шаблоном (функции button5_Click), который после записи нашего кода принимает такой вид.
Листинг 47.7. Метод для кнопки “Показать Попугая”.
private void button5_Click(object sender, EventArgs e)
{
//От начала координат в вехнем левом углу Form1
//задаем координаты "x,y" места расположения персонажа:
myPeedy.MoveTo(
Convert.ToInt16(this.Location.X + 400),
Convert.ToInt16(this.Location.Y - 130), 1000);
//Показать персонаж в заданном месте:
myPeedy.Show(0);
//Чтобы персонаж произносил речь через динамики,
//задаем ему следующие свойства:
myAgentController = new AgentObjects.Agent();
myAgentController.Connected = true;
myAgentController.Characters.Load(
"peedy", "peedy.acs");
myPeedy =
myAgentController.Characters.Character("peedy");
//Персонаж произносит текст из окна TextBox
//и показывает этот текст в виде подсказки:
myPeedy.Speak(textBox3.Text, myObject);
}
Чтобы удалить персонаж с экрана монитора при помощи кнопки “Скрыть Попугая ” на Form1 (рис. 47.5), дважды щелкаем эту кнопку в режиме редактирования. Появляется файл Form1.h с шаблоном (метода button6_Click), который после записи нашего кода принимает такой вид.
Листинг 47.8.Метод для кнопки “Скрыть Попугая”.
private void button6_Click(object sender, EventArgs e)
{
//Скрыть персонаж:
myPeedy.Hide(0);
}
Аналогично, чтобы записать нашу часть кода для показа на экране монитора последнего четвертого персонажа Robby (Робот) при помощи кнопки “Показать Робота” на Form1 (рис. 47.5), дважды щелкаем эту кнопку в режиме редактирования. Появляется файл Form1.h с шаблоном (метода button7_Click), который после записи нашего кода принимает такой вид.
Листинг 47.9.Метод для кнопки “Показать Робота”.
private void button7_Click(object sender, EventArgs e)
{
//От начала координат в вехнем левом углу Form1
//задаем координаты "x,y" места расположения персонажа:
myRobby.MoveTo(
Convert.ToInt16(this.Location.X + 400),
Convert.ToInt16(this.Location.Y - 130), 1000);
//Показать персонаж в заданном месте:
myRobby.Show(0);
//Чтобы персонаж произносил речь через динамики,
//задаем ему следующие свойства:
myAgentController = new AgentObjects.Agent();
myAgentController.Connected = true;
myAgentController.Characters.Load(
"robby", "robby.acs");
myRobby =
myAgentController.Characters.Character("robby");
//Персонаж произносит текст из окна TextBox
//и показывает этот текст в виде подсказки:
myRobby.Speak(textBox4.Text, myObject);
}
Чтобы удалить персонаж с экрана монитора при помощи кнопки “Скрыть Робота ” на Form1 (рис. 47.5), дважды щелкаем эту кнопку в режиме редактирования. Появляется файл Form1.h с шаблоном (метода button8_Click), который после записи нашего кода принимает такой вид.
Листинг 47.10. Метод для кнопки “Скрыть Робота”.
private void button2_Click(object sender, EventArgs e)
{
//Скрыть персонаж:
myRobby.Hide(0);
}
Теперь, следуя алгоритму в первом параграфе, мы записываем такой код, чтобы после нашего щелчка мышью по любому персонажу, этот персонаж:
1) выполнял анимацию, например, Confused (Смущенный);
2) произносил текст, например, такой: Есть проблемы?;
3) выполнял заключительную анимацию, например, в виде расслабленной позы отдыха RestPose. Для этого в панели Properties выбираем заголовок axAgent1 и на вкладке Events дважды щелкаем по имени события ClickEvent (рис. 47.10).
Появляется файл Form1.cs с шаблоном (метода axAgent1_ClickEvent), который после записи нашего кода (согласно алгоритму) принимает вид листинга 47.11. Аналогично в панели Properties последовательно выбираем заголовки для других элементов управления (axAgent2, axAgent3, axAgent4) и на вкладке Events дважды щелкаем по имени события ClickEvent. Появляется файл Form1.cs с шаблонами, которые после записи нашего кода принимают вид листингов 47.12, 47.13, 47.14.
Листинг 47.11.Метод, обрабатывающий щелчок по персонажу Genie.
private void axAgent1_ClickEvent(object sender,
AxAgentObjects._AgentEvents_ClickEvent e)
{
//Персонаж выполняет анимацию Confused:
myGenie.Play("Confused");
//Персонаж произносит текст:
mySpeech = "Есть проблемы?";
myGenie.Speak(mySpeech, myObject);
//Персонаж выполняет анимацию RestPose:
myGenie.Play("RestPose");
}
Листинг 47.12.Метод, обрабатывающий щелчок по персонажу Merlin.
private void axAgent2_ClickEvent(object sender,
AxAgentObjects._AgentEvents_ClickEvent e)
{
//Персонаж выполняет анимацию Confused:
myMerlin.Play("Confused");
//Персонаж произносит текст:
mySpeech = "Имеются проблемы?";
myMerlin.Speak(mySpeech, myObject);
//Персонаж выполняет анимацию RestPose:
myMerlin.Play("RestPose");
}
Листинг 47.13.Метод, обрабатывающий щелчок по персонажу Peedy.
private void axAgent3_ClickEvent(object sender,
AxAgentObjects._AgentEvents_ClickEvent e)
{
//Персонаж выполняет анимацию Confused:
myPeedy.Play("Confused");
//Персонаж произносит текст:
mySpeech = "Попка умный и хочет есть.";
myPeedy.Speak(mySpeech, myObject);
//Персонаж выполняет анимацию RestPose:
myPeedy.Play("RestPose");
}
Листинг 47.14.Метод, обрабатывающий щелчок по персонажу Robby.
private void axAgent4_ClickEvent(object sender,
AxAgentObjects._AgentEvents_ClickEvent e)
{
//Персонаж выполняет анимацию Confused:
myGenie.Play("Confused");
//Персонаж произносит текст:
mySpeech = "Есть проблемы?";
myGenie.Speak(mySpeech, myObject);
//Персонаж выполняет анимацию RestPose:
myGenie.Play("RestPose");
}
Листинг 47.15.Метод, чтобы Джин выполнял наши голосовые команды.
//Объявляем глобальный объект myCommand интерфейса
static AgentObjects.IAgentCtlUserInput myCommand;
private void axAgent1_Command(object sender,
AxAgentObjects._AgentEvents_CommandEvent e)
{
//Связываем объект myCommand с голосом пользователя:
myCommand =
(AgentObjects.IAgentCtlUserInput)(e.userInput);
//После команды голосом "MoveToMouse"
//персонаж перемещается на место курсора мыши:
if (myCommand.Voice == "MoveToMouse")
{
myGenie.MoveTo(
Convert.ToInt16(Cursor.Position.X),
Convert.ToInt16(Cursor.Position.Y), 1000);
}
//После команды голосом "Merlin"
//прежний персонаж скрывается, а новый появляется:
if (myCommand.Voice == "Merlin")
{
//Скрыть прежний персонаж:
myGenie.Hide(0);
//От начала координат в верхнем левом углу Form1
//задаем координаты "x,y" места нового персонажа:
myMerlin.MoveTo(
Convert.ToInt16(this.Location.X + 400),
Convert.ToInt16(this.Location.Y - 130), 1000);
//Показать новый персонаж в заданном месте:
myMerlin.Show(0);
//Чтобы персонаж произносил речь через динамики,
//задаем ему следующие свойства:
myAgentController = new AgentObjects.Agent();
myAgentController.Connected = true;
myAgentController.Characters.Load(
"merlin", "merlin.acs");
myMerlin =
myAgentController.Characters.Character("merlin");
//Новый персонаж произносит речь:
mySpeech = "Я - Маг. Есть проблемы?";
myMerlin.Speak(mySpeech, myObject);
}
}
Поясним этот код. После нашей голосовой команды Hide текущий персонаж скрывается (без написания дополнительного кода в данном листинге). Но если мы хотим, чтобы после произнесения нами одного из заданных по умолчанию имен персонажей (Genie, Merlin, Peedy, Robby), этот озвученный новый персонаж не просто появился в верхнем левом углу экрана, а появился в заданном нами месте и после этого произнес речь, мы должны записать это в коде, что мы и сделали в этом листинге.
Аналогично (для следующего персонажа) в панели Properties выбираем заголовок следующего элемента управления axAgent2 и на вкладке Events дважды щелкаем по имени события Command.
Появляется файл Form1.h с шаблоном (метода axAgent1_Command), который после записи нашего кода (согласно алгоритму) принимает следующий вид.
Листинг 47.16.Метод, чтобы Маг выполнял наши голосовые команды.
private void axAgent2_Command(object sender,
AxAgentObjects._AgentEvents_CommandEvent e)
{
//Связываем объект myCommand с голосом пользователя:
myCommand =
(AgentObjects.IAgentCtlUserInput)(e.userInput);
//После команды голосом "MoveToMouse"
//персонаж перемещается на место курсора мыши:
if (myCommand.Voice == "MoveToMouse")
{
myMerlin.MoveTo(
Convert.ToInt16(Cursor.Position.X),
Convert.ToInt16(Cursor.Position.Y), 1000);
}
//После команды голосом "Peedy"
//прежний персонаж скрывается, а новый появляется:
if (myCommand.Voice == "Peedy")
{
//Скрыть прежний персонаж:
myMerlin.Hide(0);
//От начала координат в верхнем левом углу Form1
//задаем координаты "x,y" места нового персонажа:
myPeedy.MoveTo(
Convert.ToInt16(this.Location.X + 400),
Convert.ToInt16(this.Location.Y - 130), 1000);
//Показать новый персонаж в заданном месте:
myPeedy.Show(0);
//Чтобы персонаж произносил речь через динамики,
//задаем ему следующие свойства:
myAgentController = new AgentObjects.Agent();
myAgentController.Connected = true;
myAgentController.Characters.Load(
"peedy", "peedy.acs");
myPeedy =
myAgentController.Characters.Character("peedy");
//Новый персонаж произносит речь:
mySpeech = "Я - Попугай. Есть проблемы?";
myPeedy.Speak(mySpeech, myObject);
}
}
Аналогично (для следующего персонажа) в панели Properties выбираем заголовок следующего элемента управления axAgent3 и на вкладке Events дважды щелкаем по имени события Command. Появляется файл Form1.cs с шаблоном (метода axAgent3_Command), который после записи нашего кода (согласно алгоритму) принимает следующий вид.
Листинг 47.17.Метод, чтобы Попугай выполнял наши голосовые команды.
private void axAgent3_Command(object sender,
AxAgentObjects._AgentEvents_CommandEvent e)
{
//Связываем объект myCommand с голосом пользователя:
myCommand =
(AgentObjects.IAgentCtlUserInput)(e.userInput);
//После команды голосом "MoveToMouse"
//персонаж перемещается на место курсора мыши:
if (myCommand.Voice == "MoveToMouse")
{
myPeedy.MoveTo(
Convert.ToInt16(Cursor.Position.X),
Convert.ToInt16(Cursor.Position.Y), 1000);
}
//После команды голосом "Robby"
//прежний персонаж скрывается, а новый появляется:
if (myCommand.Voice == "Robby")
{
//Скрыть прежний персонаж:
myPeedy.Hide(0);
//От начала координат в верхнем левом углу Form1
//задаем координаты "x,y" места нового персонажа:
myRobby.MoveTo(
Convert.ToInt16(this.Location.X + 400),
Convert.ToInt16(this.Location.Y - 130), 1000);
//Показать новый персонаж в заданном месте:
myRobby.Show(0);
//Чтобы персонаж произносил речь через динамики,
//задаем ему следующие свойства:
myAgentController = new AgentObjects.Agent();
myAgentController.Connected = true;
myAgentController.Characters.Load(
"robby", "robby.acs");
myRobby =
myAgentController.Characters.Character("robby");
//Новый персонаж произносит речь:
mySpeech = "Я - Робот. Есть проблемы?";
myRobby.Speak(mySpeech, myObject);
}
}
Аналогично (для следующего персонажа) в панели Properties выбираем заголовок следующего элемента управления axAgent4 и на вкладке Events дважды щелкаем по имени события Command. Появляется файл Form1.cs с шаблоном (метода axAgent4_Command), который после записи нашего кода (согласно алгоритму) принимает следующий вид.
Листинг 47.18.Метод, чтобы Робот выполнял наши голосовые команды.
private void axAgent4_Command(object sender,
AxAgentObjects._AgentEvents_CommandEvent e)
{
//Связываем объект myCommand с голосом пользователя:
myCommand =
(AgentObjects.IAgentCtlUserInput)(e.userInput);
//После команды голосом "MoveToMouse"
//персонаж перемещается на место курсора мыши:
if (myCommand.Voice == "MoveToMouse")
{
myRobby.MoveTo(
Convert.ToInt16(Cursor.Position.X),
Convert.ToInt16(Cursor.Position.Y), 1000);
}
//После команды голосом "Genie"
//прежний персонаж скрывается, а новый появляется:
if (myCommand.Voice == "Genie")
{
//Скрыть прежний персонаж:
myRobby.Hide(0);
//От начала координат в верхнем левом углу Form1
//задаем координаты "x,y" места нового персонажа:
myGenie.MoveTo(
Convert.ToInt16(this.Location.X + 400),
Convert.ToInt16(this.Location.Y - 130), 1000);
//Показать новый персонаж в заданном месте:
myGenie.Show(0);
//Чтобы персонаж произносил речь через динамики,
//задаем ему следующие свойства:
myAgentController = new AgentObjects.Agent();
myAgentController.Connected = true;
myAgentController.Characters.Load(
"genie", "genie.acs");
myGenie =
myAgentController.Characters.Character("genie");
//Новый персонаж произносит речь:
mySpeech = "Я - Джин. Есть проблемы?";
myGenie.Speak(mySpeech, myObject);
}
}
Отметим, что в программе речь персонажа мы можем записать не только на одной строке кода, но и на многих строках, как выше мы уже делали, например, при помощи такого кода:
mySpeech = "Попка умный " +
"и хочет есть.";
Аналогично мы можем записать код для решения любой подобной задачи согласно разработанному нами алгоритму.
Cтроим программу и запускаем на выполнение обычным образом: Build, Build Solution; Debug, Start Without Debugging. В ответ Visual C# выполняет программу и на рабочий стол выводит форму Form1 в режиме выполнения.
После щелчка первой кнопки “Показать Джина” появляется первый персонаж Genie (Джин) и произносит (через динамики компьютера) приветствующий нас текст (“Здравствуйте. Меня зовут Джин”), который мы записали выше в код программы.
В заключении этой главы дадим некоторые рекомендации по устранению ошибок, когда в режиме выполнения мы видим персонаж, но после нажатия клавиши Scroll Lock мы не видим никакой реакции персонажа на наше нажатие.