Pull to refresh

Работа с жестами под Android с использованием Linderdaum Engine

Game development
Сегодня мы поговорим о том, как сделать управление сценой мультитачем и жестом pinch-zoom на Android используя Linderdaum Engine.

Linderdaum Engine logo





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):
image
Запускаем cygwin и пишем:
ndk-build
ant copy-common-media debug

Получаем .apk файл для девайса.

3. Результат

Вот так это выглядит на девайсе:
image
Можно двигать картинку одним пальцем и скейлить двумя.

В самом SDK есть чуть более сложный пример работы с пинч-зумом.
Tags:androidndkc plus pluslinderdaum
Hubs: Game development
Total votes 7: ↑5 and ↓2 +3
Views1.4K

Popular right now