Ignore key press on collision

Hi,

I need a little help with this:
I use mouse keys arrows or left mouse clicking on screen coordinates to make a transform move over an ImageTransform.
The key presses switches between walking and standing idle.
But if and while the transform collides with another transform it should not respond anymore if user clicks in the same direction.

I have

 if Transform.LocalBoundingBox.RectangleXY.Collides(WestbeachScene8.LocalBoundingBox.RectangleXY) then
     begin
        If Transform.Worldboundingbox.Min.Y > WestbeachScene8.Worldboundingbox.Min.Y then
        if Walkback then StandBack;
    end;

Now with every click the transform “tries” to move in the direction where it collided despite of the collision.

 
 if Event.IsKey(keyArrowUp) and not Event.KeyRepeated then
  begin
    if Player.Stand then Player.GoBack else Player.StandBack;
  end;  

So on collision the key press should be ignored when player tries to move in the same direction as long as it collides with another Transform.
When user selects another ‘key’ direction (away from the transform it collides with) it should move again in that direction.

I hope I am not confusing you.

You can just extend the condition when the key is checked? I’m not sure do I understand the problem correctly :slight_smile: Basically you can wrap if Transform.LocalBoundingBox.RectangleXY.... check in a routine (e.g. nested function, or a method) and use it to extend the check:

function TMyState.CheckCollision: Boolean;
begin
  Result := 
    Transform.LocalBoundingBox.RectangleXY.Collides(WestbeachScene8.LocalBoundingBox.RectangleXY) and 
    (Transform.Worldboundingbox.Min.Y > WestbeachScene8.Worldboundingbox.Min.Y);
end;

procedure TMyState.Press(...)
begin
  ...

  if Event.IsKey(keyArrowUp) and (not Event.KeyRepeated) and (not CheckCollision) then
  begin
    if Player.Stand then Player.GoBack else Player.StandBack;
  end;  
end;

I may have mixed up the conditions above, so please check this code, don’t use directly :slight_smile:

Sorry for late reply, I had to try things out.
The extended key condition got me in the right direction but while collision is true it also prevents moving the character in another direction.
So the collision routine had to be extended too.

I have now this. It works but has its flaws because of the multiple conditions that not always work while combining and sometimes still make the character prevent walking in a different direction while colliding or make it move anyway a bit in the same direction while pressing the key for the same direction before it eventually stops.
Maybe there are better methods that are more accurate and reliable?

 if NOT Player.Transform.WorldBoundingBox.RectangleXY.Collides(WestbeachScene8.WorldBoundingBox.RectangleXY) then
    begin
      CollisionBack := false;
      CollisionFront := false;
      CollisionRight := false;
      CollisionLeft := false;
    end;

    if Player.Transform.WorldBoundingBox.RectangleXY.Collides(WestbeachScene8.WorldBoundingBox.RectangleXY) then
    begin

    if (CollisionBack = false) and (CollisionFront = false) and (CollisionLeft = false) and (CollisionRight = false) then Label2.Caption := 'just passing by';

    if Player.WalkRight then
    begin
      CollisionBack := false;
      CollisionFront := false;
      CollisionRight := false;

      if (Player.Transform.WorldBoundingBox.Max.X > WestbeachScene8.WorldBoundingBox.Min.X) and
     (Player.Transform.WorldBoundingBox.Max.X < WestbeachScene8.WorldBoundingBox.Min.X + 20) and
     (Player.Transform.WorldBoundingBox.Min.Y > WestbeachScene8.WorldBoundingBox.Min.Y - 10) and
     (Player.Transform.WorldBoundingBox.Min.Y < WestbeachScene8.Translation.Y) then
      begin
        Label2.Caption:= 'colliding object at left side';
        CollisionLeft := true;
        Player.StandRight;
      end;
    end;

    if Player.WalkLeft then
    begin
      CollisionFront := false;
      CollisionBack := false;
      CollisionLeft := false;

      if (Player.Transform.WorldBoundingBox.Min.X <= WestbeachScene8.WorldBoundingBox.Max.X) and
     (Player.Transform.WorldBoundingBox.Min.X >= WestbeachScene8.WorldBoundingBox.Min.X) and
     (Player.Transform.WorldBoundingBox.Min.Y > WestbeachScene8.WorldBoundingBox.Min.Y - 10) and
     (Player.Transform.WorldBoundingBox.Min.Y < WestbeachScene8.Translation.Y) then
      begin
        Label2.Caption:= 'colliding object at right side';
        CollisionRight := true;
        Player.StandLeft;
      end;
    end;

    if Player.WalkBack then
    begin
      CollisionBack := false;
      CollisionLeft := false;
      CollisionRight := false;

       if (Player.Transform.WorldBoundingBox.Max.X > WestbeachScene8.WorldBoundingBox.Min.X + 10) and
       (Player.Transform.WorldBoundingBox.Min.Y > WestbeachScene8.WorldBoundingBox.Min.Y - 20) and
       (Player.Transform.WorldBoundingBox.Min.Y < WestbeachScene8.Translation.Y) then
       begin
         Label2.Caption:= 'colliding object at front side';
         CollisionFront := true;
         Player.StandBack;
       end;
      end;

    if Player.WalkFront then
    begin
      CollisionFront := false;
      CollisionLeft := false;
      CollisionRight := false;

    if (Player.Transform.WorldBoundingBox.Max.X > WestbeachScene8.WorldBoundingBox.Min.X + 10) and
       (Player.Transform.WorldBoundingBox.Min.Y < WestbeachScene8.Translation.Y) and
       (Player.Transform.WorldBoundingBox.Min.Y > WestbeachScene8.WorldBoundingBox.Min.Y + 20) then
        begin
          Label2.Caption:= 'colliding object at rear side';
          CollisionBack := true;
          Player.StandFront;
        end;
    end;      

And key events:

function TStatePlay.Press(const Event: TInputPressRelease): Boolean;
 var I: Integer;


 begin
   Result := inherited;
   if Result then Exit; // allow the ancestor to handle keys


   if Event.IsKey(keyArrowLeft) and not Event.KeyRepeated and (CollisionRight = false) then
   begin
     if Player.Stand then Player.GoLeft else Player.StandLeft;
   end;

   if Event.IsKey(keyArrowRight) and not Event.KeyRepeated and (CollisionLeft = false) then
   begin
     if Player.Stand then Player.GoRight else Player.StandRight;
   end;

   if Event.IsKey(keyArrowUp) and (not Event.KeyRepeated) and (CollisionFront = false) then
   begin
     if Player.Stand then Player.GoBack else Player.StandBack;
   end;

   if Event.IsKey(keyArrowDown) and not Event.KeyRepeated and (CollisionBack = false) then
   begin
     if Player.Stand then Player.GoFront else Player.StandFront;
   end;

On a first glance, to simplify this code, maybe it would be better to generalize the idea of “4 directions” into an enum type?

I.e. right now we seem to have a lot of logic doing things to “right”, and then similar logic for “left”, and then similar logic for “forward” and “back”.

Maybe it would be a good idea to instead use an enumerated type, like

TDirection = (dirLeft, dirRight, dirForward, dirBack);

and make it a parameter of various methods? E.g. instead of 4x methods GoXxx you would have 1 method Go(const Direction: TDirection). See about enumerated types, Modern Object Pascal Introduction for Programmers | Castle Game Engine .

This will be a bigger change, you will have to redo some logic you show me. But it may be worth it – you will have a more concise description of what is going on, and you will “force yourself” to make it really consistent for all 4x directions.