Эта статья была впервые опубликована на:Уокер ИИ
При разработке игрового проекта необходимо построить платформу автоматизированного тестирования, чтобы использовать автоматизацию для тестирования внутриигровых сражений, находить внутриигровые ошибки, избегать дублирования работы, повышать эффективность тестирования и избегать ошибок в работе человека. Среда требует, чтобы проект использовал Airtest и poco для подключения к серверу обучения с подкреплением, чтобы Airtest отправлял информацию о состоянии на сервер, а сервер возвращал следующее решение.
1. Предварительные приготовления
Узнайте, как Airtest, poco и агенты обучения с подкреплением принимают решения.
1.1 Введение в аэротест
Airtest — это автоматизированная среда тестирования, основанная на распознавании изображений. Суть этого фреймворка не в методе и технологии реализации, а в концепции! Идея этого фреймворка заимствована из результатов исследования MIT (Массачусетского технологического института) Сикули, который задумал новый режим тестирования пользовательского интерфейса, основанный на элементах управления распознаванием изображений, а не на конкретных объектах управления памятью.
(1) Особенности аэротеста
- Поддерживает программируемые инструменты тестирования на основе распознавания изображений
- Кроссплатформенность
- Создать тестовый отчет
- Поддержка poco и других встроенных SDK, повышение точности распознавания пользовательского интерфейса
(2) Интерфейс Airtest (включая щелчок, слайд, оценку, снимок экрана и другие интерфейсы)
(3) Демонстрация эффекта Airtest
Приведенная выше демонстрация показывает, что Airtest взаимодействует с интерфейсом напрямую посредством распознавания изображений. Если вам нужно взаимодействовать с указанными элементами интерфейса, вам потребуются методы, предоставляемые Poco для работы с элементами интерфейса.
(4) Ограничения по воздушному тесту
Однако в реальном проекте изображение не будет статичным, нам нужно захватить динамические узлы проекта и щелкнуть, переместить и другие операции с динамическими узлами (например, узел местоположения купленного в магазине флага)
Нам нужен еще один инструмент, Поко.
1.2 Введение в Poco
В настоящее время Poco поддерживает только собственные вызовы интерфейса Android и ios, другим платформам требуется доступ к SDK соответствующей платформы.
(1) Как Poco получает дерево пользовательского интерфейса
Перемещайтесь по дочерним узлам от корневого узла вниз
В проекте единства вам необходимо установить SDK Poco в единстве
(2) Метод вызова Poco
(3) Пример вызова Poco
poco = UnityPoco()
poco('btn_start').click()
Airtest вызывает pocosdk в единстве через интерфейс, SDK проходит через все дерево пользовательского интерфейса и отправляет выгруженную информацию json обратно в Airtest.
Airtest находит информацию о расположении элемента «btn_start» в полученном дереве пользовательского интерфейса и щелкает adb.
1.3 Краткое введение в обучение с подкреплением
Среда обычно описывается марковским процессом: Агент генерирует Действие, принимая определенную Политику, взаимодействует со Средой и генерирует Вознаграждение. Затем Агент корректирует и оптимизирует текущую Политику в соответствии с Вознаграждением.
Используя приведенный выше рисунок, чтобы объяснить более наглядно, состояние - это состояние среды, а наблюдение - это состояние среды, наблюдаемое агентом.Здесь наблюдение и состояние означают одно и то же. Сначала агент наблюдает за состоянием окружающей среды, например, за стаканом воды, а затем принимает определенное поведение, которое заключается в том, что агент разбивает воду в стакане, так что состояние окружающей среды изменилось, и затем система отреагирует на это. Поведению присваивается оценка, чтобы сообщить агенту, является ли поведение правильным, а затем в соответствии с недавно измененным состоянием среды агент принимает дальнейшее поведение. Цель, которую преследует Агент, — сделать Вознаграждение максимально большим.
2. Процесс выполнения проекта:
2.1 Предыстория
Развернув обученный агент на сервере, другие могут получить доступ к серверу с помощью следующего процесса:
А. Тестовая сторона собирает информацию -> тестовая сторона преобразует информацию в согласованный формат состояния -> тестовая сторона отправляет состояние на сервер -> сервер возвращает решение агента -> тестовая сторона получает информацию и выполняет решение ->
Б. Тестовая сторона собирает информацию (начало нового цикла)...
В этом процессе на этапе тестирования больше всего времени уходит на сбор информации, и часть ее решается оптимизировать в соответствии с требованиями проекта.
2.2 Конкретные вопросы
Когда poco вызывает интерфейс дампа в первый раз, он запускает большое количество mincap и многих других исполняемых файлов, что приводит к задержке около 7 секунд.
Задержка, обнаруженная в операции Airtest, была слишком серьезной, в результате чего за раунд выполнялось всего 4-5 действий в течение 30 секунд рабочего времени игры.
Однако количество операций за раунд локально обученного агента может достигать примерно 16 на более позднем этапе, так что более поздние действия агента не могут быть полностью выполнены на клиенте.
2.3 Решения
Загрузить событие щелчка poco заранее
Поиск дампа занимает много времени, поэтому я решил начать с интерфейса sdk, чтобы уменьшить размер файла json из дампа.
А. В интерфейсе Unity добавьте параметры tagfilter, blacklist, propertylist для управления размером файла json.
Среди них tagfilter используется для фильтрации объекта unitygame по указанному тегу, который может удалить все объекты, кроме UI и Default.
черный список используется для фильтрации имени объекта unitygame, что может повысить эффективность дампа на 50%
Список свойств используется для уменьшения записи параметров одного объекта unitygame.По умолчанию один объект имеет более 10 параметров.После фильтрации можно сохранить около 6 параметров. Может повысить эффективность дампа на 33%
б. Используйте соответствующие параметры интерфейса в интерфейсе python
Этот метод прекрасно решает проблему задержки выполнения, на данный момент клиент может выполнить около 20 действий за 30 секунд за один раунд.
2.4 Конкретные шаги:
layerfilter В этом проекте 13 слоев. Рекурсивно записывайте только информацию о подузлах в UGO, чьи теги являются пользовательским интерфейсом и по умолчанию, и удаляйте сцены, специальные эффекты и другие слои, что может значительно снизить накладные расходы.
namefilter Не вся информация об узлах пользовательского интерфейса является необходимыми данными, которые должны быть получены автоматическими тестами. Следовательно, при рекурсивном запросе дочерних узлов при встрече с именем UGO, записанным в черный список, накладные расходы времени могут быть сокращены примерно на 50%.
В основном измените интерфейс dumpHierarchyImpl в AbstractDumper в poco C#, как показано на рисунке:
private Dictionary<string, object> dumpHierarchyImpl (AbstractNode node, bool onlyVisibleNode, Dictionary<string, object> extrapar)
{
if (node == null)
{
return null;
}
Dictionary<string, object> payload = new Dictionary<string, object>();
if (extrapar != null && extrapar.ContainsKey("param4") && extrapar["param4"] != null)
{
payload = node.enumerateAttrs(extrapar["param4"].ToString());
}
else
{
payload = node.enumerateAttrs(null);
}
Dictionary<string, object> result = new Dictionary<string, object> ();
string name = (string)node.getAttr ("name");
result.Add ("name", name);
result.Add ("payload", payload);
List<object> children = new List<object>();
if (extrapar!= null)
{
if (extrapar.ContainsKey("param3") && extrapar["param3"] != null)
{
requirelayer = extrapar["param3"].ToString().Split('|').ToList();
string layer = (string)node.getAttr("layer");
if (!requirelayer.Contains(layer))
{
//Debug.LogError("--dumpHierarchyImpl layer is not contains");
return result;
}
}
if (extrapar.ContainsKey("param2") && extrapar["param2"] != null)
{
try
{
filterlist.Clear();
string str = extrapar["param2"].ToString();
filterlist = str.Split('|').ToList();
}
catch
{
Debug.LogError("~~~dumpHierarchy Implextrapar param2 error");
}
if (filterlist.Contains(name))
{
return result;
}
}
}
foreach (AbstractNode child in node.getChildren())
{
if (!onlyVisibleNode || (bool)child.getAttr ("visible"))
{
children.Add (dumpHierarchyImpl (child, onlyVisibleNode, extrapar));
}
}
if (children.Count > 0)
{
result.Add ("children", children);
}
return result;
}
Параметр узла, сбрасываемый параметром propertyfilter json, по умолчанию включает:
Такие параметры, как имя, полезная нагрузка, тип, видимость, позиция, размер, масштаб, anchorPoint, zOrders, кликабельность, компоненты, _ilayer, слой, _instanceId и т. д. мы устранили
visible|scale|anchorPoint|clickable|components|_ilayer|layer|_instanceId — это параметр, который на самом деле не используется, что значительно уменьшает размер файла дампа json, что может сократить накладные расходы времени примерно на 33%.
В основном измените интерфейсы enumerateAttrs и GetPayload в UnityNode в poco C# следующим образом:
private Dictionary<string, object> GetPayload(string blackList)
{
Dictionary<string, object> all = new Dictionary<string, object>() {
{ "name", gameObject.name },
{ "type", GuessObjectTypeFromComponentNames (components) },
{ "visible", GameObjectVisible (renderer, components) },
{ "pos", GameObjectPosInScreen (objectPos, renderer, rectTransform, rect) },
{ "rawpos", GameObjectVec3Pos (objectRawPos) },
{ "rawrectpos", GameObjectVec3Pos (objectRectRawPos) },
{ "size", GameObjectSizeInScreen (rect, rectTransform) },
{ "scale", new List<float> (){ 1.0f, 1.0f } },
{ "anchorPoint", GameObjectAnchorInScreen (renderer, rect, objectPos) },
{ "zOrders", GameObjectzOrders () },
{ "clickable", GameObjectClickable (components) },
{ "text", GameObjectText () },
{ "components", components },
{ "texture", GetImageSourceTexture () },
{ "tag", GameObjectTag () },
{ "_ilayer", GameObjectLayer() },
{ "layer", GameObjectLayerName() },
{ "_instanceId", gameObject.GetInstanceID () },
};
Dictionary<string, object> payload = new Dictionary<string, object>();
if (!string.IsNullOrEmpty(blackList))
{
List<string> black_list = blackList.Split('|').ToList();
foreach(KeyValuePair<string, object> it in all)
{
if(black_list.Contains(it.Key))
{
continue;
}
payload.Add(it.Key,it.Value);
}
}
else
{
payload = all;
}
return payload;
}
PS: Для получения дополнительной технической галантереи, пожалуйста, обратите внимание на [Публичный аккаунт | xingzhe_ai] и обсудите с ходоками!