Основная идея создания компьютерных игр.
главная страница статьи файлы о сайте ссылки
Основная идея создания компьютерных игр.

Георгий Мошкин
tmtlib@narod.ru

Основная идея создания компьютерных игр состоит в максимальном упрощении. Это означает, что при создании своей игры вы должны делать её максимально просто. И поэтому нужно настроиться на то, что всё делается просто. Причём начать нужно с самого простого - с вывода точки на экран вашего компьютера. Об этом очень хорошо написано в статье game2d.

Ведь всё начинается с того, что вы научились двигать точкой по экрану. А это очень просто: достаточно увеличивать или уменьшать координаты точки (x,y) в зависимости от нажатия клавиш или по формуле. И выводить по этим координатам белую точку или спрайт.

Причём вам понятно, что точка - это и есть положение главного героя вашей игры. Далее вы пришли к необходимости описать тип героя. Это было что-то вроде:

type tGeroy = record
x,y:single; // координаты
up,down,left,right,fire:boolean; // состояние
power:integer; // энергия
end;

И у вас появилась возможность делать не только одного героя (geroy:tGeroy), но и нескольких (geroys:array[0..100] of tGeroy). Благодаря использованию массивов с элементами определённого типа всё существенно упрощается. Например, вывод всех героев игры на экран будет выглядеть так:

for i:=0 to 100 do if geroys[i].power>0 then putsprite(geroys[i].x,geroys[i].y,kartinka);

Всё предельно просто: мы в цикле меняем переменную i от нуля до ста (for i:=0 to 100 do), потом проверяем уровень энергии игрока под номером i (if geroys[i].power>0 then), и если у игрока под номером i энергия положительна, то мы выводим его на экран (putsprite(geroys[i].x,geroys[i].y,kartinka)).

Перемещения всех игроков в уровне осуществляется предельно просто: для каждого игрока у нас есть состояние его виртуальных клавиш (up,down,left,right,fire). Вы делате игру так, что у каждого персонажа игры как бы есть своя клавиатура:

for i:=0 to 100 do if geroys[i].power>0 then
begin
if geroys[i].up=true then geroys[i].y:=geroys[i].y+1;
if geroys[i].down=true then geroys[i].y:=geroys[i].y-1;
if geroys[i].left=true then geroys[i].x:=geroys[i].x+1;
if geroys[i].right=true then geroys[i].x:=geroys[i].x-1;
if geroys[i].fire=true then strelba(georys[i]);
end;

Движение игроков по уровню и их действия полностью определяется тем, какие клавиши у них нажаты. Мы делаем следующее: для всех героев уровня (for i:=0 to 100 do) проверяем их энергию (if geroys[i].power>0 then), и если она положительна, то начинаем проверку виртуальных клавиатур. Более продвинутая реализация движения игрока, как в настоящих играх, описана в статье pulki. Виртуальная клавиатура игрока под номером i определяется набором переменных:

geroys[i].up
geroys[i].down
geroys[i].left
geroys[i].right
geroys[i].fire

У каждого героя игры есть своя личная виртуальная клавиатура, в данном случае из пяти клавишь: geroys[i].up - кнопка "вверх", geroys[i].down - кнопка "вниз", geroys[i].left - кнопка "влево", geroys[i].right - "вправо", geroys[i].fire - кнопка "стрелять". Если какая-нибудь из этих переменных равна TRUE, то мы делаем соответствующее действие (меняем координаты игрока, вызываем процедуру стрельбы). Неплохое объяснение работы с виртуальной клавиатурой описано в статье brodilki.

Для каждой пули вы создаёте тип:

type tPulya = record
x,y:single; // координаты
letit:boolean; // состояние (летит или нет?)
lifetime:integer; // как давно летит
end;

И храните все пули в одном массиве (puli:array[0..1000] of tPulya). Поэтому реализация попадания пули в игрока предельна проста. Достаточно проверить столкновение всех летящих пуль со всеми героями игры. Для этого достаточно перебрать все летящие пули (letit=true) со всеми игроками с положительной энергией (power>0):

for i:=0 to 100 do
for j:=0 to 1000 do
if (geroys[i].power>0) and (puli[j].letit=true) // если игрок под номером i живой, а пуля под номером j летит
begin

a:=geroys[i].x-puli[j].x;
b:=geroys[i].y-puli[j].y;
rasst:=sqrt(a*a+b*b); // определяем расстояние между гроком под номером i и пулей под номером j
if rasst<10 then // если расстояние между пулей и игроком меньше 10 пикселей, то

begin
puli[j].letit:=false; // пуля под номером i больше не летит
geroys[i].power:=geroys[i].power-1; // уменьшаем энергию игрока под номером j
end;

end;

О том, как сделать много летающих пулек одновременно, вы можете узнать из статьи pulki.

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

Итак, у нас есть игроки (geroys:array[0..100] of tGeroy). И у каждого игрока есть своя виртуальная клавиатура из пяти клавишь (up,down,left,right,fire). Рассмотрим реализацию искуственного интеллекта "все сошли сума". Игроки в этом случае будут беспорядочно нажимать на свои кнопки:

for i:=0 to 100 do
begin

if (random(14)<7) then geroys[i].up:=true else geroys[i].up:=false;
if (random(14)<7) then geroys[i].down:=true else geroys[i].down:=false;
if (random(14)<7) then geroys[i].left:=true else geroys[i].left:=false;
if (random(14)<7) then geroys[i].right:=true else geroys[i].right:=false;
if (random(14)<7) then geroys[i].fire:=true else geroys[i].fire:=false;
end;

Как вы понимаете, это уж совсем бредовый искуственный интеллект. Герои игры будут беспорядочно дрыгаться, случайным образом выпуская пульки. Теперь попробуем сделать вот так:

for i:=0 to 100 do
begin

geroys[i].up:=true; // нажата клавиша "вверх"
geroys[i].down:=false;
geroys[i].left:=false;
geroys[i].right:=false;
geroys[i].fire:=false;
end;

В этом случае все игроки в уровне пойдут вверх, так как мы на их виртуальных клавиатурах сделали кнопке UP значение TRUE. Пусть все игроки идут вверх, а один из них будет подчиняться вашим командам. Для этого мы заменим for i:=0 to 100 do на for i:=1 to 100 do (ноль на единицу). А нулевым игроком будете управлять вы:

if key[VK_UP]=true then geroys[0].up:=true else geroys[0].up:=false;
if key[VK_DOWN]=true then geroys[0].down:=true else geroys[0].down:=false;
if key[VK_LEFT]=true then geroys[0].left:=true else geroys[0].left:=false;
if key[VK_RIGHT]=true then geroys[0].right:=true else geroys[0].right:=false;
if key[VK_SPACE]=true then geroys[0].fire:=true else geroys[0].fire:=false;

for i:=1 to 100 do
begin

geroys[i].up:=true; // нажата клавиша "вверх"
geroys[i].down:=false;
geroys[i].left:=false;
geroys[i].right:=false;
geroys[i].fire:=false;
end;

То есть мы взяли состояние реальной клавиатуры вашего компьютера (key[...]) и занесли эти данные в виртуальную клавиатуру нулевого игрока (geroys[0].up, geroys[0].down, geroys[0].left, geroys[0].right, geroys[0].fire). Обратите внимание, что кнопки "fire" на вашей клавиатуре нет. Поэтому для стрельбы мы взяли кнопку SPACE. Но можно было взять и любую другую кнопку, например ENTER (key[VK_ENTER]).

А теперь я вам покажу идею того, как просто сделать крутой искуственный интеллект. Смотрите: всё очень просто. Что делают игроки? Они бродят по уровню. А если они замечают врага, то начинают стрелять.Чтобы игроки бродили по уровню вам достаточно менять состояние кнопок (geroys[i].up, geroys[i].down, geroys[i].left, geroys[i].right). А для стрельбы - нажать space (geroys[i].fire).

Уже сейчас вы без проблем сделаете искуственный интеллект. Для этого достаточно сделать перебор в цикле между парами всех игроков, проверяя угол между двумя векторами. Первый вектор - это вектор взгляда игрока. Второй вектор - это нормализованный вектор расстояния между игроками. Если угол находится в пределах от -30 до +30 градусов, то вы просто делаете игроку geroys[i].fire:=true, а если нет - geroys[i].fire:=false.

Блуждание по уровню тоже делается достаточно просто: например, вы можете по таймеру или по проверке столкновений сменять нажатие кнопок движения (geroys[i].up, geroys[i].down, geroys[i].left, geroys[i].right). Причём используйте значения нажатых клавиш для анализа: например, если geroys[i].up=true и вы определили столкновени со стеной, то делайте geroys[i].up=false, geroys[i].down=true, geroys[i].left=true в течении, к примеру, 3 секунд.

Как видите, для создания искуственного интеллекта удобно вводить текущее время, в течении которого будут нажаты определённые клавиши. Для этого удобно использовать "мысли". О том, как сделать игрокам мысли и интерпретатор мыслей, а также более детальное объяснение идеи искуственного интеллекта дано в статье strategy. Также есть подробные комментарии о создании искуственного интеллекта в статье comments.