【发布时间】:2009-12-22 09:58:51
【问题描述】:
我有一些学校作业,我必须在 Delphi 中制作一个蛇游戏,就像诺基亚的游戏一样。我想知道哪种解决方案是最好的。我希望我的蛇是一个类,而主体是一个点数组(父类)或点的链接列表。什么是最好的?数组还是链表?
【问题讨论】:
-
我一直很喜欢关于 SO 的家庭作业问题。很想知道什么学校和班级。 . ..
我有一些学校作业,我必须在 Delphi 中制作一个蛇游戏,就像诺基亚的游戏一样。我想知道哪种解决方案是最好的。我希望我的蛇是一个类,而主体是一个点数组(父类)或点的链接列表。什么是最好的?数组还是链表?
【问题讨论】:
一个简单的解决方案是制作一个数组[horizontal][vertical]类型,这样屏幕上的每个坐标都有一个项目。每种类型都可以是蛇方向、食物、毒药、墙或空。这意味着你只需要记住蛇的头尾位置,以及食物和毒药的数量,数组描述了屏幕的样子。
这消除了处理蛇元素的麻烦,并且可以轻松地在屏幕上放置新的食物或毒物,确保您不会将其放入已经被占用的地方。
当需要移除蛇的尾部元素时,使用direction:=array[tailx,taily];获取尾部的方向然后设置数组[tailx,taily]:=empty。之后,根据方向更新tailx和taily。就是这样。
【讨论】:
链接列表更好。 (每个节点都可以指向前一个节点和下一个节点)将节点添加到链表的末尾更容易。
如果您使用数组,则需要调整其大小或将其初始化为最大可能的蛇形长度以开始,这可能会浪费内存。
更新 本文讨论 Delph 中的指针,甚至提出了一个简单的 Node 定义delphi article
【讨论】:
我为我的 Snake 实现使用了不同的东西。这个想法是你存储
这是非常有效的,而不是像简单数组那样愚蠢的解决方案,并且可以很容易地用来绘制“更漂亮”的蛇,例如圆角。
【讨论】:
这里有一些不错的起点……因为我不想做你的功课:
Pseudo Code for Snake Game to get an Idea
Thread with a german example...maybe this code helps you
如果您在编程过程中出现错误,请随时提出新问题。
【讨论】:
在 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 的列表,您必须公开属性 List...为此,只需像这样定义您的蛇体类;
TSnakeBody = class(TObjectQueue)
public
property List; //Expose the list
end;
【讨论】:
New 的语法是否有效。
我有一个非常古老的涡轮帕斯卡蛇程序。它使用一个数组作为主体。
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;
【讨论】:
您可以使用circular buffer。详细说明:
得到一个足够大的数组来容纳最大的蛇。建立两个指针,一个指向头部,一个指向尾部。
在开始时,尾部将在 #1 单元格中,头部在 #3 号单元格中。随着蛇的移动,将头部指针向右移动并写入新坐标。然后,如果没有吃的食物,也将尾部指针向右移动。如果任何一个指针试图超出数组的最右端,则将它们包装到开头。
【讨论】: