これは、オブジェクトのディープ コピーまたはクローン作成に関する問題ではありません。すでに何百万ものオブジェクトが存在するためです。最初はそれが自分で探していたものであり、それが私の唯一の選択肢である場合は、おそらくそれに頼るだろうという事実にもかかわらずです。しかし、このような単純なことには不必要に複雑すぎるようです。
私はいくつかの C++ コードを Delphi に翻訳してきました。基本的に、これに従って SDL を使用して Tetris をあからさまにコピーしています。SDLに関しては学習経験でしたが、今ではDelphiのような方法でもあります. 完全に翻訳できないコードを含む特定のページにリンクしています。ゲームは意図したとおりに動作しますが、現在落下しているブロックを切り替えて、その正方形を下にある他のブロックに追加し、次のブロックを現在落下しているブロックとして設定する必要があるポイントが来ます。
コピーしすぎない私のコードの一部を次に示します: 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;