SIGSEGV when I try to remove

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.

Any idea, what I doing wrong

Thanks

/BlueIcaro

type

{ TBulletBehavior }

TBulletBehavior = class(TCastleBehavior)
private
Speed: single;
Area: TLimites;
public
constructor Create(AOwner: TComponent); override;
procedure Update(const SecondsPassed: single; var RemoveMe: TRemoveType); override;

end;
(…)

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;

I didn’t read your code carefully but I believe it should be

Parent.RemoveDelayed(Self, true);

Otherwise Parent tries to remove itself, which indeed may result in an unexpected behavior.

However, @michalis I see that procedure castle-engine/src/transform/castletransform_transform.inc at ecd3280972626cfc6008aef929e0407d3a9dff74 · castle-engine/castle-engine · GitHub doesn’t check if the element to be removed actually belongs to the Parent or not, just schedules it for freeing? A more explicit error message may be beneficial here.

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.

Hello, thanks for answer.
I followed the code, and I got the error, in this procedure:

procedure TCastleTransform.Update(const SecondsPassed: Single; var RemoveMe: TRemoveType);

In castletransform_transformlist.inc. In this line:

UpdateChildren;

@Carring, you are right. The first time that the If are executed nothings happens. Then in the next call to Update procedure, I got the error
imagen

You said:

I would put this in a start procedure as you only have to set it up once.

What do you means?

Thanks

/BlueIcaro

P.D. Here is the code: GitHub - Blueicaro/1943BatlleOfMidway: Trying to reproduce a game like 1943 batlle of midway using Castle Game Engine

Put the loading of bullet not in an event but in the preparation procedure, like:

procedure TViewMain.Start; (it is in your ViewMain file)
begin
Bullet := TransformLoad(‘castle-data:/Assets/bullet.castle-transform’, FreeAtStop);

Hello, after many test, I found that this works:

if (Parent.TranslationXY.y > Area.Arriba + 100 ) then
begin
Parent.Parent.RemoveDelayed(Self.Parent,true);
end;

With this lines, only in update procedure it’s works nice. I don’t have to move Bullet tranformload to start.

I found the key reading the manual (Mental note: RTFM), here: Castle Game Engine: CastleTransform: Class TCastleTransform

I updated the github .

Thanks

/blueIcaro

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.

Fine that the remove now works without crash.

Hello, I load the bullet, again, because I want to make a arcade, and I use this method to create many bullets.

I got the idea from this video: Getting Physical in Your Games with Castle Game Engine - Michalis Kamburelis - Delphicon 2023 - YouTube

May be is not a good option.
is there any better way yo do it?.

/BlueIcaro

Hi!

  1. I see that the main issue is solved.

    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.

  2. Doing TransformLoad at each Press, to shoot the missile, is OK when the missile is fast to load. And you do want to create new missile each time you shoot. So this is all correct, and some of our examples also do it, and indeed I recommended it in https://www.youtube.com/watch?v=epqLUe_HapM .

    And in recent IPC workshop ( Castle Game Engine at IPC 2023 ) I recommended this approach too. See GitHub - michaliskambi/salamanca2 , salamanca2/code/gameviewsomething.pas at master · michaliskambi/salamanca2 · GitHub .

    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

    • declare a private field like

      MyBulletTemplate: TSerializedComponent;
      

      in your view class.

    • initialize it in Start like

      MyBulletTemplate := TSerializedComponent.Create('castle-data:/my_bullet.castle-transform');
      
    • in each Press, instead of

      MyBullet := TransformLoad('castle-data:/my_bullet.castle-transform', SomeOwner)
      

      do this:

      MyBulletTemplate := TransformLoad(SomeOwner)
      

    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 salamanca2/code/gameviewsomething.pas at master · michaliskambi/salamanca2 · GitHub ) 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.

Thanks @michalis for the long explanation.
/BlueIcaro