|
Как
сделать 2d игру: с чего начать, повороты и перемещения игрока, а также
различные советы. |
Георгий Мошкин
tmtlib@narod.ru
Файлы к статье:
pulki.zip (10kb) - движение игрока и летающие пульки.
WAREXE.RAR - 188 kb - реализация описанного
здесь искуственного интеллекта (EXE и исходники на Delphi).
WARCRAFT.ZIP - 25kb - только исходники
(без EXE)
Такой подход:
- сначала пишешь программу для вывода точки с координатой (x,y) на экран
- потом делаешь так, чтобы (x,y) можно было менять с клавиатуры
- потом пробуешь двигать этой точкой по формулам.
Например, смещение вправо:
x:=x+1;
draw(x,y);
|
Или движение по кругу:
t:=t+1;
x:=10*sin(t);
y:=10*cos(t);
draw(x,y);
|
- потом вместо точки выводишь спрайт
- потом пытаешься добавить if-ы
Например, движение влево-вправо с отталкиванием от краёв экрана:
x:=x+dx
if x>1024 then dx:=-1;
if x<0 then dx:=+1;
draw(x,y)
|
- потом учитываешь скорость работы компьютера
Например, для движения вправо будет
speed:=10*vremyaotrisovkikadra;
x:=x+speed;
draw(x,y);
|
- потом делаешь движение спрайта по экрану
с помощью клавиатуры, и прописываешь if-ами края экрана
- потом пробуешь добавить мышку, при клике
запоминаешь координаты "куда идти"
if MouseLeftButtonClick=true then
begin
kuda_x:=mouse.x;
kuda_y:=mouse.y;
end;
|
и двигаешь туда свой спрайт по какому-нибудь алгоритму. Например так:
if (x-kudda_x)>0 then x:=x-speed else x:=x+speed;
if (y-kudda_y)>0 then y:=y-speed else y:=y+speed;
|
- потом, если игра "вид сбоку", пробуешь
делать прыжки и "гравитацию"
Если стоит на земле, то при нажатии кнопки вверх - прыгать:
if ((KeyboardUP) and (y=0)) then y:=10;
if y>0 then y:=y-speed;
|
- потом вместо примитивного управления делаешь
более "продвинутое":
Для игры "вид сверху" управление идёт НЕ КООРДИНАТАМИ x,y, а скоростью SPEED и
углом поворота Phi.
Например, если нажата кнопка вперёд,
то делаешь SPEED:=10*vremyaotrisovkikadra;
Если назад: SPEED:=-10*vremyaotrisovkikadra;
Если ничего не нажато, то SPEED:=0;
Влево/вправо: меняешь Phi:
If KeyboardLeft then Phi:=Phi-5*vremyaotrisovkikadra;
If KeyboardRight then Phi:=Phi+5*vremyaotrisovkikadra;
Координаты тогда меняются по sin/cos:
x:=x+speed*sin(Phi));
y:=y+speed*cos(Phi));
Т.е. если speed=0 то спрайт останется на месте.
DrawSprite(x,y);
|
- потом начинаешь задавать типы и массивы.
Создаёшь тип живого существа и масссив
переменных этого типа (много существ).
- потом создаёшь массив летящих пуль/стрел/ракет
в уровне
Tpulya=record
x,y:single;
phi:single;
tippuli:integer;
lifetime:integer;
end;
puli:array[0..1000] of Tpulya;
Если tippuli = 0 - элемент массива свободен
Если tippuli > 0 - то это пуля с разрушительной силой, соответствующей индексу
После выстрела:
- ищешь свободный элемент массива (где tippuli=0);
- загоняешь в этот элемент данные (координату откуда вылетает (x,y) и угол под
которым она выпущена (phi)).
- ставишь этой пуле какой-нибудь тип в соответствии с оружием, из которого
вылетела пуля (tippuli:=...);
- ставишь этой пуле время жизни (например, lifetime=10 секунд).
В игре меняешь координаты пули также, как и у игроков (см. выше). Каждый кадр
уменьшаешь время жизни пули для всех пуль в массиве:
for i:=0 to 1000 do
if puli[i].tippuli>0 then
begin
// МЕНЯЕМ КООРДИНАТЫ ПУЛИ
puli[i].x:=puli[i].x+10*sin(puli[i].phi);
puli[i].y:=puli[i].y+10*cos(puli[i].phi);
// ВЫРУБАЕМ ПУЛЮ, ЕСЛИ СЛИШКОМ ДОЛГО ЛЕТИТ:
puli[i].lifetime:=puli[i].lifetime - vremyaotrisovkikadra;
if puli[i].lifetime<0 then puli[i].tippuli=0;
end;
|
- в этом же цикле с пулями можешь проверять
на столкновение с игроками. Если
происходит столкновение с игроком, то можно отнять у игрока часть его
"энергии"
power:=power-1 и ДЕЗАКТИВИРОВАТЬ ПУЛЮ: puli[i].tippuli=0;
- создаёшь формат уровня на своё усмотрение.
Или какую-нибудь "сетку" (двухмерный
массив). Или одномерный массив, в котором задаются координаты и тип объектов
(например, 157 элемент такого массива говорит нам, что это стена с координатой
(x,y)
=1414.44,776.15)
ДАЛЬШЕ
- создаёшь сначала простые взаимодействия
массива игроков с массивом уровня. Просто для начала можно хранить старые
координаты всех игроков. Например, для главного героя:
1. Сохраняешь координаты игрока old.x:=x; old.y:=y;
2. Перемещаешь игрока по клавиатуре, мышке или по AI (меняешь x,y).
3. Проверяешь координаты игрока x,y на совпадение со стенами и любыми преградами.
4. Если есть совпадение (точка x,y попала "в стену"), то восстанавливаешь
старые значения:
x:=old.x;
y:=old.y;
|
- только что я описал метод, при котором
игрок не может скользить по стенам, а только застревает в них. Чтобы выйти
из состояния застревания придётся развернуться задом к стене и отойти
от неё. Игрока будет "цеплять" за стены.
- ищешь другие алгоритмы - выбираешь какая
проверка столкновений тебе больше нравится
- если делаешь стратегию, то дополняешь запись
данных игрока данными "свой-чужой":
tigrok=record
ai:integer; // 0 - управляется с клавиатуры/мышки, 1,2,3,4 - управляется компом по
алгоритму AI-1, AI-2, AI-3,... (1-мышь, 2-овца, 3-крокодил, 4-робот, 5-вертолёт и т.д.).
color:integer // ЦВЕТ (на самом деле и есть данные "свой-чужой"
end;
|
- продолжаю про стратегию: делаешь массив
из игроков. Допустим будет три рассы (люди,
орки и нло).
igroki:array[0..300] of TIgrok;
Треть игроков делаешь ( 0-100) color:=1;
Вторую треть (100-200) - color:=2;
А третью (200-300) - color:=3;
В алгоритме AI и т.п. делаешь проверку: Если игрок видет игрока с другим цветом,
то AI переходит в режим "атаки".
|
- режим атаки, и как сделать кто за кем гоняется.
tigrok=record
ai:integer;
color:integer;
x,y,phi:single;
power:integer;
ВЫШЕ ВСЁ ПОНЯТНО, ТЕПЕРЬ НОВОЕ:
zakemhodit:integer;
kogoatakovat:integer;
end;
То есть если ты с клавиатуры нажал мышкой атаку над монстром igrok[123],
то делаешь у своего игрока kogoatakovat:=123;
Вообщем, если ты мышкой выбрал своего игрока под номером,
допустим, 555, то делаешь так:
igrok[555].kogoatakovat:=123;
|
- Откуда взялись числа 555 и 123? Это просто.
Ты просто сделаешь алгоритм выбора мышкой. Допустим, у тебя на экране
есть спрайты. И есть курсор мышки. Нужно сделать процедуру, которая при
нажатии мышкой проверяет КТО СИДИТ ПОД МЫШКОЙ! Если под мышкой кто-то
есть, то ты проверяешь его номер (например, 555). И задаёш SeychasUpravlyaem:=555;
igrok[SeychasUpravlyaem].kogoatakovat:=PoluchitNomerIgrokaPodMishkoy(x,y);
а смысл будет прежним:
igrok[555].kogoatakovat:=123;
|
- Потом делаешь AI, который проверяет параметры
всех, кто вокруг него. Если вокруг слишком много ВРАГОВ (враги - это другой
цвет). То убегаешь (AI убегает).
- Чтобы в стратегии могли ходить друг за
другом и группами ты одного выбираешь главным и его управление переключается
с AI на клавиатуру. Хотя может быть и комбинированно (управляешь с клавиатуры,
но если наткнёшься на врага - то автаматически врубать режим атаки).
tigrok=record
ai:integer;
color:integer;
x,y,phi:single;
power:integer;
zakemhodit:integer; - ВОТ ЭТО ЗА КЕМ ХОДИТЬ
kogoatakovat:integer;
end;
|
- Опять же, если стратегия, можешь сделать
подражание действиям главного. Например, если у десятерых игроков zakemhodit:=15,
то они все будут брать себе kogoatakovat от 15-го игрока.
- Как только сделан формат уровней, сразу
же нужно писать УДОБНЫЙ РЕДАКТОР УРОВНЕЙ. Простой удобный редактор уровней
- это главное. То есть хороший формат (типы, массивы) и хороший к ним
редактор. И вообще разные утилиты для редактирования игры.
- Как только хорошо получилось делать один
уровень. Редактировать его, загружать, играть в нём. Тогда уже делаешь
переходы между уровнями.
- Делаешь всё просто. Не стоит изумляться
чужим творениям и исходникам. Порою за красивой графикой скрывается ужасающе
кошмарный исходник. Глюки в своих программах замечаешь лучше, чем в новом
чужом исходнике. Новый чужой исходних ощущаешь как "дар от внеземных цивилизаций",
хотя на самом деле это не так!
- Лучший способ с чужими исходниками - это
прочистить их как следует. Если есть несколько версий исходников, стоит
особое внимание обратить на первые версии (ранние версии). Обычно с ростом
версии маразм крепчает, исходники обрастают бредовыми навесками и приходят
в негодность.
ВСЁ =)
|
|