Namespaces

Variants
Actions

Please note that as of October 24, 2014, the Nokia Developer Wiki will no longer be accepting user contributions, including new entries, edits and comments, as we begin transitioning to our new home, in the Windows Phone Development Wiki. We plan to move over the majority of the existing entries over the next few weeks. Thanks for all your past and future contributions.

Анимация

From Wiki
Jump to: navigation, search
Article Metadata

Статья
Автор: Den123 (12 Nov 2007)
Последнее редактирование: hamishwillee (10 Nov 2011)
== Анимация на стороне клиента ==

Наиболее простой вариант – использовать таймер (например - CPeriodic) для организации задержки между сменой кадров. По окончанию задержки рассчитывать и отображать очередной кадр.

Реализация может быть следующей:

  • В заголовочном файле класса-котейнера (AppView) необходимо объявить:
public:
void DrawNewFrame(); // отображение очередного кадра
 
private:
static TInt Period( TAny* aPtr );
CPeriodic* iPeriodicTimer;
  • При создании AppView, в методе ConstructL(), добавить инициализацию и запуск таймера:
iPeriodicTimer = CPeriodic::NewL( CActive::EPriorityStandard );
// указываем минимально возможные интервалы
iPeriodicTimer->Start( 1, 1, TCallBack( CYourAppView::Period, this) );
  • Реализовать статический метод Period():
TInt CYourAppView :: Period( TAny* aPtr )
{
CYourAppView view = static_cast< CYourAppView *>( aPtr );
// расcчет и отображение очередного кадра
view->DrawNewFrame();
return ETrue;
}

У данного подхода есть свои достоинства и недостатки.

Достоинства:

  • Простота реализации
  • Компактность
  • Не требуется каких-либо специальных capabilities

Недостатки:

  • Для организации задержки используется активны объект - таймер. Активные объекты реализуют кооперативную многозадачность. Активных объектов, в рамках одного приложения, может быть достаточно много - соответственно, нет гарантий того, что callback-функция будет вызываться таймером через строго равные промежутки времени (другой активный объект может слишком долго не передавать управление). В результате, анимация может получиться "рваной". Частично эту проблему можно решить, указав таймеру при создании более высокий приоритет, однако это может помочь далеко не всегда.
  • Клиентский процесс имеет низкий приоритет (по сравнению с серверными процессами), соответственно, более высокоприоритетные процессы могут излишне часто его "вытеснять" – в результате анимация, опять же, может получиться "рваной".

Contents

Анимация на стороне сервера

В Symbian представлены специальные возможности для создания качественной анимации. Подход следующий:

  • Отображение кадров происходит благодаря плагину к Window Server. Плагин выполняется ввиде отдельной DLL с полиморфным интерфейсом. Соответственно, функционирует плагин в рамках высокоприоритетной серверной нити.
  • Для взаимодействия с серверной частью приложения создается клиентская DLL со статическим интерфейсом. Эта библиотека реализует механизм пересылки команд серверу.
  • Основное приложение взаимодействует с клиентской библиотекой для активация и передачи команд серверу.

Такой подход исключает недостатки, возникающие при реализации анимации на стороне клиента. Отрисовка кадров происходит в рамках высокоприоритетной серверной нити, количество одновременно функционирующих активных объектов, необходимых для отображения, легко сводится к минимуму. Однако у такого подхода, помимо возросшей сложности, есть еще один существенный недостаток. Для всех трех компонентов необходим расширенный набор возможностей (capabilities): PowerMgmt ReadDeviceData WriteDeviceData ProtServ. Соответственно, для установки этого примера на смартфон потребуется сертификат разработчика.

Пример реализации анимации на стороне сервера

В качестве примера рассмотрим приложение в котором осуществляется вращение двух параллелепипедов в разных плоскостях.

AnimExample.PNG

Вращение осуществляется благодаря постоянному изменению углов поворота. Для расчета координат вершин параллелепипедов в каждый момент времени производится умножение вектора с координатами на матрицу поворота. Текущий параллелепипед выбирается с помощью кнопок 1,2. Приращение углов поворота можно менять(с помощью кнопок влево-вправо) и сбрасывать(кнопка 0) с помощью индикаторов - для этого нужный индикатор необходимо предварительно выбрать (вверх-вниз).

Исходный код данного примера: File:AnimExampleSrc.zip.

Реализация серверной части

Для создания серверной DLL нужно реализовать собственного потомка класса CAnimDll, в нем должна быть реализована чистая виртуальная функция-фабрика CAnim* CreateInstanceL( TInt aType ). Эта функция, как видно из прототипа, возвращает указатель на созданный объект-потомок абстрактного класса CAnim.

class CAnimServerDll : public CAnimDll
{
public:
CAnimServerDll();
 
public:
IMPORT_C CAnim* CreateInstanceL( TInt aType );
};

В Symbain представлены три потомка класса CAnim, которые можно использовать для создания анимации: CWindowAnim, CFreeTimerWindowAnim, CSpriteAnim. В этом примере используется класс, порожденный от CWindowAnim.

class CAnimation : public CWindowAnim, public MTimerNotifier
{
public:
CAnimation( TInt aNo );
virtual ~CAnimation();
 
public: // MTimerNotifier
void TimedOut();
 
public:
void ConstructL( TAny* aArgs, TBool aHasFocus );
TInt CommandReplyL( TInt aCommand, TAny* aArgs );
void Command( TInt aCommand, TAny* aArgs );
 
void Redraw();
void Animate( TDateTime* aDateTime );
 
void FocusChanged( TBool /*aState*/ ) {}
TBool OfferRawEvent( const TRawEvent &aRawEvent );
 
private:
CParallelepiped *iPrl; // вся логика расчета и отображения объекта
TInt iNo; // номер объекта
CAnimTimer* iServerTimer;
};

Данный класс реализует интерфейс MTimerNotifier так как для задержки между отображением кадров используется собственный таймер CAnimTimer. Следует отметить, что у объектов, порожденных от CAnim, уже есть специализированный таймер, который может использоваться системой для аналогичных целей, однако в данном случае он не используется. Поэтому Timeout() содержит собственный вызов Animate() (с помощью члена-данного iFunctions, который предварительно отключает графический контекст, а затем вызывает метод Animate() данного класса) и инициирует новую задержку таймера.

void CAnimation::TimedOut()
{
// установка значения задержки таймера для следующего вызова
iServerTimer->After( KTimerPeriod );
// с помощью данного вызова происходит отрисовка текущего кадра
iFunctions->Animate( 0 );
}

Метод Animate(), в свою очередь, производит расчет новых координат вершин параллелепипеда и инициирует обновление экрана.

void CAnimation::Animate( TDateTime* /* aDateTime */ )
{
// расчет новых координат
iPrl->Calc();
// экран должен быть обновлен
iWindowFunctions->Invalidate( iWindowFunctions->WindowSize() );
}

Обновление экрана производится в методе Redraw() который отображает параллелепипед, координаты которого были рассчитаны предварительно.

void CAnimation::Redraw()
{
// отображение очередного кадра
iPrl->Draw( *iGc );
}

Методы CommandReply(), Command() - это обработчики команд, полученных от клиента. Оба метода объявлены как чистые виртуальные в предке, в качестве параметров, принимают идентификатор команды TInt aCommand и ее параметры TAny* aArgs. В данном примере используется только метод Command(). Рассмотрим, каким образом передаются параметры команд:

Клиентская часть инициирует команду:

   TPckgBuf<TInt> param;
param() = 55;
RAnim::Command( KChangeGaugeValue, param );

Серверная часть ( CAnim :: Command() ) ее обрабатывает:

   switch( aCommand )
{
...
case KChangeGaugeValue:
TInt cmdValue = *( STATIC_CAST( TInt*, aArgs ) );
...
break;
}

Для корректной сборки серверной библиотеки необходимо правильно задать ряд параметров проекта (см. mmp-файл):

TARGETTYPE: ani
UID2: 0x10003b22

Клиентская библиотека

Для создания клиентской библиотеки необходимо реализовать собственного потомка класса RAnimDll

class RAnimClientDll : public RAnimDll
{
public:
IMPORT_C RAnimClientDll( RWsSession& aSession );
};

Кроме того, необходимо реализовать класс, который инициализирует серверную анимацию и предоставляет интерфейс для посылки команд. Класс должен быть потомком RAnim:

class RAnimation : public RAnim
{
public:
IMPORT_C RAnimation( RAnimDll& aAnimDll );
IMPORT_C void CreateAnimation( onst RWindowBase& aDevice, TInt aType, TDisplayMode aMode );
 
IMPORT_C void AnimCommand( TInt aCommand, const TPtrC8 &aArgs );
IMPORT_C void AnimCommand( TInt aCommand );
 
public:
 
IMPORT_C void ChangeCurrentValue( TBool aInc );
IMPORT_C void ChangeCurrent( TBool aNext );
IMPORT_C TInt CurrentGauge();
 
// команды, обрабатываемые на сервере
enum KAnimCommands
{
KReset = 1,
KResolutionChange = 2,
KChangeFocus = 3,
KChangeGauge = 4,
KChangeGaugeValue = 5
};
 
private:
TInt iDx, iDy, iDz; // значение приращений углов поворота
TInt* iCurrent; // текущее приращение
};

Метод CreateAnimation() используется для инициализации серверного объекта – для этого вызывается метод предка RAnim :: Construct(). В качестве параметра создаваемому объекту передается значение TDisplayMode, которое используется для конструирования объектов, отвечающих за двойную буферизацию.

Методы AnimCommand() используются для передачи команд серверному объекту, команды могут быть как с параметрами, так и без них.

Методы:

  • ChangeCurrentValue() - изменяет значение текущего индикатора и посылает команду серверу
  • ChangeCurrent() – изменяет текущий индикатор и посылает команду серверу
  • CurrentGauge() – возвращает значение текущего индикатора

Использование в пользовательском интерфейсе

Для взаимодействия с серверной частью в рамках GUI, нужно использовать клиентскую библиотеку.

Для инициализации и загрузки сервером библиотеки с анимацией необходимо вызвать метод Load() у объекта класса RAnimClientDll (потомок RAnimDll). В качестве параметра этот метод принимает полное имя файла серверной библиотеки. Нужно учитывать - на эмуляторе и в реальном устройстве строки, содержащие полный путь до библиотеки, не совпадают.

Для каждого серверного объекта, отвечающего за отображение анимации, создается клиентская часть с помошью которой выполняется инициализация и посылка команд. В данном примере, для отображения двух параллелепипедов в рамках AppUi, создаются два объекта класса RAnimation. Эти объекта создаются в конструкторе AppUi, а в методе ConstructL() инициализируют серверную часть с помощью метода CreateAnimation().

AppUi содержит обработчик событий клавиатуры - метод HandleKeyEventL(). В нем, в зависимости от нажатой клавиши, вызываются функции объектов класса RAnimation результатом которых является посылка команд на сервер.

Замечание: для того чтобы приложение, содержащее данное GUI, успешно скомпоновалось, необходимо в список библиотек (в mmp-файле) добавить клиентскую библиотеку - в данном случае AnimClient.lib

This page was last modified on 10 November 2011, at 03:18.
222 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×