Помощь - Поиск - Пользователи - Календарь
Полная версия: Все таже змейка
Форум «Всё о Паскале» > Pascal, Object Pascal > Написание игр
a100
Здравствуйте! Благодаря информации с вашего форума, получилось написать, так сказать. костяк программы) не просто списать, а понять что для чего, это получилось. Опыт программирования еще совсем маленький.
Вот мой код:

Program Snake;
uses crt;
const
xn=1; {предел экрана слева}
xx=80; {предел экрана справа}
yn=1; {верхний предел экрана}
yx=25; {нижний предел экрана}
H='0'; {голова змеи}
dt=400; {задержка}

var
x:integer=xx div 2; {начальное расположение змеи}
y:integer=yx div 2;
vx:integer=-1; {начальное направление змеи}
vy:integer=0;
xe:integer=15; {начальные координаты яблока}
ye:integer=15;
var
c:char;


begin
randomize;
clrscr;
gotoxy(xe,ye); {рисуем первое яблоко}
write ('$');

while (x>=xn) and (x<=xx) and (y>=yn) and (y<=yx) do {обозначаем границы экрана}
begin
GoToXY(x,y); {рисуем новое положение символа}
write(H);
Delay(dt); {задержка, иначе символ будет бегать быстро}
if keypressed then {если нажата клавиша читаем ее}
begin
c:=readkey;
case c of {если это был управляющий символ, изменяем движение}
'w':begin vx:=0; vy:=-1 end; {изменяем движение на движение вверх}
's':begin vx:=0; vy:=1 end; {изменяем движение на движение вниз}
'a':begin vx:=-1; vy:=0 end; {изменяем движение на движение влево}
'd':begin vx:=1; vy:=0 end; {изменяем движение на движение вправо}
end;
end;
gotoxy(x,y);
write(' ');
inc(x,vx); {вычисляем новое положение змейки}
inc(y,vy);
if (x=xe) and (y=ye) then {если координаты змеи совпадают с координатами яблока}
begin
xe:=random(75); {рисуем новое яблоко, случайным образом}
ye:=random(20);
gotoXY(xe,ye);
write('$');
end;
end;
end.



пока не хватает знаний, чтоб сделать хвост змее, который растет, когда змея съедает яблоко...

надеюсь на вашу помощь
Lapp
Цитата(a100 @ 15.12.2010 12:45) *
надеюсь на вашу помощь
Самый лучший вариант - завести двумерный массив из байтов по числу клеток игрового поля
  b: array [xn..xx,yn..yx] of byte;

В нем рисуй тело от хвоста до головы. Вот такие обозначения:
0 - пустая клетка
1 - тело идет вверх
2 - тело идет вправо
3 - тело идет вниз
4 - тело идет влево
5 - голова (тело закончилось
6 - кролик
7 - мангуста
8 - препятствие
....

Вот тебе пример такого поля и змеи на нем:
0000000000
0002222300
0001000300
0021000500
0010000000
0014440000
0000000000

При этом храни в двух парах переменных текущие координаты головы и хвоста. Так ты сможешь "двигать змею". Если змея в этот момент движется вправо, то следующий кадр будет такой:
0000000000
0002222300
0001000300
0021000250
0010000000
0014400000
0000000000

Подумай над этим как следует. Если будут вопросы - задавай. Меня не будет до ночи, но кто-то еще может подсказать..
TarasBer
Цитата(Lapp @ 15.12.2010 13:37) *

  b: array [xn..xx,yn..yx] of byte;

В нем рисуй тело от хвоста до головы. Вот такие обозначения:
0 - пустая клетка
1 - тело идет вверх
2 - тело идет вправо
3 - тело идет вниз
4 - тело идет влево
5 - голова (тело закончилось
6 - кролик
7 - мангуста
8 - препятствие


Фу, это же магические числа.
Я предпочитаю делать так:


type
TField = (fEmpty, fUp, fRight, fDown, fLeft, fHead, fFood, fEnemy, fBorder);

var
b: array [xn..xx,yn..yx] of TField;


Lapp
Цитата(TarasBer @ 15.12.2010 14:30) *
Фу, это же магические числа.
Я предпочитаю делать так:


type
TField = (fEmpty, fUp, fRight, fDown, fLeft, fHead, fFood, fEnemy, fBorder);

var
b: array [xn..xx,yn..yx] of TField;


yes2.gif Одобрямс! good.gif
Только тогда с отладкой и промежуточными печатями могут быть проблемы.. Не совсем проблемы, просто дополнительная писанина + значения могут случайно съехать..
Но это все мелочи. Правильно, нужно именно так делать.
TarasBer
Как раз с отладкой проблем меньше, потому что когда видишь в отладчике число 3, то долго думаешь, что бы оно значило, а когда видишь fDown, то всё понятно.
Что касается печати, то тут да, язык в данной реализации не содержит модные фичи (рефлексия, или как её), позволяющие без ретипизации написать WriteLn(f[i, j]) так, что выведется "fDown".
Lapp
Цитата(TarasBer @ 15.12.2010 14:37) *
Что касается печати, то тут да, язык в данной реализации не содержит модные фичи (рефлексия, или как её), позволяющие без ретипизации написать WriteLn(f[i, j]) так, что выведется "fDown".
Да даже если выведется Up или Down - как тогда будет выглядет карта типа той, что я выше привел? )) Так что все равно нужно вывод организовывать с фильтром.
a100
Цитата(Lapp @ 15.12.2010 13:37) *

Самый лучший вариант - завести двумерный массив из байтов по числу клеток игрового поля
  b: array [xn..xx,yn..yx] of byte;

В нем рисуй тело от хвоста до головы. Вот такие обозначения:
0 - пустая клетка
1 - тело идет вверх
2 - тело идет вправо
3 - тело идет вниз
4 - тело идет влево
5 - голова (тело закончилось
6 - кролик
7 - мангуста
8 - препятствие
....

Вот тебе пример такого поля и змеи на нем:
0000000000
0002222300
0001000300
0021000500
0010000000
0014440000
0000000000

При этом храни в двух парах переменных текущие координаты головы и хвоста. Так ты сможешь "двигать змею". Если змея в этот момент движется вправо, то следующий кадр будет такой:
0000000000
0002222300
0001000300
0021000250
0010000000
0014400000
0000000000

Подумай над этим как следует. Если будут вопросы - задавай. Меня не будет до ночи, но кто-то еще может подсказать..


получается, сначала надо заполнить массив нулями, а потом в ячейки добавить значения? чтот пока не доходит
Lapp
Цитата(a100 @ 15.12.2010 19:54) *
получается, сначала надо заполнить массив нулями, а потом в ячейки добавить значения? чтот пока не доходит
Заполнить нулями, начальным телом змеи и поставить кролика.
Вот, смотри. Тут практически все готово кроме вывода. То есть вывод самый примитивный. Нужно добавить визуализацию на основе либо CRT, либо графики. Когда разберешься с основой, можно будет этим заняться.
uses
CRT;

const
MaxSize= 100; // m and n not to exceed this number
StartLen= 5; // start length of the snake
LenInc= 2; // length increase when rabbit eaten
MaxSizeX= MaxSize;
MaxSizeY= MaxSize;

// cell legend:
Clear= 0; Cl=Clear;
Up= 1;
Right= 2; Rt=Right;
Down= 3; Dn=Down;
Left= 4; Lt=Left;
Head= 5; He=Head;
Rabbit= 6; Ra=Rabbit;
Wall= 7; Wa=Wall;
Hole= 8; Ho=Hole;
Mongoose= 9; Mo=Mongoose;
// representatin on prints
CellPrint: string= ' ^>v<0RWOM..........';
// 01234567890

// keyboard
PreKey= #0;
UpKey= #72;
LtKey= #75;
RtKey= #77;
DnKey= #80;
EscKey= #27;



type
tCell= byte;
tBoard= array [0..MaxSizeY,0..MaxSizeX] of tCell;

var
b: tBoard;
i,j,x,y,mx,my,Len,dLen,Hx,Hy,Tx,Ty,Rx,Ry: integer;
Crash: boolean;

procedure PrintBoard;
begin
WriteLn('Len=',Len,' x=',Hx,' y=',Hy,' dLen=',dLen);
for j:=0 to my+1 do begin
for i:=0 to mx+1 do Write(CellPrint[b[j,i]+1]);
WriteLn
end
end;

var
c: char;
d: byte;
dx,dy: integer;

begin
// board preparation
mx:= 30;
my:= 15;
for j:=0 to my+1 do for i:=0 to mx+1 do
if (i=0)or(j=0)or(i>mx)or(j>my)then b[j,i]:=Wall else b[j,i]:=Clear;

// filling in inicial data
Len:= StartLen;
dLen:= 0;
Hx:= mx div 2+1;
Hy:= my div 2+1;
Tx:= Hx-Len;
Ty:= Hy;
Rx:= mx*3 div 4;
Ry:= Hy;
b[Hy,Hx]:= Head;
for i:=0 to Len-1 do b[Ty,Tx+i]:= Right;
b[Ry,Rx]:= Rabbit;

Crash:=false;
repeat
PrintBoard;
dx:=0;
dy:=0;
repeat
c:= ReadKey;
if c=PreKey then begin
c:=ReadKey;
case c of
UpKey: begin dy:=-1; d:=Up end;
RtKey: begin dx:= 1; d:=Rt end;
DnKey: begin dy:= 1; d:=Dn end;
LtKey: begin dx:=-1; d:=Lt end;
end;
c:=PreKey
end
until (c=EscKey) or (dx+dy<>0);
x:=Hx+dx;
y:=Hy+dy;
WriteLn(x,' ',y);
case b[y,x] of
// rabbit
Rabbit: begin
dLen:=dLen+LenInc;
repeat
Rx:=Random(mx)+1;
Ry:=Random(my)+1
until b[Ry,Rx]=Clear;
b[Ry,Rx]:=Rabbit
end;
// body or wall
Up,Rt,Dn,Lt,Wa: begin
Crash:=true;
WriteLn('Crash!!')
end
end;
// moving the snake
if not Crash then begin
b[Hy,Hx]:=d;
Hx:=x;
Hy:=y;
b[y,x]:=He;
if dLen=0 then begin
dx:=0;
dy:=0;
case b[Ty,Tx] of
Up: dy:=-1;
Rt: dx:= 1;
Dn: dy:= 1;
Lt: dx:=-1;
end;
b[Ty,Tx]:=Clear;
Tx:=Tx+dx;
Ty:=Ty+dy
end
else begin
Dec(dLen);
Inc(Len)
end;
end
until (c=EscKey) or Crash;
end.

a100
спаааааасибо! буду разбираться
a100
в принципе более менее разобрался)
но есть куча вопросов%)
Подскажите пожалуйста...

procedure PrintBoard;
begin
WriteLn('Len=',Len,' x=',Hx,' y=',Hy,' dLen=',dLen);
for j:=0 to my+1 do
begin
for i:=0 to mx+1 do
Write(CellPrint[b[j,i]+1]);
WriteLn
end
end;



Вот это место, Write(CellPrint[b[j,i]+1]), что оно выводит на экран, что значит?

Потом, в каком месте в коде, написано, что когда змейка идет вверх, рисовать ^ вниз V вправо > влево < и т.д.?

И по периметру стенка обозначается буквой W?

Спасибо за внимание


TarasBer
> Вот это место, Write(CellPrint[b[j,i]+1]), что оно выводит на экран, что значит?

> Потом, в каком месте в коде, написано, что когда змейка идет вверх, рисовать ^ вниз V вправо > влево < и т.д.?

Вот в нём и написано.
Посмотри описание строки CellPrint - в ней находятся все нужные символы. То есть для вывода нужного символа достаточно просто обратиться к нужному элементу строки. Например, CellPrint[1] - это первый символ строки CellPrint, CellPrint[i] - это i-ый символ этой строки итд.
Задание таких вещей в константный массив избавляет программиста от написания большого числа однообразных ветвлений и повторяющегося кода, а значит, и от попадания на ГК.
Lapp
Спасибо, Тарас, +1 (P.S. - сделаю завтра, на сегодня лимит исчерпал..)

Цитата(a100 @ 21.12.2010 11:50) *
Потом, в каком месте в коде, написано, что когда змейка идет вверх, рисовать ^ вниз V вправо > влево < и т.д.?
Обрати внимание на эти две строчки:
  CellPrint: string= ' ^>v<0RWOM..........';
// 01234567890
Комментарий внизу точно позиционирован, соотнеси цифры со строкой выше. Сам по себе комментарий, конечно, ни на что не влияет, но поможет разобраться.

Цитата
И по периметру стенка обозначается буквой W?
Да. Это та же самая стенка, которую можно при желании поставить и в поле (она обозначается числом 7). Установка такой стенки по краю избавляет от необходимости делать дополнительную проверку для выхода змеи за край поля.
a100
Друзья, огромное Вам спасибо за помощь!

попробуюс)
a100
не получается сделать, чтоб змейка постоянно была в движении((
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.