Библиотека graphics.h в C/C++: 15 примеров от новичка до профи
Для кого эта статья:
- Студенты и новички в программировании, изучающие C/C++ и графику
- Программисты, интересующиеся графическим программированием и разработкой игр
Преподаватели, ищущие наглядные примеры и проекты для обучения студентов
Библиотека graphics.h — мощный, но часто недооценённый инструмент в арсенале C/C++ программиста. Несмотря на свой возраст, она остаётся отличным способом быстро визуализировать алгоритмы, создать простые игры или графические демонстрации без погружения в сложности современных графических API. Владение этой библиотекой — навык, который не только прокачивает понимание графических принципов, но и позволяет буквально "увидеть" свой код в действии. 🚀 Рассмотрим 15 готовых примеров, которые превратят вас из новичка в уверенного пользователя graphics.h.
Изучаете программирование и хотите создавать визуальные приложения быстро и эффективно? Курс Java-разработки от Skypro погружает вас в мир современных технологий, где вы освоите не только базовые принципы программирования, но и продвинутые техники создания графических интерфейсов. В отличие от устаревшей библиотеки graphics.h, Java предлагает кроссплатформенные решения с богатым функционалом и поддержкой актуальных стандартов. Инвестируйте в навыки будущего!
Основы работы с библиотекой graphics.h в C/C++
Библиотека graphics.h — это классическое решение для работы с графикой в C/C++, разработанное Borland. Хотя она не является частью стандартной библиотеки, её широко используют в образовательных целях для обучения основам компьютерной графики. 📊
Для использования библиотеки необходимо включить следующие заголовочные файлы:
- graphics.h — основной файл, содержащий объявления графических функций
- conio.h — для консольного ввода-вывода
- dos.h — для доступа к функциям DOS (при работе в устаревших средах)
Первый пример демонстрирует базовую инициализацию графического режима:
#include <graphics.h>
#include <conio.h>
int main() {
int gd = DETECT, gm;
initgraph(&gd, &gm, "C:\\TC\\BGI");
outtextxy(100, 100, "Привет, Graphics.h!");
getch();
closegraph();
return 0;
}
Этот код инициализирует графический режим с автоопределением драйвера, выводит текст и ожидает нажатия клавиши перед закрытием.
Пример №2 демонстрирует работу с цветами:
#include <graphics.h>
#include <conio.h>
int main() {
int gd = DETECT, gm;
initgraph(&gd, &gm, "C:\\TC\\BGI");
// Установка цвета фона
setbkcolor(BLUE);
cleardevice(); // Применение цвета фона
// Установка цвета рисования
setcolor(YELLOW);
outtextxy(100, 100, "Жёлтый текст на синем фоне");
getch();
closegraph();
return 0;
}
Основные функции инициализации и настройки среды graphics.h:
| Функция | Назначение | Пример использования |
|---|---|---|
| initgraph() | Инициализирует графический режим | initgraph(&gd, &gm, "путькдрайверам"); |
| closegraph() | Закрывает графический режим | closegraph(); |
| setcolor() | Устанавливает цвет рисования | setcolor(RED); |
| setbkcolor() | Устанавливает цвет фона | setbkcolor(BLACK); |
| cleardevice() | Очищает экран | cleardevice(); |
Пример №3 показывает, как получить информацию о графическом режиме:
#include <graphics.h>
#include <conio.h>
#include <stdio.h>
int main() {
int gd = DETECT, gm;
char driver[10], mode[10];
initgraph(&gd, &gm, "C:\\TC\\BGI");
// Получаем информацию о текущем драйвере и режиме
getdrivername(driver);
getmodename(gm, mode);
// Выводим информацию на экран
settextstyle(DEFAULT_FONT, HORIZ_DIR, 1);
outtextxy(10, 10, driver);
outtextxy(10, 30, mode);
sprintf(driver, "Разрешение: %dx%d", getmaxx()+1, getmaxy()+1);
outtextxy(10, 50, driver);
getch();
closegraph();
return 0;
}
Александр Петров, руководитель курса компьютерной графики
Однажды ко мне обратился студент второго курса, который никак не мог понять, почему его код с библиотекой graphics.h выглядит иначе на разных компьютерах. "На моём ноутбуке круги выглядят как эллипсы, а линии толще чем нужно," — жаловался он.
После анализа мы обнаружили, что он не учитывал аспектное соотношение пикселей. Мы модифировали его код, добавив коррекцию с использованием функций getaspectratio() и setaspectratio(). Результат поразил студента — его визуализация физической модели маятника теперь выглядела идеально на любом дисплее. Этот случай стал отличным практическим уроком о важности понимания особенностей графических систем.

Простые геометрические фигуры и анимации в graphics.h
Библиотека graphics.h предоставляет широкий набор функций для рисования базовых геометрических фигур. Освоив их, вы сможете создавать как статичные изображения, так и простые анимации. 🔶
Пример №4 демонстрирует рисование основных фигур:
#include <graphics.h>
#include <conio.h>
int main() {
int gd = DETECT, gm;
initgraph(&gd, &gm, "C:\\TC\\BGI");
// Рисование линии
setcolor(RED);
line(50, 50, 200, 50);
// Рисование прямоугольника
setcolor(GREEN);
rectangle(50, 70, 200, 120);
// Рисование окружности
setcolor(BLUE);
circle(125, 170, 50);
// Рисование эллипса
setcolor(YELLOW);
ellipse(125, 270, 0, 360, 75, 25);
// Рисование дуги
setcolor(MAGENTA);
arc(125, 350, 45, 315, 50);
getch();
closegraph();
return 0;
}
Пример №5 показывает заполненные фигуры:
#include <graphics.h>
#include <conio.h>
int main() {
int gd = DETECT, gm;
initgraph(&gd, &gm, "C:\\TC\\BGI");
// Закрашенный прямоугольник
setfillstyle(SOLID_FILL, RED);
bar(50, 50, 150, 100);
// Прямоугольник с узором
setfillstyle(HATCH_FILL, GREEN);
bar3d(200, 50, 300, 100, 20, 1);
// Закрашенный круг
setfillstyle(SOLID_FILL, BLUE);
fillellipse(100, 200, 50, 50);
// Закрашенный сектор
setfillstyle(SOLID_FILL, YELLOW);
pieslice(250, 200, 30, 300, 50);
getch();
closegraph();
return 0;
}
Различные стили заливки и линий доступные в graphics.h:
| Тип стиля | Константы | Описание |
|---|---|---|
| Стили заливки | ||
| EMPTY_FILL | Без заливки | |
| SOLID_FILL | Сплошная заливка | |
| HATCH_FILL | Штриховая заливка | |
| PATTERN_FILL | Пользовательский узор | |
| Стили линий | ||
| SOLID_LINE | Сплошная линия | |
| DOTTED_LINE | Точечная линия | |
| DASHED_LINE | Пунктирная линия |
Пример №6 демонстрирует создание простой анимации — движущегося круга:
#include <graphics.h>
#include <conio.h>
#include <dos.h>
int main() {
int gd = DETECT, gm;
initgraph(&gd, &gm, "C:\\TC\\BGI");
int x = 50;
int y = getmaxy() / 2;
int radius = 30;
int max_x = getmaxx() – radius;
// Анимация движения круга
while(!kbhit()) {
// Очистка предыдущего кадра
cleardevice();
// Рисуем круг в новой позиции
setcolor(YELLOW);
setfillstyle(SOLID_FILL, RED);
fillellipse(x, y, radius, radius);
// Обновляем позицию
x += 5;
if(x > max_x) x = radius;
// Задержка для видимости анимации
delay(50);
}
getch();
closegraph();
return 0;
}
Пример №7 показывает создание "отскакивающего" мяча с физикой:
#include <graphics.h>
#include <conio.h>
#include <dos.h>
int main() {
int gd = DETECT, gm;
initgraph(&gd, &gm, "C:\\TC\\BGI");
int x = 100;
int y = 100;
int radius = 20;
int dx = 5;
int dy = 3;
int max_x = getmaxx() – radius;
int max_y = getmaxy() – radius;
while(!kbhit()) {
// Стираем предыдущий кадр
cleardevice();
// Рисуем мяч
setcolor(WHITE);
setfillstyle(SOLID_FILL, RED);
fillellipse(x, y, radius, radius);
// Обновляем позицию
x += dx;
y += dy;
// Проверяем столкновения со стенками
if(x <= radius || x >= max_x) dx = -dx;
if(y <= radius || y >= max_y) dy = -dy;
delay(30);
}
getch();
closegraph();
return 0;
}
Создание интерактивных элементов с помощью graphics.h
Библиотека graphics.h позволяет не только рисовать, но и создавать интерактивные элементы, реагирующие на ввод пользователя. Эти возможности превращают статичные изображения в интерактивные приложения. 🖱️
Пример №8 демонстрирует использование мыши в программе с graphics.h:
#include <graphics.h>
#include <conio.h>
#include <dos.h>
void initialize_mouse();
void show_mouse();
void get_mouse_position(int *button, int *x, int *y);
int main() {
int gd = DETECT, gm;
initgraph(&gd, &gm, "C:\\TC\\BGI");
initialize_mouse();
show_mouse();
int button, x, y;
char pos[40];
outtextxy(10, 10, "Кликните для рисования точки. ESC для выхода.");
while(1) {
if(kbhit() && getch() == 27) break; // ESC
get_mouse_position(&button, &x, &y);
sprintf(pos, "X: %d, Y: %d ", x, y);
outtextxy(10, getmaxy() – 20, pos);
if(button == 1) { // Левая кнопка мыши
putpixel(x, y, RED);
}
delay(50);
}
closegraph();
return 0;
}
// Функции работы с мышью через прерывания DOS
void initialize_mouse() {
union REGS regs;
regs.x.ax = 0;
int86(0x33, ®s, ®s);
}
void show_mouse() {
union REGS regs;
regs.x.ax = 1;
int86(0x33, ®s, ®s);
}
void get_mouse_position(int *button, int *x, int *y) {
union REGS regs;
regs.x.ax = 3;
int86(0x33, ®s, ®s);
*button = regs.x.bx;
*x = regs.x.cx;
*y = regs.x.dx;
}
Пример №9 показывает создание простой кнопки:
#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#include <dos.h>
// Структура для представления кнопки
struct Button {
int x1, y1, x2, y2;
char *label;
int color, hover_color;
int is_hover;
};
// Функция проверки наведения на кнопку
int is_mouse_over(struct Button *btn, int mx, int my) {
return (mx >= btn->x1 && mx <= btn->x2 && my >= btn->y1 && my <= btn->y2);
}
// Функция отрисовки кнопки
void draw_button(struct Button *btn) {
// Основной прямоугольник
setfillstyle(SOLID_FILL, btn->is_hover ? btn->hover_color : btn->color);
bar(btn->x1, btn->y1, btn->x2, btn->y2);
// Граница
setcolor(WHITE);
rectangle(btn->x1, btn->y1, btn->x2, btn->y2);
// Текст кнопки
int text_width = textwidth(btn->label);
int text_height = textheight(btn->label);
int text_x = btn->x1 + (btn->x2 – btn->x1 – text_width) / 2;
int text_y = btn->y1 + (btn->y2 – btn->y1 – text_height) / 2;
setcolor(WHITE);
outtextxy(text_x, text_y, btn->label);
}
// Функции для работы с мышью
void initialize_mouse();
void show_mouse();
void get_mouse_position(int *button, int *x, int *y);
int main() {
int gd = DETECT, gm;
initgraph(&gd, &gm, "C:\\TC\\BGI");
initialize_mouse();
show_mouse();
// Создаем кнопку
struct Button btn;
btn.x1 = 150;
btn.y1 = 150;
btn.x2 = 350;
btn.y2 = 200;
btn.label = "Нажми меня!";
btn.color = BLUE;
btn.hover_color = RED;
btn.is_hover = 0;
int button, mx, my;
char message[40] = "";
while(1) {
if(kbhit() && getch() == 27) break; // ESC
get_mouse_position(&button, &mx, &my);
// Проверка наведения
int hover = is_mouse_over(&btn, mx, my);
if(hover != btn.is_hover) {
btn.is_hover = hover;
draw_button(&btn);
}
// Проверка клика
if(button == 1 && hover) {
strcpy(message, "Кнопка была нажата!");
cleardevice();
draw_button(&btn);
}
// Вывод сообщения
setcolor(WHITE);
outtextxy(150, 220, message);
delay(50);
}
closegraph();
return 0;
}
// Реализации функций для работы с мышью
void initialize_mouse() {
union REGS regs;
regs.x.ax = 0;
int86(0x33, ®s, ®s);
}
void show_mouse() {
union REGS regs;
regs.x.ax = 1;
int86(0x33, ®s, ®s);
}
void get_mouse_position(int *button, int *x, int *y) {
union REGS regs;
regs.x.ax = 3;
int86(0x33, ®s, ®s);
*button = regs.x.bx;
*x = regs.x.cx;
*y = regs.x.dx;
}
Пример №10 демонстрирует создание простого рисовального приложения:
#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
// Функции для работы с мышью
void initialize_mouse();
void show_mouse();
void hide_mouse();
void get_mouse_position(int *button, int *x, int *y);
int main() {
int gd = DETECT, gm;
initgraph(&gd, &gm, "C:\\TC\\BGI");
initialize_mouse();
show_mouse();
int current_color = WHITE;
int brush_size = 2;
int prev_x = -1, prev_y = -1;
int button, x, y;
char message[80];
// Отображаем инструкции
sprintf(message, "ЛКМ: рисовать | ПКМ: стереть | +/-: размер кисти | 1-9: цвета | ESC: выход");
outtextxy(10, 10, message);
while(1) {
if(kbhit()) {
char key = getch();
if(key == 27) break; // ESC
// Изменение размера кисти
if(key == '+' && brush_size < 10) brush_size++;
if(key == '-' && brush_size > 1) brush_size--;
// Выбор цвета (1-9 соответствуют разным цветам)
if(key >= '1' && key <= '9') {
current_color = key – '1' + 1; // Маппинг 1-9 на цвета 1-9
}
// Обновление информации
setcolor(WHITE);
setfillstyle(SOLID_FILL, BLACK);
bar(10, getmaxy() – 30, getmaxx() – 10, getmaxy() – 10);
sprintf(message, "Цвет: %d | Размер кисти: %d", current_color, brush_size);
outtextxy(10, getmaxy() – 20, message);
}
get_mouse_position(&button, &x, &y);
// Проверка, находится ли курсор в области рисования
if(y > 30 && y < getmaxy() – 30) {
if(button == 1) { // Левая кнопка – рисование
hide_mouse(); // Скрываем курсор перед рисованием
setcolor(current_color);
if(prev_x != -1 && prev_y != -1) {
// Рисуем линию к новой позиции для плавности
setlinestyle(SOLID_LINE, 0, brush_size);
line(prev_x, prev_y, x, y);
} else {
// Рисуем точку при первом клике
for(int i = 0; i < brush_size; i++) {
circle(x, y, i);
}
}
show_mouse(); // Показываем курсор после рисования
prev_x = x;
prev_y = y;
} else if(button == 2) { // Правая кнопка – стирание
hide_mouse();
setcolor(BLACK);
setfillstyle(SOLID_FILL, BLACK);
fillellipse(x, y, brush_size*2, brush_size*2);
show_mouse();
prev_x = x;
prev_y = y;
} else {
// Сбрасываем предыдущую позицию, если кнопка не нажата
prev_x = prev_y = -1;
}
}
delay(10);
}
closegraph();
return 0;
}
// Реализации функций для работы с мышью
void initialize_mouse() {
union REGS regs;
regs.x.ax = 0;
int86(0x33, ®s, ®s);
}
void show_mouse() {
union REGS regs;
regs.x.ax = 1;
int86(0x33, ®s, ®s);
}
void hide_mouse() {
union REGS regs;
regs.x.ax = 2;
int86(0x33, ®s, ®s);
}
void get_mouse_position(int *button, int *x, int *y) {
union REGS regs;
regs.x.ax = 3;
int86(0x33, ®s, ®s);
*button = regs.x.bx;
*x = regs.x.cx;
*y = regs.x.dx;
}
Ирина Соколова, старший преподаватель программирования
Запомнила случай с группой третьего курса, когда мы изучали взаимодействие с пользователем через graphics.h. Студент Михаил пытался создать простую игру-лабиринт, но столкнулся с проблемой: при нажатии клавиш персонаж двигался рывками, а не плавно, что портило впечатление от игры.
После консультации мы перестроили логику работы с клавиатурой. Вместо проверки нажатий в основном цикле с помощью getch() мы использовали неблокирующее чтение с помощью kbhit() и отслеживали состояние клавиш. Это позволило реализовать более плавную анимацию, а заодно добавить одновременное отслеживание нескольких клавиш. Михаил был поражён, насколько лучше стала работать его игра. "Это же совсем другой уровень!" — сказал он после тестирования. Этот подход стал стандартным в нашем курсе для всех проектов, требующих взаимодействия с пользователем.
Практические проекты: от простых игр до визуализаций
Библиотека graphics.h открывает возможности для создания разнообразных проектов: от классических игр до визуализации алгоритмов. Рассмотрим примеры, демонстрирующие практическое применение знаний о графике в C/C++. 🎮
Пример №11 — простая игра "Змейка":
#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <time.h>
#define MAX_LENGTH 100
// Структуры для представления координат
struct Point {
int x, y;
};
int main() {
int gd = DETECT, gm;
initgraph(&gd, &gm, "C:\\TC\\BGI");
randomize(); // Инициализация генератора случайных чисел
// Настройки игры
int cell_size = 10;
int width = getmaxx() / cell_size;
int height = getmaxy() / cell_size;
int score = 0;
int game_over = 0;
// Инициализация змейки
struct Point snake[MAX_LENGTH];
int length = 3;
int direction = 0; // 0-вправо, 1-вниз, 2-влево, 3-вверх
// Начальное положение змейки
for(int i = 0; i < length; i++) {
snake[i].x = width / 2 – i;
snake[i].y = height / 2;
}
// Случайное положение еды
struct Point food;
food.x = rand() % width;
food.y = rand() % height;
char score_text[20];
// Игровой цикл
while(!game_over) {
// Очистка экрана
cleardevice();
// Отображение счета
sprintf(score_text, "Score: %d", score);
setcolor(WHITE);
outtextxy(10, 10, score_text);
// Проверка нажатий клавиш
if(kbhit()) {
char key = getch();
switch(key) {
case 'w': if(direction != 1) direction = 3; break;
case 's': if(direction != 3) direction = 1; break;
case 'a': if(direction != 0) direction = 2; break;
case 'd': if(direction != 2) direction = 0; break;
case 27: game_over = 1; break; // ESC для выхода
}
}
// Перемещение змейки (сначала хвост)
for(int i = length – 1; i > 0; i--) {
snake[i] = snake[i-1];
}
// Перемещение головы
switch(direction) {
case 0: snake[0].x++; break;
case 1: snake[0].y++; break;
case 2: snake[0].x--; break;
case 3: snake[0].y--; break;
}
// Проверка столкновения со стеной
if(snake[0].x < 0 || snake[0].x >= width ||
snake[0].y < 0 || snake[0].y >= height) {
game_over = 1;
}
// Проверка столкновения с собой
for(int i = 1; i < length; i++) {
if(snake[0].x == snake[i].x && snake[0].y == snake[i].y) {
game_over = 1;
}
}
// Проверка съедания еды
if(snake[0].x == food.x && snake[0].y == food.y) {
length++;
score += 10;
// Новая позиция еды
food.x = rand() % width;
food.y = rand() % height;
}
// Отрисовка змейки
setcolor(GREEN);
setfillstyle(SOLID_FILL, GREEN);
for(int i = 0; i < length; i++) {
int x = snake[i].x * cell_size;
int y = snake[i].y * cell_size;
fillellipse(x + cell_size/2, y + cell_size/2, cell_size/2, cell_size/2);
}
// Отрисовка еды
setcolor(RED);
setfillstyle(SOLID_FILL, RED);
fillellipse(food.x * cell_size + cell_size/2,
food.y * cell_size + cell_size/2,
cell_size/2, cell_size/2);
delay(100); // Скорость игры
}
// Экран окончания игры
cleardevice();
setcolor(WHITE);
settextstyle(DEFAULT_FONT, HORIZ_DIR, 2);
outtextxy(getmaxx()/2 – 100, getmaxy()/2 – 20, "GAME OVER");
sprintf(score_text, "Final Score: %d", score);
outtextxy(getmaxx()/2 – 100, getmaxy()/2 + 20, score_text);
getch();
closegraph();
return 0;
}
Пример №12 — визуализация сортировки пузырьком:
#include <graphics.h>
#include <conio.h>
#include <stdlib.h>
#include <dos.h>
#include <time.h>
#define ARR_SIZE 50
void drawArray(int arr[], int size, int highlight1, int highlight2) {
cleardevice();
int bar_width = getmaxx() / size;
int max_height = getmaxy() – 50;
// Находим максимальное значение для масштабирования
int max_val = arr[0];
for(int i = 1; i < size; i++) {
if(arr[i] > max_val) max_val = arr[i];
}
// Рисуем каждый элемент массива как столбец
for(int i = 0; i < size; i++) {
int height = (arr[i] * max_height) / max_val;
int x1 = i * bar_width;
int y1 = getmaxy() – height;
int x2 = x1 + bar_width – 1;
int y2 = getmaxy();
// Выделяем текущие сравниваемые элементы
if(i == highlight1 || i == highlight2) {
setfillstyle(SOLID_FILL, RED);
} else {
setfillstyle(SOLID_FILL, WHITE);
}
bar(x1, y1, x2, y2);
}
delay(50); // Замедление для наблюдения
}
void bubbleSort(int arr[], int size) {
for(int i = 0; i < size – 1; i++) {
for(int j = 0; j < size – i – 1; j++) {
// Визуализируем текущее сравнение
drawArray(arr, size, j, j+1);
if(arr[j] > arr[j+1]) {
// Обмен элементов и визуализация
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
drawArray(arr, size, j, j+1);
}
}
}
// Финальное отображение отсортированного массива
drawArray(arr, size, -1, -1);
}
int main() {
int gd = DETECT, gm;
initgraph(&gd, &gm, "C:\\TC\\BGI");
randomize();
// Инициализация массива случайными значениями
int arr[ARR_SIZE];
for(int i = 0; i < ARR_SIZE; i++) {
arr[i] = rand() % 100 + 1; // Значения от 1 до 100
}
// Отображение начального состояния
drawArray(arr, ARR_SIZE, -1, -1);
getch(); // Ожидание нажатия клавиши для начала сортировки
// Сортировка и визуализация
bubbleSort(arr, ARR_SIZE);
getch();
closegraph();
return 0;
}
Пример №13 — визуализация фрактала (дерево):
#include <graphics.h>
#include <conio.h>
#include <math.h>
#define PI 3.14159265
// Рекурсивная функция для рисования фрактального дерева
void drawTree(int x, int y, double angle, int depth) {
if(depth == 0) return;
int length = depth * 10;
// Вычисляем конечную точку ветви
int x2 = x + (int)(cos(angle * PI / 180) * length);
int y2 = y – (int)(sin(angle * PI / 180) * length);
// Цвет зависит от глубины
if(depth < 3) {
setcolor(GREEN);
} else {
setcolor(BROWN);
}
// Рисуем линию (ветвь)
line(x, y, x2, y2);
// Рекурсивно рисуем левую и правую ветви
drawTree(x2, y2, angle – 20, depth – 1);
drawTree(x2, y2, angle + 20, depth – 1);
}
int main() {
int gd = DETECT, gm;
initgraph(&gd, &gm, "C:\\TC\\BGI");
// Рисуем фрактальное дерево
drawTree(getmaxx() / 2, getmaxy() – 10, 90, 9);
getch();
closegraph();
return 0;
}
Сравнение различных типов практических проектов на основе graphics.h:
| Тип проекта | Сложность | Основные компоненты | Учебная ценность |
|---|---|---|---|
| Игры (Snake, Pong, Tetris) | Средняя | Анимация, обработка ввода, коллизии | Алгоритмы, управление состоянием, интерактивность |
| Визуализация алгоритмов | Средняя | Отрисовка данных, пошаговая визуализация | Понимание алгоритмов, представление данных |
| Фракталы и математические визуализации | Высокая | Рекурсия, математические формулы | Рекурсивное мышление, математическое моделирование |
| Редакторы и инструменты | Высокая | UI элементы, обработка событий | Разработка интерфейсов, управление пользовательским опытом |
Пример №14 — простой редактор фигур:
#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
// Функции для работы с мышью
void initialize_mouse();
void show_mouse();
void hide_mouse();
void get_mouse_position(int *button, int *x, int *y);
// Типы фигур
#define SHAPE_LINE 0
#define SHAPE_RECT 1
#define SHAPE_CIRCLE 2
int main() {
int gd = DETECT, gm;
initgraph(&gd, &gm, "C:\\TC\\BGI");
initialize_mouse();
show_mouse();
int current_color = WHITE;
int current_shape = SHAPE_LINE;
int start_x = -1, start_y = -1;
int button, x, y;
int drawing = 0;
char message[80];
// Отображаем инструкции
sprintf(message, "L: линия | R: прямоугольник | C: круг | 1-9: цвет | ESC: выход");
outtextxy(10, 10, message);
while(1) {
if(kbhit()) {
char key = getch();
if(key == 27) break; // ESC
// Выбор фигуры
if(key == 'l' || key == 'L') current_shape = SHAPE_LINE;
if(key == 'r' || key == 'R') current_shape = SHAPE_RECT;
if(key == 'c' || key == 'C') current_shape = SHAPE_CIRCLE;
// Выбор цвета (1-9 соответствуют разным цветам)
if(key >= '1' && key <= '9') {
current_color = key – '1' + 1;
}
// Обновление информации
setfillstyle(SOLID_FILL, BLACK);
bar(10, getmaxy() – 30, getmaxx() – 10, getmaxy() – 10);
setcolor(WHITE);
sprintf(message, "Форма: %s | Цвет: %d",
current_shape == SHAPE_LINE ? "Линия" :
current_shape == SHAPE_RECT ? "Прямоугольник" : "Круг",
current_color);
outtextxy(10, getmaxy() – 20, message);
}
get_mouse_position(&button, &x, &y);
// Если нажата левая кнопка мыши
if(button == 1) {
if(!drawing) {
// Начало рисования
drawing = 1;
start_x = x;
start_y = y;
} else {
// Предварительный просмотр фигуры
hide_mouse();
// Очистка предыдущего превью
setcolor(BLACK);
setwritemode(XOR_PUT);
switch(current_shape) {
case SHAPE_LINE:
line(start_x, start_y, x, y);
break;
case SHAPE_RECT:
rectangle(start_x, start_y, x, y);
break;
case SHAPE_CIRCLE:
int radius = sqrt((x-start_x)*(x-start_x) + (y-start_y)*(y-start_y));
circle(start_x, start_y, radius);
break;
}
setwritemode(COPY_PUT);
show_mouse();
}
} else if(drawing) {
// Завершение рисования
drawing = 0;
// Рисуем окончательную фигуру
hide_mouse();
setcolor(current_color);
setlinestyle(SOLID_LINE, 0, 1);
switch(current_shape) {
case SHAPE_LINE:
line(start_x, start_y, x, y);
break;
case SHAPE_RECT:
rectangle(start_x, start_y, x, y);
break;
case SHAPE_CIRCLE:
int radius = sqrt((x-start_x)*(x-start_x) + (y-start_y)*(y-start_y));
circle(start_x, start_y, radius);
break;
}
show_mouse();
}
delay(50);
}
closegraph();
return 0;
}
// Реализации функций для работы с мышью
void initialize_mouse() {
union REGS regs;
regs.x.ax = 0;
int86(0x33, ®s, ®s);
}
void show_mouse() {
union REGS regs;
regs.x.ax = 1;
int86(0x33, ®s, ®s);
}
void hide_mouse() {
union REGS regs;
regs.x.ax = 2;
int86(0x33, ®s, ®s);
}
void get_mouse_position(int *button, int *x, int *y) {
union REGS regs;
regs.x.ax = 3;
int86(0x33, ®s, ®s);
*button = regs.x.bx;
*x = regs.x.cx;
*y = regs.x.dx;
}
Советы по отладке и оптимизации кода с graphics.h
Работа с графикой часто требует не только творческого подхода, но и умения оптимизировать код для достижения плавных анимаций и эффективной работы программы. Рассмотрим некоторые техники отладки и оптимизации при использовании библиотеки graphics.h. 🔧
Пример №15 — оптимизированная анимация с двойной буферизацией:
#include <graphics.h>
#include <conio.h>
#include <stdlib.h>
#include <dos.h>
#include <stdio.h>
#include <time.h>
// Функция для реализации двойной буферизации
void* createBuffer() {
// Создаем буфер в памяти размером с экран
void* buffer = malloc(imagesize(0, 0, getmaxx(), getmaxy()));
return buffer;
}
// Переключаем буфер на экран
void swapBuffers(void* buffer) {
// Сохраняем текущий экран в буфер
getimage(0, 0, getmaxx(), getmaxy(), buffer);
// Переносим буфер на экран
putimage(0, 0, buffer, COPY_PUT);
}
int main() {
int gd = DETECT, gm;
initgraph(&gd, &gm, "C:\\TC\\BGI");
// Инициализация двойной буферизации
void* buffer = createBuffer();
if(!buffer) {
outtextxy(10, 10, "Ошибка: не удалось создать буфер");
getch();
closegraph();
return 1;
}
randomize();
// Создаем множество шариков
#define NUM_BALLS 50
struct Ball {
int x, y;
int dx, dy;
int radius;
int color;
} balls[NUM_BALLS];
// Инициализируем шарики случайными значениями
for(int i = 0; i < NUM_BALLS; i++) {
balls[i].x = rand() % getmaxx();
balls[i].y = rand() % getmaxy();
balls[i].dx = (rand() % 5) + 1;
balls[i].dy = (rand() % 5) + 1;
balls[i].radius = (rand() % 10) + 5;
balls[i].color = (rand() % 15) + 1;
}
// Измерение FPS
clock_t start_time, end_time;
int frames = 0;
double fps = 0;
char fps_text[20];
start_time = clock();
// Основной цикл анимации
while(!kbhit()) {
// Очистка буфера
cleardevice();
// Отрисовка и обновление позиций всех шариков
for(int i = 0; i < NUM_BALLS; i++) {
setcolor(balls[i].color);
setfillstyle(SOLID_FILL, balls[i].color);
fillellipse(balls[i].x, balls[i].y, balls[i].radius, balls[i].radius);
// Обновление позиции
balls[i].x += balls[i].dx;
balls[i].y += balls[i].dy;
// Обработка столкновений со стенами
if(balls[i].x – balls[i].radius <= 0 ||
balls[i].x + balls[i].radius >= getmaxx()) {
balls[i].dx = -balls[i].dx;
}
if(balls[i].y – balls[i].radius <= 0 ||
balls[i].y + balls[i].radius >= getmaxy()) {
balls[i].dy = -balls[i].dy;
}
}
// Отображение FPS
frames++;
end_time = clock();
// Обновляем FPS каждую секунду
if((double)(end_time – start_time) / CLOCKS_PER_SEC >= 1) {
fps = frames / ((double)(end_time – start_time) / CLOCKS_PER_SEC);
frames = 0;
start_time = end_time;
}
setcolor(WHITE);
sprintf(fps_text, "FPS: %.1f", fps);
outtextxy(10, 10, fps_text);
// Выводим буфер на экран
swapBuffers(buffer);
// Задержка для ограничения FPS
delay(10);
}
free(buffer);
getch();
closegraph();
return 0;
}
Ключевые рекомендации по оптимизации кода с graphics.h:
- Используйте двойную буферизацию для устранения мерцания при анимации
- Минимизируйте очистку экрана — перерисовывайте только изменившиеся части
- Оптимизируйте циклы отрисовки — располагайте тяжёлые вычисления за пределами циклов
- Кэшируйте результаты тригонометрических и других сложных вычислений
- Используйте целочисленную арифметику вместо вычислений с плавающей точкой, где возможно
- Применяйте стратегию "грязных прямоугольников" — отслеживайте и обновляйте только изменённые области
Распространённые ошибки при работе с graphics.h и способы их исправления:
| Проблема | Причина | Решение |
|---|---|---|
| "BGI Error: Graphics not initialized" | Не найдены драйвера BGI или неправильный путь | Указать корректный путь к драйверам или использовать detectgraph() |
| Программа закрывается сразу после открытия | Отсутствие ожидания ввода пользователя | Добавить getch() перед closegraph() |
| Мерцание при анимации | Перерисовка всего экрана каждый кадр | Использовать двойную буферизацию или XOR_PUT для временных объектов |
| Низкая производительность | Неэффективные алгоритмы отрисовки | Оптимизировать циклы, уменьшить количество вызовов функций отрисовки |
| Искажение пропорций изображения | Различное аспектное соотношение пикселей | Использовать getaspectratio() и корректировать координаты |
Для отладки графических программ рекомендуется использовать следующие подходы:
- Выводите диагностические сообщения на экран с помощью outtextxy()
- Добавляйте визуальные маркеры в ключевых точках алгоритма
- Создавайте режим отладки с замедленной анимацией и отображением дополнительной информации
- Используйте пошаговый режим, где каждый шаг алгоритма выполняется по нажатию клавиши
- Внедряйте измерение FPS для отслеживания производительности
Помните, что современные компиляторы могут требовать дополнительной настройки для работы с библиотекой graphics.h. В некоторых случаях может потребоваться использование специальных заголовочных файлов или компиляторов, таких как Turbo C или WinBGIm для современных систем.
Продвигаясь вперёд от примитивной графики graphics.h к профессиональным графическим библиотекам, важно осознать эволюцию технологий визуализации. Эти 15 примеров демонстрируют не только базовые графические возможности C/C++, но и лежащие в их основе принципы, актуальные для любой графической библиотеки. Вы можете видеть, как от простых линий и кругов мы перешли к интерактивным приложениям, играм и визуализациям. Каждый пример — это ступенька к мастерству в мире компьютерной графики, независимо от используемых инструментов.
Читайте также
- Графика в C: освоение примитивов для создания визуальных приложений
- Рисование прямоугольников в C: библиотеки, функции и алгоритмы
- Графическое программирование на C с Allegro: возможности библиотеки
- Библиотека graphics.h: полное руководство для C/C++ разработчиков
- Графические библиотеки C: выбор инструментов для 2D и 3D разработки
- Настройка графики на C: OpenGL, GLFW, SDL2 для новичков
- Построение графиков функций в C: лучшие библиотеки и примеры
- Загрузка и сохранение изображений в C: оптимальные библиотеки
- OpenGL и C: базовые принципы создания 2D и 3D графики
- Графическое программирование на C: точки и координаты как основа