Сегодня мы поговорим о том, как сделать управление сценой мультитачем и жестом pinch-zoom на Android используя Linderdaum Engine.
1. Подготовка
Будем считать, что Linderdaum Engine SDK уже установлен и настроен. Про настройку SDK и то, как скомпилировать приложение, можно прочитать в посте habrahabr.ru/blogs/gdev/121062 Единственное, что нам понадобится дополнительно — это Android-девайс с поддержкой мультитача.
2. Пишем приложение
Чтобы написать самый компактный код мы воспользуемся новой фичей — классом clPinchZoomHandler. Для самостоятельной работы с мультитачем и написания обработчиков других жестов есть класс clGestureHandler. Если же вы хотите хардкор, то можно перехватывать событие L_EVENT_MOTION, в которое будут приходть все нажатия и отпускания пальцев на экране (включая мышь на PC, чтобы было удобнее отлаживать).
Запускаем Project Wizard и выбираем:
Выкидываем из .cpp файла всё, что нагенерилось, и пишем туда следующий код:
В папку Data сохраняем файл banner.jpg. Вот такой (256x128):
Запускаем cygwin и пишем:
Получаем .apk файл для девайса.
3. Результат
Вот так это выглядит на девайсе:
Можно двигать картинку одним пальцем и скейлить двумя.
В самом SDK есть чуть более сложный пример работы с пинч-зумом.
1. Подготовка
Будем считать, что Linderdaum Engine SDK уже установлен и настроен. Про настройку SDK и то, как скомпилировать приложение, можно прочитать в посте habrahabr.ru/blogs/gdev/121062 Единственное, что нам понадобится дополнительно — это Android-девайс с поддержкой мультитача.
2. Пишем приложение
Чтобы написать самый компактный код мы воспользуемся новой фичей — классом clPinchZoomHandler. Для самостоятельной работы с мультитачем и написания обработчиков других жестов есть класс clGestureHandler. Если же вы хотите хардкор, то можно перехватывать событие L_EVENT_MOTION, в которое будут приходть все нажатия и отпускания пальцев на экране (включая мышь на PC, чтобы было удобнее отлаживать).
Запускаем Project Wizard и выбираем:
- C++ empty project;
- Задаём название проекту (без пробелов);
- Project Folder ставим в подкаталог установленного движка (иначе не будет работать Android NDK);
- нажимаем Next...;
- отмечаем «Generate Android SDK and NDK configs» и «Add events processing code: Events + Scene»;
- ставим Resolution: 800x480 (это нужно, чтобы удобно отлаживать на PC).
Выкидываем из .cpp файла всё, что нагенерилось, и пишем туда следующий код:
#include "Linderdaum.h"
sEnvironment* Env = NULL;
clScene* g_Scene = NULL;
clPinchZoomHandler* g_PinchZoomHandler = NULL;
LMatrix4 Position = LMatrix4::IdentityStatic();
LMatrix4 PositionDelta = LMatrix4::IdentityStatic();
LMatrix4 ZoomDelta = LMatrix4::IdentityStatic();
int g_PlaneID;
// этот обработчик будет вызываться каждый раз, когда надо нарисовать кадр
void Event_DRAW( LEvent Event, const LEventArgs& Args )
{
// отрисуем сцену
g_Scene->RenderForward();
// если никаких валидных жестов нет, то нам здесь делать нечего
if ( !g_PinchZoomHandler->IsGestureValid() ) return;
if ( g_PinchZoomHandler->IsDraggingValid() )
{
// обновим параметры перемещения
PositionDelta = g_PinchZoomHandler->GetTranslationMatrix();
}
else
{
// применим текущую трансформацию и сбросим её
Position = Position * PositionDelta;
PositionDelta = LMatrix4::Identity();
}
float ZoomFactor = 1.0f;
if ( g_PinchZoomHandler->IsPinchZoomValid() )
{
// обновим параметры зума
ZoomFactor = g_PinchZoomHandler->GetPinchZoomFactor();
ZoomDelta = g_PinchZoomHandler->GetPinchZoomMatrix();
}
else
{
// применим текущую трансформацию и сбросим её
Position = Position * ZoomDelta;
ZoomDelta = LMatrix4::Identity();
}
// обновим трансформацию объекта в сцене
g_Scene->SetLocalTransform( g_PlaneID, Position * PositionDelta * ZoomDelta );
// вывидем инфо про текущее количество пальцев на экране и коэффициент зума
size_t NumContacts = g_PinchZoomHandler->GetMotionData()->GetNumTouchPoints();
clCanvas* C = Env->Renderer->GetCanvas();
LString Str1( "Zoom factor: " + LStr::ToStr( ZoomFactor ) );
LString Str2( "Active : " + LStr::ToStr( NumContacts ) );
C->TextStrFreeType( LRect( 0.0f, 0.0f ), Str1, 0.05f, LC_White, NULL, TextAlign_Left );
C->TextStrFreeType( LRect( 0.0f, 0.05f ), Str2, 0.05f, LC_White, NULL, TextAlign_Left );
}
// инициализация
APPLICATION_ENTRY_POINT
{
Env = new sEnvironment();
Env->DeployDefaultEnvironment( "", "../../CommonMedia" );
Env->Connect( L_EVENT_DRAWOVERLAY, Utils::Bind( &Event_DRAW ) );
// создадим объект, который мы будем двигать жестом
clGeom* TestGeom1 = Env->Resources->CreatePlane( 0.1f, 0.2f, 0.9f, 0.8f, -0.1f, 10 );
// создадим и настроим сцену
g_Scene = Env->Linker->Instantiate( "clScene" );
g_Scene->SetCameraTransform( LMatrix4::GetTranslateMatrix( LVector3(0.0f) ) );
g_Scene->SetCameraProjection(
Env->Renderer->GetCanvas()->GetOrthoMatrices()->GetProjectionMatrix()
);
g_Scene->SetUseOffscreenBuffer( false, false );
// добавим в сцену нашу плоскость
g_PlaneID = g_Scene->AddGeom( TestGeom1 );
// и установим ей материал
clMaterial* Mtl = Env->Resources->CreateMaterial();
Mtl->SetPropertyValue( "DiffuseMap", "banner.jpg" );
g_Scene->SetMtl( g_PlaneID, Mtl );
// создадим обработчик жестов - он сам будет перехватывать все нужные события
g_PinchZoomHandler = Env->Linker->Instantiate( "clPinchZoomHandler" );
Env->RunApplication( DEFAULT_CONSOLE_AUTOEXEC );
APPLICATION_EXIT_POINT( Env );
}
// деинициализация
APPLICATION_SHUTDOWN
{
delete( g_Scene );
delete( g_PinchZoomHandler );
}
В папку Data сохраняем файл banner.jpg. Вот такой (256x128):
Запускаем cygwin и пишем:
ndk-build
ant copy-common-media debug
Получаем .apk файл для девайса.
3. Результат
Вот так это выглядит на девайсе:
Можно двигать картинку одним пальцем и скейлить двумя.
В самом SDK есть чуть более сложный пример работы с пинч-зумом.