Анимация новогоднего поздравления начинается неожиданно для пользователя компьютера, вызывая у обладателей чувства юмора 😊 положительные эмоции. Установка программы заключается в незаметном копировании папки с файлами на компьютер кандидата получения радости от новогоднего поздравления. После запуска программы, через установленное время выводится анимированное шоу поздравления поверх всех окон, после отработки установленного количества показа программа автоматически закрывается. Исходный код можно применить для создания других поздравительных компьютерных анимаций.
Исходный код программы написан на C# и платформе Windows Presentation Foundation (WPF) существенно облегчающей создание красочных анимаций. Исходник поздравления состоит из двух классов: главного окна MainWindow и класса автономной анимации AnimationObject.
Класс MainWindow - отвечает за размещение контейнера для изображений и визуальной панели настройки режимов работы и запуска программы. Здесь же находится метод запуска анимированного новогоднего поздравления.
Класс AnimationObject - осуществляет анимацию картинок елочных игрушек и вывод текста «С Новым Годом!». В классе определено событие завершения анимации для использования во внешнем коде.
Основное изображение с елочными ветками и снежинками загружается фиксированно в элемент Image из кода разметки XAML. Анимация появления елочных игрушек и текста «С Новым Годом!» происходит на дополнительном элементе Image и накладывается поверх основного изображения. Совпадение размеров и расположения основного и дополнительного Image создает видимость единой мультипликации.
В классе MainWindow происходит управление запусками и исчезновением анимированного окна. Новогоднее поздравление построено на пошаговом выполнении отдельных анимаций. Для этого используются события завершения анимаций, в обработчиках которых запускается следующий этап мультика. Чтобы не раскидывать код на многие методы, все обработчики событий Completed определяются локально посредством лямбда-выражений в одном методе. При таком построении кода каждый обработчик должен обязательно определяться до вызова метода запуска своей анимации.
В первую очередь запускается плавная анимация спуска окна сверху экрана на объекте класса DoubleAnimation, затем объект класса AnimationObject начинает дискретно-повременной показ фреймов елочных украшений на ObjectAnimationUsingKeyFrames с обратной анимацией. И последней включается анимация плавного исчезновения поздравления управляя свойством Opacity главного окна посредством DoubleAnimation.
Программный код пошаговой анимации новогоднего поздравления с локальными определениями событий:
// Последовательная анимация новогоднего поздравления
private void AnimationWindow()
{
// Координаты начального положения окна
double fromY = -(Height + _offsetWindow);
double toY = 0;
// Подготовка объекта анимации.
AnimationObject animObject = new(mainGrid);
// Настройки анимации спуска окна сверху экрана.
DoubleAnimation yAnimation = new()
{
From = fromY,
To = toY,
Duration = new Duration(TimeSpan.FromSeconds(_durationDropdown)),
FillBehavior = FillBehavior.Stop,
};
// Локальное определение обработчика события завершения анимации появления окна.
// Данный обработчик должен определяться перед запуском соответствующей анимации.
yAnimation.Completed += (sender, eArgs) =>
{
// Локальное определение обработчика завершения анимации кадров объекта.
// Данный обработчик должен определяться перед
// запуском соответствующей анимации.
animObject.CompletedEvent += () =>
{
DoubleAnimation opacity = new()
{
From = 1,
To = 0,
Duration = new Duration(TimeSpan.FromSeconds(_durationOpacity)),
FillBehavior = FillBehavior.Stop,
};
// Локальное определение обработчика события
// завершения анимации прозрачности.
opacity.Completed += (sender, eArgs) =>
{
// Возврат окна к исходной позиции
Top = -(Height + _offsetWindow);
// Уменьшаем счетчик повторений анимированного поздравления.
_mainCounter--;
// Закончилось количество повторений показов поздравления,
// после этого закрываем программу.
// Меньше нуля может быть при установке пользователем 0 повторений.
if (_mainCounter <= 0)
{
// Закрытие программы новогоднего поздравления.
Close();
// Обязательный выход из метода для успешного закрытия программы,
// иначе во время закрытия программы
// дальнейший код может запуститься и вызвать исключение.
return;
}
// Запуск повтора анимации поздравления через определенное время.
DelayAnimation();
};
BeginAnimation(OpacityProperty, opacity);
};
// Запуск работы объекта анимации
animObject.Animation();
};
// Запуск анимации спуска окна главной картинкой
BeginAnimation(TopProperty, yAnimation);
}
Повторение анимированного окна поздравлений происходит через определенное время. Запуском анимации управляет локальный DispatcherTimer из метода DelayAnimation() класса MainWindow. К таймеру подключается анонимный обработчик тиков, определенный как лямбда выражение. Лямбда выражения позволяют создавать компактные программные коды с большой функциональностью. После отработки одного тика таймер выгружается из памяти.
Метод DelayAnimation() периодического запуска анимированного поздравления с локальным таймером:
// Запуск анимации поздравления через определенное время.
private void DelayAnimation()
{
// Локальный таймер для запуска первой анимации через назначенное время.
DispatcherTimer timer = new() { Interval = TimeSpan.FromSeconds(_repeatPeriod) };
// Подключение к событию тиков таймера анонимного обрабочика
timer.Tick += (sender, args) =>
{
timer.Stop();
// Запуск рабочей анимации новогоднего поздравления.
AnimationWindow();
};
timer.Start();
}
AnimationObject - класс автономной анимации изображений по кадрам. Список названий изображений из ресурсов приложения хранится в массиве. В своем составе класс имеет событие окончания анимации, обработчик которого можно определять во внешних классах.
При создании объекта AnimationObject в его конструкторе создается элемент Image и добавляется на главную панель окна приложения, Этот Image служит плоскостью для воспроизведения анимации, накладываемой поверх основного изображения, определенного в файле XAML приложения.
Во время работы метода Animation() в объекте ObjectAnimationUsingKeyFrames на базе списка изображений создается коллекция фреймов (кадров) из элементов класса DiscreteObjectKeyFrame. Каждому фрейму выделяется определенное время показа в процентах от общего времени анимации. В этом же методе локально подключается обработчик события завершения анимации фреймов, который, в свою очередь, вызывает событие CompletedEvent для внешнего использования.
Листинг кода класса AnimationObject:
class AnimationObject
{
// Собственное событие завершения анимации объектом данного класса.
public delegate void CompletedEventHandler();
public event CompletedEventHandler? CompletedEvent;
// Массив кадров анимации
readonly string[] uriSources = {
// Нулевой фрейм загружается в XAML
//"img/frame0.png",
"img/frame1.png",
"img/frame2.png",
"img/frame3.png",
"img/frame4.png",
"img/frame5.png",
"img/frame6.png",
"img/frame7.png"
};
// Контейнер для объекта изображения
private readonly Panel? _parent = null;
// Плоскость для анимации фреймов из изображений ресурсов
private readonly Image image;
public AnimationObject(Panel parent)
{
_parent = parent;
// Инициализация объекта изображения.
// Это экран для показа картинок анимации.
image = new()
{
Margin = new Thickness(0, 0, 0, 0),
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top,
Stretch = System.Windows.Media.Stretch.Fill,
Visibility = Visibility.Visible
};
// Добавляем изображение-экран на главную панель окна программы.
_parent.Children.Add(image);
}
public void Animation()
{
// Количество кадров
int numberFrames = uriSources.Length;
// Создание объекта управления кадрами анимации
ObjectAnimationUsingKeyFrames objectAnimation = new()
{
// Общее время анимации
Duration = new Duration(TimeSpan.FromSeconds(4)),
AutoReverse = true,
};
// Подключение обработчика события завершения анимации кадров.
objectAnimation.Completed += (sender, e) =>
{
// Вызываем событие завершения анимации для внешнего использования.
CompletedEvent?.Invoke();
};
// Добавление кадров анимации с одинаковым временем показа.
for (int i = 0; i < numberFrames - 2; i++)
{
objectAnimation.KeyFrames.Add(
new DiscreteObjectKeyFrame()
{
Value = new BitmapImage(new Uri(uriSources[i], UriKind.Relative)),
KeyTime = KeyTime.FromPercent(0.1 * i),
}
);
}
// Добавление 2-х кадров текстового поздравления с Новым Годом!
// с более длительным временем показа.
objectAnimation.KeyFrames.Add(
new DiscreteObjectKeyFrame()
{
Value = new BitmapImage(new Uri(uriSources[numberFrames - 2],
UriKind.Relative)),
KeyTime = KeyTime.FromPercent(0.6),
}
);
objectAnimation.KeyFrames.Add(
new DiscreteObjectKeyFrame()
{
Value = new BitmapImage(new Uri(uriSources[numberFrames - 1],
UriKind.Relative)),
KeyTime = KeyTime.FromPercent(0.75),
}
);
// Запуск однократной анимации
image.BeginAnimation(Image.SourceProperty, objectAnimation);
// TODO Подключение события после запуска анимации не функционально.
//objectAnimation.Completed += ObjectAnimation_Completed;
}
}
Папка с файлами программы копируется на компьютер. Запускается приложение , при необходимости производится настройка количества повторов и время промежутков между ними. Далее нажимается кнопка «Старт», окно программы исчезает и новогоднее поздравление появляется через время, определенное в настройках.
После отработки указанного количества повторов приложение автоматически закрывается. Принудительно закрыть видимое приложение можно сочетанием нажатии любой клавиши Ctrl и щелчком кнопки мыши на любую часть приложения. Невидимое приложение можно закрыть с помощью Диспетчера задач Windows в контекстном меню на названии программы пунктом «Снять задачу».
Ниже прикреплен архив исходника приложения анимации новогоднего поздравления. Программный код написан в Visual Studio 2022, .NET6. Минимальная операционная система Windows 7 с установленной .NET Desktop Runtime version 6. Код приложения легко приспособить для создания других подобных анимаций.