Всё сдал! - помощь студентам онлайн Всё сдал! - помощь студентам онлайн

Реальная база готовых
студенческих работ

Узнайте стоимость индивидуальной работы!

Вы нашли то, что искали?

Вы нашли то, что искали?

Да, спасибо!

0%

Нет, пока не нашел

0%

Узнайте стоимость индивидуальной работы

это быстро и бесплатно

Получите скидку

Оформите заказ сейчас и получите скидку 100 руб.!


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

Тип Реферат
Предмет Информатика и программирование
Просмотров
484
Размер файла
44 б
Поделиться

Ознакомительный фрагмент работы:

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

Зміст

Вступ

Розділ 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 filesCommon FilesBorland 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 filescommon filesborland sharedimagesbuttonsarrowlr.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() <<fsBold<<fsUnderline

Color Колір символів. Як значення можна використовувати константу типу TColor

При виведенні тексту вельми корисні методи TextWidth і TextHeight, значеннями яких є відповідно ширина і висота області виведення тексту, які, очевидно, залежать від характеристик використовуваного шрифту. Обом цим методам як параметр передається рядок, який передбачається вивести на поверхню методом TextOutA.

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

void fastcall TForml: : ForroPaint (TObject *Sender)

{AnsiStringms = "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() <<fsBold<< fsltalic;

// текст розмістимо в центрі вікна

х = (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: РХ <= Imagel->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 якою запишіть код, аналогічний приведеному вище, але що конкретизує функцію:

#definePi 3.14159

float X, Y; // координати функції

int РХ, PY; // координати пикселов

for (РХ = 0: РХ <- Imagel->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|:WINDOWSSYSTEModbcjt32.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 <vcl.h>

#pragma hdrstop

#include "UBilliard.h"

#include <math.h>

#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); }

void TBall::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; j <=Lose->Count-1; j ++)

for( i = 0; i <=Ball->Count-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 )

{ 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; i <=Ball->Count-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 )

{ minAng = abs(a2Lz-a);

nearestBall = b;

Result = a; } }

for( i := 0 to Ball.Count-1 do

begin

b := Ball.Items[i];

if (b.ID = Bl.ID) or (not b.exist)

continue;

d := sqrt(sqr(b.x-Bl.x)+sqr(b.y-Bl.y));

if d < minD then

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; i <=Lose->Count-1; i ++)

{ lz = Lose->Items[i];

lz->Draw; }

for( i = 0; i <=Ball->Count-1; i ++)

{ b = Ball->Items[i];

if(b->exist ) b->Draw; }

if(Cue->visible ) Cue->Draw; }

gsGameOver:

{ }

case } // case;break;; }

void TLose::Draw()

{ with Form1->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()

{ with Form1->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; i <=BilliardTable->Lose->Count-1; i ++)

{ lz = BilliardTable->Lose->Items[i];

inLz = sqrt(sqr(x-lz->x)+sqr(y-lz->y)) <== lz->R;

if(inLz )

{ Number = i;

Result = True;

inc(InLoses);

Exit; } } }

pBall TBall->CollisedWith();

{ int j;

pBall bb;

real d, delta, ddx, ddy;

Result = NULL;

if(! exist ) exit;

for( j = 0; j <=BilliardTable->Ball->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 + bb->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;

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{}

void __fastcall TForm1::StopAll(){

{ int i;

TBall *b = new TBall;

{ for( i =0; i<=BilliardTable->Ball->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 __fastcall TForm1::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 __fastcall TForm1::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 < 0 do

Cue.Angle := Cue.angle + 6.28;

*/ if (CompMove != 0 && Player == 1)

{ Cue->Angle = Cue->Angle + Step*CompMove;

if(abs(CompAngle-Cue->Angle) <= Step)

{ CompMove = 0;

Cue->Angle = CompAngle;

MustBeHitted = True; } }

if(Player == 0 ) MustBeHitted = False;

if(MustBeHitted )

if(Cue->energy > MaxEnergy/2 )

{ Cue->Hit();

MustBeHitted = False; } for(int i =0; i <=Ball->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 < BilliardTable->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 < BilliardTable->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 < MovementLimit )

{ b->Stop; }

Cue->energy = Trunc(MaxEnergy/2*cos(tick/5)+MaxEnergy/2)+1; }

allstopped = True;

for( i = 0; i <=Ball->Count - 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 __fastcall TForm1::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 __fastcall TForm1::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 __fastcall TForm1::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 <=1; j ++)

for( i = -1; 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 <=PyramidHeight; j ++)

for( i = 1; i <=j; 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 __fastcall TForm1::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++: Practical Techniques for Building Better Software Авторы: Philip Romanik, Amy Muntz 2003г. 470 стр.

6. C++ Unleashed Автор: Jesse Liberty 2005г.396p.


Нет нужной работы в каталоге?

Сделайте индивидуальный заказ на нашем сервисе. Там эксперты помогают с учебой без посредников Разместите задание – сайт бесплатно отправит его исполнителя, и они предложат цены.

Цены ниже, чем в агентствах и у конкурентов

Вы работаете с экспертами напрямую. Поэтому стоимость работ приятно вас удивит

Бесплатные доработки и консультации

Исполнитель внесет нужные правки в работу по вашему требованию без доплат. Корректировки в максимально короткие сроки

Гарантируем возврат

Если работа вас не устроит – мы вернем 100% суммы заказа

Техподдержка 7 дней в неделю

Наши менеджеры всегда на связи и оперативно решат любую проблему

Строгий отбор экспертов

К работе допускаются только проверенные специалисты с высшим образованием. Проверяем диплом на оценки «хорошо» и «отлично»

1 000 +
Новых работ ежедневно
computer

Требуются доработки?
Они включены в стоимость работы

Работы выполняют эксперты в своём деле. Они ценят свою репутацию, поэтому результат выполненной работы гарантирован

avatar
Математика
История
Экономика
icon
159599
рейтинг
icon
3275
работ сдано
icon
1404
отзывов
avatar
Математика
Физика
История
icon
156450
рейтинг
icon
6068
работ сдано
icon
2737
отзывов
avatar
Химия
Экономика
Биология
icon
105734
рейтинг
icon
2110
работ сдано
icon
1318
отзывов
avatar
Высшая математика
Информатика
Геодезия
icon
62710
рейтинг
icon
1046
работ сдано
icon
598
отзывов
Отзывы студентов о нашей работе
63 457 оценок star star star star star
среднее 4.9 из 5
Филиал государственного бюджетного образовательного учреждения высшего образования Московской област
Спасибо Елизавете за оперативность. Так как это было важно для нас! Замечаний особых не бы...
star star star star star
РУТ
Огромное спасибо за уважительное отношение к заказчикам, быстроту и качество работы
star star star star star
ТГПУ
спасибо за помощь, работа сделана в срок и без замечаний, в полном объеме!
star star star star star

Последние размещённые задания

Ежедневно эксперты готовы работать над 1000 заданиями. Контролируйте процесс написания работы в режиме онлайн

решить 6 практических

Решение задач, Спортивные сооружения

Срок сдачи к 17 дек.

только что

Задание в microsoft project

Лабораторная, Программирование

Срок сдачи к 14 дек.

только что

Решить две задачи №13 и №23

Решение задач, Теоретические основы электротехники

Срок сдачи к 15 дек.

только что

Решить 4задачи

Решение задач, Прикладная механика

Срок сдачи к 31 дек.

только что

Выполнить 2 задачи

Контрольная, Конституционное право

Срок сдачи к 12 дек.

2 минуты назад

6 заданий

Контрольная, Ветеринарная вирусология и иммунология

Срок сдачи к 6 дек.

4 минуты назад

Требуется разобрать ст. 135 Налогового кодекса по составу напогового...

Решение задач, Налоговое право

Срок сдачи к 5 дек.

4 минуты назад

ТЭД, теории кислот и оснований

Решение задач, Химия

Срок сдачи к 5 дек.

5 минут назад

Решить задание в эксель

Решение задач, Эконометрика

Срок сдачи к 6 дек.

5 минут назад

Нужно проходить тесты на сайте

Тест дистанционно, Детская психология

Срок сдачи к 31 янв.

6 минут назад

Решить 7 лабораторных

Решение задач, визуализация данных в экономике

Срок сдачи к 6 дек.

7 минут назад

Вариационные ряды

Другое, Статистика

Срок сдачи к 9 дек.

8 минут назад

Школьный кабинет химии и его роль в химико-образовательном процессе

Курсовая, Методика преподавания химии

Срок сдачи к 26 дек.

8 минут назад

Вариант 9

Решение задач, Теоретическая механика

Срок сдачи к 7 дек.

8 минут назад

9 задач по тех меху ,к 16:20

Решение задач, Техническая механика

Срок сдачи к 5 дек.

9 минут назад
9 минут назад
10 минут назад
planes planes
Закажи индивидуальную работу за 1 минуту!

Размещенные на сайт контрольные, курсовые и иные категории работ (далее — Работы) и их содержимое предназначены исключительно для ознакомления, без целей коммерческого использования. Все права в отношении Работ и их содержимого принадлежат их законным правообладателям. Любое их использование возможно лишь с согласия законных правообладателей. Администрация сайта не несет ответственности за возможный вред и/или убытки, возникшие в связи с использованием Работ и их содержимого.

«Всё сдал!» — безопасный онлайн-сервис с проверенными экспертами

Используя «Свежую базу РГСР», вы принимаете пользовательское соглашение
и политику обработки персональных данных
Сайт работает по московскому времени:

Вход
Регистрация или
Не нашли, что искали?

Заполните форму и узнайте цену на индивидуальную работу!

Файлы (при наличии)

    это быстро и бесплатно