oxygine flow_ru - oxygine/oxygine-framework GitHub Wiki
Oxygine-Flow
https://github.com/oxygine/oxygine-flow
oxygine-flow это расширение для oxygine, позволяющее организовывать удобную систему диалогов/сцен и переходов между ними, построенной на асинхронной модели событий.
Общая функциональность oxygine-flow будет описана на одном примере, начиная с простого и постепенно усложняя его. За основу примера берется пустой проект по шаблону HelloWorld из oxygine-framework. Работа ведется только в одном файле example.cpp.
Полностью завершенный пример находится в папке oxygine-flow\examples\HelloFlow
Видео демонстрация работы примера oxygine-flow: https://www.youtube.com/watch?v=Z4p1ol1-cLM&feature=youtu.be
Веб версия: http://oxygine.org/online_demo.php кнопка Run Oxygine-Flow example
Первым делом добавим вызов основных функций и все необходимые нам includes в example.cpp:
#include "oxygine-framework.h"
#include "oxygine-flow.h"
using namespace oxygine;
void example_preinit()
{
}
void example_init()
{
//initialize oxygine-flow
flow::init();
}
void example_update()
{
//update oxygine-flow each frame
flow::update();
}
void example_destroy()
{
//free oxygine-flow
flow::free();
}
Scene
Основной класс, с которым вы будете иметь дело - это Scene. Необходимо отнаследоваться от него и прикрепить к Актеру Scene::_holder все ваши элементы интерфейса.
Cоздадим класс MyScene для нашей простой сцены с кнопкой по центру:
class MyScene : public ox::flow::Scene
{
public:
MyScene()
{
setName("MyScene");
spBox9Sprite view = new Box9Sprite;
_view = view;
_view->setSize(_holder->getSize());
_view->attachTo(_holder);
spButton btn = new Button;
btn->setPosition(_view->getSize() / 2 - btn->getSize() / 2);
btn->attachTo(_view);
}
spActor _view;
};
Покажем MyScene на экране при старте приложения:
void example_init()
{
//initialize oxygine_flow
flow::init();
//create scene and display it
flow::show(new MyScene);
}
Пока что кнопка в центре ни на что не реагирует, добавим закрытие сцены (в конструкторе MyScene) при ее нажатии, вызвав метод Scene::finish():
btn->addEventListener(TouchEvent::CLICK, [=](Event*){
finish();
});
для простоты тут используется lambda будьте внимательны: finish() вызывается для класса MyScene
Теперь MyScene будет закрываться при клике на кнопку. Как узнать что сцена закрылась? Один из вариантов передать Callback в метод flow::show:
flow::show(new MyScene, [](Event* event){
logs::messageln("scene closed");
});
Усложним пример и добавим еще один класс для диалога, который отличается от сцены только установленным флажком Scene::_dialog, который сообщает системе о том, что данную сцену надо показывать поверх уже открытой, не скрывая ее на экране:
class MyDialog: public flow::Scene
{
public:
MyDialog()
{
setName("MyDialog");
_dialog = true;
spBox9Sprite view = new Box9Sprite;
_view = view;
_view->setSize(400, 300);
_view->attachTo(_holder);
_view->setPosition(_holder->getSize() / 2 - _view->getSize() / 2);
spButton btn = new Button;
btn->setPosition(120, 200);
btn->attachTo(_view);
btn->addEventListener(TouchEvent::CLICK, [=](Event*) {
finish();
});
}
spActor _view;
};
Открытие MyDialog добавим в класс MyScene, в обработчик клика на кнопку, который перепишем таким образом:
btn->addEventListener(TouchEvent::CLICK, [=](Event*){
flow::show(new MyDialog, [=](Event*){
//finish();
logs::messageln("dialog closed");
});
});
Теперь каждый раз при клике по кнопке в MyScene будет открываться MyDialog. Можете раскомментировать //finish(); выше и тогда после закрытия MyDialog следом закроется и MyScene.
Пока что появление MyDialog на экране выглядит очень просто, сделаем его открытие чуть красивее. Добавим в конструктор MyDialog:
flow::TransitionMove::assign(this);
Теперь MyDialog будет отображаться плавно выезжая сверху экрана и затеняя под собой MyScene.
Special Events
Давайте научимся пользоваться некоторыми ключевыми Events, о которых умеет уведомлять класс Scene. Например, перед каждым показом MyDialog будем менять цвет фона диалога на случайный, добавим в конструктор MyDialog:
addEventListener(EVENT_PRE_SHOWING, [=](Event*) {
view->setColor(Color(rand() % 255, rand() % 255, rand() % 255, 255));
});
А когда он уже окончательно открылся (выехал с края экрана) - плавно сменим цвет на белый, каким он был изначально, добавив в конструктор MyDialog:
addEventListener(EVENT_POST_SHOWING, [=](Event*) {
view->addTween(Sprite::TweenColor(Color::White), 300);
});
Аналогичные события есть и на скрытие сцены:
- EVENT_PRE_HIDING
- EVENT_POST_HIDING
Событие нажатия кнопки Esc/Back (Back для Android):
- EVENT_BACK
Добавим обработку EVENT_BACK в конструктор MyDialog, где будем закрывать MyDialog, также как мы это делали по событию CLICK на btn:
addEventListener(EVENT_BACK, [=](Event*) {
finish();
});
События оповещающие, что поверх сцены открыли/закрыли другую сцену:
- EVENT_SCENE_SHOWN
- EVENT_SCENE_HIDDEN
События входа и выхода сцены:
- EVENT_ENTERING
- EVENT_LEAVING
Important
- Все открытые сцены хранятся в Stack, работающему по принципу Last In First Out, открытая Scene всегда ждет, когда к ней будет возвращено управление. Список открытых сцен отображается в DebugActor
- Если сцена уже открыта, т.е она находится в стеке открытых сцен, нельзя ее показать повторно, до тех пор пока вы ее не закрыли (т.е не удалили из Stack). Даже если она сейчас не видна экране.
- Если вам нужно удалить невидимую, но открытую ранее сцену используйте Scene::remove.
- Стек с открытыми сценами можно отследить в DebugActor.
- Нельзя (!!!) показывать поверх уже открытого Диалога - Сцену, сначала дождитесь закрытия диалога и из Callback в flow::show покажите свою сцену.
- Все EVENTS, описанные выше логируются. Вы можете отследить их в вашем логе.
Transitions
В состав oxygine-flow входит небольшой набор разных анимаций перехода между диалогами и сценами:
- TransitionMove - выезд сверху экрана + затенение заднего фона
- TransitionFade - плавное появление через прозрачность
- TransitionShutters - пример перехода со "шторками"
- TransitionQuads - сложный переход "лесенкой"