Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lexzii_08 / lexs_11_animaz.doc
Скачиваний:
15
Добавлен:
17.05.2015
Размер:
205.82 Кб
Скачать

Лекція 11. Анімація

Це, напевно, сама цікава тема. Під анімацією ми з вами будемо розуміти зображення екрану, яке швидко змінюється, нарисовані об’єкти якого змінюють свої координати і тим самим, рухаються по екрану. Ми можемо задати їм визначену траєкторію руху або примусити їх підкорятись деяким законам, які, можливо, будуть динамічно змінюватись в ході виконання програми.

Поміркуємо, як можна організувати анімацію. Нам потрібен цикл, в тілі якого будуть послідовно формуватись кадри зображення і швидко виводитись на екран. Перед рисуванням кожного кадра, треба очищати всю область екрана і потім рисувати уже змінену картинку. Вихід із циклу — натискання будь-якої клавіші. Всередині циклу поставимо невелику затримку, щоб людське око встигало сприймати кожний нарисований кадр.

Приклад. Написати програму, в якій кулька рухається зліва направо. При досягненні правої межі вона перестрибує на своє початкове положення, і все повторюється спочатку.

Для рисування кульки (замість кульки може бути будь-яка інша фігура), ми визначимо функцію Draw(x,y), при виклику якої буде відбуватись рисування зображення.

/* рухаюча кулька */

# include <conio.h>

# include <graphics.h>

# include <dos.h>

void Draw (int x1, int y1)

{

circle( x1,y1,20 );

}

void main( )

{

int x,y;

int gd=DETECT, gm;

x=20; // ініціалізація початкових

y=200; // координат кульки

initgraph ( &gd, &gm,” ” );

while ( !kbhit( ) ) // цикл: поки не натиснута

{ // будь-яка клавіша, виконувати

cleardevice( ); // очищення екрану

Draw (x,y); // рисуємо кульку по координатах (x,y)

delay (10); // затримка

х++; // зміщуєм кульку вправо на один піксель

if (x>620) x=20; // якщо дойшли до правої межі, то х=20

}

getch( );

closegraph( );

}

Головний цикл програми — while. Функція kbhit() повертає не нуль, якщо була натиснута будь-яка клавіша і нуль, якщо буфер клавіатури пустий. Функція описана в файлі conio.h. За допомогою функції dalay (мілісек.) із бібліотеки dos.h, ми створюємо затримку на 10 мілісекунд для кожного кадру.

В написаній програмі є один суттєвий недолік — зображення блимає. Чому так відбувається? Річ в тому, що функція cleardevice( ) працює не дуже швидко, тому що потрібно зафарбовувати весь екран, наше око не встигає впіймати момент, коли на екрані нічого немає. Що ж робити? Перше, що приходить в голову — це спробувати очищати не весь екран, а тільки ту область, де намальований об’єкт. Давайте перепишемо програму так, щоб спочатку рисувалась кулька кольором фону за старими координатами, а потім, іншим кольором, на новому місці.

/* рухаюча кулька */

# include <conio.h>

# include <graphics.h>

# include <dos.h>

Void Draw (int x1, int y1)

{

circle( x1,y1,20 );

}

Void main()

{

int x,y;

int gd=DETECT, gm;

x=20;

y=200;

initgraph( &gd, &gm, ” ” );

setbkcolor(1); // встановлює колір фону 1 - синій

while (!kbhit())

{

setcolor(1); // рисуємо кольором

Draw (x,y); // фону кульку по старим

х++; // координатам (х,у)

if (x>620) x=20;

setcolor(10); // рисуємо зеленим

Draw (x,y); // кольором кульку по

delay (10); // обновленим координатам (х,у)

}

getch();

closegraph();

}

Якщо у вас комп’ютер достатньо швидкий, то ви помітите невелике поліпшення, але блимання повністю не зникне. І чим складніше фігура в функції Draw, тим довше працює замальовування і стирання зображення, і тим більше помітно блимання. Тобто такий засіб підходить тільки для анімації простих рисунків.

Для того, щоб можна було звільнитись від блимання, необхідно зрозуміти принцип роботи монітора і механізм формування зображення. Всередині кінескопу є так називаєма електронно-струменева пушка, яка “стріляє” електронами (зарядженими частинками) по внутрішній поверхні екрана. Ця поверхня покрита спеціальною люмінісцентною речовиною, яка світиться при зіткненні з електронами. Пучок електронів можна відхиляти за допомогою магнітного поля і при необхідності виключати. В кожний момент часу на екрані світиться тільки одна точка — те місце, куди летять електрони. Ця світящася пляма починає рухатись з лівого верхнього кута по горизонталі. Доходячи до кінця екрану, промінь вимикають і переводять на початок слідуючого рядка. Цей процес має назву горизонтальної ретрасировки. Так продовжується доти, поки промінь не пройде всі рядки екрана, і не опиниться в правому нижньому куту. Потім промінь знову вимикають і переводять в початок екрану. Це — вертикальна ретрасировка. Промінь “бігає” настільки швидко, що людське око сприймає всі точки, як одне ціле. За одну секунду екран монітора оновлюється 60 разів. В цьому випадку говорять, що вертикальна розгортка екрана 60Гц. Чим вище це число, тим менше стомлюється око. Безпечним вважається значення, яке дорівнює 75Гц і вище. Зараз існують монітори з частотою вертикальної розгортки до 120Гц.

Дані про зображення беруться з відеопам’яті. Це є ніщо інше, як масив пікселів. І коли ми “ рисуємо ” щось на екрані, ми насправді записуємо нові значення в цей масив. При проходженні променя по екрану, зчитується значення відповідного пікселя з відеопам’яті, і піксель виводиться на екран потрібним кольором (інтенсивністю). Що ж буде, якщо ми запишемо в відеопам’ять нові значення пікселів в той момент, коли у нас вже частина попереднього зображення сформована? Пам’ять оновлюється (швидкість читання/запису в пам’ять набагато більша, ніж швидкість переміщення променя по екрану) і далі, промінь уже буде малювати вже новий кадр.

В прикладі приводиться функція, яка чекає початку вертикальної ретрасировки. Вона перевіряє четвертий біт порта 0х3DA. Якщо він дорівнює 1, то буде вертикальна ретрасировка, якщо 0, то зображення кадру ще не до кінця сформовано. Як тільки промінь досяг правого нижнього кута, виставляється 1 і функція завершує роботу, даючи можливість швидко відновити відеопам’ять.

Функцію доцільно ставити безпосередньо перед перемалюванням відеосторінок.

void WaitWerticalRetrace( )

{

while (inportb(0x3DA)&0x08);

while (!inportb(0x3DA)&0x08);

}

Приклад: Написати програму, в якій кулька, яка має початкову швидкість рухається рівномірно по екрану, відскакуючи від стінок.

/* Міні більярд */

#include <graphics.h>

#include <stdio.h>

#include <conio.h>

#include <dos.h>

void WaitWerticalRetrace( )

{

while (inportb( 0x3DA )&0x08);

while (!inportb( 0x3DA )&0x08);

}

void main( void )

{

int gd=DETECT, gm;

int x,y,dx,dy;

initgraph(&gd, &gm, "" );

setbkcolor(1); // колір фону 1 - синій

x=100;

y=100; // задаємо початкові координати

dx=2; // і швидкість по горизонталі

dy=2; // і по вертикалі

while( !kbhit ( ) )

{

setcolor(1);

WaitWerticalRetrace( ); // ждемо початку

circle(x,y,15); // вертикальної ретрасировки

x+=dx; // збільшуємо х

y+=dy; // збільшуємо у

if( x>625 || x<15 )

dx=-dx; // якщо край екрану, то

if( y>465 || y<15 ) // змінюємо знак у dx

dy=-dy;

setcolor(14);

circle( x,y,15 );

}

closegraph( );

}

Соседние файлы в папке lexzii_08