# Flappy Bird(WIP)

![](/files/-LfMKsMaBTArTYUMo4-g)

Flappy GNOME - руководство по разработке игр с боковой прокруткой, использующее Vala и GTK +.

Финальным результатом урока является мини-игра в стиле Flappy Bird.

Шаги учебника должны быть простыми, каждый шаг должен быть одним коммитом с минимальным необходимым различием. Кроме того, код довольно хорошо прокомментирован, короток и организован, поэтому его должно быть легко читать. Я осознаю тот факт, что GTK + не является фреймворком для разработки игр, не предназначен для этой цели, однако для простых игр его поддержки должно быть достаточно.

#### 1. Базовый интерфейс игры

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

#### &#x20;2. Прокрутка анимации

* на клавиатуре Space отпущена, запустить анимацию
* анимация прокручивает игровую область
* когда достигните конца полосы прокрутки, остановитесь

#### &#x20;3. Бесконечная прокрутка

* когда мы прокручиваем в крайнее левое положение, изменим размер игровой области и добавим новую трубу

#### &#x20;4. Управление игроком и движение

* игрок падает по умолчанию
* игрок прыгает на кнопку Space отпущен
* игра заканчивается, когда игрок падает на дно

#### &#x20;5. Обнаружение столкновения

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

#### &#x20;6. Новая поддержка игры

* добавлена ​​клавиша F2 для запуска новой игры

#### &#x20;7. Стиль интерфейса

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

#### &#x20;8. Дальнейшие улучшения интерфейса

* использовать общедоступные изображения SVG вместо стрелок
* добавить кнопку перезагрузки для легкого перезапуска игры

```
const string SCORE_TEMPLATE = "Score: <b>%u</b>";

private static bool original = false;

private const GLib.OptionEntry[] options = {
    { "original", 0, 0, OptionArg.NONE, ref original, "Run with original icons", null },
    { null }
};

int main (string[] args) {
    try {
        var opt_context = new OptionContext ();
        opt_context.set_help_enabled (true);
        opt_context.add_main_entries (options, null);
        opt_context.parse (ref args);
    } catch (OptionError e) {
        warning ("error: %s\n", e.message);
        error ("Run '%s --help' to see a full list of available command line options.\n", args[0]);
        return 0;
    }

    Gtk.init (ref args);

    var css_provider = new Gtk.CssProvider ();                  // Initialize a CSS provider
    try {
        css_provider.load_from_resource ("/org/gtk/Flappy/flappy.css"); // from the css file in the current directory
    } catch (GLib.Error e) {
        warning ("Error loading css styles: %s", e.message);    // warn in case of an error
    }

    Gtk.StyleContext.add_provider_for_screen (                  // use the css provider
        Gdk.Screen.get_default (),                              // on the default screen
        css_provider,
        Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);

    var window = new Gtk.Window ();                             // Set up a window
    window.window_position = Gtk.WindowPosition.CENTER;         // centered on the screen
    window.title = "FlappyGnome";                               // proudly displaying the application name in the titlebar
    window.set_size_request (WIN_WIDTH, WIN_HEIGHT);            // with an appropriate size requested
    window.resizable = false;                                   // as we don't want to deal with dynamic resizing for now
    window.destroy.connect (Gtk.main_quit);                     // and quit the application when this window is closed

    var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);        // add a box representing the content area

    var scrolled_window = new Gtk.ScrolledWindow (null, null);  // Add a scrollable area
    scrolled_window.set_policy (Gtk.PolicyType.ALWAYS,          // always show the horizontal scrollbar
                                Gtk.PolicyType.NEVER);          // but never show the vertical one
    scrolled_window.expand = true;                              // use all available space for this component
    scrolled_window.set_placement (Gtk.CornerType.BOTTOM_LEFT); // move the scrollable content below the horizontal scrollbar

    var ground = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);   // static component without scrolling
    ground.set_size_request (WIN_WIDTH, GROUND_HEIGHT);         // with a fixed size
    ground.get_style_context ().add_class ("ground");           // used as the floor

    var restart_button = new Gtk.Button.from_icon_name (        // create a restart button
                                "view-refresh-symbolic",        // with a refresh icon
                                Gtk.IconSize.DND);              // with an image 32x32 px
    restart_button.set_size_request (64, 64);
    ground.pack_start (restart_button, false, false, 0);        // add the restart button to the bottom left corner
    restart_button.margin = 20;                                 // add a margin to avoid the restart button expanding to the window border
    restart_button.can_focus = false;                           // disable can_focus to avoid stealing space keypress after clicked

    var score_label = new Gtk.Label ("");                       // create a score widget
    ground.pack_end (score_label, false, false, 0);             // pack it in the bottom right corner
    score_label.margin = 20;                                    // add a margin to avoid the score label expanding to the window border

    box.add (scrolled_window);                                  // add the scrolled area to the content area
    box.add (ground);                                           // add the floor to the content area
    window.add (box);                                           // and add the content container to the main window

    var game_area = new GameArea (original);                    // Add the game area
    scrolled_window.add (game_area);                            // to the scrollable to support scrolling, as we are doing a side-scroller

    game_area.score_changed.connect ( (score) => {              // connect to the score changed signal
        score_label.set_markup (SCORE_TEMPLATE.printf (score)); // and update the score label on each change
    });

    restart_button.clicked.connect ((event) => {                // connect to the restart button clicked signal
        game_area.setup_new_game ();                            // to start a new game
    });
    game_area.setup_new_game ();                                // setup a new game
    window.show_all ();                                         // Show the window and each component withing

    Gtk.main ();                                                // Start the application
    return 0;
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://vala.gitbook.io/vala/examples/gtk/flappy-bird.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
