Гра Більярд



 

Міністерство освіти і науки молоді та спорту України

Закарпатський державний університет

 

Факультет інформаційних технологій

Кафедра програмного забезпечення систем

 

 

Реєстраційний №______

Дата ________________

 

 

 

 

 

 

КУРСОВА РОБОТА

з Об’єктно-орієнтовного програмування

 

Тема: Гра “Більярд”

 

 

 

 

 

Рекомендована до захисту

“____” ____________ 2012р.

Робота захищена

“____” ____________ 2012р.

з оцінкою

_______________________

Підписи членів комісії

Студента 2 курсу             

заочного відділення

Сочки В.В.

Науковий керівник

                                                                                                                  Стойкович О.Р.

 

 

 

Ужгород 2012р.


Зміст

Вступ……………………………………………………………………………….3

1. Опис моделі більярду…………………………………………………………..4

2. Основні класи моделі…………………………………………………………..5

2.1. Клас CRect (прямокутник)………………………………………………….6

2.2. Клас CWall (стінка більярдного столу)…………………………………….8

2.3. Клас CHole (луза більярдного столу)……………………………………..10

2.4. Клас CBall (більярдна шкуля)……………………………………………...13

3. Реалізація динамічної поведінки моделі…………………………………….19

Висновки…………………………………………………………………………23

Список літератури……………………………………………………………….24

 

 

 

 

 

 


Вступ

Дана курсова робота є прикладом реалізації завдання про гру в більярд, написаної із застосуванням об'єктно-орієнтованого програмування на мові високого рівня С++.

Мова програмування C++ була розроблена на основі мови С Бьярном Страуструпом.

Особливість мови С полягає в тому, що будучи мовою високого рівня, вона зберегла багато рис мови низького рівня. Мова С розташована десь між мовами дуже високого рівня і мовами низького рівня, і в цьому її сильні і одночасно слабкі сторони. Як і мова асемблера (мова низького рівня), мова програмування С може безпосередньо керувати пам'ятю комп'ютера. З іншого боку, С має риси мов високого рівня, тому програми на мові С читати і створювати легше, ніж програми на мові асемблера. Мова С є дуже зручним для написання системних програм, але в програмах на мові С для інших цілей часто важче розібратися, ніж в програмах, написаних на інших мовах. Мова С також має менше можливостей для автоматичної перевірки програм, ніж деякі інші мови високого рівня.

В даний час широкого поширення набули реалізації мови в системах Visual C + +, Borland C + + xx, Borland C + + Builder x та ін.

У даній роботі розглядається програма, що імітує рух куль з більярдного столу зі стінками і лузами. Щоб розібратися в цій програмі, треба вивчити лекції по ООП і знати основні методи роботи з бібліотекою OpenGL. OpenGL застосовується в дещо незвичному для ОС Windows виді: як бібліотека двовимірної графіки. Це дозволяє істотно зменшити результатний текст програми в порівнянні з варіантом програми, який для малювання користується функціями Windows API.

Основна увага при розробці програми "Більярд" приділяється створенню автономних агентів, що взаємодіють між собою для досягнення бажаного результату - імітації руху куль з більярдного столу.

1. ОПИС МОДЕЛІ БІЛЬЯРДУ

Програма відображує на екрані вікно,в якому в виді прямокутника зображений більярдний стіл. В його 4-х кутах знаходяться лузи. На столі розташовані 15 синіх куль і 1 біла куля(рис.5.1).

Клацанням лівої кнопки миші в довільній точці столу користувач імітує удар києм по білій кулі,повідомляючи їй деяку початкову швидкість в напрямі курсору миші. Рухома куля пружно відбивається від стінок та інших куль. При рухові по столу кулі втрачають енергію за рахунок тертя і з часом зупиняються. При попаданні в лузу сині кулі видаляються зі столу,а біла куля поміщається в початкову позицію(рис.5.1).
 

Рис. 5.1. Зображення більярдного столу з 4-ма кутовими лузами.

 

 

 


2. ОСНОВНІ КЛАСИ МОДЕЛІ

Основними класами в даній задачі є стінки,лузи и кулі. Об’єктам цих класів приписана деяка екранна область і вони вміють показувати себе всередині цієї області. Будемо називати ці об’єкти  графічними об’єктами. Графічні об’єкти кожного типу зберігаються  в програмі у вигляді зв’язкових списків. Для цього в кожному класі є покажчик на наступний об’єкт списку.

Розміщення посилань всередині об’єктів для об’єднання цих об’єктів в деякий абстрактний тип даних (наприклад,зв’язковий список) вважається поганим стилем програмування. Краще відділити реалізацію АТД від об’єктів,які в ньому зберігаються. Але рішення цієї задачі містить деякі нетривіальні аспекти, які ускладнили б розглянуту програму.

Приймемо спрощене припущення, що всі графічні об’єкти займають прямокутну область. Звичайно, для круглих об’єктів (наприклад, куль і луз) це невірно. Але облік форми об’єктів значно б ускладнив програму. Голові цілі в її вивченні – розгляд способу, за допомогою якого об’єкти наділяються  власною поведінкою і як організована взаємодія об’єктів. Кожен графічний об’єкт не тільки вміє зображати себе, але і може взаємодіяти з іншими об’єктами моделі більярду.

 

 


2.1 Клас CRect (прямокутник)

Клас СRect є допоміжним класом,який призначений для збергання координат прямокутника і виконання деяких операцій з цими координатами. Операції з координатами прямокутників застосовуються при реалізації поведінки графіних об’єктів. Далі наведено об’яву класу,в якому більша частина функцій-членів зроблені вбудованими.

class CRect {

    public :

// Конструктори

CRect()

{ x1 = y1 = x2 = y2 = 0; }

CRect( int nx1, int ny1, int nx2, int ny2 )

{ x1 = nx1; y1 = ny1; x2 = nx2; y2 = ny2; }

// Ініціалізація координат прямокутника

void SetRect( int left, int top, int right, int bottom )

{ x1 = left; y1 = top; x2 = right; y2 = bottom; }

// Зміщення прямокутника

void OffsetRect( int dx, int dy )

{ x1 += dx; y1 += dy; x2 += dx; y2 += dy; }

// Отримання координат центру прямокутника

void CenterPoint( int* x, int* y )

{ *x = (x1 + x2)/2; *y = (y1 + y2)/2; }

// Перевірка на збіг координат кутів прямкутника

bool IsRectEmpty()

{ return ( x1 == x2 && y1 == y2 ); }

// Отримання ширини прямкутника

int Width()      { return x2 - x1 + 1; }

// Отримання висоти прямокутника

int Height()     { return y2 - y1 + 1; }

// Функція обчислює перетин об’екту з прямокутником another

CRect IntersectRect( CRect& another );

// Нормалізація координат прямокутника

void NormalizeRect();

// Загальнодоступні атрибути

int x1, y1, x2, y2;

};

Атрибути прямокутника (координати) зроблені загальнодоступним ,так як цей клас дуже простий,не має власної поведінки і нема значної небезпеки від несанкціованої зміни координат.

Будемо називати прямокутник нормалізованим, якщо його координати (х1, у1) і (х2, у2) відповідають лівому верхньому і правому нижньому куту. Таке впорядкування координат спрощує розрахунок перетину прямокутників. Ця операція виконується функцією-членом IntersectRect() і потрібна для відстежування зштовхувань графічних об’єктів.


2.2 Клас CWall (стінка більярдного столу)

Клас СWall оголошується наступним чином:

class CWall {

   public:

CWall ( int left, int top, int right, int bottom,

double cf, CWall* pNextWall );

// Малюнок стінки

void Draw();

// Оповіщення тсінки про те, що в неї попала куля

void HitBy( CBall* pBall );

CRect GetRegion()              { return region; }

CWall* GetLink()               { return pLink; }

   private:

CWall* pLink;

CRect region;                      // Екранні координати стінки

double convertFactor;          // Значення, з якого віднімається

                                             // напрямок вдарившої кулі, щоб

                                             // вийшло зеркальне відображення

};

 

Атрибут  pLink служить для організації зв'язного списку об'єктів CWall. Значення цього атрибуту, а також координати області для малювання стінки і параметр відскоку ініціалізуються в конструкторі:

 

CWall::CWall( int left, int top, int right, int bottom,

double cf, CWall* pNextWall )

{

convertFactor = cf;

region.SetRect( left, top, right, bottom );

pLink = pNextWall;

}

 

Стінка малюється на екрані як суцільний зелений прямокутник. Це робиться за допомогую функцій OpenGL:

 

void CWall::Draw()

{

glColor3ub( 0, 255, 0 );

glRecti( region.x1, region.y1, region.x2, region.y2 );

}

 

Коли в стінку вдаряється куля, то напрям її руху змінюється у відповідності із значенням атрибуту convertFactor. Для горизонтальних стінок convertFactor=0, а для вертикальних convertFactor=Pi. В результаті куля зеркально відображується від стінки :

 

void CWall::HitBy( CBall* pBall )

{             

pBall->SetDirection( convertFactor - pBall->GetDirection() );

}


2.3 Клас CHole (луза більярдного столу)

Нижче приведено оголошення класу CHole:

class CHole {

   public:

CHole (int x, int y, CHole * pNextHole);

/ / Малювання лузи

void Draw ();

/ / Повідомлення лузи про те, що в неї потрапила куля

void HitBy (CBall * pBall);

CRect GetRegion ()      {return region;}

CHole * GetLink ()      {return pLink;}

   private:

CHole * pLink;            / / Покажчик на наступну лузу для утворення

                                    / / зв'язного списку

CRect region;             / / Екранні координати області лузи

};

 

Конструктор і функція-член для малювання лузи влаштовані дуже просто:

CHole :: CHole (int x, int y, CHole * pNextHole)

{

/ / Прямокутник для лузи з центром в точці (x, y)

region.SetRect (x - 5, y - 5, x + 5, y + 5);

pLink = pNextHole;

}

void CHole :: Draw ()

{

/ / Луза малюється у вигляді жовтого кола, вписаного в область            region

glColor3ub (255, 255, 0);

glPointSize ((float) region.Width ());

glEnable (GL_POINT_SMOOTH);

glBegin (GL_POINTS);

int cx, cy;

region.CenterPoint (& cx, & cy);

glVertex2i (cx, cy);

glEnd ();

glDisable (GL_POINT_SMOOTH);

}

 

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

 

void CHole :: HitBy (CBall * pBall)

{

/ / Енергія кулі обнуляється

pBall-> SetEnergy (0.0);

if (pBall-> IsCue ())

pBall-> SetCenter (50, 108);

else

{

pBall-> SetCenter (10 + saveRack * 15, 250);

saveRack + +; / / Збільшення глобального лічильника забитих куль

}

}


2.4 Клас CBall (більярдна шкуля)

Останнім графічним об'єктом є куля, яка визначається наступним описом класу:

class CBall {

   public:

CBall (int x, int y, bool fc, CBall * pNextBall);

/ / Малювання кулі в поточному положенні

void Draw ();

/ / Зміна положення кулі в припущенні, що з моменту

/ / попередньї зміни пройшов одиничний проміжок часу

void Update ();

/ / Повідомлення кулі про те, що в неї потрапила інша куля

void HitBy (CBall * pBall);

/ / Розрахунок кута між віссю OX і напрямком від центру кулі до точки,

/ / зміщеної від центру кулі на (dx, dy)

double HitAngle (double dx, double dy);

/ / Функції-члени для доступу до змінних класу

void SetEnergy (double v)                      {energy = v;}

void SetCenter (int newx, int newy);

void SetDirection (double newDir)        {direction = newDir;};

CRect GetRegion ()                                {return region;}

CBall * GetLink ()                                {return pLink;}

double GetEnergy ()                             {return energy;}

void GetCenter (int * x, int * y);

double GetDirection ()                         {return direction;}

bool IsCue ()                                        {return fCue;}

   private:

CBall * pLink;                  / / Покажчик на наступну кулю зв'язного списку

CRect region;                  / / Екранна область, в яку вписана куля

double direction ;           / / Напрямок руху кулі (кут в радіанах

                                        / / відносно осі OX)

double energy;              / / Енергія кулі

bool fCue;                     / / Ознака білої кулі

};

 

Специфічними для кулі атрибутами є direction (напрям руху), energy (кінетична енергія кулі) і прапор fCue, що дорівнює true для єдиної в моделі білої кулі. Кулі ініціалізувалися координатами центру (подібно лузам), ознакою білої кулі і покажчиком на наступну кулю в списку. Енергія і напрям кулі спочатку дорівнюють нулю.

CBall :: CBall (int x, int y, bool fc, CBall * pNextBall)

{

SetCenter (x, y);

SetDirection (0);

SetEnergy (0.0);

pLink = pNextBall;

fCue = fc;

}

 

На екрані куля малюється у вигляді кола білого або синього кольору. Відображення виконує функція-член Draw ().

void CBall :: Draw ()

{

if (IsCue ())

glColor3ub (255, 255, 255);        / / Білий колір

else

glColor3ub (0, 0, 255);               / / Синій колір

glPointSize ((float) region.Width ());

glEnable (GL_POINT_SMOOTH);

glBegin (GL_POINTS);

int cx, cy;

region.CenterPoint (& cx, & cy);

glVertex2i (cx, cy);

glEnd ();

glDisable (GL_POINT_SMOOTH);

}

 

Функція-член Update () використовується для зміни положення кулі через одиничний проміжок часу, що пройшов з моменту попереднього виклику цієї функції. Якщо куля володіє достатньою енергією, то вона переміщується і потім провіряє, чи не зачепила вона інший об'єкт. Якщо хоча б одна куля на столі зрушилася, то глобальна змінна-прапор fBallMoved встановлюється рівною true. Якщо куля зачепила інший об'єкт, то куля повідомляє про це об'єкту. Повідомлення бувають трьох типів: вони відповідають ударам по лузі, стінці й іншій кулі.

void CBall :: Update ()

{

/ / Для руху у кулі повинна бути деяка кінетична енергія

if (energy <= 0.5)

return;

fBallMoved = true;

/ / На кожному кроці енергія кулі зменшується за рахунок тертя

energy - = 0.05;

/ / Зміщення кулі обчислюється з урахуванням квадратичної залежності

/ / кінетичної енергії від швидкості. Константа 2.0 обрана для

/ / забезпечення більш-менш реалістичного руху куль

int dx = (int) (2.0 * sqrt (energy) * cos (direction));

int dy = (int) (2.0 * sqrt (energy) * sin (direction));

region.OffsetRect (dx, dy);

 

/ / Перевірка на потрапляння в лузу

CHole * hptr = listOfHoles;

while (hptr)

{

CRect is = region.IntersectRect (hptr-> GetRegion ());

if (! is.IsRectEmpty ())

{

hptr-> HitBy (this);

hptr = NULL;

}

Else

hptr = hptr-> GetLink ();

}

/ / Перевірка на потрапляння в стінку

CWall * wptr = listOfWalls;

while (wptr)

{

CRect is = region.IntersectRect (wptr-> GetRegion ());

if (! is.IsRectEmpty ())

{

wptr-> HitBy (this);

wptr = NULL;

}

else

wptr = wptr-> GetLink ();

}

/ / Перевірка на потрапляння в іншу кулю

CBall * bptr = listOfBalls;

while (bptr)

{

if (bptr! = this)

{

CRect is = region.IntersectRect (bptr-> GetRegion ());

if (! is.IsRectEmpty ())

{

bptr-> HitBy (this);

break;

}

}

bptr = bptr-> GetLink ();

}

}

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

void CBall :: HitBy (CBall * pBall)

{

/ / Зменшуємо енергію ударившегося кулі вдвічі

pBall-> SetEnergy (pBall-> GetEnergy () / 2.0);

/ / і додаємо її до власної енергії

energy + = pBall-> GetEnergy ();

/ / Розрахунок нового напряму для поточного кулі

int cx1, cy1, cx2, cy2;

GetCenter (& cx1, & cy1);

pBall-> GetCenter (& cx2, & cy2);

SetDirection (HitAngle (cx1 - cx2, cy1 - cy2));

/ / Модифікація напрямку ударившої кулі

double da = pBall-> GetDirection () - GetDirection ();

pBall-> SetDirection (pBall-> GetDirection () + da);

}

/ / Розрахунок кута між віссю OX і вектором (dx, dy). Функція повертає

/ / значення кута радіанах у діапазоні (0, PI) або (-PI, 0)

double CBall :: HitAngle (double dx, double dy)

{

double na;

if (fabs (dx) <0.05)

na = PI / 2;

else

na = atan (fabs (dy / dx));

if (dx <0)

na = PI - na;

if (dy <0)

na =-na;

return na;

}


3. РЕАЛІЗАЦІЯ ДИНАМІЧНОЇ ПОВЕДІНКИ МОДЕЛІ

Динамічна поведінка моделі більярдного столу забезпечується за допомогою трьох функцій зворотного зв'язку OpenGL: обробника клацання лівої кнопки миши, фонової функції і функції відображення сцени.

В обробнику події миші MouseButtonDown () імітується удар києм по білій кулі. Цій кулі приписується деяка початкова енергія і напрям руху "на вказівник миші".

 

void CALLBACK MouseButtonDown (AUX_EVENTREC * event)

{

/ / Запам'ятовування координат покажчика миші в правій системі координат,

/ / пов'язаної з нижнім лівим кутом вікна (тому що в структурі event

/ / вони зберігаються в лівій системі координат, пов'язаної з лівим

/ / верхнім кутом вікна)

int mouse_x = event-> data [0];

int mouse_y = WINDOW_HEIGHT - event-> data [1];

/ / Білій кулі передається деяка початкова енергія

pCueBall-> SetEnergy (20.0);

/ / і присвоюється напрямок руху "на вказівник"

int cx, cy;

pCueBall-> GetCenter (& cx, & cy);

pCueBall-> SetDirection (pCueBall-> HitAngle (mouse_x-cx, mouse_y-cy));

/ / Прапор наявності хоча б одної рухомої кулі

fBallMoved = true;

}

 

Фонова функція Idle () при наявності хоча б одної рухомої кулі (на це вказує глобальна змінна-прапор fBallMoved () оновлює положення куль і цілком перемальовує сцену. Щоб кулі рухалися не дуже швидко, наприкінці фонової функції організована невелика затримка, протягом якої виконання програми призупиняється.

 

/ / Фонова функція

void CALLBACK Idle ()

{

/ / Положення куль оновлюється, тільки якщо є хоча б

/ / одна рухома куля

if (! fBallMoved)

return;

/ / Оновлення положення куль

fBallMoved = false;

CBall * bptr = listOfBalls;

while (bptr)

{

bptr-> Update ();

bptr = bptr-> GetLink ();

}

Display (); / / Відображення сцени

Sleep (25); / / Затримка на 25 мс

}

Функція відображення сцени реалізована досить прямолінійно: в режимі подвійної буферизації малюються всі графічні об'єкти.

void CALLBACK Display ()

{

glClear (GL_COLOR_BUFFER_BIT);

/ / Малювання стінок столу

CWall * pWall = listOfWalls;

while (pWall)

{

pWall-> Draw ();

pWall = pWall-> GetLink ();

}

/ / Малювання луз

CHole * pHole = listOfHoles;

while (pHole)

{

pHole-> Draw ();

pHole = pHole-> GetLink ();

}

/ / Малювання куль

CBall * pBall = listOfBalls;

while (pBall)

{

pBall-> Draw ();

pBall = pBall-> GetLink ();

}

auxSwapBuffers ();

}


Висновки

Об'єктно-орієнтоване програмування (ООП) - це сукупність понять (клас, об'єкт, інкапсуляція, поліморфізм, спадкування), прийомів їх використання при проектуванні програм, а Сі+ + - інструмент цієї технології.

Центральними в ООП є поняття класу та об'єкта. Образно кажучи, ООП полягає не стільки у використанні класів і об'єктів у програмі, скільки в заміні принципу програмування "від функції до функції" принципом програмування "від класу до класу".

Технологія ООП насамперед накладає обмеження на способи представлення даних у програмі. Будь-яка програма відображає в них стан фізичних предметів або абстрактних понять, для роботи з якими вона призначена. Всі дані про об'єкт програмування і його зв'язки з іншими об'єктами можна об'єднати в одну структуровану змінну. У першому наближенні її можна назвати об'єктом. Крім того, з об'єктом зв'язується набір дій, інакше званих методами. З точки зору мови програмування це функції, які отримують в якості обов'язкового параметра покажчик на об'єкт. Технологія ООП забороняє працювати з об'єктом інакше, ніж через методи, тобто внутрішня структура об'єкта прихована від зовнішнього користувача. Опис безлічі однотипних об'єктів називається класом.

В даній курсовій роботі описується програмний продукт, що реалізує гру в «Більярд».

Для користувача більярдний стіл являє собою вікно, що містить прямокутник з лузами по кутках, 15 чорних куль і 1 білу кулю. Натисненням кнопки миші користувач імітує удар києм по кулі, повідомляючи йому деяку енергію.

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


СПИСОК ЛІТЕРАТУРИ

1.   C + + для чайників (+ CD-ROM): Стефан Р. Девіс - Санкт-Петербург, Діалектика, Вільямс, 2009 р. - 336 с.

2.   C + +. Майстер-клас в задачах і прикладах : Максим Кузнєцов, Ігор Сімдянов - Москва, БХВ-Петербург, 2007 р. - 480 с.

3.   C + +. Об'єктно-орієнтоване програмування. Практикум: Т. А. Павловська, Ю. А. Щупак - Москва, Пітер, 2008 р. - 272 с.

4.   C / C + +. Структурний і об'єктно-орієнтоване програмування. Практикум: Т. А. Павловська, Ю. А. Щупак - Санкт-Петербург, Пітер, 2010 р. - 352 с.

5.   Об'єктно-орієнтоване моделювання на С + +: Ілля Труб - Санкт-Петербург, Пітер, 2006 р. - 416 с.

6.   Об'єктно-орієнтоване програмування в С + +: Р. Лафоре - Санкт-Петербург, Пітер, 2011 р. - 928 с.

7.   Об'єктно-орієнтоване програмування на С + +: Айра Пол - Москва, Не вказано, Біном, Невський Діалект, 2001 р. - 464 с.

24

 



Гра Більярд