Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум «Всё о Паскале» _ Написание игр _ ТАНКИ

Автор: blackhard 15.02.2008 4:08

хочу написать простую игру (дано допустим 2 танка 1 управляется пользователем а 2 компьютером ) в ходе написания возник ряд вопросов 1) как сделать чтобы одновременно выполнялось несколько действий допустим я стреляю и пока летит снаряд я хочу переместить свой танк а враг может попытаться увернутся от снаряда.на данном этапе написания когда я стреляю я не могу переместить танк пока не далетит снаряд.2)как установить границы экрана чтобы танк не заезжал за границы и вообще как разграничить экран я пробовал спомощью setviewport но чето ничего не получилось.

вот то что я уже написал набрОсал танки 1им из них можно управлять стрелками и стрелять на пробел выход на esc.танки я нарисовал линиями чтоб легче было работать с координатами

program igra;
uses graph,crt;
var
ch:char;
tx,ty,tx2,ty2:integer;
d,m,i,x,y,k:integer;
procedure vistrel;
var
vx,vy,i,k:integer;
begin
vx:=tx;
vy:=ty;
for i:=1 to 640-(vx+60) do begin
setcolor(15);
circle(vx+64+i,vy+23,3);
setcolor(0);
circle(vx+64+i-1,vy+23,3);
delay(200);
if (vy+23>=ty2) and (vy+23<=ty+48) then
circle(213,120,2);
end;
setcolor(15);
end;
begin
d:=detect;
initgraph(d,m,'e:\tp7.1\bgi');
tx:=1;
ty:=120;
tx2:=610;
ty2:=120;
{kab}
repeat
{\\\\\\\\\\\\\\\\\tank22\\\\\\\\\\\\\\\\\\\\\ }
{kab}
line(tx2,ty2,tx2+23,ty2);
line(tx2+23,ty2,tx2+23,ty2+48);
line(tx2,ty2+48,tx2+23,ty2+48);
line(tx2,ty2,tx2,ty2+48);
arc(tx2+11,ty2+6,23,154,13);
arc(tx2+11,ty2+42,206,337,13);
{pil}
line(tx2+10,ty2+9,tx2+10,ty2+39);
line(tx2+17,ty2+9,tx2+10,ty2+9);
line(tx2+10,ty2+39,tx2+17,ty2+39);
{puh}
line(tx2,ty2+12,tx2-12,ty2+12);
line(tx2,ty2+36,tx2-12,ty2+36);
line(tx2-12,ty2+12,tx2-12,ty2+36);
{dulo}
line(tx2-12,ty2+26,tx2-29,ty2+26);
line(tx2-29,ty2+20,tx2-29,ty2+28);
line(tx2-12,ty2+22,tx2-29,ty2+22);
{gluh}
line(tx2-29,ty2+20,tx2-36,ty2+20);
line(tx2-29,ty2+28,tx2-36,ty2+28);
line(tx2-36,ty2+20,tx2-36,ty2+28);
{\\\\\\\\\\\=tank\\\\\\\\\\\\\\\\}
line(tx,ty,tx+23,ty);
line(tx+23,ty,tx+23,ty+48);
line(tx,ty+48,tx+23,ty+48);
line(tx,ty,tx,ty+48);
arc(tx+11,ty+6,23,154,13);
arc(tx+11,ty+42,206,337,13);
{pil}
line(tx+17,ty+9,tx+17,ty+39);
line(tx+10,ty+9,tx+17,ty+9);
line(tx+10,ty+39,tx+17,ty+39);
{puh}
line(tx+23,ty+12,tx+35,ty+12);
line(tx+23,ty+36,tx+35,ty+36);
line(tx+35,ty+12,tx+35,ty+36);
line(tx+35,ty+22,tx+53,ty+22);
{dulo}
line(tx+35,ty+26,tx+53,ty+26);
line(tx+53,ty+20,tx+53,ty+28);
{gluh}
line(tx+53,ty+20,tx+60,ty+20);
line(tx+53,ty+28,tx+60,ty+28);
line(tx+60,ty+20,tx+60,ty+28);
ch:=readkey;
case ch of
#72:ty:=ty-5;
#75:tx:=tx-5;
#77:tx:=tx+5;
#80:ty:=ty+5;
#32:vistrel;
#27:halt;
end;{case}
cleardevice;
until ch=#27;
readln;
closegraph;
end.
объяснити хоть на словах как сделать то о чем я написал.спасибо!

Автор: spill 15.02.2008 18:12

Игры так не пишут.
В игре должен быть ОДИН цикл. В нем ты, например, если нажат пробел, устанавливаеш флаг, например fVystrel. А потом, в том же цикле смотриш, если флаг возведен, то пересчитываеш координаты выстрела. Когда попадет в цель или выйдет за пределы экрана, сбрасываеш флаг.

Автор: andriano 15.02.2008 23:12

Ты бы хоть, прежде чем писать, почитал темы, находящиеся рядом. На многие твои вопросы там уже есть ответы.
Любая игра строится по единому шаблону: все действия выполняются в основном игровом цикле. Сам цикл может организовываться по-разному, скажем, в DOS и Windows, но сути это не меняет.
В цикле определяется состояние органов управления (нажата клавиша, передвинута мышь, отклонен джойстик...), текущее время и на основании этого состояние системы изменяется по определенным формулам. Например, если скорость объекта (Vx,Vy) а координаты (X,Y), то через время dt, прошедшее с предыдущей отрисовки кадра, новые координаты станут (X+Vx*dt, Y+Vy*dt). При необходимости создаются новые объекты (пуля при выстреле, новый враг ...) и уничтожаются старые (сначала пуля при попадании, а затем и враг, в которого она попала).
Анализируется состояние каждого объекта (для обеспечения возможности перебора ведется список объектов). Когда посчитано новое состояние, оно отображается на экране.
Затем цикл повторяется.
Пример можно посмотреть несколькими темами ниже: "про кораблики".

Автор: blackhard 16.02.2008 0:01

Цитата(andriano @ 15.02.2008 19:12) *

Ты бы хоть, прежде чем писать, почитал темы, находящиеся рядом. На многие твои вопросы там уже есть ответы.
Любая игра строится по единому шаблону: все действия выполняются в основном игровом цикле. Сам цикл может организовываться по-разному, скажем, в DOS и Windows, но сути это не меняет.
В цикле определяется состояние органов управления (нажата клавиша, передвинута мышь, отклонен джойстик...), текущее время и на основании этого состояние системы изменяется по определенным формулам. Например, если скорость объекта (Vx,Vy) а координаты (X,Y), то через время dt, прошедшее с предыдущей отрисовки кадра, новые координаты станут (X+Vx*dt, Y+Vy*dt). При необходимости создаются новые объекты (пуля при выстреле, новый враг ...) и уничтожаются старые (сначала пуля при попадании, а затем и враг, в которого она попала).
Анализируется состояние каждого объекта (для обеспечения возможности перебора ведется список объектов). Когда посчитано новое состояние, оно отображается на экране.
Затем цикл повторяется.
Пример можно посмотреть несколькими темами ниже: "про кораблики".

спасибо за разъеснение,буду пробовать.

Автор: blackhard 19.02.2008 3:57

И опять мне нужна помощь. теперь проблема с ИИ ну то что я сделал нельзя конечно назвать ИИ smile.gif ну в общем у меня 2 объекта 1 можно управлять а 2 перемещается вдоль оси У я написал для этого вот такую процедуру

procedure move2;
var
d:integer;
begin
if t=0 then begin
d:=random(3);
t:=random(30);
end;
if (d=1) and (t<>0) then begin
dec(t);
ty2:=ty2-5;
circle(tx2,ty2,10);
setcolor(black);
circle(tx2,ty2+5,10);
end;
if (d=2) and (t<>0) then begin
dec(t);
ty2:=ty2+5;
circle(tx2,ty2,10);
setcolor(black);
circle(tx2,ty2-5,10);
end;
if (b=0) and (t<>0) then
begin
dec(t);
circle(tx2,ty2,10);
end;
if ty2=0 then ty2:=300;
setcolor(15);
end;
идея тут втом что есть 3 состояния движение вверх вниз и наместе состояние задается случайным образом как d:=random(3); а t:=random(30); задает сколько это перемещение будет длится. в теории вроде все хорошо токо на практике как всегда круг дальше нижней половины экрана не выходит и движется рывками nea.gif .
подскажите более удачьный алгоритм или помогите этот доработать.вот вся программа
program igra;
uses graph,crt;
var
ch:char;
b,tx2,ty2:integer;
d,m,t,x,y,k,q:integer;
procedure move1;
begin
if q=1 then begin
y:=y-5;
circle(x,y,10);
setcolor(black);
circle(x,y+5,10);
setcolor(15);
q:=0;
end;
if q=2 then begin
x:=x-5;
circle(x,y,10);
setcolor(black);
circle(x+5,y,10);
setcolor(15);
q:=0;
end;
if q=3 then begin
x:=x+5;
circle(x,y,10);
setcolor(black);
circle(x-5,y,10);
setcolor(15);
q:=0;
end;
if q=4 then begin
y:=y+5;
circle(x,y,10);
setcolor(black);
circle(x,y-5,10);
setcolor(15);
q:=0;
end;
end;
procedure move2;
var
i,d:integer;
begin
if t=0 then begin
d:=random(3);
t:=random(30);
end;
if (d=1) and (t<>0) then begin
dec(t);
ty2:=ty2-5;
circle(tx2,ty2,10);
setcolor(black);
circle(tx2,ty2+5,10);
end;
if (d=2) and (t<>0) then begin
dec(t);
ty2:=ty2+5;
circle(tx2,ty2,10);
setcolor(black);
circle(tx2,ty2-5,10);
end;
if (b=0) and (t<>0) then
begin
dec(t);
circle(tx2,ty2,10);
end;
if ty2=0 then ty2:=300;
setcolor(15);
end;
begin
d:=detect;
initgraph(d,m,'e:\tp7.1\bgi');
x:=30;
y:=120;
tx2:=300;
ty2:=320;
{kab}
t:=0;
circle(x,y,10);
repeat
if keypressed then
begin
ch:=readkey;
case ch of
#72:q:=1;
#75:q:=2;
#77:q:=3;
#80:Q:=4;
#27:halt;
end;{case}
end;
move1;
move2;
delay(5000);
until ch=#27;
readln;
closegraph;
end.

Автор: spill 19.02.2008 17:34

Вот твои ошибки:
1. Используй Randomize один раз в начале программы, или числа не будут случайными
2. Переменная D в процедуре MOVE1 - ЛОКАЛЬНАЯ! то есть при каждом вызове она создается заново и ее значение не определено. Сделай ее глобольной

Добавлено через 19 мин.
И вот еще что надо бы переделать. Анимация делается по-другому.
Алгоритм:
1. Пересчитать координаты
2. Нарисовать объект
3. Подождать
4. Стереть

У тебя должны быть такие процедуры:
1. Нарисовать объект в определенных координатах
Draw (X, Y).
Если хочешь, чтобы противники были разного цвета, или еще как различать, можешь передавать еще и цвет.
2. Стереть объект в определенных координатах
Cleare (X, Y)
3. Пересчитать координаты противника
MovePr
Тут, в зависимости от переменных T и D пересчитываешь координаты, но НЕ рисуешь.

И общий алгоритм:
1. Нарисовать оба танка
2. Цикл
2.1. Пересчитываешь координаты
2.1.1. Читаешь клавиатуру
2.1.2. Вызываешь MovePr
2.2. Рисуешь оба танка
2.3. Ждешь
2.4. Стираешь оба танка в текущих координатах
Такой алгоритм применяется почти во всех подобных программах

Автор: blackhard 20.02.2008 2:35

Цитата(spill @ 19.02.2008 13:34) *

Вот твои ошибки:
1. Используй Randomize один раз в начале программы, или числа не будут случайными
2. Переменная D в процедуре MOVE1 - ЛОКАЛЬНАЯ! то есть при каждом вызове она создается заново и ее значение не определено. Сделай ее глобольной

Добавлено через 19 мин.
И вот еще что надо бы переделать. Анимация делается по-другому.
Алгоритм:
1. Пересчитать координаты
2. Нарисовать объект
3. Подождать
4. Стереть

У тебя должны быть такие процедуры:
1. Нарисовать объект в определенных координатах
Draw (X, Y).
Если хочешь, чтобы противники были разного цвета, или еще как различать, можешь передавать еще и цвет.
2. Стереть объект в определенных координатах
Cleare (X, Y)
3. Пересчитать координаты противника
MovePr
Тут, в зависимости от переменных T и D пересчитываешь координаты, но НЕ рисуешь.

И общий алгоритм:
1. Нарисовать оба танка
2. Цикл
2.1. Пересчитываешь координаты
2.1.1. Читаешь клавиатуру
2.1.2. Вызываешь MovePr
2.2. Рисуешь оба танка
2.3. Ждешь
2.4. Стираешь оба танка в текущих координатах
Такой алгоритм применяется почти во всех подобных программах

спасибо большое за алгоритм smile.gif и зато что нашел ошибку good.gif

Автор: andriano 20.02.2008 13:16

Цитата(spill @ 19.02.2008 13:34) *

И вот еще что надо бы переделать. Анимация делается по-другому.
Алгоритм:
1. Пересчитать координаты
2. Нарисовать объект
3. Подождать
4. Стереть
...
Такой алгоритм применяется почти во всех подобных программах

Строго говоря, анимация делается чуть по-другому:
1. Пересчитать координаты
2. Сформировать картинку в буфере:
2.1. Нарисовать фон
2.2. Нарисовать по очереди от дальних к ближним все объекты
3. Подождать синхронизацию с обратным ходом луча
4. Вывести буфер на экран

Автор: spill 20.02.2008 16:03

Да пожалуйста, если что, обращайся еще.
Кстати, если делать вообще по науке, то нужно вот как:
Для каждого объекта кроме координат X и Y должна быть пара DX и DY, которой задается вектор перемещения объекта. Тогда при анализе клавы или генерации очередного хода противника изменяешь DX или DY (Если ход вверх, то DX = 0, DY = -5; Если вправо, то DX = 5, DY = 0 и т.д.). А потом пересчитываешь координаты X := X + DX; Y := Y + DY.
Это позволит сделать анализ границ. То есть, пересчитывать координаты нужно только в том случаи, если следующий ход попадает в границы экрана (псевдокод):

Код

If X + DX больше 0 и меньше 640
Then X := X + DX
If Y + DY больше 0 и меньше 480
Then Y := Y + DY

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

Автор: blackhard 20.02.2008 22:45

Цитата(spill @ 20.02.2008 12:03) *

Да пожалуйста, если что, обращайся еще.
Кстати, если делать вообще по науке, то нужно вот как:
Для каждого объекта кроме координат X и Y должна быть пара DX и DY, которой задается вектор перемещения объекта. Тогда при анализе клавы или генерации очередного хода противника изменяешь DX или DY (Если ход вверх, то DX = 0, DY = -5; Если вправо, то DX = 5, DY = 0 и т.д.). А потом пересчитываешь координаты X := X + DX; Y := Y + DY.
Это позволит сделать анализ границ. То есть, пересчитывать координаты нужно только в том случаи, если следующий ход попадает в границы экрана (псевдокод):
Код

If X + DX больше 0 и меньше 640
Then X := X + DX
If Y + DY больше 0 и меньше 480
Then Y := Y + DY

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

спасибо сделал таким способом с границами теперь никаких проблем good.gif и наконец надеюсь последний вопрос по поводу выстрела.тут я вижу 2 возможности я стреляю пуля летит и пока она не вылетит за экран или кудато не попадет я выстрелить не могу собственно сейчас у меня именно так , а я хотел бы сделать чтобы пока 1 пуля летит я перемещаю танк и стреляю еще раз(1 пуля все еще летит) и еще пусть не бесконечное число раз но и не 1. так вот в чем сложность сейчас для координат пули у меня 2 переменные vx,vy так получается что для хранения координат 2 пули которая выпущена до попадания 1 нужны другие переменные?или может тут както с массивом можно сделать? чето я с этим совсем запутался?

Автор: andriano 20.02.2008 23:31

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

Автор: blackhard 20.02.2008 23:40

Цитата(andriano @ 20.02.2008 19:31) *

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

спасибо буду пробовать good.gif

Автор: blackhard 23.03.2008 17:58

Я решил переделать игру.Теперь обьекты у меня это отдельные изображения которые сохраняются в памяти.И возник вопрос как при таком методе сделать анимацию?Я вот написал небольшую програмку где анимация делается так как в предыдущем варианте игры.Т.Е вначале перещитываются координаты потом рисуется изображение программа ждет и стирает это изображение.вот только тут изображение упорно не хочит стераться

 program igra;
uses graph,crt;
var
ch:char;
b,tx2,ty2:integer;
blank:pointer;
size:word;
d,m,t,x,y,k,q,v,vx,vy,av,i,i1,i2:integer;
{shute sistem from tank}
procedure pereshet1;
begin
if q=1 then
begin
y:=y-{5}8;
if (y=70) or (y<70) then y:=75;
q:=0;
end;
if q=2 then
begin
x:=x-{5}8;
if (x=9) or (x<9) then x:=12;
q:=0;
end;
if q=3 then
begin
x:=x+{5}8;
if (x=625-60) or (x>625-60) then x:=625-60;
q:=0;
end;
if q=4 then
begin
y:=y+{5}8;
if (y=460-46) or (y>460-46) then y:=460-46;
q:=0;
end;
end;
procedure move1(x,y,i:integer);
begin
putimage(x,y,blank^,0);
end;
procedure clr1(x,y:integer);
begin
if (q<>0) and (q<>5) then
begin
putimage(x,y,blank^,3);
end;
end;
begin
d:=detect;
initgraph(d,m,'e:\tp7.1\bgi');
x:=12;
y:=230;
tx2:=625;
ty2:=320;
vx:=x;
vy:=y;
{kab}
t:=0;
i:=0;
i1:=0;
i2:=0;
rectangle(12,230,12+23,230+48);
arc(12+11,230+6,23,154,13);
arc(12+11,230+42,206,337,13);
line(12+17,230+9,12+17,y+39);
line(12+10,230+9,12+17,230+9);
line(12+10,230+39,12+17,230+39);
rectangle(12+23,230+12,12+35,230+36);
rectangle(12+35,230+22,12+53,230+26);
rectangle(12+53,230+20,12+60,230+28);
setfillstyle(9,2);
floodfill(13,232,15);
size:=imagesize(11,230-8,73,278+8);
new(blank);
getmem(blank,size);
getimage(11,230-8,73,278+8,blank^);
cleardevice;
repeat
randomize;
pereshet1;
if keypressed then
begin
ch:=readkey;
case ch of
#72:q:=1;
#75:q:=2;
#77:q:=3;
#80:q:=4;
#27:halt;
end;
end;
move1(x,y,i);
delay(80);
clr1(x,y);
until ch=#27;
readln;
closegraph;
dispose(blank);
end.
единственный способ которым у меня получилось сделать анимацию это использовать cleardevice; но это выглядит жутко не красиво.помогите правильно сделать анимацию!

Автор: andriano 23.03.2008 21:11

Поясни, пожалуйста, как именно ты стираешь изображение?

Автор: blackhard 23.03.2008 21:28

Цитата(andriano @ 23.03.2008 17:11) *

Поясни, пожалуйста, как именно ты стираешь изображение?

putimage(x,y,blank^,3); вот так

Автор: andriano 23.03.2008 22:36

Это я вижу.
Но ты сам сказал, что это не работает. Значит, где-то есть ошибка. Вот чтобы ее найти и надо сформулировать, что именно ты делаешь, словами по-русски.

Автор: blackhard 23.03.2008 23:31

Цитата(andriano @ 23.03.2008 18:36) *

Это я вижу.
Но ты сам сказал, что это не работает. Значит, где-то есть ошибка. Вот чтобы ее найти и надо сформулировать, что именно ты делаешь, словами по-русски.

делаю следующее:для анимации у меня 3 процедуры 1)перещитывает координаты изображения 2)рисует это изображение в вычесленных в предыдущей функции координатах потом программа немного ждет и стерает изображение для этого есть 3я процедура.и все начинается сначала.вот в общем и все.

Автор: andriano 24.03.2008 3:01

Третий раз спрашиваю: как именно стираешь изображение?

Автор: blackhard 24.03.2008 3:16

Цитата(andriano @ 23.03.2008 23:01) *

Третий раз спрашиваю: как именно стираешь изображение?

ДА все я уже разобрался при рисованиинадо использовать 3им параметром putimage normal put а при стирании xorput а до этого я использовал andput.тольковот изображение дергается слегга при движении ну тоесть прорисовка видна можно както этого избежать?

Автор: andriano 25.03.2008 0:00

Дергается или мерцает?
Если дергается, что-то не в порядке с измерением времени или синхронизацией, а если мерцает - это в морг: надо отказываться от модуля graph.

Автор: blackhard 25.03.2008 0:36

Цитата(andriano @ 24.03.2008 20:00) *

Дергается или мерцает?
Если дергается, что-то не в порядке с измерением времени или синхронизацией, а если мерцает - это в морг: надо отказываться от модуля graph.

эх мерцает...

Автор: andriano 25.03.2008 0:49

Только что разместил ссылки на статьи в соответствующем разделе форума и обнаружил, что исходники оттуда опять пропали.
Буду разбираться.
А пока даю ссылку на тот же материал в другом месте:
http://pascal.sources.ru/articles/087.htm

Автор: blackhard 22.04.2008 17:57

Теперь я решил сделать чтобы у меня там солдатики бегали так вот как правильно сделать: нарисовать 1го сохранить это изображения а потом егоже и для всех остальных выводить на экран или для каждого солдата нужно создавать свое собственное изображение?

Автор: renesko1 22.04.2008 21:32

Попробуй сделать обьект солдат и метод paint
Создай список солдат и работай с ним .
Так удобней выходит.
(Если не лень конечно)

Автор: blackhard 5.05.2008 16:43

А можно както в подобной игре сделать нормальный звук?

Автор: andriano 5.05.2008 16:59

Игра - имеется в виду под DOS?

Автор: blackhard 5.05.2008 17:23

Цитата(andriano @ 5.05.2008 13:59) *

Игра - имеется в виду под DOS?

Ну да

Автор: andriano 5.05.2008 21:14

Пробежал глазами тему.
"Нормальный звук" сделать труднее, чем "нормальную графику".
Поскольку "нормальной графики" пока нет, то и за звук браться, думаю, не стоит.