Неблокирующая игровая петля OpenGL (OpenTK) в C # - PullRequest
0 голосов
/ 12 октября 2019

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

Игра представляет собой консольное приложение Windows и использует OpenTK.

  • Когда игра запускается сама по себе (как отдельное приложение), OpenTK создает GameWindow, который обрабатывает свой игровой цикл внутри себя (вы вызываете window.Run(updateSpeed, renderSpeed), и он запускает цикл, все еще опрашивая и обрабатываяоконные сообщения в процессе.
  • Когда игра запускается редактором, игра получает ссылку на редактор GLControl и обрабатывает различные события из элемента управления.

Редактор - это отдельный проект в том же решении, это приложение WPF, использующее WindowsFormsHost, содержащее GLControl для игры, которому принадлежит пространство в окне, рядом с панелями для различных элементов управления редактора.

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

AccessViolationException

... как только будут сделаны какие-либо вызовы GL (например, очистка цветового буфера).

С точки зрения того, как все это работает в коде, класс игры имеет некоторые частные переменные, которыеопределить, встроен ли он в редактор. При нормальном запуске это false / null, и игра создает окно и работает нормально (все работает нормально). При запуске редактора редактор инициализирует GLControl, а затем вызывает функцию в игре, которая устанавливает ссылки и сообщает игре, что она находится в редакторе. Затем, как только все компоненты WPF инициализированы, кнопка «play» вызывает функцию Run() игры (это та же функция, которая вызывается точкой входа при запуске в качестве автономного приложения; она просто решает, что делать, основываясь на условиипеременных редактора, не являющихся ложными / нулевыми). Редактор WPF также имеет кнопку «Стоп», которая вызывает функцию игры Shutdown(). Я бы хотел потенциально реализовать способ горячей перезагрузки кода игры с работающим редактором, в конце концов (возможно, я сделаю игру DLL и загрузлю ее таким образом - это не очень важно, верносейчас, а может и не произойти, зависит от того, действительно ли это возможно, не стесняйтесь вникнуть в это, если считаете, что это возможно). Как только игра запущена, она должна иметь возможность обновлять и рендерить (желательно на разных скоростях - мне нужно, чтобы обновление происходило 30 раз в секунду и рендерилось 60 раз в секунду (конечно, в конечном итоге это будет учитывать V-Sync))), без блокировки интерфейса редактора.

Как я могу это сделать? Я предполагаю, что потоки будут абсолютной необходимостью, поэтому мне нужен способ доступа к контексту GL из отдельного потока (предположительно). Любая помощь будет принята с благодарностью. Если кому-то нужен код, скажите мне, какие части вам нужны, поскольку их довольно много, и я не думаю, что размещать все это здесь было бы хорошей идеей. Надеюсь, вам это не понадобится, так как здесь описана настройка проекта, и в настоящее время сама игра не состоит из большого количества;пока он просто визуализирует белый квад в середине окна просмотра, пока я не перенесу свой код из более старой версии проекта;но сначала мне нужно получить основы и запустить).

1 Ответ

0 голосов
/ 12 октября 2019

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

Что я сделал:

  • Прежде всего, я перешел с использования Task на использование Thread.
  • Во-вторых, до того, какЯ создаю нить, сохраняю значение Thread.CurrentThread.
  • Затем внутри вновь созданного потока игрового цикла у меня есть цикл while (Running). Каждый раз, когда вводится цикл, я вызываю функции обновления и рендеринга игры, а также функцию GLControl SwapBuffers() из вызова: Dispatcher.FromThread(mainThread).Invoke(( ) => { ... });

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

Вот код потока игрового цикла, в надежде, что это поможет кому-то в будущем (и ПОЖАЛУЙСТА, если это ужасный код (и я уверен, что это так), скажите мне, почему и как его можно улучшить)

Код темы игрового цикла:

Thread mainThread = Thread.CurrentThread;
new Thread(() =>
{
    Dispatcher.FromThread(mainThread).Invoke(() =>
    {
        Debug.LogInfo("Game loop thread started!", EditorTextColour.Green);
    });

    while (Running)
    {
        if (IsInitialized)
        {
            Dispatcher.FromThread(mainThread).Invoke(() =>
            {
                Update();
                Render();
                if (Embedded)
                {
                    EmbeddedControl.SwapBuffers();
                }
            });
        }
        Thread.Sleep(200); // TODO: Tune this using actual timing values!!
    }
}).Start();

Результат:

Двигательзапускает игру, сообщает, что она встроена в редактор, и вызывает функцию Run() игры. Игра замечает, что она встроена, и предпочитает не создавать окна, вместо этого запускает код, показанный выше (после вызова функции Initialize(), чтобы убедиться, что перед использованием их можно установить любые необходимые значения). Поток игрового цикла вызывает функции Update() и Render() игры из основного потока через Dispatcher и спит после каждого цикла. Et Voilá, у нас есть игра, работающая в собственном редакторе WPF! Довольно аккуратно, для учебного упражнения!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...