Реферат по предмету "Информатика, программирование"


Система координат канви

/>Зміст
Вступ
Розділ 1. Теоретична частина
1.1 Компонент Image і деякі йоговластивості
1.2 Вивід зображень за допомогоюпікселів
1.3 Збереження конфігурації в файлах.ini
Розділ 2. Практична частина
2.1 Код гри
2.2 Опис гри
Висновок
Використана література
Додатки

Вступ
Багато компонентів в C++Builder маютьвластивість Canvas (канва, полотно), є областю компоненту, на якій можнамалювати або відображати готові зображення. Цю властивість мають форми,графічні компоненти Image, PaintBox, Bitmap і багато інших. Канва міститьвластивості і методи, що істотно спрощують графіку C++Builder. Всі складнівзаємодії з системою заховані для користувача, так що малювати в C++Builderможе людина абсолютно не досвідчена в машинній графіці.
Кожна точка канви має координати X іY. Система координат канви, як і скрізь в C++Builde, має початком лівий верхнійкут канви. Координата X зростає при переміщенні зліва направо, а координат Y —при переміщенні зверху вниз.
З координатами ви вже мали справубагато разів, але поки вас не дуже цікавило, що стоїть за ними, в яких одиницяхвони вимірюються. Координати вимірюються в пікселах. Піксел — це найменшийелемент поверхні малюнка, з яким можна маніпулювати. Найважливіша властивістьпіксела — його колір. Для опису кольору використовується тип TColor. З кольоромви зустрічаєтеся практично в кожному компоненті і знаєте, що в C++Builderвизначена безліч констант типу TColor. Одні з них безпосередньо визначаютькольори (наприклад clBlue — синій), інші визначають кольори елементів вікон,які можуть мінятися залежно від вибраної користувачем палітри квітів Windows(наприклад, clBtnFace — колір поверхні кнопок).

Розділ 1.Теоретична частина
1.1  Компонент Image і деякі йоговластивості
Нерідковиникає потреба прикрасити своє застосування якимись картинками. Це можебути графічна заставка, що є логотипом вашого застосування. Або цеможуть бути фотографії при розробці застосування, що працює з базою данихспівробітників якоїсь установи. У першому випадку вам буде потрібно компонентImage, розташований на сторінці Additional бібліотеки компонентів, вдругому — його аналог DBImage, пов'язаний з даними і розташований на сторінці Data Controls.
Почнемознайомство з цими компонентами. Відкрийте нове застосування і перенесіть на формукомпонент Image. Його властивість, яка може містити картинку, — Picture.Натисніть на кнопку з багатокрапкою біля цієї властивості або просто зробіть подвійне клацання наImage, і перед вами відкриється вікно Picture Editor, що дозволяє завантажити увластивість Picture який-небудь графічний файл(кнопка Load), а також зберегти відкритий файл під новим ім'ям або в новому каталозі. Клацніть на Load, щоб завантажитиграфічний файл. Перед вами відкриється вікно Load Picture. У міру переміщеннякурсора в списку по графічних файлахв правому вікні відображаються зображення, що містяться в них. Ви можете знайтиграфічні файли в каталозі Images. Він зазвичайрозташований в каталозі ...\Program files\CommonFiles\Borland Shared.
У вікнізавантаження графічного файлу ви можете не тільки проглянути зображення, що зберігається увибираному файлі, але і побачити розмір зображення — цифри в дужках справа вгорі. В деяких випадках, як ви побачитепізніше, це важливо.
Післязавантаження файлу клацніть на ОК і у вашому компоненті Image відобразиться вибрана вами картинка. Можетезапустити ваше застосування і помилуватися нею. Втім, ви і так побачитекартинку, навіть не виконуючи програма.
Коли ви в процесі проектування завантажиликартинку з файлу в компонент Image, він не просто відображає її, але і зберігаєв застосуванні. Це дає вам можливість поставляти ваше застосування без окремогографічного файлу. Втім, як ми побачимо пізніше, в Image можна завантажувати ізовнішні графічні файли в процесі виконання застосування.
Повернемося до розгляду властивостейкомпоненту Image.
Якщо встановити властивість AutoSizeв true, то розмір компоненту Image автоматично підганятиметься під розмірпомішаної в нього картинки. Якщо ж властивість AutoSize встановлена в false, тозображення може не поміститися в компонент або, навпаки, плошадь компонентуможе опинитися багато більше площі зображення.
Інша властивість — Stretch дозволяєпідганяти не компонент під розмір малюнка, а малюнок під розмір компоненту.Встановіть AutoSize в false, розтягніть або стисніть розмір компоненту Image івстановіть Stretch в true. Ви побачите, що малюнок займе всю площу компоненту,але оскільки навряд чи реально встановити розміри Image пропорційними розмірумалюнка, те зображення спотвориться. Встановлювати Stretch в true може матисенс тільки для якихось узорів, але не для картинок. Властивість Stretch не дієна зображення піктограм, які не можуть змінювати своїх розмірів.
Властивість— Center, встановлене в true, центрує зображення на площі Image, якщо розмір компонентубільше розміру малюнка.
Розглянемоеше одна властивість — — Transparent (прозорість). Якщо Transparent рівнеtrue, то зображення в Image стає прозорим. Це можна використовувати для накладення зображень одинна одного. Помістите на форму другий компонент Image і завантажите в нього іншукартинку. Тільки постарайтеся узяти яку-небудь малозаполненую, контурнукартинку. Можете, наприклад, узяти картинкуз числа тих, що поміщаються зазвичай на кнопки, наприклад, стрілку (файл ...\program files\commonfiles\borland shared\images\buttons\arrowlr.bmp). Пересуньтеваші Image так, щоб вони перекривали один одного, і у верхньомукомпоненті встановите Transparent рівним true. Ви побачите, що верхнякартинка перестала затуляти нижнюю. Одне з можливих застосувань цієївластивості — накладення на картинку написів, виконаних у вигляді бітової матриці. Цінаписи можна зробити за допомогою вбудованоїв C++Builder програми Image Editor, яка буде розглянута пізніше.
Врахуйте,що властивість Transparent діє тільки на бітові матриці.
Будь-яка картинка, креслення абосхема можуть розглядатися як сукупність графічних примітивів: крапок, ліній,кіл, дуг і ін. Таким чином, для того, щоб на екрані з'явилася потрібнакартинка, програма повинна забезпечити викреслювання (вивід) графічнихелементів — примітивів, складових цю картинку.
Викреслювання графічних примітивів наповерхні (форми або компоненту image — області виведення ілюстрації)здійснюється застосуванням відповідних методів до властивості Canvas цієїповерхні.
Викреслювання прямої лінії виконуєметод LineTo. Метод малює лінію з тієї точки, в якій в даний момент знаходитьсяолівець (ця точка називається поточною позицією олівця або просто «поточною»),в точку, координати якої вказані в інструкції виклику методу.
Наприклад, оператор
Canvas->LineTo(100,200)
малює лінію в точку з координатами(100, 200), після чого поточною стає точка з координатами (100, 200).
Початкову точку лінії можна задати, перемістившиолівець в потрібну точку графічної поверхні. Зробити це можна за допомогоюметоду MoveTo, вказавши як параметри координати точки початку лінії. Наприклад,оператори
Canvas->MoveTo(10,10);//встановити олівець в точку (10,10)
Canvas->LineTo(50,10);
// лінія з точки (10,10) в точку(50,10)
малюють горизонтальну лінію з точки(10, 10) в точку (50, 10).
Використовуючи властивість поточноїточки, можна намалювати ламану лінію. Наприклад, оператори
Canvas->MoveTo(10,10);
Canvas->LineTo(50,10);
Canvas->LineTo(10,20);
Canvas->LineTo(50,20);
малюють лінію, схожу на букву Z.
Виведення тексту (рядків типуAnsiString) на поверхню графічного об'єкту забезпечує метод TextOutA. Інструкція виклику методу TextOutA в загальному вигляді виглядаєтаким чином:
Canvas->TextOutA(x, у, Текст)
Параметр текст задає текст, щовиводиться. Параметри х і у визначають координати точки графічної поверхні, відякої виконується виведення тексту.
Шрифт, який використовується длявиведення тексту, визначається значенням властивості Font відповідного об'єкту Canvas. Властивістю Font є об'єкт типуTFont. У табл. 3.4 перераховані властивості об'єкту TFont, що визначаютьхарактеристики шрифту, використовуваного методом TextOutA для виведення тексту.
Name          Використовуваний шрифт.Як значення слід використовувати назву шрифту (наприклад, Arial)
Size   Розмір шрифту в пунктах(points). Пункт — це одиниця вимірюваннярозміру шрифту, використовується в поліграфії. Один пункт рівний 1/72 дюйми.
Style Стиль зображення символів.Можливо: нормальним, напівжирним, курсивним, підкресленим, перекресленим. Стильзадається за допомогою наступних констант: fsBold (напівжирний), fsltalic(курсив), fsUnderline (підкреслений), fsStrikeOut (перекреслений). ВластивістьStyle є множиною, що дозволяє комбінувати необхідні стилі. Наприклад,інструкція, яка встановлює стиль «напівжирний курсив», виглядає так:
Canvas->Font->Style=TFontStyles()
Color Колір символів. Як значенняможна використовувати константу типу TColor
При виведенні тексту вельми корисніметоди TextWidth і TextHeight, значеннямияких є відповідно ширина і висота області виведення тексту, які, очевидно,залежать від характеристик використовуваного шрифту. Обом цим методам якпараметр передається рядок, який передбачається вивести на поверхню методомTextOutA.
Наступний фрагмент коду демонструєвикористання методів, що забезпечують виведення тексту на поверхню форми.Приведена функція обробки події OnPaint закрашує верхню половину вікна білим,нижню — блакитним кольором, потім в центрі вікна, по межі закрашених областей,виводить текст.
void  fastcall TForml:: ForroPaint (TObject *Sender)
{AnsiString ms = «Borland C++Builder»;
TRect aRect;
int x,y; // точка, від якої будевиведений текст
// верхню половину вікна фарбуємобілим
aRect =Rect(0,0,ClientWidth,ClientHeight/2);
Canvas->Brush->Color = clWhite; Canvas->FillRect(aRect);
// нижню половину вікна фарбуємоблакитним
aRect =Rect(0,ClientHeight/2,ClientWidth,ClientHeight);
Canvas->Brush->Color = clSkyBlue;
Canvas->FillRect(aRect);
Canvas->Font->Name = «Times New Roman»;
Canvas->Font->Size = 24;
// Canvas->Font->Style = TFontStyles()
// текст розмістимо в центрі вікна
х = (ClientWidth — Canvas->TextWidth(ms))/2;
у = ClientHeight/2 — Canvas->TextHeight(ms)/2;
Canvas->Brush->Style = bsClear;// область виведення тексту
// не закрашувати
Canvas->Font->Color = clBlack;Canvas->TextOutA(x,y,ms); // вивести текст }
/>/>
1.2  Вивід зображень за допомогоюпікселів
Малювати на канві можна різнимиспособами. Перший варіант — малювання по пикселам. Для цього використовуєтьсявластивість канви Pixels. Цією властивістю є двовимірний масивCanvas->Pixels[intX][int Y], який відповідає за кольори канви. Наприклад,Canvas->PixeIs[10][20] відповідає кольору пиксела, 10-го зліва і 20-гозверху. З масивом пикселов можна звертатися як з будь-якою властивістю:змінювати колір, задаючи пикселу нове значення, або визначати його колір позначенню, що зберігається в нім. Наприклад, Canvas->PixeIs[10][20]= clBlack— це завдання пикселу чорного кольору.
Давайте спробуємо намалювати графікдеякої функції F(X) наканве компоненту Imagel, якщо відомий діапазон її зміни Ymaxі Ymin і діапазон зміни аргументу Xmin і Хтах. Це можна зробити такоюпроцедурою:
float X,Y;   // координати функції
int PX,PY;  // координати пикселов
for (РХ = 0: РХ Width; Рх++)
//Х- координата, відповідна пикселу зкоординатою РХ
X = Xmin + РХ * (Xmax — Xmin) / Imagel->Width;
Y = F(X); //PY — координата пиксела, відповіднакоординаті Y
PY = imagel->Height — (Y — Ymin)*Imagel->Height/(Ymax-Ymin); //Устанавливается чорний колір вибраного пиксела
Imagel->Canvas->Pixels[PX][PY] = clBlack;}
У цьому коді вводяться змінні X і Y,що є значеннями аргументу і функції, а також змінні РХ і PY, що є координатамипикселов, відповідними X і Y. Сама процедура складається з циклу по всіхзначеннях горизонтальної координати пикселов РХ компоненту Imagel. Спочаткувибране значення Рхнересчитиваєтсявсоответствующєєзначенієх. Потім проводитьсявиклик функції і визначається її значення Y. Це значення перераховується увертикальну координату пиксела PY. І на закінчення колір пиксела з координатами(РХ, PY) встановлюється чорним.
Спробуйте створити відповіднезастосування і подивитися, як воно працює. Хай для простоти миорієнтуватимемося на функцію sin(X), для якої Xmin=0, Хmax=4pi (2 періоди врадіанах), Ymin=-1, Ymax=l.
Почніть новий проект, помістіть нанього компонент Image і кнопку з написом «Намалювати», в обробник події OnClickякою запишіть код, аналогічний приведеному вище, але що конкретизує функцію:
#define Pi 3.14159
float X, Y;  // координати функції
int РХ, PY; // координати пикселов
for (РХ = 0: РХ Width; PX++)
{//X — координата, відповідна пикселуз координатою РХ
X = РХ * 4 * Pi / imagel->Width;
Y = sin(X); //PY — координата пиксела,відповідна координаті У
PY = Imagel->Height — (Y+1) * Imagel->Height/ 2; //Устанавливается чорний колір вибраного пиксела
Imagel->Canvas->Pixels(PX][PY] = clBlack; }
1.3 Збереженняконфігурації в файлах ini
|Файли .ini — це текстові файли,призначені для зберігання інформації про настройкирізних програм. Інформація у файлі логічно групується врозділи, кожен з яких починається оператором заголовка, поміщеним в квадратні дужки. Наприклад [Desktop|].У рядках, наступних за заголовком, міститься інформація, що відноситься доданого розділу, у формі:
=
[dBASE| Files|]
Driver32=C|:\WINDOWS\SYSTEM\odbcjt32.dll
Файли .ini, як правило,зберігаються в каталозіWindows|, який можназнайти за допомогою функціїGetWindowsDirectory|.
У C++Builder|роботу з файлами.ini найпростіше здійснювати за допомогою створення в програмі об'єкту типуTIniFile|. Цейтип описаний в модулі inifiles|, який треба підключати до програми оператором uses|(автоматично це не робиться).
При створенні об'єкту типу TlniFile| внього передається ім'я файлу .ini, з яким він зв'язується.Файл повинен існувати до створення об'єкту.
Для записузначень ключів існує багато методів: WriteString|,WriteInteger|, WriteFloat|, |і ін. Кожен з них записує значення відповідноготипу. Оголошення всіх цих методів дуже схожі. Наприклад:
void|   fastcall| WriteString| (const|AnsiString| Section|
const| AnsiString| Ident|, const| AnsiString| Value|);
void|   fastcall| Writelnteger| (const|AnsiString| Section|
const| AnsiString| Ident|, int| Value|);
У всіх оголошеннях Section| — розділ файлу, Ident| — ключ цього розділу, Value| — значення ключа.Якщо відповідний розділабо ключ відсутнійу файлі, він автоматично створюється.
Є аналогічні методичитання: ReadString|, Readlnteger|,ReadFloat|, ReadBool| і ін. Наприклад:
AnsiString|  fastcall| ReadString| (const| AnsiString| Section|
const| AnsiString| Ident|, const| AnsiString| Default|);
int| fastcall| Readlnteger| (const|AnsiString| Section|
const| AnsiString| Ident|, int| Default|);
Методи повертають значення ключа|розділу Section|. Параметр Default| визначає значення, щоповертається у випадку, якщо у файлі не вказано значення відповідного ключа.
Перевірити наявність значення ключа можна методом ValueExists|, в який передаються імена розділу і ключа. МетодDeleteKey| видаляє з файлу значення вказаного ключа у вказаному розділі. Перевірити наявність у файлінеобхідного розділу можна методом SectionExists|. Метод EraseSection|видаляє з файлу вказаний розділ разом зі всімайого ключами. Є ще ряд методів, які ви можете подивитися увбудованій довідці C++Builder|.
Подивимося на прикладі, як все це можна використовувати для установкипрограми, запам'ятовування її настройоки і для видалення програми.
Зробіть просте тестову програму. Перенесіть на форму три кнопки Button| і діалог FontDialog|.Перша кнопка (назвіть її BInst| і задайте напис Install|)імітуватиме установку програми. Точніше, не самуустановку, оскільки копіювати файли з загрузочної дискетими не будемо, а тільки створення файлу .ini у каталозі Windows|. Друга кнопка (назвітьїї BUnlnst| і задайте напис Unlnstall|) імітуватиме видалення програми. Тут ми невидалятимемо саму програму з диска, а тільки видалимо зкаталога Windows| наш файл, а третя кнопка(назвіть її BFont| і задайте напис Font|) дозволятиме змінювати ім'я шрифту,використовуваного у формі, і забезпечить запам'ятовування цього шрифту у файлі.ini, щоб надалі при запуску програми можна було читати цю настройку ізадавати її формі.

Розділ 2.Практична частина
 
2.1 Код гри
#include
#pragma hdrstop
#include«UBilliard.h»
#include
#include«inifiles.hpp»
#pragma package(smart_init)
#pragma resource"*.dfm"
// розмір столу
int const w = 600;
int const h = 300;
class TGameStatus {
protected: char* gsStatus;
public:
void gsBegin(){
gsStatus=«qsBegin»;}
void gsGame(){
gsStatus=«gsGame»;}
void gsGameOver(){
gsStatus=«gsGameOver»;}};
TGameStatus *GameStatus =new TGameStatus;
struct TPlayer{
int balls; };
class TLose{
public:
int x,y;
int ballsInside;
int R;
void Draw();};
class TBall { public:
float x,y, dx,dy;
int R;
bool exists, stopped ;
int col,ID,count;
TList *Items;
void Draw();
void Stop();
bool InLose(int&Number);
void outFrom(TBall b);
TBall CollisedWith();
~TBall();};
class TCue {
public:
bool Visible;
TBall ToBall;
float Angle, energy;
void draw();
void Hit();};
void TCue::Hit(){
TBall *ToBall;
ToBall->dx=-cos(Angle)*energy;
ToBall->dy =-sin(Angle)*energy;
ToBall->stopped = False;
Visible = False;}
class TBilliardTable{
public:
int Width, Height, Left,Right, Top, Bottom;
TList* Ball;
TList* Lose;
TCue Cue;
void Draw();};
float GetAngToXY( pBall b;float hitX, hitY){
float dx, dy, d;
dx = b->x — hitX;
dy = b->y — hitY;
d = sqrt(dx*dx+dy*dy);
if(dy>0)
Result = arccos(dx/d);
else Result = -arccos(dx/d);}
voidTBall::outFrom(pBall:b){
{ AB,
aa, bb,
V1, V2,
aPrXx, aPrXy,
aPrYx, aPrYy,
aPrX, aPrY,
bPrXx, bPrXy,
bPrYx, bPrYy,
bPrX, bPrY,
alfaA, betaA, gammaA,
Extended alfaB, betaB,gammaB;
if(b == NULL ) exit;
AB = sqrt(sqr(x-b->x)+sqr(y-b->y));
V1 = sqrt(dx*dx+dy*dy);
V2 = sqrt(b->dx*b->dx+b->dy*b->dy);
aPrXx = 0;
aPrXy = 0;
bPrXx = 0;
bPrXy = 0;
////////-ball #1-
if(V1>0 ) {
if((b->y-y)>0
alfaA = arccos((b->x-x)/AB);
else alfaA = -arccos((b->x-x)/AB);
if(dy>0
then gammaA = arccos(dx/V1)
else gammaA = -arccos(dx/V1);
betaA = gammaA-alfaA;
aPrX = V1*cos(betaA);
aPrY = V1*sin(betaA);
aPrXx = aPrX*cos(alfaA);
aPrXy = aPrX*sin(alfaA);
aPrYx = aPrY*sin(alfaA);
aPrYy = aPrY*cos(alfaA); }
//////////////-ball #2-
if(V2>0 ) {
if((y-b->y)>0
then alfaB = arccos((x-b->x)/AB);//=alfaA+pi
else alfaB = -arccos((x-b->x)/AB);
if(b->dy>0)
then gammaB = arccos(b->dx/V2);
else gammaB = -arccos(b->dx/V2);
betaB = gammaB-alfaB;
bPrX = V2*cos(betaB);
bPrY = V2*sin(betaB);
bPrXx = bPrX*cos(alfaB);
bPrXy = bPrX*sin(alfaB);
bPrYx = bPrY*sin(alfaB);
bPrYy = bPrY*cos(alfaB); }
dx = ((dx — 2*aPrXx) +bPrXx)*mu; // = mu*(bPrXx — aPrXx)
dy = ((dy — 2*aPrXy) +bPrXy)*mu; // = mu*(bPrXy — aPrXy)
b->dx = ((b->dx — 2*bPrXx) + aPrXx)*mu; // = mu*(aPrXx — bPrXx)
b->dy = ((b->dy — 2*bPrXy) + aPrXy)*mu; // = mu*(aPrXy — bPrXy)}
void InitSound(){
pcm->wFormatTag = WAVE_FORMAT_PCM;
pcm->nChannels = 1;
pcm->nSamplesPerSec = 44100;
pcm->nAvgBytesPerSec = 2*44100;
pcm->nBlockAlign = 2;
pcm->wBitsPerSample = 16;
pcm->cbSize = 0;
WaveOut = 0;
open_status = waveOutOpen(&WaveOut,0, &pcm, Form1->Handle,
0, callback_Window)}
float CalCulateAngle(){
{ int i, j;
pLose ToLz, lz;
pBall nearestBall, Bl, b;
float hitX, hitY;
minAng, a2Lz, minD,
float dx, dy, a, minDist, d;
minDist = 1.7e+308;
minD = minDist;
with BilliardTable do
{ for( j = 0; jCount-1; j ++)
for( i = 0; iCount-1; i ++)
{ lz = Lose->Items[j];
b = Ball->Items[i];
if(! b->exist ) continue;
d = sqrt(sqr(b->x-lz->x)+sqr(b->y-lz->y));
if(d
{ minDist = d;
ToLz = lz;
Bl = b; } }
if((Bl == NULL) ) exit;
dx = Bl->x — ToLz->x;
dy = Bl->y — ToLz->y;
d = sqrt(dx*dx+dy*dy);
if((dy)>0
a2Lz = arccos(dx/d);
else a2Lz = -arccos(dx/d);
hitX = Bl->x +cos(a2Lz)*Bl->R;
hitY = Bl->y +sin(a2Lz)*Bl->R;
minAng = 1.7e+308;
for( i = 0; iCount-1; i ++)
{  b = Ball->Items[i];
if((b->ID == Bl->ID)|| (not b->exist)
continue;
a = GetAngToXY(b, hitX,hitY);
if(abs(a2Lz-a)
{  minAng = abs(a2Lz-a);
nearestBall = b;
Result = a; }  }
for( i := 0 to Ball.Count-1do
begin
b := Ball.Items[i];
if (b.ID = Bl.ID) or (notb.exist)
continue;
d :=sqrt(sqr(b.x-Bl.x)+sqr(b.y-Bl.y));
if d
begin
minD := d;
nearestBall := b;
end;
end;
dx := Bl.x — ToLz.x;
dy := Bl.y — ToLz.y;
d := sqrt(dx*dx+dy*dy);
if (dy)>0
a2Lz := arccos(dx/d)
else a2Lz := -arccos(dx/d);
hitX := Bl.x +cos(a2Lz)*Bl.R;
hitY := Bl.y +sin(a2Lz)*Bl.R;
dx := nearestBall.x — hitX;
dy := nearestBall.y — hitY;
d := sqrt(dx*dx+dy*dy);
if (dy)>0
then a := arccos(dx/d)
else a := -arccos(dx/d);
Result := a;}
void ComputerMove(){
Cue->visible = True;
CompAngle = CalculateAngle;
if(CompAngle >Cue->angle)
CompMove = 1;
else CompMove = -1;}
void TBilliardTable::Draw(){
{ int i;
pBall *b;
pLose *lz;
char* WhoIsIt;
Canvas->Brush->Color =clBlack;
Canvas->Pen->Color = clBlack;
Canvas->Rectangle(0,0,Width,Height);
Canvas->Brush->Color =$336699;
Canvas->Pen->Color = clYellow;
Canvas->Rectangle(BilliardTable->Left- LoseSize, BilliardTable->Top — LoseSize,
BilliardTable->Right +LoseSize, BilliardTable->Bottom + LoseSize);
Canvas->Brush->Color =clGreen;
Canvas->Rectangle(BilliardTable->Left,BilliardTable->Top, BilliardTable->Right, BilliardTable->Bottom);
Canvas->Pen->Color = clYellow;
Canvas->Pen->Color = clBlack;
Canvas->Ellipse(BilliardTable->Left+ (3 * BilliardTable->Width / 4)-2,
BilliardTable->Top +(BilliardTable->Height / 2)-2,
BilliardTable->Left + (3* BilliardTable->Width / 4)+2,
BilliardTable->Top +(BilliardTable->Height / 2)+2);
Canvas->Brush->Color =$336699;
Canvas->Font->Color = clYellow;
Canvas->Font->Style = [];
if(Player == 0
then WhoIsIt = «Игрок»;
if(Player == 1
then WhoIsIt = «Компьютер»;
Canvas->TextOut(BilliardTable->Left+30,dh + 1,
«Ход:»+WhoIsIt+«а»);
Canvas->TextOut(BilliardTable->Left+30,BilliardTable->Bottom,
«Влузах:»+IntToStr(InLoses));
if(Player == 0 )Canvas->Font->Style = [fsBold];
Canvas->TextOut(BilliardTable->Right-150,BilliardTable->Bottom,
«Игрок:»+IntToStr(PlayerN[0]->balls));
Canvas->Font->Style = [];
if(Player == 1 )Canvas->Font->Style = [fsBold];
Canvas->TextOut(BilliardTable->Right-150,dh + 1,
«Компьютер:»+IntToStr(PlayerN[1]->balls));
Canvas->Brush->Color =clBlack;
Canvas->Font->Color = clYellow;
Canvas->Font->Style = [fsBold];
Canvas->Font->Style = [];
for( i = 0; iCount-1; i ++)
{ lz = Lose->Items[i];
lz->Draw; }
for( i = 0; iCount-1; i ++)
{ b = Ball->Items[i];
if(b->exist ) b->Draw;}
if(Cue->visible )Cue->Draw; }
gsGameOver:
{ }
case } // case;break;; }
void TLose::Draw()
{ withForm1->Image1->Canvas do
{ Brush->Color = clBlack;
Pen->Color = clYellow;
Ellipse(Trunc(x-r),Trunc(y-r),
Trunc(x+r), Trunc(y+r));
Font->Color = clWhite;
TextOut(x-4,y-8,IntToStr(ballsInside)); } }
void TBall::Draw()
{ withForm1->Image1->Canvas do
{ Brush->Color = col;
Pen->Color = col;//clBlack;
Ellipse(Trunc(x-r),Trunc(y-r),
Trunc(x+r), Trunc(y+r));
Brush->Color = clWhite;
Pen->Color = clWhite;
Ellipse(Trunc(x-r*sqrt(2)/2*0.5-2),Trunc(y-r*sqrt(2)/2*0.5-2),
Trunc(x-r*sqrt(2)/2*0.5+2),Trunc(y-r*sqrt(2)/2*0.5+2));
Brush->Color = col;
Font->Color = clWhite — col;
if(ShowID )
{ TextOut(Trunc(x-4),Trunc(y-8), IntToStr(ID)); }
Refresh; } }
void TCue->Draw()
{ int x1, y1, x2, y2, x3,y3;
Brush->Color = clYellow;
Pen->Color = clYellow;
Pen->Width = 4;
x1 = Trunc(ToBall->x+cos(Angle)*(ToBall->R+energy));
y1 = Trunc(ToBall->y+sin(Angle)*(ToBall->R+energy));
x2 = Trunc(ToBall->x+cos(Angle)*(ToBall->R+CueLength+energy));
y2 = Trunc(ToBall->y+sin(Angle)*(ToBall->R+CueLength+energy));
x3 = Trunc(ToBall->x-cos(Angle)*1000);
y3 = Trunc(ToBall->y-sin(Angle)*1000);
MoveTo(x1, y1);
LineTo(x2, y2);
Pen->Width = 1;
Brush->Color = clWhite;
Pen->Color = clWhite;
Ellipse(x1-2,y1-2,x1+2,y1+2);
if(ShowLine )
{ Pen->Style = psDash;
MoveTo(x1, y1);
LineTo(x3, y3);
Pen->Style = psSolid; } }}
void TBall->Stop;
{ dx = 0;
dy = 0;
stopped = true; }
bool TBall::InLose(){
int Number;
int i;
pLose lz;
boolean inLz;
Result = False;
if(! exist ) exit;
for( i = 0; iLose->Count-1; i ++)
{ lz = BilliardTable->Lose->Items[i];
inLz = sqrt(sqr(x-lz->x)+sqr(y-lz->y))R;
if(inLz )
{ Number = i;
Result = True;
inc(InLoses);
Exit; } } }
pBallTBall->CollisedWith();
{ int j;
pBall bb;
real d, delta, ddx, ddy;
Result = NULL;
if(! exist ) exit;
for( j = 0; jBall->Count-1; j ++)
{ bb = BilliardTable->Ball->Items[j];
if(! bb->exist )continue;
if(bb->ID == ID )continue;
d = sqrt(sqr(x-bb->x)+sqr(y-bb->y));
if((d R) )
{ delta = (R+bb->R — d)/2+ 1;
ddx = (bb->x-x)/d;
ddy = (bb->y-y)/d;
x = x — ddx*delta;
y = y — ddy*delta;
bb->x = bb->x +ddx*delta;
bb->y = bb->y +ddy*delta;
Result = bb;
exit; }  }  }
//initial
int ballSize = 10; //розміркуль
int loseSize = ballSize + 5;
int MaxEnergy= 20; // силамаксимального удару
int CueLength = 200;//довжина кия
float mu = 0.97;
float Step = 0.03; //переміщення
int PyramidHeight;//величина піраміди
float MovementLimit; //переміщення
bool BallsInMove=false;
int Player=0;
float CompAngle;
int CompMove;
float CalculateAngle;
int tick;
bool MustBeHitted;
int Balls;
int ballsIn;
TForm1 *Form1;
TCue *Cue=new TCue;
TBall *Ball=new TBall;
TBilliardTable*BilliardTable= new TBilliardTable;
__fastcallTForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{}
void __fastcallTForm1::StopAll(){
{ int i;
TBall *b = new TBall;
{ for( i =0;iBall->Count-1; i ++)
{ //b=BilliardTable->Ball->Items[i];
b->dx = 0;
b->dy = 0; }
Cue->Visible = True; } }}
void ComputerMove(){
Cue->Visible = True;
CompAngle = CalculateAngle;
if(CompAngle >Cue->Angle)
CompMove = 1;
else CompMove = -1;}
void __fastcallTForm1::FormKeyDown(TObject *Sender, WORD &Key,
TShiftState Shift)
{{ int cur;
TBall *b= new TBall;
TBilliardTable*BilliardTable= new TBilliardTable;
{ if(BallsInMove) exit;
if(! Cue->Visible ) exit;
if(Player == 1 ) exit;//нельзя управлять во время хода компьютера!
// cur = Cue->ToBall->ID;
if(Key == VK_DOWN)
Cue->Angle = Cue->Angle- Step;
if(Key == VK_UP)
Cue->Angle = Cue->Angle+ Step;
if(Key == VK_RIGHT )
{ cur = (cur + 1) % Ball->count;
//b = Ball->Items[cur];
}while( b->exists);
if(Key == VK_LEFT )
do{ cur = (cur — 1 +Ball->count) % Ball->count;
// b = Ball->Items[cur];
}while( b->exists);
if(Key == 32 ) if(Cue->Visible) Cue->Hit();
if(Key == 13 )ComputerMove();
if (Key = 13) StopAll();
// Cue->ToBall = Ball->Items[cur];} }}
void __fastcallTForm1::Timer1Timer(TObject *Sender)
{{ int cur, i, num;
TBall *b, *b2 = new TBall;
boolean allstopped;
TLose *lz = new TLose;
float d;
char* Mess;
{ tick++;
/* while( Cue.Angle >6.28 do
Cue.Angle := Cue.angle — 6.28;
while( Cue.Angle
Cue.Angle := Cue.angle +6.28;
*/ if (CompMove != 0&& Player == 1)
{ Cue->Angle = Cue->Angle+ Step*CompMove;
if(abs(CompAngle-Cue->Angle)
{ CompMove = 0;
Cue->Angle = CompAngle;
MustBeHitted = True; } }
if(Player == 0 )MustBeHitted = False;
if(MustBeHitted )
if(Cue->energy >MaxEnergy/2 )
{ Cue->Hit();
MustBeHitted = False; } for(inti =0; i count-1; i++)
{ // b = Ball->Items[i];
if(!b->exists ) continue;
if(b->InLose(num) )
{ b->Stop();
b->exists = False;
Balls--;
ballsIn++;
//lz = BilliardTable->Lose->Items[num];
lz->ballsInside++;
//PlayerN[Player]->balls++;
if(Balls == 1 )
{ GameStatus->gsGameOver();
Timer1->Enabled = False; }
cur = Cue->ToBall->ID;
do{
cur = (cur + 1) % Ball->Count;
b = Ball->Items[cur];
}while( b->exist);
Cue->ToBall = b; }
b->dx = b->dx*mu;
b->dy = b->dy*mu;
if((b->x+b->dx >BilliardTable->Right-b->R)
|| (b->x+b->dx Left+b->R)
b->dx = -b->dx * mu;
b->x = b->x +b->dx;
if((b->y+b->dy >BilliardTable->Bottom-b->R)
|| (b->y+b->dy Top+b->R)
b->dy = -b->dy * mu;
b->y = b->y +b->dy;
b2 = b->collisedWith;
b->outFrom(b2);
d = sqrt(sqr(b->dx)+sqr(b->dy));
if(d
{ b->Stop; }
Cue->energy = Trunc(MaxEnergy/2*cos(tick/5)+MaxEnergy/2)+1;}
allstopped = True;
for( i = 0; iCount — 1; i ++)
{ b = Ball->Items[i];
allstopped = (b->dx == 0)&& (b->dy == 0) && allstopped; }
if(allstopped && MovedLater)
{ Cue->visible = True;
if(ballsIn == 0
then Player = 1 — Player;
if(Player == 1 )ComputerMove;
ballsIn = 0; }
MovedLater = !allstopped;
BallsInMove = !allStopped;
Draw; } }}
void __fastcallTForm1::FormKeyPress(TObject *Sender, char &Key)
{ if(BallsInMove ) exit;
if(Key in [«i»,«I»] )
{ ShowID =! ShowID; }
if(Player == 1 ) exit;//нельзя управлять во время хода компьютера!
if(Key in [«h»,«H»] then ComputerMove;// help me!}
void __fastcallTForm1::FormDestroy(TObject *Sender)
{ INI = TIniFile->Create(ExtractFilePath(ParamStr(0))+"\settings.ini");
INI->Writeint («Phisics»,«ballSize», ballSize);
INI->Writeint («Phisics»,«PocketSize», loseSize);
INI->Writeint («Phisics»,«MaxEnergy», MaxEnergy);
INI->Writeint («Phisics»,«CueLength», CueLength);
INI->Writeint («Phisics»,«PyramidHeight», PyramidHeight);
INI->WriteFloat(«Phisics»,«Friction», mu);
INI->WriteFloat(«Phisics»,«AngleStep», Step);
INI->WriteFloat(«Phisics»,«MovementLimit», MovementLimit);
INI->Writeint («Phisics»,«TimeInterval», Timer1->Interval);}
void __fastcallTForm1::Button1Click(TObject *Sender)
{ int i, j;
pBall b;
pLose luza;
boolean unique, inrect;
randomize;
Player = 0;
CompMove = 0;
Timer1->Enabled = True;
with Image1->Canvas do
{  Brush->Color = clWhite;
Pen->Color = clBlack;
Rectangle(0, 0, Width,Height); }
BilliardTable->Ball->Clear;
BilliardTable->Lose->Clear;
balls = -1;
new(b);
inc(balls);
b->x = BilliardTable->Width/ 4 + BilliardTable->Left;
b->y = BilliardTable->Height/ 2 + BilliardTable->Top;
b->R = ballSize;//Random(20)+10;
b->col = clLtGray;//Random(clWhite);
b->dx = Random*2-1;
b->dy = Random*2-1;
b->ID = 0;
b->exist = True;
BilliardTable->Ball->Add(b);
PlayerN[0]->balls = 0;
PlayerN[1]->balls = 0;
GameStatus = gsGame;
loses = -1;
for( j = 0; j
for( i = -1; i
{  new(luza);
inc(loses);
luza->x = BilliardTable->Left+ (BilliardTable->Width / 2)*(i+1);
luza->y = BilliardTable->Top+ (BilliardTable->Height / 2)*(j*2);
luza->R = loseSize;
if(abs(i)==1 )
{  luza->x = trunc(luza->x- i*luza->R*sqrt(2)/2);
luza->y = trunc(luza->y-(j*2-1)*luza->R*sqrt(2)/2); }
luza->ballsInside = 0;
BilliardTable->Lose->Add(luza);}
for( j = 1; j
for( i = 1; i
{  new(b);
inc(balls);
b->R = ballSize; //Random(20)+10;
b->col = clLtGray; //Random(clWhite);//clLtGray;
b->dx = Random*2-1;
b->dy = Random*2-1;
b->ID = balls;
b->exist = True;
if(j % 2 != 0
then b->y = -((j-1) / 2)*2*b->R+(i-1)*2*b->R+ H / 2
else b->y = -((j-1) / 2)*2*b->R+(i-1)*2*b->R- b->R + H / 2;
b->y = b->y + dh;
b->x = (j-1)*2*b->R +3 * BilliardTable->Width / 4 + dw + LoseSize;
BilliardTable->Ball->Add(b);}
inc(Balls);
BilliardTable->Cue->ToBall= BilliardTable->Ball->Items[0];
BilliardTable->Cue->angle= 180*Pi/180;
BilliardTable->Cue->visible= False;
StopAll;
void __fastcallTForm1::FormCreate(TObject *Sender)
{  INI = TIniFile->Create(ExtractFilePath(ParamStr(0))+"\settings.ini");
ballSize = INI->Readint («Phisics»,«ballSize», 10);
loseSize = INI->Readint («Phisics»,«PocketSize», ballSize + 5);
MaxEnergy = INI->Readint («Phisics»,«MaxEnergy», 20);
CueLength = INI->Readint («Phisics»,«CueLength», 200);
PyramidHeight = INI->Readint(«Phisics», «PyramidHeight», 5);
mu = INI->ReadFloat(«Phisics»,«Friction», 0.97);
Step = INI->ReadFloat(«Phisics»,«AngleStep», 0.03);
MovementLimit = INI->ReadFloat(«Phisics»,«MovementLimit», 0.01);
Timer1->Interval = INI->Readint(«Phisics», «TimeInterval», 20);
Width = Screen->Width-4;
Height = Screen->Height-4;
Panel1->Width = ClientWidth;
Panel1->Height = ClientHeight;
Image1->Width = ClientWidth;
Image1->Height = ClientHeight;
dw = (Image1->Width — W) /2;
dh = (Image1->Height — H)/ 2;
BilliardTable = TBilliardTable->Create;
BilliardTable->Ball = TList->Create;
BilliardTable->Lose = TList->Create;
BilliardTable->Cue = TCue->Create;
Left = dw + loseSize;
Top = dh + loseSize;
Width = W — LoseSize*2;
Height = H — LoseSize*2;
Right = Left + Width;
Bottom = Top + Height;
Player = 0;
Button1Click(Sender);}

2.2 Опис гри
Грають двоє: людина ікомп'ютер. Першим робить хід чоловік. Хід передається іншому гравцеві, якщо данийгравець не забив в лузи жодної кулі (див. Додаток А).
Сила удару залежить відвідстані в даний момент кия від битка (див. Додаток Б).
Управління:
Курсори:
вгору-вниз — обертання кия
вліво-управо — перемикання з однієї кулі на іншій
«пропуск» — удар києм
«H»,«h» — підказка для людини (як на його місцізробив би хід чоловік)
«I»,«i» — включення/виключення нумерації куль
«S»,«s» — включення/виключення лінії прицілювання
Опис файлу конфігураціїsettings.ini:
ballsize=10 — розмір куль
Pocketsize=20 — розмір лузи
Maxenergy=20 — максимальна сила удару
Cuelength=200 — довжина кия
Friction=0,97 — коефіцієнт тертя (строго менше 1)
Pyramidheight=5 — кількість рівнів в піраміді з кулями
Anglestep=0,03 — крок повороту кия навколо кулі
Movementlimit=0,1 — межа вектора швидкості, після якого рух кулі вважається припиненим.
Timeinterval=20 — час між кадрами перемальовування (у мілісекундах)

Висновок
Використання методів Canvas для відображенняграфіки в проектах C++Builder допомогло реалізувати поставлену задачу. Але цейметод від малювання графіки на формі об’єктів є досить не практичний і томуважливо кожного разу перемалювати всю сцену з її об’єктами, а коли ми маємоанімацію то перемалювання сцени має ще й відбуватись непомітно для окакористувача, хоча цього часом буває досить важко добитись, особливо коли багатоанімацій відбувається одночасно для декількох обєктів, що збільшує час виводупевного зображення на екран.
В даній роботі я змігдобитись пере малювання куль, кия та всього столу буз затримки картинки, щостворює ілюзію анімації для людського ока. Сама логіка гри дуже проста, коликілі торкаються одна одної то кожній передається імпульс і прискорення з початковоюшвидкістю, котра зменшується з часом та відбиттям від інших об’єктів, тобтозіткненням.
Програма широковикористовує фізичні закони, для моделювання гри в середовищі C++Builder.

Використана література
1. С++ для начинающих Липпман2003г 332 стр.
2. Введение в язык С++ БьярнСтраустрап, 1995 г.; Книга по Си; уроки Visual C++ 2004г, 560 стр.
3. http://forums.delphi.com/ab_cplus/start
4. Программирование на языкеСИ Ю.Ю.Громов, С.И.Татаренко 1998г 545 стр.;
5. Applied C++: PracticalTechniques for Building Better Software Авторы: Philip Romanik, Amy Muntz 2003г. 470 стр.
6. C++ Unleashed Автор: JesseLiberty 2005г. 396 p.


Не сдавайте скачаную работу преподавателю!
Данный реферат Вы можете использовать для подготовки курсовых проектов.

Поделись с друзьями, за репост + 100 мильонов к студенческой карме :

Пишем реферат самостоятельно:
! Как писать рефераты
Практические рекомендации по написанию студенческих рефератов.
! План реферата Краткий список разделов, отражающий структура и порядок работы над будующим рефератом.
! Введение реферата Вводная часть работы, в которой отражается цель и обозначается список задач.
! Заключение реферата В заключении подводятся итоги, описывается была ли достигнута поставленная цель, каковы результаты.
! Оформление рефератов Методические рекомендации по грамотному оформлению работы по ГОСТ.

Читайте также:
Виды рефератов Какими бывают рефераты по своему назначению и структуре.