Collision between arrays of Transforms

Hi.
This is part of code I use to detect collision between a (Avatar) class with transforms (walking characters) and scenery images on screen.
The problem is that if a transform within Avatar collides with a scenery image all other avatar transforms behave if they collide too. In this case if the Y value of the colliding transform < scenery image all avatar transforms y values will be - 0.01 (and disappear).
So every available avatar transform (there are 4 present in this situation) should individually check with all scenery scenes.

Avatar transforms:

Player.transform
Location.npc[1].transform
Location.npc[2].transform
Location.npc[3].transform

How can this be done?

procedure TAvatar.Scenery_Collision;
 var
  I: Integer;
  PlayerT: TVector3;
 begin
   with StatePlay do
   begin

    if Location.SceneryAmount > 0 then
    begin
      For I := 1 to SceneryAmount do
      begin

        if Transform.WorldBoundingBox.RectangleXY.Collides(Location.Scenery[I].Image.WorldBoundingBox.RectangleXY) then
        begin
          PlayerT := Transform.Translation;
          If Transform.Worldboundingbox.Min.Y > Location.Scenery[I].Image.Worldboundingbox.Min.Y then
        begin
          PlayerT.Z := Location.Scenery[I].Image.Translation.Z - 0.01;
          Transform.Translation := PlayerT;
        end
        else
          PlayerT.Z := Location.Scenery[I].Image.Translation.Z + 0.01;
          Transform.Translation := PlayerT;
        end
   end;
;

Hm, I admit I do not folow the question (or example code) with enough precision to answer.

Can you provide more context and/or reformulate the question to be simpler – what exactly is missing, what is that you don’t know how to implement? I want to help but I’m not sure how in this case :slight_smile:

@michalis

First I want to check collision between player transform (which is a transform in my TAvatar type) and the array of scenes (scenery images) so if I make Transform into Player.Transform this works okay:

procedure TAvatar.Scenery_Collision;
 var
  I: Integer;
  PlayerT: TVector3;
 begin
   with StatePlay do
   begin

    if Location.SceneryAmount > 0 then
    begin
      For I := 1 to SceneryAmount do
      begin

        if Player.Transform.WorldBoundingBox.RectangleXY.Collides(Location.Scenery[I].Image.WorldBoundingBox.RectangleXY) then
        begin
          PlayerT := Transform.Translation;
          If Player.Transform.Worldboundingbox.Min.Y > Location.Scenery[I].Image.Worldboundingbox.Min.Y then
        begin
          PlayerT.Z := Location.Scenery[I].Image.Translation.Z - 0.01;
          Player.Transform.Translation := PlayerT;
        end
        else
          PlayerT.Z := Location.Scenery[I].Image.Translation.Z + 0.01;
          Player.Transform.Translation := PlayerT;
        end
   end;

But there are more player transforms in TAvatar, for every character on screen.
These are Location.npc[1], Location.npc[2] etcetera.

So for collision between npc and the array I could make:

procedure TAvatar.Scenery_Collision;
 var
  I: Integer;
  PlayerT: TVector3;
 begin
   with StatePlay do
   begin

    if Location.SceneryAmount > 0 then
    begin
      For I := 1 to SceneryAmount do
      begin

        if Location.NPC[1].Transform.WorldBoundingBox.RectangleXY.Collides(Location.Scenery[I].Image.WorldBoundingBox.RectangleXY) then
        begin
          PlayerT := Player.Transform.Translation;
          If  Location.npc[1].Transform.Worldboundingbox.Min.Y > Location.Scenery[I].Image.Worldboundingbox.Min.Y then
        begin
          PlayerT.Z := Location.Scenery[I].Image.Translation.Z - 0.01;
          Location.NPC[1].Transform.Translation := PlayerT;
        end
        else
          PlayerT.Z := Location.Scenery[I].Image.Translation.Z + 0.01;
          Location.NPC[1].Transform.Translation := PlayerT;
        end
   end;

But how can I put this in one procedure (loop? ) so player and npc transforms are all read one by one and check individually with the array of image scenes?

Hm, I don’t understand all details, but maybe you just want a for loop within a for loop?

for I := 1 to SceneryAmount do
  for NpcIndex := 1 to ... do
  begin
    if Location.NPC[NpcIndex].Transform.WorldBoundingBox.RectangleXY.Collides(Location.Scenery[I].Image.WorldBoundingBox.RectangleXY) then
...

Note: Use local variables to make a long lines like that shorter. E.g.

SceneryImage := Location.Scenery[I].Image;
NpcTransform := Location.NPC[NpcIndex].Transform;
if  NpcTransform.WorldBoundingBox.RectangleXY.Collides(SceneryImage.WorldBoundingBox.RectangleXY) then
...

You can also define helper routines, like

function BoxesCollideIn2D(const T1, T2: TCastleTransform): Boolean;
begin
  Result := T1.WorldBoundingBox.RectangleXY.Colldes(T2.WorldBoundingBox.RectangleXY);
end;

Great! This is indeed what I looked for. Why did I not think of that? :slight_smile:

Hm, I don’t understand this function, sorry :slight_smile: