Продолжая нашу замечательную линейку 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), которые нам пригодятся для следующего типа кнопки.
Данный элемент мне очень приглянулся, наверно, что-то подобное сделаю и на 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'а, ведь теперь у нас в распоряжении кнопки, что сильно упрощает сборку нормальной демки...
p.s. Хотя мне не терпится продемонстрировать всю мощь MenuManager'а, ведь теперь у нас в распоряжении кнопки, что сильно упрощает сборку нормальной демки...
давно очень жду новых примеров, они будут?
ОтветитьУдалитьпривет!
Удалитьочень рад слышать, что эти наработки интересны! спасибо!
дело в том, что я больше не программирую на Glscene или Delphi... в основном работаю на Flash.
поэтому я не планировал дальше развивать тему gui на Glscene... все-таки движок действительно умирает, хотя очень жаль это признавать...
тема красивого интерфейса мне очень интересна, поэтому я бы с радостью продолжил написание демок... но не знаю, в каком направлении лучше двигаться дальше...
если не трудно - напиши, что именно было полезным из примеров?
если сама идея создания того или иного элемента - я могу попробовать продолжить подобные заметки, но о создании интерфейсных элементов на Flash.
заранее спасибо за помощь!