Мы с вами попытаемся создать приложение, которое заставит монитор истекать кровью. Использовать эту программу можно на компьютере жертвы во время праздника Хэллоуин.
Готовую программу необходимо будет скопировать заранее на компьютер друга и установить дату и время срабатывания. В назначенный час на мониторе выбранной жерты появится стекающая кровь, после чего появится картинка какого-нибудь монстра. Все это безобразие будет сопровождаться криком. Это должно напугать жертву, который любит отмечать праздник Хэллоуина.
Нам понадобится прозрачная форама на весь экран поверх все окон, чтобы закрыть все поверхность экрана. Форма послужит нам рабочей поверхностью для эффекта стекающей крови.
Установите у формы следующие свойства:
BackColor – Fuchsia
FormBorderStyle – None
DoubleBuffered – True
Text - <empty string>
WindowState – Maximized
ShowInTaskbar – False
TransparencyKey – Fuchsia
TopMost - True
Итак, мы создали необходимую форму без заголовка, значка на панели задач, границ и т.д. Теперь мы можем рисовать на форме все, что нам захочется. Хотя форма будет развернута, благодаря своей прозрачности, пользователь по-прежнему может нажимать на кнопки, которые находятся за нашей формой.
Создадим класс BloodDrop, который будет отвечать за кровь, стекающую по экрану. Этот эффект реализован при помощи заранне подготовленных картинок, сохраненных как ресурсы программы. Вы можете увидеть эти картинки в папке images. Чтобы включить картинки в ресурсы программы, необходимо установить у каждой картинки в свойстве Build Action значение Embedded Resource.
Картинки, которые хранятся как ресурсы, мы можем загружать в конструкторе BloodDrop следующим образом:
public BloodDrop() { // load each animation frame from the app's resources and add it to our frame list foreach(string file in _files) { Image img = Image.FromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream("Halloween.images." + file)); _frames.Add(img); } // set our first frame _image = _frames[0]; }
Метод FromStream объекта Image позволяет загружать файл с изображением из ресурсов. Для этого нам необходимо знать имя ресурса и имя файла. В нашем случае это Halloween.images.<filename>. Мы загружаем каждый файл и сохраняем его в списке List объекта Image.
Для гладкой анимации мы сделаем следующее. Мы будем использовать событие Tick для перерисовки экрана, при этом будет срабатывать событие OnPaint. Для плавности анимации мы установим значение свойства DoubleBuffered в True.
Для анимации крови используется таймер с интервалом 100 миллисекунд, который просто вызывает метод Invalidate. При этом срабатывает переопределенное событие OnPaint. Внутри обработчика OnPaint мы создаем новый объект BloodDrop и устанавливаем в случайном порядке горизонтальную позицию и скорость стекания капельки крови. Это создаст интересный эффект на экране монитора. Новый созданный объект BloodDrop добавляется в список List типа BloodDrop. Наконец, мы перечисляем список капель крови для анимации и вывода на экран.
// create a new blood drop BloodDrop drop = new BloodDrop(); // set it to a random location on the screen drop.Location = new Point(_random.Next(SystemInformation.PrimaryMonitorSize.Width), 0); // set it's velocity to a random number drop.Velocity = _random.Next(40) + 20; // add it to our drawing list _dropList.Add(drop); // enumerate the drawing list foreach(BloodDrop bd in _dropList) { // animate and then draw the drop bd.Animate(); bd.Draw(g); }
При запуске программы, создается экземпляр класс Random, который сохраняется в переменной _random . Метод Next использует параметр для максимального случайного значения числа. Для этого параметра мы будем использовать ширину экрана, которую можно определить с помощью объекта SystemInformation. Для скорости стекания капли будем использовать значение 40 пикселов и добавочные 20 пикселов, чтобы случайное число не было очень маленьким.
Само рисование капли очень просто. Метод Draw класса BloodDrop выглядит следующим образом:
// draw the drop public void Draw(Graphics g) { // if we're in "drop" mode, draw the stream behind it if(_index >= 4) g.DrawImage(_frames[4], this._location.X + 24, 0, _frames[4].Width, this._location.Y + 10); // if we're beyond the bottom of the screen, don't bother drawing the drop if(this._location.Y < SystemInformation.PrimaryMonitorSize.Height) g.DrawImage(_image, this._location.X, this._location.Y, _image.Width, _image.Height); }
Мы используем объект Graphics и используем метод DrawImage для рисования нужного кадра в нужной позиции. Чтобы не перегружать процессор компьютера, мы сначала определяем, когда капля достигнет нижнего края экрана и больше ее не рисуем. Размер экрана определяется при помощи метода PrimaryMonitorSize класса SystemInformation.
Чтобы не возникало искажений и мерцаний картинки, нужно установить следующие настройки для объекта Graphics перед выводом в OnPaint.
protected override void OnPaint(PaintEventArgs e) { ... // grab the Graphics object for this app and set some properties for correct drawing Graphics g = e.Graphics; g.PixelOffsetMode = PixelOffsetMode.Half; g.InterpolationMode = InterpolationMode.NearestNeighbor; g.CompositingQuality = CompositingQuality.HighSpeed; ... }
После того, как кровь стечет по экрану в течение нескольких секунд (по умолчанию 10 сек.), таймер анимации останавливается, экран очищается и неожиданно показывается страшная картинка с монстром и это действие сопровождается криком, который должен напугать пользователя.
Нам понадобится создать PictureBox на лету и загрузить в нее картинку. Затем объект добавляется в коллекцию Controls формы и выводится на экран. Дополнительно, мы создаем два обработчика событий, которые закрывают приложение, когда пользователь нажимает на клавишу или кнопку мыши.
Следует заметить, что звук также загружается из ресурсов и проигрывается через SoundPlay:
// disable the animation timer tmrAnim.Enabled = false; // create a Picturebox PictureBox pb = new PictureBox(); // pull in the scary image from our resources pb.Image = Image.FromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream("Halloween.images.scary.jpg")); // set it to fill the screen pb.SizeMode = PictureBoxSizeMode.Zoom; pb.Width = SystemInformation.PrimaryMonitorSize.Width; pb.Height = SystemInformation.PrimaryMonitorSize.Height; pb.BackColor = Color.Black; // if it gets clicked, or someone presses a key, we want to end the app pb.Click += new EventHandler(pb_Click); this.KeyDown += new KeyEventHandler(MainForm_KeyDown); // add the Picturebox to the controls list this.Controls.Add(pb); // play a scary sound SoundPlayer sp = new SoundPlayer(Assembly.GetExecutingAssembly().GetManifestResourceStream("Halloween.scream.wav")); sp.Play();
Теперь нам необходимо установить программу на компьютере жертвы и выбрать дату и время запуска. Для этого создадим простое окно конфигурации, которое показывает первое время запуска приложения. С помощью этой настройки можно будет выбрать нужную дату и время для кровавой анимации. Эти настройки сохраняются при помощи объекта Settings. Таким образом, можно скопировать программу в папку Автозагрузка или прописать запуск в реестре, чтобы в дальнейшем программа сама могла запуститься.
Для настроек заходим в Project | Properties | выбираем вкладку Settings и устанавливаем новое значение:
Теперь, при запуске, приложение проверяет установленные настройки. При этом включается таймер планировщика, который сравнивает текущее время с заданным каждую минуту. И если оно больше или равно заданному, то таймер отключается, скрытое окно разворачивается на весь экран и запускается таймер анимации.
// called once per minute to check whether it's time to run the show private void tmrScheduler_Tick(object sender, EventArgs e) { // if the current time is greater than the time set by the user if(DateTime.Now >= Properties.Settings.Default.Time) { // re-maximize the window this.WindowState = FormWindowState.Maximized; // disable this timer tmrScheduler.Enabled = false; // enable the animation timer tmrAnim.Enabled = true; } }
Так как, картинки и звук в программе используются как ресурсы, то достаточно использовать один файл для распространения и файл конфигурации.
Для показа окна настроек нужно вызвать программу с параметром -config
Наша программа готова. Вы можете модифицировать ее под свой вкус, добавив собственные картинки и звуки. Отмечайте праздник Хэллоуина.
Перевод: Василий Котов
Скачать пример