Forum > Games
Best way to delete an instance of a game object
Tomi:
Hello everybody!
I would like delete those instances in my game, which are no longer necessary.
The logic in my program is the following:
When I create an instance of an object, I set its variable named 'exists' to true and when this instance become unnecessary, I set it to false. Finally, I check whether it should be delete.
To delete I used the FreeAndNil() function, but this threw an error in an Assembly window. So, instead of that, now I use the function Delete() in this mode:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---if numberofunits>0 then begin for i:=0 to numberofunits-1 do begin if gameunits[i].exists=false then begin delete(gameunits,i,1); dec(numberofunits,1); end else(...)
These instances are in a dynamic array. Now, there is no errors yet, but I don't know what will be if I set an instance to another to target?
Because in this case if this array is rearranged, the instance will pursue a wrong target, maybe a friendly one instead of enemies.
Let me show it you more precisely:
I choose for example the first instance in the array to target for the player. This is the index 0. But when the array is rearranged because we remove an element of it, the following indexes will shift to left and overwrite the 0. with its own datas and so on.
Finally, the target will be a totally different instance.
So, how can I delete instances from dynamic array to prevent this mixing? Maybe FreeAndNil(gameunits) would be good for this? But why cause error when an instance destroyed?
Handoko:
Try this:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit Unit1; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls; type TItem = record Item: TShape; Useless: Boolean; end; { TForm1 } TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure ItemMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); private Items: array of TItem; procedure MarkRemove(Item: TShape); procedure DoRemove; end; var Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject);var Item: TShape; i: Integer;begin Width := 520; Caption := 'Please click some squares'; Button1.Visible := False; SetLength(Items, 5); for i := 0 to Length(Items)-1 do begin Item := TShape.Create(nil); Item.Parent := Self; Item.Left := 60 + i*80; Item.Top := 50; Item.Brush.Color := Random($FFFF); Item.OnMouseDown := @ItemMouseDown; Items[i].Item := Item; Items[i].Useless := False; end;end; procedure TForm1.Button1Click(Sender: TObject);begin DoRemove; Caption := 'Please click some squares';end; procedure TForm1.ItemMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);const SelectedCount: Integer = 0;begin if not(Sender is TShape) then Exit; MarkRemove(Sender as TShape); (Sender as TShape).Brush.Color := clWhite; Inc(SelectedCount); if SelectedCount < 2 then Exit; Caption := 'Click the button to remove all white squares' ; Button1.Visible := True;end; procedure TForm1.MarkRemove(Item: TShape);var i: Integer;begin if not(Item is TShape) then Exit; for i := 0 to Length(Items)-1 do if Items[i].Item = Item then Items[i].Useless := True;end; procedure TForm1.DoRemove;var RemovedCount: Integer; IndexStart, IndexEnd: Integer; i, j: Integer;begin RemovedCount := 0; for i := 0 to Length(Items)-1 do begin if Items[i].Useless then begin Items[i].Item.Free; Inc(RemovedCount); Continue; end; if RemovedCount > 0 then Items[i-RemovedCount] := Items[i]; end; SetLength(Items, Length(Items)-RemovedCount);end; end.
~edit~
The variables IndexStart, IndexEnd, J in line #95 and #96 are not needed. I forgot to remove them.
Tomi:
Thanks, Handoko, for your example code! So, you use Free and SetLength() in your code.
Meanwhile I figured out a trick: what if I would add a unique number for all instances? Like this:
Instance 0. - id:=0;
Instance 1. - id:=1;
(...)
Instance n. - id:=n;
And when this array rearranged, the index changes but the id remains the same. I'm just worried that in this case more difficult follow and handle the instances, because a for loop is not enough, but I also need check the id, besides the number of id's will constantly increasing.
Bart:
A bit unrelated, but please don't do
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} --- if Condition=False then ...But do
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} --- if not Condition then ...
There is no ndeed to compare a boolean variable (or function result) to either True or False.
If that would be needed then, since the expression (Condition = False) itself is a boolean expression, you would have to do (to stay consistent)
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} --- if ((((((((((((((Condition = False) = True) = True) = True) {etc. at infinitum}))))))))))
Bart
Чебурашка:
--- Quote from: Tomi on May 28, 2023, 03:32:40 pm ---Hello everybody!
I would like delete those instances in my game, which are no longer necessary.
The logic in my program is the following:
When I create an instance of an object, I set its variable named 'exists' to true and when this instance become unnecessary, I set it to false. Finally, I check whether it should be delete.
To delete I used the FreeAndNil() function, but this threw an error in an Assembly window. So, instead of that, now I use the function Delete() in this mode:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---if numberofunits>0 then begin for i:=0 to numberofunits-1 do begin if gameunits[i].exists=false then begin delete(gameunits,i,1); dec(numberofunits,1); end else(...)
These instances are in a dynamic array. Now, there is no errors yet, but I don't know what will be if I set an instance to another to target?
Because in this case if this array is rearranged, the instance will pursue a wrong target, maybe a friendly one instead of enemies.
Let me show it you more precisely:
I choose for example the first instance in the array to target for the player. This is the index 0. But when the array is rearranged because we remove an element of it, the following indexes will shift to left and overwrite the 0. with its own datas and so on.
Finally, the target will be a totally different instance.
So, how can I delete instances from dynamic array to prevent this mixing? Maybe FreeAndNil(gameunits) would be good for this? But why cause error when an instance destroyed?
--- End quote ---
One useful trick when you deal with variable arrays(*) or lists, and you scan them to selectively delete their contents, is to scan them in reverse mode.
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---// assuming it goes from 0 to (numberofelements - 1)for i = numberofelements - 1 downto 0
in this way, when you delete an element, the following ones will move one position back (*) but this doesn't affect your process. If you scan it forward, in case of delete you have to prevent i to do +1 otherwise you miss the item after the deleted one (this is why to scan forward is better to use a loop instead like while, repeat, even goto + label if you are braveheart).
* = in arrays when you delete an element you have to take care of moving backwards all subsequent elements, in lists this is done for you...
Navigation
[0] Message Index
[#] Next page