В предыдущих постах про Октодон мы уже не раз упоминали о скорости печати, которую нам удалось достигнуть, и получили много вопросов, сколько же надо для этого тренироваться.
На определенном этапе этим вопросом задались и мы, а способ получить ответ только один — тестировать. В этой статье я расскажу, как мы обучались печати на собственной клавиатуре и сделали приложение для Android, где каждый может узнать свою скорость печати и посоревноваться с другими людьми, использующими другие методы ввода!
Обучающее приложение
Изначальный замысел — по примеру других клавиатур (вроде игр MessagEase), сделать обучающее приложение с несколькими уровнями:
- Тренировка отдельных букв. Юзер знакомится с нашей раскладкой, поочередно осваивая задние джойстики.
- Тренировка слов и распространённых буквосочетаний. Юзер узнаёт, что раскладка оптимизирована для самых частотных диадтриад (например: no | on | at | er | the | and и т.п.)
- Тренировка слов. Юзер печатает небольшие текстыстихи и постепенно превращается из новичка в полноценного пользователя.
Художник вооружился фотографией зверька Octodon Degus и сделал нам арт, а я взялся за программирование. Имея небольшой опыт геймдева под iOS, я полагал, что средств родного Android-фреймворка хватит, чтобы сделать небольшую игру с примитивной анимацией из спрайтов. Однако я жестоко ошибался. Несколько потраченных впустую дней привели меня на форум с целой веткой из нецензурных сообщений, касающихся сильных тормозов и глюков при работе с 2D графикой, с которыми я и столкнулся.
Отложив грабли в сторону, я занялся тем, что должен был сделать сразу — нагуглил замечательный движок AndEngine. Для решения большинства задач мне хватило примеров из репозитория AndEngineExamples. Также в сети обитает множество туториалов и большой форум пользователей.
public class MenuActivity extends BaseGameActivity implements Scene.IOnSceneTouchListener {
private Camera mCamera;
private MenuResMan resMan;
//инициализируем движок и камеру
@Override
public Engine onLoadEngine() {
this.mCamera = new Camera(0, 0, UIConstants.CAMERA_WIDTH, UIConstants.CAMERA_HEIGHT);
return new Engine(new EngineOptions(true, ScreenOrientation.PORTRAIT, new RatioResolutionPolicy(UIConstants.CAMERA_WIDTH, UIConstants.CAMERA_HEIGHT), this.mCamera));
}
//загружаем ресурсы
@Override
public void onLoadResources() {
resMan = new MenuResMan(this);
resMan.LoadResources();
}
//загружаем сцену
@Override
public Scene onLoadScene() {
mEngine.registerUpdateHandler(new FPSLogger());
final Scene scene = resMan.LoadScene();
scene.setOnSceneTouchListener(this);
String lang = getApplicationContext().getResources().getConfiguration().locale.getLanguage();
testingModel.ChangeLang(lang);
return scene;
}
@Override
public void onLoadComplete() {
<...>
}
@Override
protected void onCreate(Bundle pSavedInstanceState) {
<...>
}
@Override
protected void onStop() {
<...>
}
Для перехода между экранами меню я создаю дочерние сцены с необходимым контентом (для самой игры и других больших элементов создается отдельная activity) и добавляю следующий код для корректной работы кнопки Back:
@Override
public void onBackPressed()
{
Scene scene = this.mEngine.getScene();
if(scene.hasChildScene()){
scene.back();
}
else{
this.finish();
}
}
Всю работу с ресурсами (загрузка картинок, шрифтов, звуков, создание сцены и ее компоновка) находится в отдельном классе ResMan.
public class MenuResMan {
private BaseGameActivity activity;
private BitmapTextureAtlas textFontTexture;
public Font textFont;
private BitmapTextureAtlas backgroundTexture;
public TextureRegion mainBackgroundRegion;
public Sprite mainBackground;
public void LoadResources()
{
BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("Menu/");
//должны быть степени двойки
backgroundTexture = new BitmapTextureAtlas(512, 1024, TextureOptions.REPEATING_BILINEAR_PREMULTIPLYALPHA);
textFont = new Font(textFontTexture, Typeface.create(Typeface.DEFAULT, Typeface.NORMAL),
UIConstants.TEXT_FONT_SIZE, true, Color.BLACK);
activity.getTextureManager().loadTexture(backgroundTexture);
activity.getTextureManager().loadTexture(textFontTexture);
activity.getFontManager().loadFont(textFont);
mainBackgroundRegion = BitmapTextureAtlasTextureRegionFactory
.createFromAsset(backgroundTexture, activity, "mymenu.png", 0, 0); //480x800
<...>
}
public Scene LoadScene()
{
Scene scene = new Scene();
mainBackground = new Sprite(0,0,mainBackgroundRegion);
scene.attachChild(mainBackground);
Rectangle textBackground = new Rectangle(0,0,
UIConstants.CAMERA_WIDTH - UIConstants.BORDER_WIDTH*2,
UIConstants.CAMERA_HEIGHT - UIConstants.BORDER_WIDTH*2 - headerBackground.getHeight()
);
speedText = new ChangeableText(UIConstants.TESTING_BORDER_WIDTH, UIConstants.TESTING_BORDER_WIDTH, headerFont, " ", 10);
textBackground .attachChild(speedText);
scene.attachChild(textBackground);
//аттач всего необходимого к сцене
<...>
return scene;
}
public MenuResMan(BaseGameActivity activity)
{
this.activity = activity;
}
}
Далее осталось аналогичным образом создать активность для игры и подключить игровые графические элементы. Есть некоторые тонкости, (например, чтобы была возможность менять цвет текста, используемый шрифт должен быть инициализирован в белом цвете), но в целом движок крайне прост для освоения.
Эту программу с некоторыми доработками мы выложим одновременно с выпуском Октодона, а пока она обучает на первых этапах наших тестеров и дожидается своего часа.
Сбор статистики
Параллельно с разработкой, мы решили обратиться к признанным специалистам по клавиатурам Logitech и спросить, как они оценивают новые клавиатуры. В ответ нам прислали методику тестирования (о том, как мы проводили по ней тесты — в следующих постах), включающую использование специального онлайн-сервиса. Однако он не работал браузерах на Android, а найденные в вебе и на GooglePlay аналоги в были очень куцые и предоставляли либо мало данных, либо вообще давали использовать только встроенную в них клавиатуру.
Мы пришли к выводу, что писать надо своё, тем более, что у нас уже есть готовый уровень для работы с текстами из обучающей игры. Оставалось добавить туда возможность быстро подгружать свои тексты и, для отслеживания скорости, способность замерять основные показатели печати:
- Time — время тренировки, для последующего вычисления «Х в минуту»
- CorrectEntries, IncorrectEntries, FixedMistakes — основная подсчитываемая тройка, из которой вычисляется все остальное
- TotalEntries = CorrectEntries + IncorrectEntries
- ErrorRate = (IncorrectEntries − FixedMistakes) / Time
- KeySpeed = (CorrectEntries + FixedMistakes) / Time — метрика, более известная как CPM
- RawSpeed = TotalEntries / (5*Time) — коэффициент 5 используется повсеместно, как средняя длина слова в англ.языке, т.е. показатель означает слова в минуту, но без учета ошибок
- Speed = KeySpeed / 5 — главная метрика, более известная как WPM, стандарт для оценки скорости печати.
- Accuracy = 100*CorrectEntries / TotalEntries — точность в процентах
В итоговом лаконичном приложении «Typing Test» пользователь предварительно пишет свое имя, метод ввода, выбирает текст и время тренировки, на выходе получает лог со статистикой. Можно сделать скриншот и твит счёта. Также есть отдельный уровень с каноническим текстом про пираний, на котором можно попробовать установить новый мировой рекорд.
Мы думаем, что идея измерения скорости печати будет интересна многим, поэтому решили выложить приложение на GooglePlay и планируем развивать это приложение и далее, но уже независимо от Октодона. Как сервис, на котором можно будет замерять производительность ввода на любой клавиатуре и для любого языка, где эти результаты можно будет наглядно сравнить и проанализировать статистику.
Приложение на GooglePlay
Кривые обучения
Сбор статистики был очень нужен нам ещё и по маркетинговым причинам. Если проводить тестирование Октодона на случайных людях в течение небольшого времени, то, конечно, мы получим далеко не впечатляющие результаты. Есть много причин, почему так происходит: метод ввода новый, юзер в шоке, что за баян на телефоне и т.д. Но без материальных доказательств это звучит неубедительно, как для потребителей, так и для инвесторов.
Кривая обучения — очень веский аргумент в таком споре, она позволяет показать якобы мучительный процесс обучения в реальном свете. При достаточной выборке она показывает реальную динамику — определенное время тренировки перерастает в определенную скорость печати.
Каждый сеанс тестирования проводился на случайном тексте из 5 существующих, ограничение по времени — 3 минуты. Ниже представлены графики по собранным данным. На оси X отмечено суммарное время, потраченное на набор текстов пользователем.
По количеству слов в минуту:
По точности:
Вот график для скорости по всем имеющимся данным без масштабирования:
Из графиков можно сделать несколько выводов:
- Самый важный для нас — что даже при достигнутой скорости печати в 40-45 WPM, кривая обучения не имеет тенденции к выполаживанию, значит практический предел обучения еще не достигнут.
- Скорость обучения индивидуальна для каждого, однако, примерно через час человек достигает комфортных для работы 20WPM. Что примерно в полтора раза больше скорости среднего пользователя (по данным нашего тестирования) на экранной qwerty-клавиатуре.
- После перехода на слепую печать требуется около часа, чтобы восстановить свою прежнюю скорость.
- Точность так же индивидуальна, и зависит прежде всего от внимательности пользователя и его желания писать без ошибок.
На данный момент, в целях улучшения раскладки, мы начали сбор статистики по времени между нажатиями различных пар-направлений джойстиков и думаем, что бы собирать помимо этого (будем рады вашим идеям и предложениям).
В следующих постах мы расскажем про наше массовое тестирование методов ввода на пользователях, процесс создания раскладки для Октодона, также вас ждет обзор back-typing клавиатуры AlphaGrip. Оставайтесь с нами! :)
Автор: kotlyarovsa