11 мая 2012

Gui: ButtonsDemo

Продолжая нашу замечательную линейку gui-элементов, я решил немного отдохнуть, порисовав контента для будущих демок. В итоге моих вечерних трудов, я понял, что анимировать задуманное нетрудно, поэтому сразу вставил получившиеся картинки в тестовый проект и проверил работоспособность отдельных элементов. Демо получилось простенькое, но симпатичное!
Итак, сегодня я решил показать, как можно легко и быстро строить простые кнопки, расширяя базовый функционал основных gui-объектов.
В итоге, наше демо выглядит так:


Впрочем, анимацию ведь сложно выразить скриншотом?! Поэтому я решил записать видео, как обычно:

Думаю, проще всего идти от одного элемента к другому, расписывая код каждого анимационного эффекта.
Итак, приступим!

Scale-кнопка

Данный объект меняет свои размеры при наведении кнопки мыши (в нашем демо такая кнопка имеется надпись $19)
Мы уже научились манипулировать прозрачностью спрайтов, поэтому менять размер не представляет труда. Достаточно написать вот такой код, и все начнет работать как часы:

  fScale := 1 + 0.2 * (fAnimationTime - cst_animTimeShow) / (cst_animTimeActive - cst_animTimeShow);

  fHudSprite.Width := fScale * fActiveMaterial.Texture.Image.Width;
  fHudSprite.Height := fScale * fActiveMaterial.Texture.Image.Height;

Однако, сам эффект линейного изменения размера выглядит немного "деревянным", некрасивым. Поэтому я решил воспользоваться готовым tween-модулем, для создания более живого и веселого эффекта. В итоге наш класс scale-кнопки выглядит достаточно просто:

  TGUIScaleButton = class(TGUICustomTweenButton)
  protected
    fBaseSize: TVector;
    fScale: Single;
  public
    Procedure DoRender(var ARci: TRenderContextInfo; ARenderSelf, ARenderChildren: Boolean); override;
    Procedure Activate; override;
    Procedure DeActivate; override;
    Procedure SetMaterial(fButtonMaterialName: String; aMatLib: TGlMaterialLibrary);
  end;

А вот и реализация Activate/Deactivate, с использованием твининга:

Procedure TGUIScaleButton.Activate;
begin
  inherited Activate;
  fTweener.DeletePSingle(@fScale);
  fTweener.AddTweenPSingle(@fScale, ts_ElasticEaseIn, fScale, 1.2, 1.5);
end;

Procedure TGUIScaleButton.DeActivate;
begin
  inherited DeActivate;
  fTweener.DeletePSingle(@fScale);
  fTweener.AddTweenPSingle(@fScale, ts_ElasticEaseIn, fScale, 1, 1);
end;


Slide-кнопка

Если честно, не уверен, что данный элемент может быть часто применим. Возможно, для каких-то отдельных страниц игры вроде кредитсов или же в качестве выделенного объекта, который бы не так часто нажимался юзером. В противном случае, у игрока может начать рябить в глазах от выползаний дополнительной строки. Так или иначе, я все же решил продемонстрировать, как можно создать подобную кнопку, совсем немного расширив базовый класс.

Procedure TGUISliderButton.DoRender(var ARci: TRenderContextInfo; ARenderSelf, ARenderChildren: Boolean);
begin
  fHudSprite.Position.x := Position.x;
  fHudSprite.Position.y := Position.y;

  PrepareButtonPosition;
  fHudSprite.Material := fSliderMaterial;
  fHudSprite.Width := fSliderMaterial.Texture.Image.Width;
  fHudSprite.Height := fSliderMaterial.Texture.Image.Height;
  fHudSprite.DoRender(ARci, true, false);

  PrepareSliderPosition;
  fHudSprite.Material := fButtonMaterial;
  fHudSprite.Width := fButtonMaterial.Texture.Image.Width;
  fHudSprite.Height := fButtonMaterial.Texture.Image.Height;
  fButtonMaterial.FrontProperties.Diffuse.Alpha := 1;
  fHudSprite.DoRender(ARci, true, false);
end;

То есть отрисовывается наша кнопка в два захода: сначала задняя, движущаяся часть, а затем передняя стационарная картинка. Для унификации процесса движения, я решил добавить два виртуальных метода (PrepareButtonPosition и PrepareSliderPosition), которые нам пригодятся для следующего типа кнопки.

3d-кнопка
Данный элемент мне очень приглянулся, наверно, что-то подобное сделаю и на Flash'е в какой-нибудь своей игре. Принцип работы идентичен до безобразия с принципом выезжания slide-кнопкой. Только вот движется верхний слой, плюс само перемещение происходит по диагонали, для создания эффекта 3д.

Procedure TGUI3dSlideButton.PrepareButtonPosition;
begin
  fHudSprite.Position.x := Position.x;
end;

Procedure TGUI3dSlideButton.PrepareSliderPosition;
begin
  fHudSprite.Position.x := fHudSprite.Position.x + 5 + 3*fSlidePos;
  fHudSprite.Position.y := fHudSprite.Position.y - 5 - 3*fSlidePos;
end;

Остальные кнопки в текущем демо, это уже известные нам TGUIAlphaButton. Добавил в демонстрацию я их лишь для того, чтобы показать разнообразие, которое можно быстро получить, всего лишь нарисовав две картинки (обычное и подсвеченное состояния кнопки). А ведь скорость разработки при минимальных затратах - это ключевое звено для успешности в индустрии!

Новые классы кнопок я решил положить в отдельный модуль, дабы не захламлять базовые юниты отсылкой к Tweener-классам. В итоге, скачать демонстрационную программу можно здесь, или же достаточно обновиться через svn (27ая ревизия), и скомпилировать проект ButtonsDemo.

Конечно, можно заметить и недостатки:
  • некоторые кнопки подсвечиваются немного в большей области, чем изображение самой кнопки (то есть навели на пустоту рядом с кнопкой, а она "подумала", что нужно бы подсветиться)
  • нет понятия "круговой области", то есть hitArea сейчас только прямоугольник
  • недостаточно развитая система событий, на данный момент кнопки посылают только OnClick
  • без класса "список кнопок" как-то угрюмо
Вот этими мелочами и займемся в следующий раз, продолжая нашу эпопею с кнопками :)
p.s. Хотя мне не терпится продемонстрировать всю мощь MenuManager'а, ведь теперь у нас в распоряжении кнопки, что сильно упрощает сборку нормальной демки...

Сообщения, схожие по тематике:

2 коммент.:

  1. давно очень жду новых примеров, они будут?

    ОтветитьУдалить
    Ответы
    1. привет!
      очень рад слышать, что эти наработки интересны! спасибо!
      дело в том, что я больше не программирую на Glscene или Delphi... в основном работаю на Flash.
      поэтому я не планировал дальше развивать тему gui на Glscene... все-таки движок действительно умирает, хотя очень жаль это признавать...

      тема красивого интерфейса мне очень интересна, поэтому я бы с радостью продолжил написание демок... но не знаю, в каком направлении лучше двигаться дальше...
      если не трудно - напиши, что именно было полезным из примеров?
      если сама идея создания того или иного элемента - я могу попробовать продолжить подобные заметки, но о создании интерфейсных элементов на Flash.
      заранее спасибо за помощь!

      Удалить