2D Scene Collision

I spend many days trying out but find the Kraft physics too difficult to use for 2D scene collision.
How can I use the Scene.BoundingBox.RectangleXY or a TFloatRectangle collision so it takes the dimensions of the image loaded in the scene for collision between scenes?

Or is there a more easy way to use it in TUI game stateplay?
I need a simple example. Thanks.

What exactly do you need from 2D Scene collision?

The “right way to do it” is using Physics engine (currently only Kraft is available). I must admit I’ve never used it properly myself, but I’d start with examples\physics\physics_2d_collisions example and then try checking out more advanced game-example examples\physics\physics_2d_game_sopwith.

Scene.BoundingBox solution may be easier at the beginning, but it won’t “scale” - i.e. it will become a burden in time. Unless you are up to implementing your own (simplified) physics engine yourself - this is also possible, but remember that it’s a huge drain of time.

Yes, you can use simple images instead of TCastleScene, yes the same comment as above applies here - this solution doesn’t scale well. It’s easier to start, but if you want to implement something complex, it’ll get to a dead end eventually forcing you to implement your own sort of TCastleScene instead of using a ready solution.

Thanks for your reply.

My mouse is a scene and I want it to collide with Player and NPC. And between Player and NPC.

I already looked at and tried the examples you mentioned. Parts of the first one I put in my code (see topic Collison Course). I also looked at the “3d_rendering_processing/collisions” example that looks totally different without setting up a rigidbody but a set up in TUI state instead of the other Window examples. So this confuses me. But as I would use the CGE editor that automatically makes a setup in TUI I would like to use this.
I think I have set up the rigid body allright but I don’t know how to set up the part in the update procedure.

btw: Is everything okay with Michalis? He would make an announcement the weekend before past weekend and it looks like he is almost 2 weeks not on github. I hope he is not ill?

It should then work as Mouse.BoundingBox.Collides(Player.BoundingBox) or better Mouse.BoundingBox.RectangleXY.Collides(Player.BoundingBox.RectangleXY) (as Z in your 2D setup means depth) in this case. Note, that I didn’t test it - but there shouldn’t be any troubles here, it’s relatively straight-forward.

Many thanks.
You mean in Window update procedure?

if Mouse.BoundingBox.RectangleXY.Collides(Player.BoundingBox.RectangleXY) then…
?
That looks understandable, i will try this out. Thanks again.

That is bad. I had a feeling it could be this. I wish him the best and hope he will recover soon.

Yes. Or wherever you need to know if they collide.

Thank you. I was indeed “off” for most of April due to COVID, but I’m happy to say I’m back on my feet now! :slight_smile:

As for the question, I see Eugene already answered it. If you just want to resolve collisions yourself, by intersecting simple 3D axis-aligned boxes (TBox3D type) or 2D rectangles (TFloatRectangle) then it is definitely possible, just use the Collides method of them.

1 Like

I still have no success with the collisions.
Is this code correct and what should I set in the update procedure to make collision between mouse scene and ‘standidle’ scene?

When I put
if Mouse.BoundingBox.RectangleXY.Collides(StatePlay.StandIdleAnim.BoundingBox.RectangleXY) then Label1.Caption := ‘You really touched it!’ else Label1.Caption := ’ '; in the update procedure it works okay. What is the difference with the Physics collision? Keep it track of expanding and shrinking boxes and the RectangleXY collides not?


  type
    TStatePlay = class(TUIState)
    private
      Mouse: TCastleScene;
      StandIdleAnim: TCastleScene;
      procedure MakeMousePhysics;
      procedure MouseCollisionEnter(const CollisionDetails: TPhysicsCollisionDetails);
      procedure MakeStandIdlePhysics;

      public
      constructor Create(AOwner: TComponent); override;
      procedure Start; override;
      procedure Update(const SecondsPassed: Single; var HandleInput: Boolean); override;
      function Press(const Event: TInputPressRelease): Boolean; override;
    end;

var
  StatePlay: TStatePlay;

implementation

uses SysUtils, Math,
  GameStateMenu;

{ TStatePlay ----------------------------------------------------------------- }

var
  MainViewport: TCastleViewport;

Procedure TStatePlay.MouseCollisionEnter(const CollisionDetails: TPhysicsCollisionDetails);
begin
  if CollisionDetails.OtherTransform <> nil then
   begin
     if CollisionDetails.OtherTransform = StandIdleAnim then Application.Terminate;
   end;
end;

Procedure TStatePlay.MakeMousePhysics;
 var
  Size: TVector3;
  Collider: TBoxCollider;
begin
  Mouse.RigidBody := TRigidBody.Create(Mouse);
  Mouse.RigidBody.Dynamic:= true;
  Mouse.RigidBody.Setup2D;
  Mouse.RigidBody.OnCollisionEnter:= @MouseCollisionEnter;

  Collider := TBoxCollider.Create(Mouse.RigidBody);

  Size := Mouse.LocalBoundingBox.Size;
  Size.Z := Max(0.1, Size.Z);
  Collider.Size := Size;
end;

Procedure TStatePlay.MakeStandIdlePhysics;
 var
  Size: TVector3;
  Collider: TBoxCollider;
begin
  StandIdleAnim.RigidBody := TRigidBody.Create(Mouse);
  StandIdleAnim.RigidBody.Dynamic:= true;
  StandIdleAnim.RigidBody.Setup2D;

  Collider := TBoxCollider.Create(StandIdleAnim.RigidBody);

  Size := StandIdleAnim.LocalBoundingBox.Size;
  Size.Z := Max(0.1, Size.Z);
  Collider.Size := Size;
end;

constructor TStatePlay.Create(AOwner: TComponent);
begin
  inherited;
  end;

procedure TStatePlay.Start;
begin
  inherited;
   DesignUrl := 'castle-data:/westbeach-gamestateplay.castle-user-interface';
   MainViewport := DesignedComponent ('Viewport') as TCastleViewport;
   Mouse := DesignedComponent ('Mouse') as TCastleScene;
StandIdleAnim := DesignedComponent ('StandIdleAnim') as TCastleScene;
end;

procedure TStatePlay.Update(const SecondsPassed: Single; var HandleInput: Boolean);
begin
 // call procedure mousecollision here and how?
  Mouse.Translation := Vector3(Mainviewport.PositionTo2DWorld(Container.MousePosition, true), 9);
end;

end.

Unfortunately I don’t think I can help you much here without actually debugging your project. Just a couple of notes here:

what should I set in the update procedure to make collision

Nothing, it should work automatically, as you assign Mouse.RigidBody.OnCollisionEnter.

However, you don’t seem to ever call MakeStandIdlePhysics or MakeMousePhysics. Shouldn’t you do that in Start?

Also note that you should call inherited in Update the same way as you do in Start. Otherwise it may misbehave.

If it doesn’t help, try setting a breakpoint or do a WriteLnLog inside MouseCollisionEnter to see if it’s called at all and what exactly is passed in CollisionDetails.

Hm, I think you’re right, but when I add these I get a SIG error again and in the castletransform_physics unit:

image

That means something is not initialized. Are you sure you are calling MakeStandIdlePhysics and MakeMousePhysics after you assign Mouse and StandIdleAnim variables?

Set a breakpoint inside the first procedure to call and use F8 to step over each line to see which one causes the SIGSEGV. Check if all variables are properly initialized at this line.

Ok.
I // all lines and the SIG appears with the Mouse.RigidBody.Create(Mouse) line.

The TUI code is:

    private
      Mouse: TCastleScene;
      StandIdleAnim: TCastleScene;
      procedure MakeMousePhysics;
      procedure MouseCollisionEnter(const CollisionDetails: TPhysicsCollisionDetails);
      procedure MakeStandIdlePhysics;

      public
      constructor Create(AOwner: TComponent); override;
      procedure Start; override;
      procedure Update(const SecondsPassed: Single; var HandleInput: Boolean); override;
      function Press(const Event: TInputPressRelease): Boolean; override;
    end;                      

Procedure TStatePlay.MakeMousePhysics;
 var
  Size: TVector3;
  Collider: TBoxCollider;
begin
  Mouse.RigidBody := TRigidBody.Create(Mouse);
 // Mouse.RigidBody.Dynamic:= true;
//  Mouse.RigidBody.Setup2D;
//  Mouse.RigidBody.OnCollisionEnter:= @MouseCollisionEnter;

//  Collider := TBoxCollider.Create(Mouse.RigidBody);

//  Size := Mouse.LocalBoundingBox.Size;
//  Size.Z := Max(0.1, Size.Z);
 // Collider.Size := Size;
end;     
    
 procedure TStatePlay.Start;
begin
  inherited;
   DesignUrl := 'castle-data:/westbeach-gamestateplay.castle-user-interface';
   MainViewport := DesignedComponent ('Viewport') as TCastleViewport;
   Mouse := DesignedComponent ('Mouse') as TCastleScene;
   StandIdleAnim := DesignedComponent ('StandIdleAnim') as TCastleScene;
  
   MakeMousePhysics;
   MakeStandIdlePhysics;
end;

Has it something to do with:

![image|690x452](upload://AckOkhPHk36Du47PkTkSH1a7Moz.png)

Can you make sure Mouse <> nil? Usually howering your mouse over it is enough if you set a breakpoint at this line. You can also check if Mouse <> nil then begin… before this piece of code.

One more thing to try is to Mouse.RigidBody := TRigidBody.Create(Self); - maybe it doesn’t like to be parented to Mouse?

Maybe it is this? I have not set this.

That did not help.

image

This is exactly what you are doing by Mouse.RigidBody := TRigidBody.Create(Self) AFAIU, just try use (Self) instead of (Mouse) and see if it works.

image

image

Did you do the same changes in MakeStandIdlePhysics?

Note, it’s a very good idea to use a breakpoint here. It may tell a lot about when exactly SIGSEGV is happening. Is it at Mouse.RigidBody := TRigidBody.Create(Self) or on other line… or maybe after Start is over (i.e. somewhere around Update).

I had temporary switched off MakeStandIdlePhysics to focus on the Mouse, so this can cause no errors for now.
I tried setting up a breakpoint at every line in the code and then press F8. It gives no error indication though.

Additional: