Всем привет! Свой блог я хочу посвятить теме разработки видеоигр. Немного погуглив и полазив в сообществе Game dev на юви, я нашел блог @Nuligine, который уже больше года неактивен, и сайты gamedev.kz и gamez.kz, которые тоже уже давно находятся в инактиве. На этих сайтах конечно есть интересные статьи и уроки, но они, как правило, по UNITY3D. Я считаю, что изучение этой темы (да и не только этой) нужно начинать, грубо говоря, со дна (или как можно ближе к нему).
Как известно из истории индустрии видеоигр, первые примитивные компьютерные игры были разработаны в 1950-x и 1960-x годах и работали на таких платформах, как университетские мейнфреймы и компьютеры EDSAC. Мы же сегодня попробуем реализовать одну из тех первых программ, имитирующую игру «крестики-нолики». В качестве среды программирования выбрана старая добрая Borland C++, которую на современных компьютерах можно запустить с помощью эмулятора DosBox. Его дистрибутив можно скачать с официального сайта разработчиков. Для запуска приложений необходимо в командной строке эмулятора прописать следующие команды по очереди: mount d d: и d: (где d - имя диска). Для вызова исполняемого файла прописываем его полный путь (например, foldergame.exe).
Теперь перейдем непосредственно к реализации программы. В первую очередь подключим необходимые библиотеки и объявим глобальные переменные:
-
#include <stdlib.h>
-
#include <iostream.h>
-
#include <conio.h>
-
#include <math.h> //библиотека для выполнения некоторых математических действий
-
#include <graphics.h>
-
char a[3][3];//матрица, равная игровому полю 3x3 и принимающая значения X, O и -, если ячейка свободна
-
char strike[1];// периодически меняет свое значение с X на O и наоборот
-
int hit=0;//счетчик ходов
-
int style,midx,midy,i,x,y,j;
-
void*ptr;//резервируем пустой указатель - стартовая ячейка памяти, начиная в которой мы будем хранить наш так называемый прицел (пригодится для его перемещения по игровому полю)
-
unsigned int size;//в этой переменной будем хранить данные о том, сколько наш прицел будет занимать в памяти
Графический интерфейс фирмы Borland International (BGI - Borland Graphics Interface) состоит из двух компонент: постоянного ядра графической системы и набора графических драйверов. Ядро графической системы воспринимает все запросы прикладной программы на выполнение графических функций. Оно не зависит от типа подключенного дисплейного адаптера. Аппаратно-зависимой частью являются графические драйверы, осуществляющие интерфейс между ядром системы и конкретным дисплейным адаптером.
Графические драйверы содержаться в отдельных файлах с расширением .bgi. Каждый файл содержит бинарный образ (binary image) драйвера для одного или нескольких близких по типу адаптеров.
После объявления глобальных переменых опишем функции, которые будут выводить на экран игровое поле и прицел:
-
void draw(int x, int y)
-
{
-
setlinestyle(SOLID_LINE,1,3); //устанавливаем стиль линии (сплошная и толстая)
-
line(x+70,y-70,x+70,y+70);
-
line(x-70,y-70,x-70,y+70); //рисуем 4 линии
-
line(x+200,y-25,x-200,y-25); //4 цифры в скобках - это координаты линии
-
line(x+200,y+25,x-200,y+25);
-
}
-
void check(int x, int y)
-
{
-
rectangle(x,y,x+15,y+10); //рисуем прямоугольник, который и будет нашим прицелом
-
}
Отмечу, что перемещение прицела по игровому полю будет ограничено координатами (это будет описано в функции int main(void), которую найдете ниже). Затем описываем функции рисования «крестика» и «нолика»:
-
void stroke(int x, int y)
-
{if(hit %2==0)//если ход четный, то ставим «крестик» (ходы считаются с нуля, поэтому всегда начинаем с «крестика»). %2==0 - проверка, делиться ли число пополам без остатка. Для этого была подключега библиотека <math.h>
-
{ strike[0]='x';
-
line(x+35,y-10,x-40,y+15);
-
line(x+40,y+15,x-35,y-10);}
-
else{ circle(x,y,40); strike[0]='o';} //если нечетный, то ставим "нолик"
-
hit++;}
-
void step(int x, int y){
-
if((x+y==218)&&(a[0][0]=='-')){//проверяем, соответствует ли положение прицела позиции левой верхней ячейки и свободна ли она
-
putimage(x-30, y-20, ptr, XOR_PUT);
-
stroke(x,y);a[0][0]=strike[0]; //если свободна, то рисуем
-
putimage(x-30, y-20, ptr, XOR_PUT);}
-
if((x+y==368)&&(a[0][1]=='-')){ //здесь тоже самое для верхней центральной позиции и т.д.
-
putimage(x-30, y-20, ptr, XOR_PUT); //повторно выводим прицел, чтобы не сливался с "крестиком"
-
stroke(x,y);a[0][1]=strike[0];
-
putimage(x-30, y-20, ptr, XOR_PUT);}
-
if((x+y==518)&&(a[0][2]=='-')){
-
putimage(x-30, y-20, ptr, XOR_PUT);
-
stroke(x,y);a[0][2]=strike[0];
-
putimage(x-30, y-20, ptr, XOR_PUT);}
-
if((x+y==268)&&(a[1][0]=='-')){
-
putimage(x-30, y-20, ptr, XOR_PUT);
-
stroke(x,y);a[1][0]=strike[0];
-
putimage(x-30, y-20, ptr, XOR_PUT);}
-
if((x+y==418)&&(a[1][1]=='-')){
-
putimage(x-30, y-20, ptr, XOR_PUT);
-
stroke(x,y);a[1][1]=strike[0];
-
putimage(x-30, y-20, ptr, XOR_PUT);}
-
if((x+y==568)&&(a[1][2]=='-')){
-
putimage(x-30, y-20, ptr, XOR_PUT);
-
stroke(x,y);a[1][2]=strike[0];
-
putimage(x-30, y-20, ptr, XOR_PUT);}
-
if((x+y==318)&&(a[2][0]=='-')){
-
putimage(x-30, y-20, ptr, XOR_PUT);
-
stroke(x,y);a[2][0]=strike[0];
-
putimage(x-30, y-20, ptr, XOR_PUT);}
-
if((x+y==468)&&(a[2][1]=='-')){
-
putimage(x-30, y-20, ptr, XOR_PUT);
-
stroke(x,y);a[2][1]=strike[0];
-
putimage(x-30, y-20, ptr, XOR_PUT);}
-
if((x+y==618)&&(a[2][2]=='-')){
-
putimage(x-30, y-20, ptr, XOR_PUT);
-
stroke(x,y);a[2][2]=strike[0];
-
putimage(x-30, y-20, ptr, XOR_PUT);}}
Далее нам нужна функция определения победы или ничьи, а также очистка игрового поля, если это определено. Но юви дальше отказывается сохранять код, поэтому вы можете скачать весь исходник и сам exe-шник здесь (если планируете запускать через DosBox, то папку bgi и exe-шник нужно закидывать в корень диска).