Page 1 of 4 123 ... LastLast
Results 1 to 10 of 31

Thread: Collission detection on level ( source Travels doc + some other examples)

  1. #1

    Collission detection on level ( source Travels doc + some other examples)

    Hello everyone,

    This weekend I've managed to get a bit further on my road to making some platform games in the future...

    Anyway using Traveler's guide for platform game + some andorra 2d examples... I've managed to create a simple level , load it, and my hero ( the big bad red block ) can move around and hits the wall... only problem is I dunno why, but sometimes he does not exactly hits it but stops a bit earlier...

    I'm including my complete source + attached the zipped program so you can see what I mean, I've tried to implement my own method of detecting the edges, by defining the 4 points of the block, not much different from the original guide, but I understand this one atleast ...

    Code:
    unit Main;
    interface
    uses
      Windows,Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, AdDraws, AdClasses, AdTypes, AdPerformanceCounter, AdDevIL,AdSprites;
      type
      //Types that are used to tell the character which key has been pressed
      TKey = (kyUp, kyDown, kyLeft, kyRight);
      TKeys = set of TKey;
      TTileInfo = Record
      tilenr : integer;
      end;
      TPlatform = class(TImageSprite)
        private
        protected
          procedure DoMove(TimeGap: Double); override;
          procedure DoCollision(Sprite:TSprite; var Done:boolean); override;
        public
          constructor Create(AParent:TSprite);override;
        end;
      TBlurp = class(TImageSprite)
        private
        FKeys:TKeys;
        X_Direction:double;
        Y_Direction:double;
        isfalling:boolean;
        iswall:boolean;
        protected
          procedure DoMove(TimeGap: Double);override;
          procedure DoCollision(Sprite:TSprite; var Done:boolean);override;
        public
          constructor Create(AParent:Tsprite);override;
          procedure SetKeys(Keys:TKeys);
          function testForWall(spriteXpos,spriteYpos:single;spriteWidth,spriteHeight:integer):boolean;
        end;
      TForm1 = class(TForm)
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure FormKeyDown(Sender: TObject; var Key: Word;
          Shift: TShiftState);
      private
        { Private declarations }
      public
        { Public declarations }
        AdDraw:TAdDraw;
        AdSpriteEngine:TSpriteEngine;
        AdImageList:TAdImageList;
        AdPerCounter:TAdPerformanceCounter;
        AdPixelCollisionTester: TAdSpritePixelCollisionTester;
        Blurp:TBlurp;
        procedure Idle(Sender:TObject; var Done:boolean);
        procedure LoadLevel;
      end;
    var
      Form1: TForm1;
      TileInfo : array [1..39, 0..28 ] of TTileInfo;
      ActTime : double;
    implementation
    {$R *.dfm}
    procedure TForm1.LoadLevel;
    var
      level:TStringList;
      ax,ay:integer;
    begin
      level := TStringList.Create;
      level.LoadFromFile(ExtractFilePath(Application.ExeName)+'level2.txt');
      for ay := 0 to level.Count-1  do
      begin
        for ax := 1 to length(level[ay]) do
        begin
          case level[ay][ax] of
            'x':
            begin
              TileInfo[ax,ay].tilenr:=1;
              with TPlatform.Create(AdSpriteEngine) do
              begin
                Image := AdImageList.Find('Kocka');
                x := ax*64;
                y := ay*64;
                z := 0;
              end;
            end;
            'X':
            begin
              TileInfo[ax,ay].tilenr:=1;
              with TPlatForm.Create(AdSpriteEngine) do
              begin
                Image := AdImageList.Find('Kocka2');
                x := ax*64;
                y := ay*64;
                z := 0;
              end;
            end;
            '-': TileInfo[ax,ay].tilenr:=2;
          end;
        end;
      end;
      level.Free;
    end;
    procedure TBlurp.SetKeys(Keys: TKeys);
    begin
      if Keys = FKeys then exit;
      FKeys := Keys;
      if kyRight in Keys then x_direction:=1.5;
      if kyLeft in Keys then x_direction:=-1.5;
      if kyUp in Keys then y_direction:=-1.5;
      if kyDown in Keys then y_direction:=1.5;
      if Keys = [] then
        begin
          x_direction:=0;
          y_direction:=0;
        end;
    end;
     
    constructor TPlatform.Create(AParent: TSprite);
    begin
      inherited;
    end;
    constructor TBlurp.Create(AParent: TSprite);
    begin
      inherited;
    end;
     
    procedure TBlurp.DoMove(TimeGap: Double);
    begin
      inherited;
     { X:=X+X_direction;
      Y:=Y+Y_direction; }
     
     { if X <= 0 then X:=0;
      if X > 640-Image.Width then X:=640-Image.Width;
      if Y < 0 then Y:=0;
      if Y > 480-Image.Height then Y:=480-Image.Height; }
      Collision;
    end;
    function TBlurp.testForWall(spriteXpos,spriteYpos:single;spriteWidth,spriteHeight:integer):boolean;
    begin
      testForWall := false;
      if not (TileInfo[round(spriteXpos) div 64, round(spriteYpos) div 64].tilenr in [2]) or not
      (TileInfo[(round(spriteXpos)+spriteWidth) div 64, round(spriteYpos) div 64].tilenr in [2]) or not
      (TileInfo[round(spriteXpos)div 64, (round(spriteYpos)+spriteHeight) div 64].tilenr in [2]) or not
      (TileInfo[(round(spriteXpos)+spriteWidth) div 64, (round(spriteYpos)+spriteHeight) div 64].tilenr in [2]) then testForWall :=true;
    end;
    procedure TPlatform.DoMove(TimeGap : Double);
    begin
      inherited;
      Collision;
    end;
     
    procedure TBlurp.DoCollision(Sprite:TSprite; var Done:boolean);
    begin
      if Sprite is TPlatform then
        begin
          isFalling:=false;
        end;
    end;
    procedure TPlatform.DoCollision(Sprite:TSprite; var Done:boolean);
    begin
    end;
     
     
    procedure TForm1.FormCreate(Sender: TObject);
    var i: integer;
    begin
      AdPerCounter := TAdPerformanceCounter.Create;
      AdDraw := TAdDraw.Create(self);
      AdDraw.DllName := 'AndorraDX93D.dll';
     with AdDraw.Display do
        begin
        {  Width := 640;
          Height := 480;
          BitDepth := ad16Bit; //The colour depth. The values "ad16Bit" and "ad32Bit" are allowed here.
          DisplayMode := dmFullscreen; }
        end;
     
    if AdDraw.Initialize then
      begin
        Application.OnIdle := Idle;
        AdImageList := TAdImageList.Create(AdDraw);
        AdImageList.LoadFromFile('BackGround.ail');
     
        //create the SpriteEngine
         AdSpriteEngine := TSpriteEngine.Create(nil);
         AdSpriteEngine.Surface := AdDraw;
        //Create the collision tester
        AdPixelCollisionTester := TAdSpritePixelCollisionTester.Create(AdDraw);
        LoadLevel;
        //create TImageSprite
        Randomize;
            Blurp := TBlurp.Create(AdSpriteEngine);
            with Blurp.Create(AdSpriteEngine) do
              begin
                Image := AdImageList.Find('Hero');
                X := 128;
                Y := 128;
                Z := 0;
                CollisionTester := AdPixelCollisionTester;
                SetKeys([]);
                isfalling:=true;
              end;
     
     
        // ************* hater *********************************
      end
     else
      begin
         ShowMessage('Error while initializing Andorra 2D. Try to use another display'+
                   'mode or use another video adapter.');
        halt; //<-- Completely shuts down the application
      end;
    end;
    procedure TForm1.Idle(Sender: TObject; var Done: boolean);
    var keys: TKeys;
     begin
       if AdDraw.CanDraw then // Only continue, if drawing is possible
       begin
        AdPerCounter.Calculate;
        AdPerCounter.MaximumFrameRate:=60;
     
        AdDraw.ClearSurface(clBlack); // Fill the surface with black color
        AdDraw.BeginScene;
        // Here you need to perform all drawing operations later
        ActTime := ActTime + AdPerCounter.TimeGap;
        if ActTime > 25 then
        begin
             keys := [];
              if GetKeyState(VK_LEFT) < 0 then
                begin
                  if not Blurp.testForWall(Blurp.X-3,Blurp.Y,Blurp.Image.Width,Blurp.Image.Height) then
                    begin
                      Blurp.X:=Blurp.X-3;
                      AdSpriteEngine.X:=AdSpriteEngine.X+3;
                    end;
                end;
              if GetKeyState(VK_RIGHT) < 0 then
                begin
                  if not Blurp.testForWall(Blurp.X+3,Blurp.Y,Blurp.Image.Width,Blurp.Image.Height) then
                    begin
                      Blurp.X:=Blurp.X+3;
                      AdSpriteEngine.X:=AdSpriteEngine.X-3;
                    end;
                end;
              if GetKeyState(VK_UP) < 0 then
                begin
                  if not Blurp.testForWall(Blurp.X,Blurp.Y-3,Blurp.Image.Width,Blurp.Image.Height) then
                    begin
                      Blurp.Y:=Blurp.Y-3;
                      AdSpriteEngine.Y:=AdSpriteEngine.Y+3;
                    end;
                end;
              if GetKeyState(VK_DOWN) < 0 then
                begin
                  if not Blurp.testForWall(Blurp.X,Blurp.Y+3,Blurp.Image.Width,Blurp.Image.Height) then
                    begin
                      Blurp.Y:=Blurp.Y+3;
                      AdSpriteEngine.Y:=AdSpriteEngine.Y-3;
                    end;
                end;
              Blurp.SetKeys(Keys);
          ActTime := 0;
        end;
       { if Blurp.isfalling = true then
          begin
            Blurp.Y:=Blurp.Y+1;
          end;
        Blurp.isfalling:=true;}
     
        AdSpriteEngine.Draw;
        AdSpriteEngine.Move(25/1000);
        AdSpriteEngine.Dead;
        // debug
        AdDraw.Canvas.Textout(0,40,'Ido: '+inttostr(TileInfo[1,1].tilenr));
    //    AdDraw.Canvas.TextOut(0,80,'Player Collision:' +Blurp.testForWall(Blurp.X,Blurp.Y,Blurp.Image.Width,Blurp.Image.Height));
     
     
        AdDraw.EndScene;
        AdDraw.Flip; // Draws you result on the screen. Otherwise, you would not see anything
       end;
      Done := false; // Important, otherwise the function will not be called in every loop
     end;
    procedure TForm1.FormDestroy(Sender: TObject);
    begin
       AdSpriteEngine.Free;
       AdImageList.Free;
       AdPerCounter.Free;
       AdDraw.Free;
    end;
    procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    begin
      if Key = VK_ESCAPE then Close;
    end;
    end.
    this worked :

    Code:
       function TOurSprite.testForWall(spriteXpos,spriteYpos:single; 
                  spriteWidth,spriteHeight:integer):boolean;
    begin
        testForWall := false;
      //test topside
      if not (TileInfo[((round(spriteXpos)+spriteWidth) div 32),
            (round(spriteYpos) div 32)].tilenr in [6,7,100])
      //test bottomside
      or not ((TileInfo[((round(spriteXpos)+spriteWidth) div 32),
            ((round(spriteYpos)+spriteHeight) div 32)].tilenr in [6,7,100])
         and (TileInfo[(round(spriteXpos) div 32),
            ((round(spriteYpos)+spriteHeight) div 32)].tilenr in [6,7,100]))
      then testForWall := true;
    only thing was I was not able to figure it out how and why I was able to figure out that
    it was checking , these coordinates in this order

    X------1
    | -------|
    3------2 Why was it not checking 4 x,y have no idea... it worked... but I did not want to use
    something I don't understand...

    Anyway back to my way I defined all 4 points
    X----X
    | ------|
    X----X

    only problem is sometimes my Hero Character stops a bit earlier then it should...
    I must stop him a bit sooner otherwise... I get wallhit true...and cannot move in any direction...

    Please help me out a bit here ( I try to do as much as possible by myself...but I'm really stuck here...)

    Egyszeru 5 figura maga.zip

    Greetings

    Robert

  2. #2
    Maybe this site can help?
    http://www.tonypa.pri.ee/tbw/tut05.html

    It is using action script (Flash) but I managed to folow the tutorials, especially "Hit the Wall" and "Jumping" to make a simple platform game with collision that worked quite well

    cheers,
    Paul

  3. #3
    Code:
    function TBlurp.testForWall(spriteXpos,spriteYpos:single;spriteWidth,spriteHeight:integer):boolean;
    begin
      testForWall := false;
      if not (TileInfo[round(spriteXpos) div 64, round(spriteYpos) div 64].tilenr in [2]) or not
      (TileInfo[(round(spriteXpos)+spriteWidth) div 64, round(spriteYpos) div 64].tilenr in [2]) or not
      (TileInfo[round(spriteXpos)div 64, (round(spriteYpos)+spriteHeight) div 64].tilenr in [2]) or not
      (TileInfo[(round(spriteXpos)+spriteWidth) div 64, (round(spriteYpos)+spriteHeight) div 64].tilenr in [2]) then testForWall :=true;
    end;
    Test with changing round() to trunc(). There is a difference in how they work, and tiles are usually drawn from their top left corner, not from middle.

  4. #4

    Red face

    Hi,

    same thing with Trunc...

    I don't get this : "and tiles are usually drawn from their top left corner, not from middle."
    - why did you write this ? am I doing something wrong when checking the 4 corners?

    By the way... if I use it like this :

    Code:
     if not Blurp.testForWall(Blurp.X,Blurp.Y,Blurp.Image.Width,Blurp.Image.Height) then
    for any direction... it stops when it hits the wall... but since it HIT the wall I can no longer
    move in any direction... that is why I did that -3 here +3 here... I'm a bit confused there... I should check if after the next step there is a wall...

    Greetings
    Rob

  5. #5
    There are two ways to counter the-getting-stuck-in-the-wall problem.

    1) Move away from the wall when you're inside it. (the preferred method)
    For example, you're moving to the left at 3 pixel/cycle. You're going to hit the wall in 11px. Meaning you'll end up in the wall (and get stuck) in 4 cycles. At the fourth cycle your position is 1px inside the wall, so you correct that by setting the sprite position 2 pixels back.

    2) Change the testwall function to include the direction. Meaning when you go to the right you only test if the right side of your sprite is inside a wall. If you're going left, only test if you with with the left part. This way you can still move if one side of your sprite is inside a wall.
    Last edited by Traveler; 15-08-2011 at 10:08 PM.

  6. #6
    The tutorial site I posted seems to do the testing like this:

    Code:
    find new object position (position + velocity).
    if edge inside a wall
      move object so it touches edge of wall 
    else 
      do full movement in that direction
    Oh, and it breaks up the movement and does it vertically then horizontally (or is it the other way around...I forget LOL)

    I hope this helps

    cheers,
    Paul

  7. #7
    @Robert: hmm...I tried running your test program to take a look, but it doesn't run for me

    I get the dialog box error below:
    ---------------------------
    Dreamworld: DreamWorld.exe - Unable To Locate Component
    ---------------------------
    This application has failed to start because d3dx9_33.dll was not found. Re-installing the application may fix this problem.
    ---------------------------
    OK
    ---------------------------
    cheers,
    Paul

  8. #8
    you can download those dll files manually.

  9. #9
    ok, thanks

    cheers,
    Paul

  10. #10
    Hello,

    I've changed the movement from 3 to 4 now, so that it can be divided correctly... since my level is made of 64x64 tiles ...

    I think the problem is here but don't know how to fix....

    Left and Top works always on my level everywhere... it stops right there when it reaches the wall (no pixel left out...) , and I can continue to move in any other direction ...

    Left = works
    Top = works
    Right = stops 4 pixels sooner then it should...always
    Bottom = stops 4 pixels sooner then it should...always

    meanwhile I've also found out that it's important where my character starts... so I've set the starting position to

    X (3x64)-32
    Y (3x64)-32

    I hope I'm not wrong here, but currently my tiles are 64x64, whereas my character is 32x32.

    I've checked the Right and Bottom testwall functions... it works as it should because it is right that if it lets another +4 to x or +4 to y ... it is true... only thing is I can't seem to firugre it out... how the heck does it work correctly for Left and Top...
    Code:
     
     
               if GetKeyState(VK_LEFT) < 0 then
                begin
                  if not Blurp.testForWall(Blurp.X-4,Blurp.Y,Blurp.Image.Width,Blurp.Image.Height) then
                    begin
                      Blurp.X:=Blurp.X-4;
                      AdSpriteEngine.X:=AdSpriteEngine.X+4;
                    end;
                end;
              if GetKeyState(VK_RIGHT) < 0 then
                begin
                  if not Blurp.testForWall(Blurp.X+4,Blurp.Y,Blurp.Image.Width,Blurp.Image.Height) then
                    begin
                      Blurp.X:=Blurp.X+4;
                      AdSpriteEngine.X:=AdSpriteEngine.X-4;
                    end;
                end;
              if GetKeyState(VK_UP) < 0 then
                begin
                  if not Blurp.testForWall(Blurp.X,Blurp.Y-4,Blurp.Image.Width,Blurp.Image.Height) then
                    begin
                      Blurp.Y:=Blurp.Y-4;
                      AdSpriteEngine.Y:=AdSpriteEngine.Y+4;
                    end;
                end;
              if GetKeyState(VK_DOWN) < 0 then
                begin
                  if not Blurp.testForWall(Blurp.X,Blurp.Y+4,Blurp.Image.Width,Blurp.Image.Height) then
                    begin
                      Blurp.Y:=Blurp.Y+4;
                      AdSpriteEngine.Y:=AdSpriteEngine.Y-4;
                    end;
    Code:
    function TBlurp.testForWall(spriteXpos,spriteYpos:single;spriteWidth,spriteHeight:integer):boolean;
    begin
      testForWall := false;
      if not (TileInfo[round(spriteXpos) div 64, round(spriteYpos) div 64].tilenr in [2]) or not
      (TileInfo[(round(spriteXpos)+spriteWidth) div 64, round(spriteYpos) div 64].tilenr in [2]) or not
      (TileInfo[round(spriteXpos)div 64, (round(spriteYpos)+spriteHeight) div 64].tilenr in [2]) or not
      (TileInfo[(round(spriteXpos)+spriteWidth) div 64, (round(spriteYpos)+spriteHeight) div 64].tilenr in [2]) then testForWall :=true;
    end;
    Greetings
    Rob

Page 1 of 4 123 ... LastLast

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •