У меня есть некоторая домашняя работа для моей школы, и я должен сделать игру змеи, как Nokia, в Delphi. Интересно, какое решение является лучшим. Я хочу свою змею быть классом, и тело является массивом точек (родительский класс) или связанный список точек. Что является лучшим? Массив или связанный список?
Скомпонованный список лучше. (Каждый узел может указывать на предыдущий и следующий) Проще добавить узлы в конец связанного списка.
Если вы используете массив, вам нужно либо изменить его размер, либо инициализировать его до Максимально возможной длины змейки, для начала с которой можно расточительно расходовать память.
UPDATE Эта статья рассказывает об указателях в Delph и даже предлагает простое определение узла delphi article
В Delphi я бы использовал TQueue, который определяется в модуле Contnrs. Вы можете «протолкнуть» новую координату в нее (змеиная голова), и когда ваш максимальный размер змеи будет достигнут, вам просто нужно вызвать «pop», чтобы освободить змеиный хвост.
lp := new(PPoint);
lp^.X := x;
lp^.X := y;
Body.Push(lp);
if Body.count > iSnakeLength then
Dispose(Body.Pop); // Free the last TCoord that is pop'ed.
Затем все, что вам нужно сделать, это нарисовать что в этом TObjectQueue. Чтобы получить доступ к списку TQueue, вы должны открыть список свойств ... Для этого просто определите свой класс тела змеи следующим образом:
TSnakeBody = class(TObjectQueue)
public
property List; //Expose the list
end;
Простым решением является создание массива [горизонтального] [вертикального] типа, чтобы на экране было по одному элементу для каждой координаты. Каждый тип может быть змеиным, пищевым, ядовитым, настенным или пустым. Это означает, что нужно только запомнить положение головы и хвоста змеи, а также количество еды и ядов, и массив описывает, как выглядит экран.
Это снимает хлопоты по обращению с элементами змеи и облегчает размещение на экране новой еды или яда, гарантируя, что вы не поместите их в место, которое уже занято.
Когда вам нужно удалить элемент хвоста змеи, получите направление хвоста, используя direction:=array[tailx,taily]; а затем установите array[tailx,taily]:=пустую. После этого обновляйте хвост и ежедневно в зависимости от направления. Вот так.
Вот несколько хороших исходных пунктов для вас... поскольку я не хочу делать домашнее задание:
Псевдокод для игры в змею, чтобы получить идею
Тема с немецким примером... может быть, этот код поможет вам
Если в процессе программирования возникнут ошибки, не стесняйтесь открывать новый вопрос.
У меня очень старая программа турбоваскальных змей. Она использует массив для тела.
const MaxBodyLength = 100;
type
TSnake = record
Dir : (nord,sud,est,oest);
Head : tpoint;
BodyLength : integer;
Body : array[1..MaxBodyLength] of tPoint;
Tail : tpoint;
end;
var
Snake : TSnake;
Fruit : tPoint;
и код, который перемещает змею вокруг...
procedure Slither;
var i : integer;
npos,lpos : tPoint;
hasEaten:boolean;
begin
npos:=Snake.Head;
lpos:=Snake.Tail;
case Snake.dir of
East : inc(npos.x);
West : dec(npos.x);
South : inc(npos.y);
North : dec(npos.y);
end;
hasEaten:=(npos.x=fruit.x) and (npos.y=fruit.y);
if hasEaten then
inc(Snake.BodyLength)
else
Snake.Tail:=Snake.Body[Snake.BodyLength];
for i:=Snake.BodyLength downto 2 do
Snake.Body[i]:=Snake.Body[i-1];
Snake.Body[1]:=Snake.Head;
if not hasEaten then
Snake.Head:=npos;
writeP(idHead,Snake.Head);
writeP(idBody,Snake.Body[1]);
if not hasEaten then
begin
writeP(idTail,Snake.Tail);
writeP(idResidual,lPos);
end;
if hasEaten then
NewFruit;
end;