Zorko

Участник

Активность: 3 г. назад

  1. 3 г. назад
    Thu Mar 12 18:25:17 2015

    @devolonter Потоки, применять в Monkey не советую, но если очень хочется можно воспользоваться недокументированным модулем brl.thread в связке с brl.asyncevent. Но если честно, боюсь, что это принесет немало головной боли.

    Я охотно верю Вам, Артур.

    Вопрос к Monkey-программистам, имеющим опыт использования потоков. Что использовали? brl.thread/brl.asyncevent? Стабильно ли ведёт себя? А видели модуль Diddy.Threading с примерами coroutineDemo, testCoroutine и threadTest? Кто-нибудь тестировал этот код? Там заявлены таргеты "ios", "stdcpp", "glfw", "android", "bmax" и "xna", что вполне неплохо. Правда, нету таргетов html5 и flash(actionscript), а тоже интересные таргеты.

  2. Thu Mar 12 18:15:37 2015
    Zorko прокомментировал SetUpdateRate(0).

    Благодарю за ответ. Буду пока пользоваться Mungo. (вот и ниша для Mungo, раз Марк раздаёт пока версию 77a, видимо, считая её стабильной?)

    У меня много вопросов, связанных с непониманием механизмов работы Monkey, например:

    1. Есть ли указатели на функции? на методы? Или их аналог.

    2. Вот в этом участке кода:

    Function Main:Int()
    	New MyApp
    	Return 0
    End Function

    очевидно, что основной поток исполнения всё время крутится внутри класса MyApp, а до строчки Return 0 дело доходит только после вызова EndApp() или ручного закрытия приложения. Как именно устроен диспетчер вызова сообщений - дело внутренностей класса App, однако же там явно находится код, ожидающий поступающих сообщений и обрабатывающий их. Вполне возможно, что сюда входят и сообщения от таймера, приводящие к вызову OnUpdate и OnRender.

    3. Методы OnUpdate и OnRender работают гарантированно в одном потоке или могут в разных? насколько большая вероятность их одновременного вызова? что будет с перерисовкой если OnUpdate задержит нить исполнения на большое время?

    4. Очевидно, что событийная схема работы приложения диктуется устроением современных технологий, и она является вполне экономичной. Несобытийная схема активного опроса состояния событий - это, скорее, выходец из прошлого, однако старые игры для старых платформ (MSX, DOS, Spectrum) работают именно так. Я вижу возможность перенести их логику на событийность, однако это сложная работа, требующая указателей на методы/функции. Но я полагаю, это всё есть в Monkey. Вместе с тем заманчиво иметь готовый фреймворк (каркас), который бы реализовал несобытийную схему работы приложения, давая точку входа в метод, который бы владел единолично потоком исполнения, и давая аналог ProcessMessages и метод задержки исполнения на заданное время. В SDL это всё возможно (есть процедура SDL_Delay(msec) ).

    Как будет устроен этот каркас (скорее всего тоже поверх Mojo) - я пока не знаю, но буду рад услышать мнение опытных людей по этому вопросу.

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

  3. Tue Mar 10 14:02:22 2015

    Успехов проекту Mungo! Буду его использовать. Если у Вас есть что-то вроде плана работ (чем будет отличаться от Monkey, каковы предпосылки для появления форка), то я бы с удовольствием разместил эту информацию на нашем форуме по модульным языкам .

    Кстати, идеология Monkey X мне близка непонаслышке. Я являюсь автором подобной Monkey среды XDev , которая тоже спроектирована для разработки под различные таргеты с единого исходника (правда, набор таргетов другой - MS-DOS, ZX Spectrum, MSX, Windows 32/64 бит, Linux, Java ME, готовится подсистема для Android). Лучше всех проработан таргет ZX Spectrum, остальные находятся в различной степени готовности и доступны с репозитория проекта XDev .

    XDev работает по тому же принципу, что и Monkey - транслирует исходный текст в Си (а также в байт-код JVM) и вызывает средства сборки для нужной платформы. Входной язык XDev - паскалеподобный Оберон , наследник Модулы-2, и его надмножества (Оберон-2, Компонентный Паскаль). Это ещё более простые языки, чем Monkey.

    Мне кажется, такие средства как Monkey и XDev - реакция инди-разработчика на избыточную сложность IT-индустрии; ведь каждый новый язык, который с большим или меньшим восторгом принимается программистами, решая проблемы в одной области, часто порождает ворох проблем в другой (расходы на обучение специалистов, сопряжение с другими средствами и т.п.). Простой исходный язык и мультитаргетность - общие моменты Monkey и XDev.

    Унифицировать "старые" платформы, подводя под единый стиль разработки, - весьма нетривиальная задача, значительно более трудная, чем с современными платформами. И вот, кстати, я при разработке XDev примерялся к SDL 2 как к основе для современных таргетов. Но пока ещё не перешёл на неё - использую SDL 1.2

    Могу также дать парочку ссылок на неоконченные игры, разрабатываемые на XDev, не чтобы поиграть, а, скорее, чтобы оценить идеологический подход:

    Порт игры Dark Woods на Оберон - ZX Spectrum, Windows 32/64, Linux, Java ME.

    Игра Dash для J2ME, MS DOS и ZX Spectrum Скриншоты

  4. Tue Mar 10 12:57:37 2015
    Zorko прокомментировал SetUpdateRate(0).

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

    Слегка дополню Ваш код. На таргете Desktop Game (glfw) если свернуть приложение и потом развернуть - экран не перерисовывается. Опытным путём выяснилось: при развёртывании приложения метод OnResume вызывается не всегда, а OnResize всегда (даже при #GLFW_WINDOW_RESIZABLE=False). Поэтому дополним код:

    	Method OnResume: Int ()
    		dirty = 2
    	End Method
    
    	Method OnResize: Int ()
    		dirty = 2
    	End Method

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

    Вижу два варианта решения:

    1) простой; из OnCreate не возвращаемся никогда, а остальные события обрабатываем оттуда же с помощью аналога Дельфи Application.ProcessMessages (если такой конечно имеется в Monkey);

    2) на потоках (тредах, нитях). OnCreate запускает новую нить, которая делает всю работу, в т.ч. и по опросу событий и графической отрисовке.

    Прокомментируйте, пожалуйста. Если удастся решить и эту проблему, моя задумка (порт карточной игры) больше не упирается в логические препятствия. Впрочем, Monkey меня уже впечатлил: несмотря на скромность средств Mojo получается выстроить нужную логику перерисовки экрана с лёгкостью, и всё действительно работает как надо.

    @devolonter По поводу Вашего примера - какую версию Monkey вы используете (номер версии)? Т.к. это похоже на баг, круг должен двигаться самостоятельно и во всех таргетах. Именно это у меня и происходит.

    Использовал версию Monkey X - FREE, которая доступна сейчас с оф. сайта после регистрации. Это MonkeyX77a. В репозитории доступна версия v83a, но я пока не умею её собирать, а исполняемых файлов там нет. Можно ли откуда-то скачать собранную версию для Windows?

    Так что Ваш код я тестировал в Mungo. Кстати, действительно работает не так как в MonkeyX77a, а как Вы сказали. В Mungo всё собирается и работает отлично.

    Спасибо, Артур! :)

  5. Sun Mar 8 04:52:49 2015

    Артур, Вы писали здесь (цитирую примерно): "вы платите $99 не за Monkey, а за Mojo и техническую поддержку". В связи с чем вопрос: чего стоит в плане разработки для Android не-Pro-версия Monkey X? Предвидя отрицательный ответ я хотел бы внести рациональное предложение - развивать другие таргеты без Mojo и без $99. Конечно Марк вполне молодец, заработал свои деньги и заслужил наше уважение. Но здесь тонкий баланс, учитывающий особенности ментальности жителей постсоветского пространства. По-моему, по популярности такой прекрасной среды как Дельфи самый сильный удар нанесло отсутствие бесплатной версии, пусть даже с ограниченным функционалом. Да, лицензию на ТурбоДельфи раздавали безплатно, но недолго. ;) В результате про Дельфи почти все забыли, а теперь есть FreePascal и Monkey X, которые превосходят его по количеству таргетов и пользователей. Участи Дельфи для Monkey не хотелось бы, мне очень нравится его идеология — вместо того чтобы изучать 5-10 или больше сильно похожих друг на друга Си-подобных языков и огромное количество встроенных в различные устройства программных интерфейсов здесь при сильной ограниченности общей картины всё же предлагается универсализация — один язык, один интерфейс для всех таргетов. При минимальном присутствии аналогов #if Android .. #endif.

    Мне тут задали вопрос, который переадресовываю Вам, программистам на Monkey.

    "Kubanych" Насколько я понял из сайта, Mojo -это всего лишь один из фреймворков, там есть и бесплатные (например, http://www.fantomgl.com/fantomengine-monkey-x/ ). И в целом monkey-x можно пользоваться бесплатно. Поправьте меня, если я неправ.

    А я не удивлюсь если эти упомянутые фреймворки работают поверх Mojo. ;)

  6. Sun Mar 8 04:45:19 2015

    Есть такая мультиплатформенная графическая библиотека - SDL 2 . Список таргетов очень значителен и весьма впечатляет - Android и iOS, Linux, Windows, Windows CE, BeOS, Mac OS X, FreeBSD, NetBSD, OpenBSD, BSD/OS, Solaris, IRIX и QNX — и вдобавок есть неофициальные порты на другие системы.

    Насколько трудоёмким будет создание нового таргета для Monkey, базирующегося на SDL API как на платформе? Вероятно, самые трудности лежат в использовании указателей? (Или это как-то можно обойти использованием Poke?). Интерес не праздный, я бы использовал такое на ура, особенно если можно будет отвязаться от Mojo и от $99, имея возможность иметь кучу SDL-таргетов на не-Pro-версии Monkey X.

  7. Sat Mar 7 05:07:34 2015
    Zorko прокомментировал SetUpdateRate(0).

    Спасибо за Ваш ответ, Артур.

    Я подготовил такой примерчик, чтобы потестировать SetUpdateRate(0). И результат его работы расходится с форумным заверением , что SetUpdateRate(0) - это рендер с максимально возможным фпс.

    Import mojo
    
    Class MyApp Extends App
    
    Field x: Int
    
    Method OnCreate: Int ()
      SetUpdateRate(0)
      x = 0
      Return 0
    End Method
    
    Method OnRender: Int ()
      Cls(0, 0, 0)
      DrawCircle(x, 30, 30)
      x += 1
      Return 0
    End Method
    
    End Class
    
    Function Main: Int ()
      New MyApp
      Return 0
    End Function

    На таргете glfw круг едет вправо только если водить мышку над приложением (т.е. Windows не сохраняет картинку окна приложения и просит его перерисовать самого себя когда нужно восстановить изображение под курсором мышки). На таргете html5 круг вообще никак не движется.

    А как будет вести себя этот пример на Android и других таргетах? (не могу проверить, у меня не Pro-версия).

    В любом случае, мне нравится идея нерегулярного перерисовывания экрана только при реальной необходимости. Но непонятно как активировать перерисовку в случае SetUpdateRate(0), когда пришла пора обновлять экран.

    В случае объявления ненулевого аргумента (скажем, вызов OnRender 15 раз в секунду, но возвращение из него без реальной перерисовки) предвидится проблема: как определить - пора перерисовывать экран по требованию ОС (скажем, курсор мышки проехал по экрану и нужно восстановить изображение) или же пришла пора перерисовывать ибо изменилась логика работы приложения (скажем, количество набранных очков в игре). Не знаю способа как это сделать. При SetUpdateRate(0) метод OnRender вызывается именно так как мне и нужно, но только по требованию ОС. А как перерисовывать экран самостоятельно - неясно. При SetUpdateRate(15) же получается, что из этих 15 раз в секунду реально перерисовывать экран нужно, может быть, один раз, а может и ни разу, но нет возможности определить инициатора перерисовки (ОС просит восстановить изображение или же тикнул таймер SetUpdateRate(не_нуль) ). Такая дилемма. Вариант безусловной перерисовки 15 раз в сек тоже рассматривается, но как-то без энтузиазма.

    В уме нарисовалась такая логика OnRender (если получится вызывать его так, как хочется):

    1. Нарисовать картинку из графического буфера
    2. Возможно, сделать какие-то графические изменения на экране
    3. И если изменения были, то сохранить содержимое экрана опять в буфер

    При этом если инициатива перерисовки пришла от ОС, то пункт 1 к выполнению обязателен. А вот если по тику от таймера SetUpdateRate(не_нуль), то получается, что можно бы на этом и сэкономить, ведь на экране остаётся предыдущая картинка, она не изменилась.

    Я нашёл видео-урок по созданию игр на Monkey , в котором (позиция 8:56) утверждается следующее:

    you might want to consider timestep-independent code. For this demo we assume fixed 60fps

    Из чего можно сделать вывод, что нерегулярное (т.е. именно такое как мне нужно) независимое от шага времени обновление экрана возможно. Как же этого добиться?

    Вот игра JackHammer , типично тому, что я хочу сделать. Т.е. думаете, она перерисовывает одно и то же с постоянным фпс?

    Извиняюсь за некоторое упорство. Возможно, это связано с опытом работы с библиотекой SDL , и в ней такая логика, как мне нужно, легко достижима - рисуем, обновляем по частям, опрашиваем события когда это нам нужно и т.д. Mojo же устроена для меня несколько непривычно. :)

    @devolonter Чтобы прервать рендер вы можете вызвать Return в OnRender, в этом случае рендер будет прерван.

    Но прерывание рендера ведь имеет смысл только если мы уверены, что инициатива перерисовки происходит не от ОС (потому что испортилось изображение), а потому что подоспел тик таймера перерисовки? А я пока не умею определять это.

    @devolonter Также вы можете использовать BeginRender и EndRender для ручного запуска и завершения рендера.

    Это интересно, хотелось бы примерчик.

  8. Fri Mar 6 04:00:35 2015
    Zorko начал обсуждение SetUpdateRate(0).

    Здравствуйте, уважаемые коллеги.

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

    Как я понял, логика работы любой игры на Monkey/Mojo - это обновление экрана внутри OnRender каждые N мс (а GUI-приложения на Monkey работают подобным же образом, бешено перерисовывая одни и те же контролы стопсят раз в секунду?). Поправьте, если это не так. Есть OnRender, он вызывается самим классом App (вручную вызвать его из своих методов нельзя). Минимальная задержка для обновления экрана - SetUpdateRate(1) - 1 раз в секунду. Для многих игр, очень регулярно обновляющих содержимое экрана, такая логика вполне хороша. Но как быть со спокойными играми типа карточных, где нужно вывести всю графику и спокойно ждать реакции пользователя, перерисовывая некоторые элементы на экране частями, а не лихорадочно обновлять экран каждые 60 или больше раз в секунду. Это кажется излишне нагружающим процессор (на десктопе) и садящим заряд батареи (на планшете/смартфоне).

    Я было подумал, что можно использовать SetUpdateRate(0), устанавливая внутри своего метода SetUpdateRate(60) когда пора перерисовать экран, и снова возвращать SetUpdateRate(0) внутри OnRender. Но вот что пишут про SetUpdateRate(0):

    http://socoder.net/index2.php?topic=4047&seenpost=40229

    SetUpdateRate(0) will run OnUpdate and OnRender as fast as possible.

    Т.е. аргумент 0 вовсе не значит "обновлять только по необходимости", но "обновлять с максимальной частотой".

    Логика моей программы примерно такая (не событийная):

    Нарисовать что-то одно на части экрана (появилось на экране)
    Подождать секунду
    Нарисовать что-то другое на части экрана (появилось на экране)
    Опросить управление, отреагировать на управление, перерисовав что-то на части экрана
    (предполагается наличие буфера, в котором производятся графические операции над частями экрана)

    А не:

    Method OnRender ' С крайне высоким фпс! ;)
    Пришла пора срочно перерисовать весь экран, будьте любезны его заново сформировать
    End Method

    Как мне быть? Воспользоваться средним фпс, например, SetUpdateRate(15), переведя всё-таки логику работы на событийность (предвижу трудности)? Воспользоваться многозадачностью (например, с помощью Diddy), руля логикой в отдельном потоке, но каким-то образом отдавая OnRender'у команды на перерисовку графики? У кого были подобные трудности и нашлось ли решение? Примеры кода будут очень кстати. Спасибо.

  9. Sat Feb 28 01:13:01 2015
    Zorko присоединился к форуму.