Компьютерная графика, мультимедиа и игры на Visual C#

       

Методика изображения летающих предметов 


Листинг 59.1. Объявление объекта и глобальных переменных.

//Задаем ширину и высоту прямоугольника,

//внутри которого будет летать мяч:

int width_of_rectangle = 1000;

int height_of_rectangle = 500;

//Верхняя горизонтальная линия прямоугольника отстоит

//от оси 'x' на расстоянии boundary_of_rectangle_у:

int boundary_of_rectangle_у = 15;

//Левая вертикальная линия прямоугольника отстоит

//от оси 'y' на расстоянии boundary_of_rectangle_x:

int boundary_of_rectangle_x = 15;

//Размер мяча size_of_ball, как часть (доля)

//от размеров прямоугольника:



int size_of_ball = 20;

//Величина перемещения мяча size_of_move_of_ball,

//как часть (доля) от размеров мяча:

int size_of_move_of_ball = 5;

 

//Создаем объект myBitmap класса Bitmap:

private Bitmap myBitmap;

       

//Объявляем целочисленные переменные:

int position_of_ball_x, position_of_ball_y,

      radius_of_ball_x, radius_of_ball_y,

      move_of_ball_x, move_of_ball_y,

      width_of_bitmap_of_ball, height_of_bitmap_of_ball,

      width_of_margin_of_bitmap, height_of_margin_of_bitmap;

Дважды щелкаем по диалоговой панели Form1 в режиме проектирования и в появившийся шаблон записываем следующий наш код.

Листинг 59.2. Метод Form1_Load.

private void Form1_Load(object sender, EventArgs e)

{

      //Создаем объект myGraphics класса Graphics

      //и стираем другие изображения:

      Graphics myGraphics = CreateGraphics();

      myGraphics.Clear(BackColor);

      //Задаем радиус мяча как дробь (часть)

      //от ширины или высоты прямоугольника,

      //в зависимости от того, какая дробь меньше:

      double radius_of_ball  =

      Math.Min(width_of_rectangle / myGraphics.DpiX,

      height_of_rectangle / myGraphics.DpiY) / size_of_ball;

       

      //Задаем ширину и высоту мяча в DPI (ТОЧКИ НА ДЮЙМ)

      //для единиц разрешения изображения

      //по горизонтали и вертикали, что идентично значениям

      //в направлении осей 'x' и 'y':

      radius_of_ball_x = Convert.ToInt32(radius_of_ball *


                        myGraphics.DpiX);
      radius_of_ball_y = Convert.ToInt32(radius_of_ball *
                        myGraphics.DpiY);
      //Высвобождаем ресурсы, выделенные объекту myGraphics:
      myGraphics.Dispose();
      // Задаем шаг перемещения мяча или в 1 пиксель,
      //или как часть (дробь, доля) от размера шара,
      //в зависимости от того, какая величина больше.
      //Это означает, что на каждом шаге перемещение мяча
      //пропорционально его размеру,
      //а размер мяча, в свою очередь,
      //пропорционален размеру прямоугольника.
      //Таким образом, при прочих равных условиях,
      //когда размеры прямоугольника уменьшаются,
      //перемещение мяча замедляется,
      //и когда увеличиваются, перемещение мяча убыстряется:
      move_of_ball_x = Convert.ToInt32(Math.Max(1,
                  radius_of_ball_x / size_of_move_of_ball));
      move_of_ball_y = Convert.ToInt32(Math.Max(1,
                  radius_of_ball_y / size_of_move_of_ball));
      //Значение перемещения мяча также определяет
      //поле изображения вокруг мяча.
      //На каждом шаге перемещение мяча
      //равно перемещению поля изображения,
      //что позволяет стирать предыдущее изображение мяча
      //перед каждым последующим изображением мяча
      //без мерцания:
      width_of_margin_of_bitmap = move_of_ball_x;
      height_of_margin_of_bitmap = move_of_ball_y;
      //Определяем фактический размер изображения,
      //где нарисован мяч,
      //прибавляя поля к размерам мяча:
      width_of_bitmap_of_ball = 2 * (radius_of_ball_x +
                                 width_of_margin_of_bitmap);
      height_of_bitmap_of_ball = 2 * (radius_of_ball_y +
                                height_of_margin_of_bitmap);
      //Создаем новый рисунок мяча
      //соответствующей ширины и высоты:
      myBitmap = new Bitmap(width_of_bitmap_of_ball,
      height_of_bitmap_of_ball);


      //Получаем объект класса Graphics
      //для изображения мяча,
      //удаляем существующий мяч и рисуем новый мяч.
      // Задаем черный цвет Black для мяча,
      //чтобы он был лучше виден в книге:
      myGraphics = Graphics.FromImage(myBitmap);
      myGraphics.Clear(BackColor);
      myGraphics.FillEllipse(Brushes.Black, new
                Rectangle(move_of_ball_x,
                move_of_ball_y, 2 * radius_of_ball_x, 2 *
                radius_of_ball_y));
      //Высвобождаем ресурсы, выделенные объекту myGraphics:
      myGraphics.Dispose();
       
      //Задаем расположение мяча в центре прямоугольника:
      position_of_ball_x =
                    Convert.ToInt32(width_of_rectangle / 2);
      position_of_ball_y =
                   Convert.ToInt32(height_of_rectangle / 2);
}
Чтобы подключить к работе таймер, дважды щелкаем значок для компонента Timer (ниже формы в режиме проектирования). Появляется файл Form1.cs с шаблоном, который после записи нашего кода принимает следующий вид.
Листинг 59.3. Метод для компонента Timer.
private void timer1_Tick(object sender, EventArgs e)
{
      //Создаем объект myGraphics класса Graphics:
      Graphics myGraphics = CreateGraphics();
       
      //Рисуем четыре граничные линии прямоугольника,
      //от которых будет отскакивать летающий мяч:
      myGraphics.DrawLine(new Pen(Color.Red, 3),
      boundary_of_rectangle_x, boundary_of_rectangle_у,
      width_of_rectangle, boundary_of_rectangle_у);
      myGraphics.DrawLine(new Pen(Color.Red, 3),
      boundary_of_rectangle_x, boundary_of_rectangle_у,
      boundary_of_rectangle_x, height_of_rectangle);
      myGraphics.DrawLine(new Pen(Color.Red, 3),
      boundary_of_rectangle_x, height_of_rectangle,
      width_of_rectangle, height_of_rectangle);
      myGraphics.DrawLine(new Pen(Color.Red, 3),
      width_of_rectangle, boundary_of_rectangle_у,
      width_of_rectangle, height_of_rectangle);


      // Рисуем изображение мяча на диалоговой панели Form1
      //при помощи метода DrawImage:
      myGraphics.DrawImage(myBitmap,
        Convert.ToInt32(position_of_ball_x -
        width_of_bitmap_of_ball / 2),
        Convert.ToInt32(position_of_ball_y -
        height_of_bitmap_of_ball / 2),
        width_of_bitmap_of_ball,  height_of_bitmap_of_ball);
      //Высвобождаем ресурсы, выделенные объекту myGraphics:
      myGraphics.Dispose();
      //После изображения мяча с текущими координатами
      //увеличиваем координаты мяча
      //на шаг перемещения в направлении осей 'x' и 'y':
      position_of_ball_x = position_of_ball_x +
                                             move_of_ball_x;
      position_of_ball_y = position_of_ball_y +
                                             move_of_ball_y;
 
      //Изменяем направление перемещения мяча по оси 'x',
      //когда мяч ударяется о какую-либо из двух
      //граничных вертикальных линий прямоугольника:
      if (position_of_ball_x + radius_of_ball_x >=
                                         width_of_rectangle)
      {
           move_of_ball_x = -move_of_ball_x;
           //В момент удара подаем звуковой сигнал Beep:
           Microsoft.VisualBasic.Interaction.Beep();
      }
      if (position_of_ball_x - radius_of_ball_x <=
                                    boundary_of_rectangle_x)
      {
          move_of_ball_x = -move_of_ball_x;
          Microsoft.VisualBasic.Interaction.Beep();
      }
      //Изменяем направление перемещения мяча по оси 'y',
      //когда мяч ударяется о какую-либо из двух
      //граничных горизонтальных линий прямоугольника:
      if (position_of_ball_y + radius_of_ball_y >=
                                        height_of_rectangle)
      {                     
           move_of_ball_y = -move_of_ball_y;
           Microsoft.VisualBasic.Interaction.Beep();
      }
      if (position_of_ball_y - radius_of_ball_y <=


                                    boundary_of_rectangle_у)
      {
           move_of_ball_y = -move_of_ball_y;
           Microsoft.VisualBasic.Interaction.Beep();
      }
}
В этом коде главным является вызов перегруженного метода DrawImage, который в VC# имеет много видов перегрузки. Здесь использован вид перегрузки номер 13 с сигнатурой: Overloads Public Sub DrawImage(Image, Integer, Integer, Integer, Integer). Этот метод мы уже объясняли в предыдущей главе.
Чтобы установить значение свойства Interval компонента Timer в зависимости от свойства Value ползунка элемента управления TrackBar, дважды щелкаем элемент управления TrackBar в режиме проектирования. Появляется файл Form1.cs с шаблоном, который после записи нашего кода принимает следующий вид.
Листинг 59.4. Метод для элемента управления TrackBar.
private void trackBar1_Scroll(object sender, EventArgs e)
{
    timer1.Enabled = true;
    timer1.Interval = trackBar1.Value;
}
Согласно разработанной выше методике, чтобы иметь возможность приостановить (и запустить вновь) процесс анимации на любом рисунке при помощи кнопки Stop Animation, дважды щелкаем эту кнопку в режиме проектирования (рис. 59.1). Появляется файл Form1.cs с шаблоном, выше которого объявляем переменную OffOn и присваиваем ей значение false:
//Объявляем булеву переменную OffOn
//и задаем ей значение, например, false:
bool OffOn = false;
После записи нашего кода шаблон принимает вид следующего метода.
Листинг 59.5. Метод для кнопки Stop Animation.
private void button6_Click(object sender, EventArgs e)
{
      //Задаем чередование остановки и возобновления анимации
      //после каждого щелчка кнопки button2:
      if (OffOn == false)
      {
            //Приостанавливаем анимацию:
            timer1.Enabled = false;
            //Изменяем значение OffOn на противоположное:
            OffOn = true;
      }
      else
      {
            //Возобновляем анимацию:
            timer1.Enabled = true;
            //Изменяем значение OffOn на противоположное:


            OffOn = false;
      }
}
Как и выше, наши подробные комментарии на всех листингах помогут читателю грамотно внести изменения в код (если читатель пожелает модернизировать анимацию для учета собственных требований).
Листинг 59.6. Метод для компонента PrintDocument.
private void printDocument1_PrintPage(object sender,
               System.Drawing.Printing.PrintPageEventArgs e)
{
      //Создаем объект myGraphics класса Graphics:
      Graphics myGraphics = CreateGraphics();
      //Связываем объект myGraphics с текущим принтером:
      myGraphics = e.Graphics;
       
      //Рисуем четыре граничные линии прямоугольника,
      //от которых будет отскакивать летающий мяч:
      myGraphics.DrawLine(new Pen(Color.Red, 3),
      boundary_of_rectangle_x,   boundary_of_rectangle_у,
      width_of_rectangle, boundary_of_rectangle_у);
      myGraphics.DrawLine(new Pen(Color.Red, 3),
      boundary_of_rectangle_x, boundary_of_rectangle_у,
      boundary_of_rectangle_x, height_of_rectangle);
      myGraphics.DrawLine(new Pen(Color.Red, 3),
      boundary_of_rectangle_x, height_of_rectangle,
      width_of_rectangle, height_of_rectangle);
      myGraphics.DrawLine(new Pen(Color.Red, 3),
      width_of_rectangle, boundary_of_rectangle_у,
      width_of_rectangle, height_of_rectangle);
      //Рисуем изображение мяча на диалоговой панели Form1
      //при помощи метода DrawImage:
      myGraphics.DrawImage(myBitmap,
                        Convert.ToInt32(position_of_ball_x -
                        width_of_bitmap_of_ball / 2),
                        Convert.ToInt32(position_of_ball_y -
                        height_of_bitmap_of_ball / 2),
                        width_of_bitmap_of_ball,
                        height_of_bitmap_of_ball);
       
      //Высвобождаем ресурсы, выделенные объекту myGraphics:
      myGraphics.Dispose();
}
Теперь дважды щелкаем кнопку Print (рис. 59.1). Открывается файл Form1.cs с шаблоном, который после записи нашего кода принимает следующий вид.
Листинг 59.7. Метод для кнопки Print.
private void button3_Click(object sender, EventArgs e)
{
      //Передаем объекту PrintDialog1 информацию об объекте
      //PrintDocument1 при помощи свойства Document:
      printDialog1.Document = printDocument1;
      //Выводим стандартную панель Print при помощи метода
      //ShowDialog для задания параметров печати:
      if (printDialog1.ShowDialog() == DialogResult.OK)
                        printDocument1.Print();
}
Таким образом, по разработанной в данной главе методике можно спроектировать анимацию на экране монитора и печать текущего положения анимации на принтере для любого предмета (в виде мяча, шара, пули и т.п.), летающего в открытом или замкнутом пространстве.

Содержание раздела