Лучшие андроид игры по моему мнению

Лучшие андроид игры по моему мнению

Описание игры

«Судебный поворот 3» завершает трилогию игр о молодом адвокате Рюити Хорасё. В третьей части игрока ждут пять новых дел, в которых ему предстоит вести расследования и участвовать в судебных заседаниях, а также столкнуться с таинственным прокурором Годо — человеком без прошлого и будущего. Однако не только он будет доставлять проблемы героям: кровавые призраки прошлого вновь дадут о себе знать. И для того, чтобы спасти своих близких, Рю придется проявить все свои лучшие адвокатские качества.

Особенности локализации

  • Полная локализация всех пяти дел;
  • Перевод основан на японском и частично английском скрипте;
  • События игры разворачиваются там же, где и события оригинальной Gyakuten Saiban;
  • Имена персонажей локализованы (о причинах см. ниже);
  • Переведена вся графика, за исключением английских надписей, присутствующих в японской версии;
  • Переведена анимированная графика Witness Testimony, Cross-Examination, Not Guilty, Guilty;
  • Сделана новая графика для выкриков Objection!, Hold it!, Take that!, при этом оставлены английские надписи выкриков, появляющиеся при зажатии кнопки «Y». В данном случае эти фразы нужно кричать в микрофон, поэтому их нет смысла переводить;

Улучшения текста

  • Исправлены различные смысловые ошибки в сюжете;
  • В нескольких местах внесены небольшие правки, которые уточняют противоречия в репликах свидетелей;
  • Во всей игре изменена скорость вывода текста; теперь она лучше соответствует тому, что происходит на экране;
  • Звуковые эффекты (звоны, бухи, бахи) переставлены таким образом, чтобы соответствовать смысловому ударению в тексте;

Улучшения графики

  • Заменены задники (фоны) у защиты, обвинения и у свидетеля. В оригинале они используют 16 цветов, из-за чего виден дизеринг и «лесенки». Новые изображения используют палитру из 256 цветов;
  • Также улучшено качество фона ассистента защиты и фона с общим видом на зал суда;
  • Исправлен задник у судьи (колонна справа);
  • Улучшен спрайт судьи. Теперь его палитра используется гораздо эффективней;
  • Картинки-выкрики используют сглаживание;
  • Добавлена на выбор японская озвучка, взятая из игр Gyakuten Saiban 5/6 и Gyakuten Kenji 2;
  • Исправлены прочие мелкие баги;

Установка патча

Требования к рому игры:

Версия: Nintendo DS
Регион: USA
Размер: 32,0 МБ (33 554 432 байт)
CRC32: 54505BD8
MD5: 95A45440731C1055063B77F3CD958099
SHA-1: EBB295BF6D0CDCBA494A53531C89AC9A1369819A

Патч необходимо ставить на чистую английскую версию, на которой не стоит предыдущий патч.

Установка через xdeltaUI (ПК)

1. Запустить xdeltaUI.exe.
2. Во вкладке Apply Patch расположено три пункта:
Patch: путь к патчу (ENG_voices — английская озвучка выкриков,
JAP_voices — японская озвучка выкриков.
Source File: путь к американскому рому игры. Европейская версия не подходит.
Output File: путь к новому рому игры, который будет создан после применения патча. Не забываем добавить расширение .nds в конце названия (например, Sudebnyy_povorot_3.nds).
3. Задав все параметры, жмем Patch. На выходе получаем переведенный ром. Пропатченный ром уменьшится на 10 мегабайт — это нормально.

Установка через IPS Patcher (Android)

1. Установить и запустить IPS Patcher.apk. В телефоне должна быть разрешена установка сторонних приложений (Настройки — Безопасность — Неизвестные источники).
2. В меню расположено три пункта:
Choose rom: путь к американскому рому игры. Европейская версия не подходит.
Choose patch: путь к патчу (ENG_voices — английская озвучка выкриков,
JAP_voices — японская озвучка выкриков.
Backup rom: программа сохранит оригинальный ром (в противном случае она перезапишет ром, выбранный в пункте Choose rom).
3. Задав все параметры, жмем Patch. На выходе получаем переведенный ром. Пропатченный ром уменьшится на 10 мегабайт — это нормально.

Совместимость с сохранениями от английской версии

Есть ограниченная поддержка сохранений от английской версии. Работают сохранения, которые открывают определенное дело/дела. Также работают сохранения, сделанные во время фазы расследования, когда на нижнем экране присутствует меню из четырех пунктов «Осмотреть», «Уйти», «Поговорить», «Показать». Сохранения, сделанные во время фазы суда, работать не будут (если игру загружать с пункта «С сохранения»). Но загрузка с пункта «С начала главы» работать будет в любом случае.

Сохранения от других версий патча работают аналогичным образом.

Эмуляторы для запуска игры/работа на консолях

Патченная игра работает на следующих эмуляторах:

No$GBA (Windows)

  • Игру можно полностью пройти.
  • Эмулятор поддерживает работу микрофона, но он должен быть правильно настроен в операционной системе. В самом эмуляторе настроек микрофона нет.

Проблемы:

  • Плавное появление и исчезание персонажей работает некорректно (некоторые части спрайта появляются либо раньше, либо позже, чем нужно). Ничем не исправляется, но и не особо мешает.
  • Основная кнопка на нижнем экране (с силуэтом главного героя) отображается без эффекта прозрачности, но это ни на что не влияет.

DeSmuME (Windows)

  • Игру можно полностью пройти.
  • Данный эмулятор более требователен к ресурсам компьютера, чем No$GBA.
  • Микрофон полностью поддерживается.

Проблемы:

  • Как и в No$GBA, пункты с вопросами могут отображаться некорректно. Для их исправления нужно зайти в Config — 3D settings и сменить режим Renderer с OpenGL на SoftRasterizer.
  • Звуковые эффекты звучат несколько глухо, но музыка работает без этой проблемы.
  • Заедание звука может быть вызвано двумя причинами — низкой скоростью эмуляции и неправильной настройкой звука. В последнем случае в настройках звука нужно включить Dual SPU Synch/Asynch.

Drastic (Android)

  • Игру можно полностью пройти.
  • Микрофон полностью поддерживается.
  • В целом проблем не замечено.
  • Имеет минимальные требования к начинке телефона (для данной игры), но в случае чего можно включить пропуск кадров (1 в самый раз). Так как игра полностью поддерживает сенсорное управление, игра на нем будет даже удобней, чем на консолях DS и 3DS, за счет того, что телефон можно будет держать в одной руке.
  • Для улучшения шрифтов можно включить фильтр Scale2x (Change options — Video — Filter), при этом он практически не замыливает изображение.

nds4droid (Android)

  • Игра не тестировалась на данном эмуляторе, но не исключено, что он вызывает проблемы и в третьей части игры. Не рекомендуется к использованию.

Консоли

Игра не проверялась на консолях Nintendo DS и 3DS, но, поскольку она основана том же движке, что и первая часть, особых проблем с работой возникнуть не должно.

О локализации

Данная серия игр изначально вышла в Японии под названием Gyakuten Saiban, при этом ее действие разворачивалось в Японии. В США игра была издана под названием Phoenix Wright — Ace Attorney. Данная версия подверглась серьезной локализации: помимо очевидной смены места действия, у персонажей появились новые говорящие имена, по аналогии с японской версией, многие культурные моменты были заменены на западные аналоги. То же самое произошло и в издании игры для Франции (там, как несложно догадаться, события разворачиваются во Франции).

Все это было сделано для того, чтобы игра сохранила свои особенности, но при этом была понятна западному игроку. Но в последующих частях игра стала значительно опираться на японские реалии, поэтому место действия западных локализаций стало резко противоречить сюжету и окружающей обстановке.

Данная серия игр, ввиду ряда факторов, требует полной локализации. Имена героев несут определенный смысл; они используются не только в различных шутках, но и в загадках/противоречиях/головоломках. Помимо этого, в играх много графики, содержащей текст.

В случае использования американских имен и сеттинга, возникла бы определенная проблема: персонажи имеют английские имена, действие происходит в США, но при этом они говорят по-русски, коверкают имена на русский манер, используют русские шутки и все это происходит на фоне японских «декораций» и сопровождается надписями на русском языке (включая загадки/противоречия).

Поэтому при локализации на русский язык было принято решение не допускать вышеназванные недочеты. Место действия осталось тем же, но в игре оно напрямую не упоминается. Имена имеют псевдояпонское звучание, и в них заложен определенный, но не всегда очевидный смысл. Данный подход уместен потому, что игра содержит огромное количество юмора (по сути, один из жанров игры — комедия), и потому, что русскоязычные люди практически не знакомы с восточными именами/фамилиями (в частности, с японскими). Часть имен/фамилий при этом взята из японской версии, чтобы усилить эту иллюзию.

Поскольку это локализация, а не прямой перевод, многие моменты (шутки, реалии и т. д.) изменены для лучшего их восприятия русскоязычной аудиторией.

По моему мнению, при таком подходе наши игроки смогут получить от игры такое же впечатление, как и западные от своих локализаций.

Лицензия

Устанавливая данный патч, вы соглашаетесь соблюдать следующие условия:

Патч можно распространять свободно, при условии сохранности содержимого архива. Патч и производный от него ром запрещено использовать в коммерческих целях. Также запрещена любая модификация патча или производного от него рома.

Участники

Ромхакинг, перевод, графика, программирование, тестирование, прочее — Dant

Вычитка, тестирование — KenshinX

Благодарности

Rubia Ryu the Royal — за сравнение английской серии Ace Attorney с японскими оригиналами Gyakuten Saiban (о них можно почитать в ее блоге).

Разработчикам Ace Attorney/Gyakuten Saiban и компании Capcom.

The Angular way

Я уже давно пишу на Angular, перенимая опыт у отличных инженеров, с которыми работаю, и черпая знания из обширной базы, доступной в сети. Некоторое время назад я заметил, что, хотя браузеры предоставляют огромные возможности, мало что из этого включено в Angular «из коробки». Так и задумано: ведь это просто платформа для создания своих продуктов и нужно заточить ее под свои нужды. Поэтому мы создали opensource-инициативу Web APIs for Angular. Ее цель — создание легковесных, качественных и идиоматических оберток для использования нативных API в Angular. Я бы хотел обсудить принципы написания хорошего код на примере библиотеки @ng-web-apis/intersection-observer.

По моему мнению, эти три концепции играют основную роль:


  1. Angular декларативен по природе, в то время как нативный и традиционный JavaScript-код зачастую императивный.
  2. У Angular крутая система внедрения зависимостей, которую можно активно использовать себе во благо.
  3. Angular строит логику на Observable, тогда как многие API базируются на коллбэках.

Давайте пройдемся по этим пунктам подробнее.


Декларативный vs императивный

Вот типичный кусок кода, который у вас будет, если вы захотите использовать IntersectionObserver:


const callback = entries => { ... };
const options = {
   root: document.querySelector('#scrollArea'),
   rootMargin: '10px',
   threshold: 1
};
const observer = new IntersectionObserver(callback, options);

observer.observe(document.querySelector('#target'));


Император одобряет нативный API

Здесь не так много кода, но мы успели нарушить все три принципа, названные выше. В Angular подобную логику выносят в директиву с декларативной настройкой:


I'm being observed

Вы можете узнать больше о декларативной природе директив Angular в этой статье на примере Payment Request API. Я очень советую прочитать ее, так как для подробного разбора этого аспекта тут просто слишком мало кода.

Нам понадобится 2 директивы: одна для создания наблюдателя, другая — чтобы отметить наблюдаемый элемент. Так мы сможем отслеживать несколько элементов одним наблюдателем. Внутри второй директивы мы поручим всю работу сервису. Таким образом мы сможем следить и за хостом-компонентом, где директиву использовать не получится. Это также позволит абстрагироваться от императивных вызовов observe/unobserve.

Первая директива может наследоваться непосредственно от IntersectionObserver и хранить у себя Map для сопоставления элементов и обратных вызовов. Ведь если мы отслеживаем несколько элементов, нет смысла оповещать их все, если пересечение сработало только на одном:


@Directive({
   selector: '[waIntersectionObserver]',
})
export class IntersectionObserverDirective extends IntersectionObserver
   implements OnDestroy {
   private readonly callbacks = new Map();

   constructor(
       @Optional() @Inject(INTERSECTION_ROOT) root: ElementRef | null,
       @Attribute('waIntersectionRootMargin') rootMargin: string | null,
       @Attribute('waIntersectionThreshold') threshold: string | null,
   ) {
       super(
           entries => {
               this.callbacks.forEach((callback, element) => {
                   const filtered = entries.filter(({target}) => target === element);

                   return filtered.length && callback(filtered, this);
               });
           },
           {
               root: root && root.nativeElement,
               rootMargin: rootMargin || ROOT_MARGIN_DEFAULT,
               threshold: threshold
                 ? threshold.split(',').map(parseFloat)
                 : THRESHOLD_DEFAULT,
           },
       );
   }

   observe(target: Element, callback: IntersectionObserverCallback = () => {}) {
       super.observe(target);
       this.callbacks.set(target, callback);
   }

   unobserve(target: Element) {
       super.unobserve(target);
       this.callbacks.delete(target);
   }

   ngOnDestroy() {
       this.disconnect();
   }
}

Сервис для второй директивы и необходимость передать корневой элемент для отслеживания пересечений приводят нас ко второму принципу — внедрению зависимостей.


Dependency Injection

Мы часто используем DI для передачи встроенных в Angular сущностей или сервисов, которые создаем сами. Но с его помощью можно делать куда больше. Я говорю про провайдеры, фабрики, токены и тому подобное. Например, нашей директиве необходимо получить корневой элемент, с которым мы будем отслеживать пересечения. Предоставим его с помощью токена и простой директивы:


@Directive({
   selector: '[waIntersectionRoot]',
   providers: [
       {
           provide: INTERSECTION_ROOT,
           useExisting: ElementRef,
       },
   ],
})
export class IntersectionRootDirective {}

Тогда наш шаблон станет выглядеть так:


...
I'm being observed
...

Подробнее прочитать про DI и про то, как обуздать его мощь, можно в статье о нашей декларативной Web Audio API библиотеке под Angular.

Токены — полезный инструмент. Они добавляют обособленности в код. К примеру, этот токен может предоставляться каким-нибудь хост-компонентом, когда нам нужно отслеживать пересечения дочерних элементов с его границами.

Сервис дочерней директивы получает родительскую через DI и превращает работу IntersectionObserver в RxJS Observable, что мы обсудим далее.


Observables

В то время как нативные API полагаются на коллбэки, мы в Angular используем RxJs и его реактивную парадигму. Одна особенность Observable, про которую часто забывают, — это просто класс и от него можно наследоваться. Давайте сделаем сервис-абстракцию над IntersectionObserver, который превратит его в Observable. У нас уже есть подготовленная директива, осталось в ней зарегистрироваться:


@Injectable()
export class IntersectionObserveeService extends Observable {
   constructor(
       @Inject(ElementRef) {nativeElement}: ElementRef,
       @Inject(IntersectionObserverDirective)
       observer: IntersectionObserverDirective,
   ) {
       super(subscriber => {
           observer.observe(nativeElement, entries => {
               subscriber.next(entries);
           });

           return () => {
               observer.unobserve(nativeElement);
           };
       });
   }
}

Теперь у нас есть Observable, инкапсулирующий логику IntersectionObserver. Мы даже можем использовать эти классы вне Angular, передавая параметры в new-вызовы.


Мы применили похожий подход для создания Observable-сервиса в Geolocation API и Resize Observer API, где подробно разобрали его.

Директива просто передаст этот сервис в качестве Output. Ведь класс EventEmitter, который мы привыкли использовать тоже наследуется от Observable и, соответственно, совместим с нашим сервисом:


@Directive({
   selector: '[waIntersectionObservee]',
   outputs: ['waIntersectionObservee'],
   providers: [IntersectionObserveeService],
})
export class IntersectionObserveeDirective {
   constructor(
       @Inject(IntersectionObserveeService)
       readonly waIntersectionObservee: Observable,
   ) {}
}

Теперь мы можем либо использовать директиву в шаблоне, либо запрашивать сервис и добавлять его в связки RxJs-операторов, таких как map, filter, switchMap, чтобы получить желаемую логику.