§ 17. Анімацыя

17.5. Анімацыя руху з выкарыстаннем бітавых вобразаў

Выкарыстанне бітавых вобразаў дазваляе абыходзіцца толькі адным кампанентам Image на форме. Пры спрацоўванні таймера аб'ект, які захоўваецца ў выглядзе бітавага вобраза, будзе прамалёўвацца па-над фону.

Аднак прамалёўка паверх наяўнага малюнка сапсуе малюнак фону. Таму перад прамалёўкай варта скапіраваць тую частку фону, паверх якой будзе выведзены аб'ект, у бітавы вобраз. А пры наступным спрацоўванні таймера варта аднавіць фон.

Алгарытм для рэалізацыі такой анімацыі будзе наступным:

  1. Захаваць частку фону.
  2. Намаляваць аб'ект.
  3. Запусціць таймер.
  4. Пакуль таймер працуе:
    4.1. аднавіць фон;
    4.2. разлічыць новае становішча аб'екта;
    4.3. захаваць частку фону;
    4.4. намаляваць аб'ект.

Прыклад 17.13. Стварыць праект, у якім месяц будзе лётаць вакол Зямлі.

Этапы выканання задання

  1. Змясціць на форму кампанент Image, кампаненты Timer і Button.
  2. Змяніць уласцівасці Caption у кампанента Button1 на «Старт».
  3. Устанавіць значэнне false ва ўласцівасці таймера Enabled.
  4. Устанавіць у інспектары аб'ектаў час спрацоўвання таймера роўным 100.
  5. Апісаць тры пераменных для захоўвання бітавых вобразаў: fon — для захоўвання фонавага малюнка, kadr — для захоўвання малюнка месяца, fon_kadr — для захоўвання часткі фону.
  6. Напісаць апрацоўшчык падзеі OnCreate для формы, у якім:
    6.1. Загрузіць з файла малюнак Зямлі ў бітавы вобраз fon і кампанент Image1.
    6.2. Загрузіць з файла малюнак месяца ў бітавы вобраз kadr. Апісаць пачатковае становішча месяца.
    6.3. Вызначыць прамавугольныя вобласці для бягучага становішча на фоне і для кадра.
  7. Напісаць апрацоўшчык падзеі OnClick для кампанента Button1, у якім неабходна запусціць таймер.
  8. Напісаць апрацоўшчык падзеі OnTimer, у якім варта рэалізаваць анімацыю руху месяца. Месяц рухаецца па эліптычнай арбіце.

Прыклад 17.14*. Стварыць праект, у якім матылёк будзе лётаць вакол кветкі па траекторыі ў выглядзе астроіды і мяняць свой напрамак палёту.

Этапы выканання задання

  1. Анімацыя запускаецца адразу пры загрузцы формы (без кнопкі запуск).
  2. Калі не ўлічваць неабходнасць змены напрамку матылька пры палёце, то заданне аналагічна прыкладу 17.13 (досыць змяніць формулы, якія вызначаюць пункты акружнасці на формулы, якія вызначаюць пункты астроіды — прыклад 15.11). Таму разгледзім толькі змену напрамка палёту.
  3. Напрамак будзем мяняць, калі значэнне пераменнай t зменіцца на значэнне  , г. зн. у значэннях: . Пераменная будзе вызначаць, дзе ў бягучы момант часу знаходзіцца матылёк. Значэнне пераменнай ρ вызначым наступным чынам:
    =
  4. З дапамогай лагічнай пераменнай f будзем вызначаць ці патрэбны паварот малюнка ў бягучым пункце.
  5. Калі паварот патрэбен, то для цотных значэнняў p матылёк адлюстроўваецца злева-направа, а для няцотных — зверху-ўніз.

Прыклад 17.13. Форма на этапе праектавання:

Глабальныя пераменныя:

Graphics::TBitmap  

  *kadr = new Graphics::TBitmap(),

  *fon = new Graphics::TBitmap(),

  *fon_kadr = new Graphics::TBitmap();

int w, h, x_luna, y_luna, 

  x_c = 180, y_c =130,

  R_x = 155, R_y =130;

TRect pr_kadr, pr_fon;

double t = 0

Апрацоўшчык падзеі OnClick для кампанента Button1.

void __fastcall TForm1::
Button1Click(TObject *Sender)

{

  Timer1 ->Enabled = true;

}

Апрацоўшчык падзеі OnCreate для формы.

void __fastcall TForm1::
FormCreate(TObject *Sender)

{

  //загрузка малюнкаў

  fon -> LoadFromFile("земля.bmp");

  Image1 -> Picture -> Assign(fon);

  kadr -> LoadFromFile("луна.bmp");

  w = kadr -> Width;

  h = kadr -> Height;

  kadr -> Transparent = true;

  //вызначэнне бітавага вобраза

  //для захоўвання часткі фону

  fon_kadr -> Width = w;

  fon_kadr -> Height = h;

  pr_kadr = Bounds(00, w, h);

  //пачатковае становішча месяца

  x_luna = 180;

  y_luna = 2;

  //захаванне частцы фону пад месяцам

  pr_fon = Bounds(x_luna, y_luna, w, h);

  fon_kadr -> Canvas -> CopyRect

    (pr_kadr, fon -> Canvas, pr_fon);

  //маляванне месяца

  Image1 -> Canvas -> Draw

    (x_luna, y_luna, kadr);

  pi = acos(-1);

}

Апрацоўшчык падзеі OnTimer для таймера.

void __fastcall TForm1::
Timer1Timer(TObject *Sender)

{

  //аднаўленне фону

  Image1 -> Canvas -> Draw

    (x_luna, y_luna, fon_kadr);

  //разлік каардынат эліпса

  t += 0.1;

  if (t > 2 * pi)

    t = 0;

  x_luna = x_c + ceil(R_x * sin(t));

  y_luna = y_c - ceil(R_y * cos(t));

  //захаванне часткі фону

  pr_fon = Bounds(x_luna, y_luna, w, h);

  fon_kadr -> Canvas -> CopyRect

     (pr_kadr, fon -> Canvas, pr_fon);

  //маляванне месяца

  Image1 -> Canvas -> Draw

       (x_luna, y_luna, kadr);

}

 Дадатак у час працы:

Прыклад 17.14. Апрацоўшчык падзеі OnTimer для таймера.

void __fastcall TForm1::Timer1Timer
(TObject *Sender)

{

  //аднаўленне фону

  Image1 -> Canvas -> Draw

    (x_fly, y_fly, fon_kadr);

  += 0.1;

  if (t > 2 * pi)

    t = 0;

  //вызначэнне чвэрці, у якой

  //знаходзіцца матылёк і

  //змена яе пры неабходнасці

  if (t < pi / 2){

    if ( p != 0){

      p = 0;

      f = true;

    }

  }

  else

    if (t < pi) {

      if (p != 1 ){

        p = 1;

        f = true;

      }

    }

    else

      if (t < 3 * pi /2){

        if (p != 2){

           p = 2;

           f = true;

        }

      }

      else

        if (p != 3){

          p = 3;

          f = true;

        }

  //адлюстраванне матылька

  if (f){

    f = false;

    pr_fly = pr_kadr;

    switch (p){

      case 0: case 2:{

        pr_fly.left = pr_kadr.right;

        pr_fly.right = pr_kadr.left;

        break;

      }

      case 1: case 3:{

        pr_fly.top = pr_kadr.bottom;

        pr_fly.bottom = pr_kadr.top;

        break;

      }

    }

    kadr -> Canvas -> CopyRect

      (pr_fly, kadr -> Canvas, pr_kadr);

  }

  //разлік каардынат астроіды

  x_fly = x_c + R_x * cos(t) * cos(t) * cos(t);

  y_fly = y_c - R_y * sin(t) * sin(t) * sin(t);

  //захаванне часткі фону

  pr_fon = Bounds(x_fly, y_fly, w, h);

  fon_kadr -> Canvas -> CopyRect

     (pr_kadr, fon -> Canvas, pr_fon);

  //маляванне матылька

  Image1 -> Canvas -> Draw

     (x_fly, y_fly, kadr);

}

Дадатак у час працы: