这不是关于深度复制或克隆对象的问题,因为已经有数以百万计的对象,尽管事实上这是我一开始一直在寻找自己的东西,如果这是我唯一的选择,我可能会依赖它。但是对于这样一个简单的事情来说,它似乎不必要地过于复杂。
我一直在将一些 C++ 代码翻译成 Delphi,基本上是根据this公然使用 SDL 复制俄罗斯方块。就 SDL 而言,这是一次学习体验,但现在也是一种德尔福的方式。我正在链接到包含我无法完全翻译的代码的特定页面。游戏按预期运行,但有一点我必须切换当前正在下降的方块并将其方块添加到底部的其他方块中,然后将下一个方块设置为当前正在下降的方块。
这是我的一些代码,没有复制太多:TSingleSquare
和TBlock
过程ChangeFocusBlock
。
TSingleSquare = class
private
S_TextureSurf: pSDL_SURFACE;
S_BlockType: TBlockType;
S_CenterX, S_CenterY: integer;
public
constructor Create(CX, CY: integer; T: pSDL_SURFACE; BT: TBlockType);
destructor Destroy; override;
procedure Draw(W: pSDL_SURFACE);
procedure Move(D: TDirection);
function GetCenterX: integer;
function GetCenterY: integer;
procedure SetCenterX(lX: integer);
procedure SetCenterY(lY: integer);
end;
Ttmp_ar = array of integer;
TSquaresArray = array of TSingleSquare;
TBlock = class
private
B_CenterX, B_CenterY: integer;
B_BlockType: TBlockType;
B_SquaresArray: TSquaresArray;
B_TextureSurf: pSDL_SURFACE;
public
constructor Create(CX, CY: integer; TS: pSDL_SURFACE; BT: TBlockType);
destructor Destroy; override;
procedure SetupSquares(SX, SY: integer);
procedure Draw(W: pSDL_SURFACE);
procedure Move(D: TDirection);
procedure Rotate;
function GetRotatedSquares: Ttmp_ar;
function GetSquaresArray: TSquaresArray;
function GetBlockType: TBlockType;
end;
procedure ChangeFocusBlock;
var
Square_ar: TSquaresArray;
i: integer;
begin
Square_ar := g_FocusBlock.GetSquaresArray
SetLength(g_OldSquares, (Length(g_OldSquares) + Length(Square_ar)));
for i := Low(Square_ar) to High(Square_ar) do
begin
g_OldSquares[i+Length(g_OldSquares)-Length(Square_ar)] := Square_ar[i];
Square_ar[i] := nil;
end;
g_FocusBlock := nil;
g_FocusBlock := g_NextBlock;
g_NextBlock := nil;
g_FocusBlock.SetupSquares(BLOCK_START_X, BLOCK_START_Y);
g_NextBlock := TBlock.Create(NEXT_BLOCK_CIRCLE_X, NEXT_BLOCK_CIRCLE_Y, GameBitmap, TBlockType(Random(11)));
end;
我知道我没有释放g_FocusBlock
,这就是我泄漏内存的地方,但我一开始就找不到合适的地方来释放它,如果我这样离开它,泄漏内存是我唯一的问题。一旦我开始寻找解决方案,当我尝试迭代时,它让我感到很痛苦g_OldSquares
,我明白为什么,方块仍然指向g_FocusBlock
应该被释放的方块。当我在每一步添加断点并观察值发生了什么时,我的困惑就出现了,在我将其设置为并创建一个新的下一个块g_OldSquares
之后,一切似乎都井然有序。但是后来迭代g_FocusBlock
g_NextBlock
g_OldSquares
我注意到部分方块被覆盖了,因为内存被重用了?我突然不能相信监视列表的值是真实的?
这面文字墙的底线是,我想了解发生了什么g_OldSquares
以及为什么即使通过监视列表检查时地址相同,它的值也不会改变。
但更重要的是,使这项工作正常工作的正确做法是什么?我知道使用TPersistent
和覆盖它是Assign
为了能够在彼此之间实际分配对象(尽管我也不完全确定如何实现这一点),但在这里我仍然必须摆脱“链接”或共享内存(我为任何错误使用的词道歉,我对编程不是很流利)之间g_OldSquares
和g_FocusBlock
能够释放后者。
让羞辱开始吧。
编辑:
当我这样做时会发生 AccessViolation
for i := Low(g_OldSquares) to High(g_OldSquares) do
begin
row := (g_OldSquares[i].GetCenterY - top) div row_size;
Inc(squares_in_row[row])
end;
constructor TBlock.Create(CX, CY: integer; TS: pSDL_Surface; BT: TBlockType);
var
i: integer;
begin
B_CenterX := CX;
B_CenterY := CY;
B_BlockType := BT;
B_TextureSurf:= TS;
case BT of
SQUARE_BLOCK..REVERSE_S_BLOCK: SetLength(B_SquaresArray, 4);
STRAIGHT_TRI_BLOCK..BENT_TRI_BLOCK: SetLength(B_SquaresArray, 3);
TWO_BLOCK: SetLength(B_SquaresArray, 2);
DOT_BLOCK: SetLength(B_SquaresArray, 1);
end;
SetupSquares(CX, CY);
end;
destructor TBlock.Destroy;
var
i: integer;
begin
for i := Low(B_SquaresArray) to High(B_SquaresArray) do
B_SquaresArray[i].Free;
inherited;
end;