Продолжение истории разработки мобильного приложения iOS/Android для мотивации детей заниматься математикой


Это вторая часть истории (вперемешку с рассказом о моих ошибках и их решениях) о том, как я (где-то два года в свободное время) разрабатывал мобильное приложение (под iOS/Android), которое бы мотивировало мою дочь решать примеры по математике. В итоге, получилось приложение, позволяющее ребёнку зарабатывать деньги своим умом.


Первую часть читайте тут.


План второй части


  • О написании кода
  • О контроле версий
  • Об озвучке
  • Об иконке
  • О сборке под Android и о размере
  • О сборке под iOS и о размере
  • О названии и продвижении
  • Статистика
  • О чём жалею
  • Что понял
  • Ссылки

Мелочи в программировании, которые упрощают мне жизнь


  • Ещё с Mono продолжаю использовать //TODO (в комментариях) для отметок мест, которые нужно доработать. Потом, все эти места можно удобно мониторить на закладке Task List (вызывается Ctrl+\, T):

Использования //todo для создания списка задач


  • Недавно начал пользоваться такой фичей как #region, чтобы, к примеру, прятать области перечисления переменных:

использование regions в коде


  • удобно обёртывать часть кода какими-то конструкциями с помощью последовательности горячих клавиш Ctrl+K, Ctrl+S. К примеру, выделяю часть кода, который нужно поместить внутрь if и жму Ctrl+K, а потом сразу же Ctrl+S, ввожу название нужно оператора (if) и жму Enter.
  • очень упрощает работу с кодом, если придерживаться единого стиля, к примеру, как здесь — C# Style Guide with Unity in mind.
  • я очень рад, что подружился с корутинами (Coroutine) — это, если грубо, такие функции, которые растягивают своё выполнение на несколько фреймов. Т.е. они не пытаются любую задачу выполнить за один кадр (просчитывая его полсекунды, понижая тем самым быстродействие до 2 FPS), а делают немножко в первом кадре, немножко во втором и так далее, чтобы игра не тормозила. Другое их назначение — выполнять что-то такое, что не нужно делать прям в каждом кадре (к примеру, проверять что-то 3 раза в секунду).

Пример ниже показывает корутину светофора, которая бесконечно (каждые десять секунд) зажигает по очереди жёлтый, красный, зелёный свет:


IEnumerator TrafficLights()
{                                 
    while (true)
        {
            yield return new WaitForSeconds(10f);      
            yield StartCoroutine(this.GetComponent<Lamp>().BlinkYellow());
            yield StartCoroutine(this.GetComponent<Lamp>().BlinkRed());
            yield StartCoroutine(this.GetComponent<Lamp>().BlinkGreen());
        }
}

Если человеческим языком, то инструкция yield как раз и говорит Unity, что нужно переносить выполнение функции в следующий кадр (столько раз, сколько потребуется) пока она не выполнится, а потом приступать к следующей yield инструкции. Т.о. корутина TrafficLights будет выполняться так:


  1. сначала идёт ожидание 10 секунд (первый yield),
  2. потом запускается корутина BlinkYellow (второй yield) и пока она не завершиться, корутина BlinkRed не запуститься,
  3. по завершению BlinkYellow запускается BlinkRed,
  4. по завершению BlinkRed запускается BlinkGreen,
  5. дальше цикл повторяется с начала (смотреть пункт 1).

Контроль версий, ну просто очень надо!


Видео, которое мне помогло начать использовать GitHub в связке с Unity — How to use GitHub with Unity.


Несмотря на то, что я сам (в одиночку, без команды) пишу код, я понял, что контроль версий кода мне просто жизненно необходим:


  • Я перестал боятся делать какие-то кардинальные изменения в коде, что могут запороть проект.
  • Очень легко вернуться к прежнему рабочему состоянию.
  • Удобно сравнивать файлы с кодом.
  • Можно наглядно видеть, что поменялось в коде.
  • Неважно что случается с моим компом — у меня всегда есть запасная версия в облаке.

Вот только при работе с контролем версий нужно приучить себя комитить (постить обновления) очень маленькими порциями. Чтобы не было как у меня поначалу — изменил 20 файлов, добавил тонну нового функционала и закомитил всё это за один раз под названием «Фух, теперь оно наконец-то работает».


Хорошо, что я когда-то разобрался, что лучше не добавлять в репозиторий файлы кеша (папка Library), временные файлы (папка tmp, obj), и всё что Unity генерит на лету. По сути, в репозиторий нужно было добавлять только папки Assets и ProjectSettings.


Не обязательно использовать GitHub, ведь его минус в том, что в бесплатном аккаунте нельзя сделать код приватным (видимым только для себя). Но зато есть GitLab или Bitbucket, где это возможно.


Как я тпрпрррукал в микрофон


Я воспринимаю своё приложение, как обучающее и стараюсь, по возможности, не использовать отвлекающие моменты. Поэтому, иногда пользователи жалуются, к примеру, на отсутствие музыки или сильно простецкий интерфейс (хотя простецкий интерфейс — это не потому, что я так захотел, а больше потому, что пока лучше не умею). С музыкой я немного на распутье сейчас: и хочется добавить и колется (вряд ли учителя одобрили бы решение домашки по математике под музыку).


Музыка, музыкой, но без озвучки нельзя. Сначала я искал нужные мне звуки среди бесплатно распространяемых, но потом понял, что на поиск уходит больше времени, чем если бы я их делал самостоятельно. Поэтому большинство звуков я просто насоздавал ртом в телефонный микрофон, а потом обработал с помощью Audacity (бесплатная многоплатформенная софтина для записи и редактирования аудио, которую я использовал раньше для конвертирования звука из одного формата в другой).


Чаще всего логика создания звукового эффекта в Audacity была следующей:


  1. Обрезал всё лишнее.
  2. Использовал эффект Noise Reduction (чтобы убрать шум с записи).
  3. Добавил звуку мультяшности эффектом Wahwah.
  4. Эффектами Bass and Treble игрался с частотами, чтобы звук звучал более смачно на динамиках смартфонов.
  5. Если я что-то говорил, то эффектами Change Pitch, Speed и Tempo изменял звучание своего голоса на бурундучковый.

Поначалу, у меня сильно заметно отставал звук от события (не в редакторе, а на смартфоне). Помогла опция DSP Buffer Size выставленная в режим Best latency (Edit -> Project Settings -> Audio) и вот эти советы (как в вопросе, так и в ответе).


Как дочь генерировала идеи иконок


Пока я разрабатывал приложение, то пробовал несколько раз создавать иконки самостоятельно, но ни одна из них не прижилась (да и по правде говоря, выходила какая-то муть). Поэтому, когда дело дошло до открытой публикации, я поручил разработку иконку дочери. Объяснил ей, что иконка должна быть привлекательной и объяснять смысл приложения. Она подошла с большим энтузиазмом и моментально нарисовала совершенно непригодную картинку. Я её забраковал и объяснил, что именно нужно улучшить или не использовать вовсе. Дальше всё пошло, как и ожидалось — она обиделась и перестала рисовать иконки.


Спустя полмесяца, обида прошла и она подошла к заданию более основательно: нарезала из тетради в клеточку квадратиков (по размеру как иконка на экране её iPod-а) и начала рисовать варианты один за другим:


Варианты иконок, нарисованные дочерью


Приносила мне. Я выбирал понравившиеся мне идеи. Говорил, в каком направлении двигаться дальше. Она уходила рисовать следующие варианты. Спустя два дня и три десятка вариантов мы остановились на правом нижнем (фото выше).


Дальше я попросил дочь нарисовать увеличенную версию иконки (первая слева на рис. ниже), которую я перевёл в цифровую форму (вторая слева) и… позвонил знакомому художнику, чтобы он помог мне с подбором цвета. В итоге был получен центральный вариант. Дальше я стал постепенно шлифовать иконку (вторая справа) на протяжении всей жизни приложения в магазинах. И сейчас она выглядит как крайняя правая:


Прогресс создания иконки


Сборка под Android


С созданием моего первого APK-файла мне помогло разобраться вот это видео Unity Android Build — How to, где рассказывается как всё настроить, не устанавливая тяжеленную Android Studio.


Повторюсь, что у меня нет устройств с Android-ом (я просто прошу друзей потестить после новой сборки) и поэтому ошибки с устройствами, что показаны на видео — у меня отсутствовали.


Но без задоринки всё равно не обошлось. Пришлось долго повозиться с обновлением Android SDK, поскольку Unity не хотела работать с самыми последними обновлениями. В итоге, оказалось, что нужно было дать возможность Unity самому выбирать и устанавливать нужную версию обновления. Т.е. я просто нажал кнопку Update Android SDK в самом Unity, а не пытался обновить всё самостоятельно, как это показано в видео.


Проблема при обновлении Android SDK вручную

Пока я не догадался, что нужно обновляться из-под Unity, я долго страдал, обновляясь вручную с помощью скрипта sdkmanager.bat (нужно использовать именно этот скрипт с параметром --update, а не android.bat, который указан в видео). Он во время обновления жаловался, что не может перезаписать папку tools (из которой же сам и запускался). Пробовал кучу советов и уже даже не помню, что помогло, кажись какое-то решение с symboliс links.


Ещё у меня выскакивали непонятные ошибки, связанные с java. Оказалось, что проблема с версией Java Development Kit — его также не нужно было устанавливать самую последнюю версию. Я попробовал несколько старых и на одной из них ошибки пропали и всё заработало.


С подписью apk-ашки для публикации в Google Play мне помогло видео How to sign a Unity app for the android market. Я хорошенько сохранил и забекапил эти два пароля, поскольку их нужно вводить каждый раз при создании нового билда. А если их потерять, то нельзя будет обновить приложение (только выпустить новое с новыми ключами).


Иконку, в отличии от iOS версии, нужно изначально делать со скруглёнными углами, иначе на некоторых устройствах, она так и останется идеально квадратной.


Размер сборки под Андроид


Сейчас размер моего apk-файла 22МБ.


Я хорошо уменьшил размер сборки с помощью формата сжатия текстур/спрайтов с потерями — RGBA Crunched ETC2 (для спрайтов с альфой) и RGB Crunched ETC (для текстур без альфа-канала). Главное, нужно было выставить Compressor Quality = 100 (этот параметр не влияет на быстродействие текстур на конечном устройстве, а только на качество текстуры и на скорость сжатия в редакторе).


Любые другие танцы с бубнами не позволили мне добиться какого-либо существенного уменьшения размера apk-файла (кроме некоторых нюансов, описанных ниже).


Сейчас я использую следующие..


.. настройки из Player Settings..


.. для минимального размера с одной стороны и максимального покрытия устройств с другой:


  • Unity 2018.1 (чем новее версия, тем лучше она пакует и тем больше всяких вкусностей).
  • Auto Graphics API (Unity сама выбирает OpenGLES2 и 3).
  • Scripting Backend — Mono (он может и не быстрее, чем IL2CPP, но зато сборка получается однозначно меньшего размера).
  • Target Architectures — ARMv7 и x86. Убрав поддержку Intel x86, я уменьшил размер apk ещё на 10МБ (стало бы 12МБ). Но я не знаю, как много устройств я отсекаю снятием этой галочки. То что я знаю — под эту архитектуру телефоны уже года два как не выпускаются. А те, что были, можно сосчитать на пальцах одной руки (последние, что я знаю это Asus Zenfone, Lenovo K 900, Xolo x1000 и ещё может быть какие-то). Поправьте меня, пожалуйста, в комментариях, если я чушь несу.
  • Stirpping Level — Strip Assemblies — безопасно обрезает ненужный код. Другие опции может и делают какой-то выигрыш для размера (у себя я не заметил), но не такие безопасные.
  • Build System — Gradle (позволяет активировать Minify опцию).
  • Minify — Proguard — укорачивает названия всех классов и переменных, чтобы сэкономить на размере жалкие байты, но, как бонус, делает код менее читабельным для препятствия обратной инженерии.

Сборка под iOS


Собираю я приложение на макбуке жены (помню, брали самый дешёвый MacBook Air 2015-го года).


Чтобы собирать под iOS 7 даже в XCode версии 9.3 оказалось достаточно вручную вбить значение 7.0 в поле Deployment Target (на закладке General).


Чтобы добавить языки (на которые я перевёл приложение с помощью Lean Localization) в описание приложения в AppStore, нужно было добавить следующие строчки в файл info.plist (в любое место, к примеру, сразу после <dict>):


<key>CFBundleLocalizations</key>
<array>
<string>English</string>
<string>Russian</string>
</array>

Сейчас я использую Unity 2017.4 для сборки под iOS (как я писал выше, мне нужна поддержка iOS 7, иначе я бы использовал 2018.1).


Размер сборки под iOS


Сейчас размер закачиваемого файла под мой айфон — 44 МБ.


К сожалению, под iOS я не могу использовать Crunched спрайты, поскольку они не поддерживаются на девайсах старее iPhone 5s (без поддержки Metal и OpenGL ES 3.0).


Когда я пробовал уменьшить размер билда любой ценой, то самый маленький размер (34 МБ) получался если:


  • использовать Unity 2018 (т.е. минимальная поддерживаемая версия — iOS 8),
  • Graphics API выбрать только Metal,
  • оставить Target Architectures только x64,
  • использовать Crunched textures.

Но я ещё совсем не разобрался, как работать с app thinning — это такая штука, которая позволяет апстору автоматически собирать моё приложение под конкретный iPhone/iPad/iPod конечного пользователя (что приводит к уменьшению размера скачиваемого файла). Я только успел статей в закладки себе набросать:



Мои Player Settings, которыми хочу поделиться:


  • Удобно один раз ввести Automatic Signing Team ID (его можно взять на сайте Apple Developer здесь Account > Membership) и поставить галочку Automatically Sign, чтобы не делать потом это каждый раз в XCode.
  • Accelerometer Frequency я поставил в Disabled (отключил акселерометр), поскольку я его не использую. Может сберегу людям немного батарею.
  • Behavior in BackgroundSuspend — так приложение не закрывается при нажатии кнопки Home, а продолжает работать в фоне (отловить это событие можно с помощью OnApplicationPause, чтобы сохранить игру, к примеру).

Как я выбирал название и что использовал для продвижения


Сколько пользовался Booking-ом и TripAdvisor-ом, но никогда не замечал, что их название в AppStore не просто Booking, а «Booking.com Travel Deals» и «TripAdvisor Hotels Restaurants» (название разбавлено ключевыми словами, чтобы по этим ключевым словам приложение находили в поиске апстора). Поэтому я решил не использовать старое название Math4Ami, а долго игрался с разной формулировкой, чтобы включить туда нужные мне ключевые слова. В итоге, сначала я пришёл к «Pocket Money: Math», а позже к «Learn Math & Earn Pocket Money». На русском эти варианты звучали как «Карманные деньги за математику» и «Карманные деньги и математика: учись и зарабатывай».


Продвигал я своё приложение рассылая/публикуя ссылки на него друзьям и знакомым, написал две статьи у себя на блоге и там же повесил баннер.


Кстати, если поместить в <head> web-страницы вот такую строчку:


<meta name="apple-itunes-app" content="app-id=1372434662" />

.. то, открывая эту страницу на iPhone, все будут видеть вверху баннер вашего приложения.


Статистика скачиваний


Сперва я выпустил iOS версию.


Статистика скачиваний приложения на iOS


Очень многие говорили о нелюбви к яблочным девайсам и убеждали, что Андроид куда круче. Я решил проверить и, спустя 20 дней разбирательств со сборкой apk-файла, сделал релиз в Google Play.


Статистика установок приложения на Android


Объективные выводы тут не сделаешь (или вообще никакие), но чисто субъективно — я ожидал большего от Google платформы, но она, на данный момент, оказалась в половину хуже Apple.


Я жалею о том, что:


  • не делал бекапы при переходе на новую версию Unity,
  • не использовал систему контроля версий (вроде git),
  • пытался работать с Perforce (просто ужасная система — она нереально тормозит разработку),
  • не использовал ScriptableObject (SO) раньше — это настолько круто,
  • писал код в одну длинную простыню (аж самому страшно вспоминать, как я эту простыню потом рефакторил),
  • не знал что такое запахи кода, а о них ой как нужно было знать,
  • старался везде использовать глобальные переменные, а не локальные (параноидально думая, что если я буду часто запрашивать функцию, то локальная переменная внутри функции будет создаваться снова и снова, а глобальная бы была только одна. В итоге, после сотни вызовов функции с локальными переменными, у меня была бы куча истраченной памяти и потеря производительности из-за Garbage Collector),
  • не всегда придерживался единого стиля в коде и в названии всех ассетов. Вот хороший пример для подражания для UE4 (там много полезного об именовании ассетов и я применяю это также и в Unity),
  • забывал, что я пишу приложение в первую очередь для дочери, а не ради красивого кода или в угоду другим пользователям.

Я понял что:


  • дети очень легко подсаживаются на моё приложение (сразу после установки приложения, они могут часами в нём зависать, пока батарея у телефона не сядет),
  • детей затягивает делать математику в моём приложении, даже если им не говорить о деньгах. Если детей в семье двое, то доходило даже до драк за телефон, чтобы порешать примеры,
  • детям очень быстро наскучивает моё приложение. На следующий день, редко кто игрался в приложение, даже если ребёнок понимал, что получит за это деньги,
  • плохое удержание пользователя/ребёнка — это не совсем проблема моего приложения конкретно, а специфика обучения детей (это мне школьные учителя рассказали). Приложение должно быть ну очень разнообразным, чтобы всё время поддерживать интерес у детей,
  • довольно часто родители и дети неверно истолковывают принцип работы приложения и думают, что решая примеры они получат деньги от меня (от разработчика). Мне приходили разные письма с вопросами типа: как выводить деньги, можно ли вывести на webmoney или paypal, где указывать адрес для отсылки денег чеком и т.д.,
  • если в ответах к плохим отзывам извиняться за свои ошибки и недосмотры (а также объяснять, как оно должно работать на самом деле), то люди склонны прощать ошибки и убирают плохие оценки,
  • на бесплатном продвижении своими силами далеко не уедешь,
  • дети растут очень быстро и пока я писал app — моя дочь его уже переросла. Но, у меня подрастает новый «тестер»!

Ссылки


Список ссылок из статьи в очерёдности их упоминания:


+ Как держать единый стиль кода C# Style Guide with Unity in mind.
+ GitHub и видео о том, как прикрутить git к Unity.
+ Бесплатный приватный репозиторий есть на GitLab или Bitbucket.
+ Бесплатная Audacity для записи и редактирования аудио.
+ Как убрать задержку звука.
+ Видеоурок Unity Android Build — How to.
+ Видео How to sign a Unity app for the android market.
+ Устройства Apple, поддерживающие Metal/OpenGL ES 3.
+ App thinning (Apple documentation).
+ App thinning (Unity help).
+ AssetBundle Workflow (Unity documentation).
+ Где брать Team ID.
+ Что такое запахи кода.
+ Принцип именования ассетов/ресурсов в игровых проектах на UE4.


Спасибо, что дочитали!

Комментарии (12)


  1. Igor_Sib
    22.06.2018 06:08

    > не использовал SO раньше (это настолько круто),
    А что такое SO?


    1. Feelnside
      22.06.2018 07:29

      Scriptable Objects


  1. kreo_OL
    22.06.2018 07:52

    Под андроид можно сделать разные апк под архитектуру и залит их в стор. Гугл сам будет подсовывать нужную апк для устройства.


  1. kreo_OL
    22.06.2018 07:55
    +1

    Что бы от вас не требовали денег, стоит сообщать о какой-то другой валюте. Рейтинге каком нибудь


    1. yuriki Автор
      22.06.2018 08:49

      Это хорошая идея — добавить просто победные очки. Но весь смысл приложения именно в том, чтобы мотивировать ребёнка деньгами.


      1. Desavian
        22.06.2018 10:05

        Может просто мотивировать ребенка деньгами — плохая идея?


  1. zigrus
    22.06.2018 10:07

    написал подобное для командной строки. батник в 135 строк. без картинок. но ребенок тоже участвовал. изучение таблицы умножения сразу же превратилось из мучения в игру.


    1. Quiensabe
      22.06.2018 23:41

      Подходящий объем для комментария) Поделитесь?


      1. zigrus
        23.06.2018 13:35
        +1

        Matematica_pentru_copii.bat
        @echo off
        setlocal enabledelayedexpansion
        title Matematica pentru copii
        
        rem ::: red                      ver 3 din 29.03.2018
        
        set nr1=0
        set scorr=0
        set inceputH=%Time:~0,2%
        set inceputM=%Time:~3,2%
        set inceputS=%Time:~6,2%
        
        :Begin1
        cls
        echo Invatam inmultirea                 Iesire  - [x] si Enter
        echo                                    Din nou - [n] si Enter
        echo.
        
        set /a nr1+=1
        
        set /a Elm2=(%RANDOM%*100/32768)+1
        call :VerXY %Elm2% Elm2
        set /a Elm3=(%RANDOM%*100/32768)+1
        call :VerXY %Elm3% Elm3
        set /a Elm1=%Elm2%*%Elm3%
        
        call :SemnEgal
        set /a ex=(%RANDOM%*3/32768)+1
        
        :Inca
        set Rasp=
        call :Ex%ex%
        
        if [%Rasp%] EQU [] goto Inca
        if /i %Rasp%  EQU x  Exit /b
        if /i %Rasp%  EQU n  %0
        if %Rasp%  EQU !Elm%ex%! (call :RezCor & goto Begin1) else (call :Fii1 & goto Inca)
        
        :Ex1
         set /p "Rasp=Ex %nr1%_:  [ %Elm2% ] %semn% [ %Elm3% ] %smEgal% "
              exit /b
        :Ex2
         set /p "Rasp=Ex %nr1%_:  [X] %semn% [ %Elm3% ] %smEgal% [ %Elm1% ]  -[X]="
              exit /b
        :Ex3
         set /p "Rasp=Ex %nr1%_:  [ %Elm2% ] %semn% [Y] %smEgal% [ %Elm1% ]  -[Y]="
              exit /b
        
        :VerXY
        if %~1 LEQ 3   set "%~2=1"  & Exit /b ::: 3%  din cazuri
        if %~1 LEQ 9   set "%~2=2"  & Exit /b ::: 6%  din cazuri
        if %~1 LEQ 24  set "%~2=3"  & Exit /b ::: 15% din cazuri
        if %~1 LEQ 39  set "%~2=4"  & Exit /b ::: 15% din cazuri
        if %~1 LEQ 46  set "%~2=5"  & Exit /b ::: 7%  din cazuri
        if %~1 LEQ 61  set "%~2=6"  & Exit /b ::: 15% din cazuri
        if %~1 LEQ 76  set "%~2=7"  & Exit /b ::: 15% din cazuri
        if %~1 LEQ 91  set "%~2=8"  & Exit /b ::: 15% din cazuri
        if %~1 LEQ 97  set "%~2=9"  & Exit /b ::: 6%  din cazuri
        if %~1 LEQ 100 set "%~2=10" & Exit /b ::: 3%  din cazuri
        Exit /b
        
        :RezCor
        Set /a scorr+=1
        title Matematica pentru copii         Corect!!!         Scor=%scorr%
        call :BravoScor
        exit /b
        
        :Fii1
        Set /a scorr-=1
        if %scorr% LEQ 0 set scorr=0
        title Matematica pentru copii         Fii atent         Scor=%scorr%
        echo _Fii atent                 _Scor=%scorr%
        echo.
        exit /b
        
        :BravoScor
        echo.
        if %nr1% EQU 5   if %scorr% EQU 5 echo Esti bravo, contiua tot asa. Scor=5 & call :TimpDelta
        if %nr1% EQU 5   if %scorr% NEQ %nr1% echo Staruite si o sa ai rezultate. Scor=%scorr% & call :TimpDelta
        if %nr1% EQU 10  if %scorr% EQU 10 echo 10 Raspunsuri corecte fara nici o greseala. Scor=10 & call :TimpDelta
        if %nr1% EQU 10  if %scorr% NEQ %nr1% echo Insistenta si atentia te va ajuta. Scor=%scorr% & call :TimpDelta
        if %nr1% EQU 20  if %scorr% EQU 20 echo Oho 20 raspunsuri fara greseli. Scor=20 & call :TimpDelta
        if %nr1% EQU 20  if %scorr% NEQ %nr1% echo Din 20 exercitii doar %scorr% corecte & call :TimpDelta
        if %nr1% EQU 40  if %scorr% EQU 40 echo 40 !!! Se vede ca esti tare atent. Scor=40 & call :TimpDelta
        if %nr1% EQU 40  if %scorr% NEQ %nr1% echo Poti mai bine!!! Scor=%scorr% & call :TimpDelta
        if %nr1% EQU 70  if %scorr% EQU 70 echo 70 !!! Serios? Vad ca vrei sa cistigi. Scor=70 & call :TimpDelta
        if %nr1% EQU 70  if %scorr% NEQ %nr1% echo Esti bravo, Poti daca vrei. Scor=%scorr% & call :TimpDelta
        if %nr1% EQU 100 if %scorr% EQU 100 echo 100 !!!!!!! Felicitari, ai ajuns la performanta maxima. Scor=100 & call :TimpDelta
        if %nr1% EQU 100 if %scorr% NEQ %nr1% echo Mai ai de invatat. Doar %scorr% corecte.
        echo.
        if %nr1% EQU 100 echo %date% %time:~0,-6% din 100 Ex. ai:%scorr% corecte. [ %TimpOra% h %TimpMin% min %TimpS% sec]
        if %nr1% EQU 100 echo %date% %time:~0,-6% din 100 ex ai:%scorr% corecte. Timp: %TimpOra% h %TimpMin% min %TimpS% sec >> %temp%\math.txt
        if %nr1% EQU 100 echo. & call :AfisareScor
        exit /b
        
        :SemnEgal
        SET /a temp1=(%RANDOM%*8/32768)+1 
        if %temp1% EQU 1 set "semn=inmultit cu" & set "smEgal=este" & exit /b
        if %temp1% EQU 2 set "semn=marit de" & set "smEgal=ori este" & exit /b
        if %temp1% EQU 3 set "semn=multiplicat cu" & set "smEgal=este" & exit /b
        if %temp1% EQU 4 set "semn=de" & set "smEgal=ori este" & exit /b
        if %temp1% EQU 5 set "semn=crestem de" & set "smEgal=ori este" & exit /b
        if %temp1% EQU 6 set "semn=*" & set "smEgal==" & exit /b
        if %temp1% EQU 7 set "semn=x" & set "smEgal==" & exit /b
        if %temp1% EQU 8 set "semn=•" & set "smEgal==" & exit /b
        exit /b
        
        :TimpDelta
        set TimpOraH=%Time:~0,2%
        set TimpMinM=%Time:~3,2%
        set TimpSecS=%Time:~6,2%
        if %TimpSecS% LSS %inceputS% set /a "TimpSecS+=60" & set /a "TimpMinM-=1"
        if %TimpMinM% LSS %inceputM% set /a "TimpMinM+=60" & set /a "TimpOraH-=1"
        if %TimpOraH% LSS %inceputH% set /a "TimpOraH+=24"
        set /a TimpOra=%TimpOraH%-%inceputH%
        set /a TimpMin=%TimpMinM%-%inceputM%
        set /a TimpS=%TimpSecS%-%inceputS%
        if %TimpOra% NEQ 0 echo Timp: %TimpOra% h %TimpMin% min
        if %TimpOra% EQU 0 if %TimpMin% NEQ 0 echo Timp:  %TimpMin% min %TimpS% sec
        if %TimpOra% EQU 0 if %TimpMin% EQU 0 echo Timp:  %TimpS% sec
        call :EchPau
        exit /b
        
        :AfisareScor
        echo _Scoruri precedente:
        echo.
        for /f "tokens=3" %%a in ('find /c /v "" %temp%\math.txt') do set Rinduri=%%a
        if %Rinduri% GTR 5 (set /a Ultimele=%Rinduri%-5) else type %temp%\math.txt & goto EchPau
        for /f "skip=%Ultimele% delims=" %%a in (%temp%\math.txt) do echo %%a
        :EchPau
        echo.
        echo Pentru a contiua apasati Enter...
        pause > NUL
        exit /b


        1. Quiensabe
          23.06.2018 20:49

          Спасибо!


  1. SopaXT
    22.06.2018 16:18

    Андроид на x86 обычно имеет встроенный эмулятор ARM (но он медленнее).


  1. splatt
    23.06.2018 05:27

    Почитав о ваших открытиях, которые вы сделали, очень советую вам взять хороший учебник по C# и паттернам, особенно если вы и дальше планируете разрабатывать на C# / Unity.


    Сегодня Unity это такой php образца 2005ых годов, с крайне низким порогом вхождения, но при этом он напичкан антипаттернами и прививает абсолютно отвратные практики программирования. Результат — 90% программистов Unity не знают основ языка и программируют на какой-то своей версии C# (которая у них в голове сильно искажена).