Pull to refresh
0

Flappy Bot для Flappy Bird

Reading time 5 min
Views 73K
image
Сумасшедшая игра. Какой хлопец не слышал про Flappy Bird? Про 50 000 долларов дохода в день? Игре посвящены финансовые отчеты, веселые песни, желтые статьи и научные исследования. Китайские ребята даже изобрели механического робота, гоняющего птицу.
Ах, и я установил приложение на любимый iPhone 2007 года. В моем возрасте смотришь на ползунок загрузки и думаешь А не последнее ли приложение в своей жизни ты качаешь?
Да. Погонял птичку минут 20. Дальше 10-ой башни пройти не смог. Поиграл еще минут десять. О, 22 башни — мой потолок. Нервы ни к черту.
И решили мы с приятелем Кириллом создать своего ро-бота. Забить китайцам баки, как говорил Остап.

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


Монета в пол-франка


Прежде всего, наш робот не механический. Нажатия на экран можно имитировать не механической палкой, а электрическим зарядом. Приклеиваем к экрану iPad монетку. К монетке приматываем синей изолентой провод. Подаешь по проводу ток на монетку — iPad срабатывает на нажатие. В этом месте надо говорить умные слова Ёмкостной экран и важно покачивать головой.
image
Фотограф из меня конечно никакой.

Для управления током необходим iPhone. Он снимает на видео игру, запущенную на iPad, распознает момент времени, когда надо нажать на игровой экран и посылает сигнал монетке. Как? По аудио-проводу. Генерим сигнал частотой 20КГц и длительностью 20 миллисекунд. Можно проиграть wav-файл, а лучше моделировать сигнал программно, так точнее. Тем не менее, задержка от начала команды Пи-и-и-и-и-и-и до момента имитации нажатия составляет 100-110 миллисекунд. Запомним это число.

Пример кода? Боже, это скучнее, чем новости по ОРТ, сегодня без кода, ок?

Итак сигнал от iPhone через аудио-выход бежит к конденсатору, конденсатор соединен проводом с нашей монеткой — вуа-ля, схема работает.

image

Повторим наш план

  • На iPad-е запускаем игру Flappy Bird.
  • К экрану iPad приклеиваем монетку
  • Монетка соединяется с конденсатором
  • Конденсатор соединяется с аудио-входом iPhone
  • На iPhone пишем программу, которая через видео камеру наблюдает за игрой на iPad и посылает звуковой сигнал-команду Жми, Малешкин!
  • Конденсатор посылает ток на монетку, монетка имитирует нажатие на iPad
  • Птичка послушно прыгает


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

image
При подаче аудиосигнала с уровнем >=1V pnp транзистор открывается и подает логический «1» на вход первого инвертора, вызывая изменение полярности двухзатворного FET транзистора.

Открывание FET соединяет висевшую «в воздухе» монету с землёй, увеличивая измеряемую экраном ёмкость до уровня, принимаемого за касание. Ёмкость канала затвор-сток в закрытом состоянии составляет 5pF. Транзистор смонтирован непосредственно на монете для уменьшения паразитной ёмкости соединительных проводов.
Предшествующие этому решению попытки подключения монеты к транзистору экранированным кабелем были неудачными.

Не показано на схеме: земля платы соединена с землёй планшета аудиокабелем.


Коробка из-под ксерокса


Мини-студия для робота была сделана из б/у коробки. Коробку располовинили, завалили набок, на дно бережно уложили игровой iPad с заранее приклеенной монетой. В потолке коробки проделали отверстие для видеокамеры iPhone и положили телефон сверху, так чтобы камера видела игровой экран низлежащего iPad. Уф-ф, потерпите, уже скоро конец.

Под iPad пришлось подложить книгу Численное моделирование Бахвалова, чтобы игровой экран целиком заполнял видео-кадр.
Все.

Распознавание игрового поля, птички и столбов


Здесь просто.
Для начала, я сделал скриншот игры и в фотошопе измерил пипеткой цветовую интенсивность голубого фона, красного клюва птички и зеленых, как бутылка Абсента, столбов.

Поскольку углы поля практически прямые, поймать черную рамку не представляет труда. Пробегать весь массив 1280 на 720 точек видео-буфера не надо. Я пускаю диагонали от четырех углов до нахождения первой точки игрового экрана. Это примерно 5000 операций сравнения для каждого угла. Копейки.

Да! Совсем забыл.

Какой режим видео выбрать на нашем iPhone? требуется хорошая частота.

Попробовал Low-режим видео. 192 на 144 пиксела. Частота — 20 кадров в секунду. Не годится.
Стандартный видео-захват 480 на 360 точек. Дает частоту 30 кадров в секунду. Лучше, но мало.
А вот прямой перебор видео-режимов находит 60 кадров в секунду при разрешении видео 1280 на 720. Метод перебора взят со stackoverflow.com.

П-парадоксально получается — чем выше разрешение, тем чаще кадры. А что Вы хотели от Стива Джобса? Он еще и не такие сюрпризы преподносил.

Для тех, кто шарит в iOS
@implementation ViewController

static AVCaptureDevice *cam;
static AVCaptureSession *sess;

const float requiredFps = 60.0f;

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
    sess = [AVCaptureSession new];
    cam = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    NSError *err = nil;
    AVCaptureDeviceInput *input = [[AVCaptureDeviceInput alloc] initWithDevice:cam error:&err];
    if (err) {
        NSLog(@"Failed to create AVCaptureDeviceInput: %@", err.description);
    }
    [sess addInput:input];

    AVCaptureDeviceFormat *bestFmt = nil;
    int64_t bestDim = 0;
    CMTime tfps = CMTimeMake(10, 10 * requiredFps);

    for (AVCaptureDeviceFormat *fmt in cam.formats) {
        NSLog(@"Format: %@", fmt);
        for (AVFrameRateRange *fps in fmt.videoSupportedFrameRateRanges) {
            if (fps.maxFrameRate >= requiredFps) {
                if (CMFormatDescriptionGetMediaSubType(fmt.formatDescription) ==
                    kCVPixelFormatType_420YpCbCr8BiPlanarFullRange)
                {
                    CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(fmt.formatDescription);
                    int64_t sq = dimensions.height * dimensions.width;
                    if (sq > bestDim) {
                        bestDim = sq;
                        bestFmt = fmt;
                    }
                }
            }
        }
    }
    if (bestFmt) {
        if ( [cam lockForConfiguration:&err] ) {
            NSLog(@"Selected format: %@", bestFmt);
            cam.activeFormat = bestFmt;
            cam.activeVideoMaxFrameDuration = tfps;
            [cam unlockForConfiguration];
        } else {
            NSLog(@"Failed to lock camera config: %@", err.description);
        }
    } else {
        NSLog(@"Failed to find a %f FPS format", requiredFps);
    }
    AVCaptureVideoDataOutput *output = [AVCaptureVideoDataOutput new];
    [sess addOutput:output];
    dispatch_queue_t queue;
    queue = dispatch_queue_create("cameraQueue", NULL);
    [output setSampleBufferDelegate:self queue:queue];
    [output setVideoSettings:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey]];
    [self.view bringSubviewToFront:cameraReal];
    cameraReal.transform =CGAffineTransformMakeRotation(M_PI_2);
   
   //   [sess startRunning]; turn on/off when view appear/disappear
}

- (void)viewWillDisappear:(BOOL)animated
{
     [sess stopRunning];
    [super viewWillDisappear:animated];
}

- (void)viewWillAppear:(BOOL)animated
{
    [sess startRunning];
    [super viewWillAppear:animated];
}




Завершаю. Белыми крестами на видео отмечены углы границы игрового поля. Вычисляю каждый раз, хотя это необязательно. Красным крестом помечена птичка, обязательно вычисляю эти параметры каждый такт. Зная время, зная координаты птички легко вычислить ее скорость. Также просто вычислить скорость прыжка птички после нажатия и ускорение свободного падения. 2000 пикселов на секунду за секунду, вьетнамцы любят круглые числа))

Зачем знать скорость? Из-за задержки команды нажатия в 110 миллисекнд. Приходится вычислять параболу движения птички, чтобы заранее пикнуть.

Алгоритм пока не совершенен, поскольку создан в течении сегодняшней пятницы.
Но 100 столбов наша птичка берет довольно часто. Раза два за вечер смогла, золото, а не птичка.

Думаю легко доведем это дело до 1000 и успокоимся.

Всем приятного просмотра.



Внимание, реклама


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

Спасибо


Спасибо за внимание.
Tags:
Hubs:
+155
Comments 47
Comments Comments 47

Articles

Information

Website
bashni.org
Registered
Founded
Employees
Unknown
Location
Россия