Hello, I have a exception External: SIGSEGV when I try to remove the Parent using this line:
Parent.RemoveDelayed(Parent, True);
I want to remove (and free memory) when my transforms leaves the screen.
procedure TBulletBehavior.Update(const SecondsPassed: single;
var RemoveMe: TRemoveType);
begin
inherited Update(SecondsPassed, RemoveMe);
with Parent do
begin
TranslationXY := TranslationXY + Vector2(0, Speed * SecondsPassed);
end;
//Si sale de la pantalla lo borramos
if Parent.TranslationXY.y > Area.Arriba + 100 then
begin
Parent.RemoveDelayed(Parent, True); //External: SIGSEGV
end;
end;
(…)
function TViewMain.Press(const Event: TInputPressRelease): boolean;
var
Bullet: TCastleTransform;
BulletBehavior: TBulletBehavior;
begin
Result := inherited;
if Result then Exit; // allow the ancestor to handle keys
if Event.IsKey(keySpace) then
begin
Bullet := TransformLoad(‘castle-data:/Assets/bullet.castle-transform’, FreeAtStop);
Bullet.TranslationXY := PlayerBehavior.GetPosition + Vector2(0, 40);
BulletBehavior := TBulletBehavior.Create(FreeAtStop);
Bullet.AddBehavior(BulletBehavior);
View.Items.Add(Bullet);
Exit(True);
end;
Hi, I am not that good with coding but I noticed a few things:
You keep on trying removing when translation is Area.arriba + 100 with every call, it should be called once, then the transform is erased so if you call it again you call a non existent transform so the code will cause a crash.
And I think you should place most of the press procedure in the start procedure because now with every press you create and load stuff such as the bullet which causes delay through loading. I would put this in a start procedure as you only have to set it up once.
I mean this has nothing to do with the problem you described but I think it makes no sense loading the same bullet over and over with every press event, I would load it only once in the start procedure.
Originally you tried to remove object during it’s own iteration of “pending objects to remove”, Parent.RemoveDelayed(Parent,true); . This failed as by freeing the object, you’re also freeing the list of “pending objects to remove” over which the code iterates at the moment it is freeing.
The Parent.Parent.RemoveDelayed(Self.Parent,true); (or simpler Parent.Parent.RemoveDelayed(Parent,true);) is correct.
You can really use any TCastleTransform instance, even MyViewport.Items, when calling the RemoveDelayed with FreeItem (2nd parameter) set to true. And this is OK, as freeing the item always also removes it from all possible parents. E.g. MyViewport.Items.RemoveDelayed(Parent, true) will work just as well.
I was thinking how to improve it:
CGE now makes a clear exception if you try to use RemoveDelayed with itself. So your line would raise a clear exception “Cannot remove the object from itself using RemoveDelayed”
I documented
Note: When you want to free the Item (that is, FreeItem parameter is @true)
then it actually doesn’t matter on what parent will you call this.
Freeing the Item will always remove it from all parents.
I wondered about checking whether item is currently a child of given parent (as @eugeneloza noted, this is not checked now). But I concluded that the behavior should stay as it is, i.e. we don’t check whether the item is currently a child. This is consistent with Remove and it is useful when using FreeItem, so let it be. I noticed it is documented:
Note: It is not a problem if the child scheduled to be removed
will also be removed (or even freed) directly e.g. by just calling @code(Free) on it.
We ignore removal of items that are no longer
our children, and we automatically remove the child from “pending to remove” list
if it is freed. You only need to be careful in case you add the same TCastleTransform
instance multiple times to the same parent
(see Writing code to modify scenes and transformations | Manual | Castle Game Engine )
as then each removal removes one instance (not all) of the child from parent.
If you want to optimize it: You could load only a “template” in the view “Start” method, and then clone this template in each “Press”. To do this, you can
Some CGE example using this approach: examples/audio/game_3d_sound/ (serach code for TntTemplate).
As with all optimizations: in general I advise to optimize things only once you know it will really have an impact on user. With simple bullets, that you shoot from time to time, you may ignore it. And adding an object with physical rigid body (like we do in https://github.com/michaliskambi/salamanca2/blob/master/code/gameviewsomething.pas ) will have a cost anyway. That said, if you plan to shoot often / a lot of missiles (as your example shows) I would say it may matter, and actually I recommend you do the optimization using TSerializedComponent I outlined above.